armls-spark-mcp-server
Enables Claude to query ARMLS Spark/FlexMLS real estate data including active listings, comparable sales, market statistics, and open houses via MCP tools.
README
ARMLS Spark MCP Server
Python proof-of-approach for connecting Claude to ARMLS Spark/FlexMLS data through MCP tools.
This project is scoped for an internal brokerage back-office Claude integration. It is not a public IDX display, and it does not include or claim access to live ARMLS data. Live operation requires valid ARMLS/Spark credentials, the client's license permissions, and field validation against the client's Spark metadata.
Current Status
This repository demonstrates the proposed MCP server shape before live ARMLS credentials are available:
- FastMCP-based Python server with Streamable HTTP transport.
- Starlette/Uvicorn ASGI deployment shape for Railway or Render.
- Environment-based configuration for Spark credentials and an optional generic MCP bearer guard.
- Spark API client abstraction with signed-session authentication helpers.
- Mock mode with synthetic Spark-shaped responses for demos and tests.
- Read-only MCP tool interfaces for listing search, listing lookup, comparable sales, market statistics, trends, and open houses.
- Focused tests for filters, signing helper behavior, config behavior, bearer auth parsing, and mock outputs.
This is not a completed production integration against live ARMLS data. The live implementation step is to validate Spark field names, endpoint access, and license-safe output fields using client-provided credentials.
MCP Tools
The server exposes or scaffolds these tools:
search_active_listings: search by city, ZIP, list price range, property type, and status.lookup_listing_by_mls_number: lookup by MLS number /ListingId.pull_comparable_sales: closed-sale comps by address or coordinates, radius, date range, and property type.get_market_statistics: price, DOM, sale-to-list ratio, and inventory statistics by city or ZIP.pull_active_vs_sold_trend: active-vs-sold inventory trend by city or ZIP.open_house_data_by_area: optional open-house lookup by city or ZIP using listing expansion.
Tool outputs are compacted before returning to Claude so responses stay usable in model context.
What Works In Mock Mode
Set SPARK_MOCK_MODE=true to run without Spark credentials. Mock mode returns synthetic data shaped like Spark responses and includes MockData=true markers in the payload.
Mock mode is useful for:
- Inspecting the MCP server and tool schemas.
- Testing Claude/Inspector connection behavior.
- Demonstrating expected tool output shape.
- Running local tests without ARMLS credentials.
Mock mode does not verify live ARMLS fields, live endpoint permissions, listing availability, or MLS compliance requirements.
What Requires Live Credentials
Set SPARK_MOCK_MODE=false and provide real Spark credentials to test live behavior:
- Spark session creation and signed requests.
- ARMLS Standard Fields names and searchable fields.
- Property type/status values available to the client's Spark role.
- Market statistics endpoint availability.
- Open house data access and date-window behavior.
- License-safe fields for internal brokerage use.
Setup
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
cp .env.example .env
The default .env.example runs in mock mode and does not require credentials.
Environment Variables
| Variable | Required | Notes |
|---|---|---|
SPARK_MOCK_MODE |
Yes | true for synthetic demo responses, false for live Spark calls. |
SPARK_API_KEY |
Live only | Client-provided Spark API key. |
SPARK_API_SECRET |
Live only | Client-provided Spark API secret. |
SPARK_API_BASE_URL |
Yes | Defaults to https://sparkapi.com. |
SPARK_API_VERSION |
Yes | Defaults to v1. |
SPARK_TIMEOUT_SECONDS |
Yes | HTTP timeout for Spark requests. |
MCP_AUTH_TOKEN |
Optional | Generic bearer guard for MCP clients that support custom Authorization headers. Not a direct Claude.ai static-token auth path. |
PORT |
Deploy/local | Defaults to 8000. Railway/Render may inject this. |
CORS_ALLOW_ORIGINS |
Optional | Comma-separated allowed browser origins if needed. |
Never commit a real .env file or live Spark credentials.
Run Locally
source .venv/bin/activate
armls-mcp
The server starts on:
http://localhost:8000
Useful endpoints:
GET /health: service health.GET /ready: lightweight readiness check.POST/GET /mcp: Streamable HTTP MCP endpoint.GET /sse: legacy SSE compatibility endpoint.
If MCP_AUTH_TOKEN is set, compatible MCP clients must send:
Authorization: Bearer <token>
This is useful for MCP Inspector, gateways, and clients that support custom headers. Claude.ai hosted custom connectors currently do not support user-pasted static bearer tokens.
Test
pytest
If using uv:
uv run pytest
Claude / MCP Connector Notes
For MCP Inspector:
npx -y @modelcontextprotocol/inspector
Choose Streamable HTTP and connect to:
http://localhost:8000/mcp
If MCP_AUTH_TOKEN is set for local testing, configure MCP Inspector with:
Authorization: Bearer <token>
For a hosted Claude connector, deploy the app over HTTPS and configure the connector URL as:
https://<service-host>/mcp
For Claude.ai hosted custom connectors, validate the connector authentication path before production. Current Claude connector documentation supports OAuth-style connector auth or no-auth servers; it does not support user-pasted static bearer tokens. The bearer guard in this repo should be treated as an interim proof-of-approach guard for Inspector, gateway testing, or non-Claude clients unless OAuth support is added.
Deployment Notes
Railway
- Create a new service from this repository.
- Set environment variables in Railway.
- Use the included
Procfile:web: armls-mcp. - Keep
SPARK_MOCK_MODE=trueuntil live credential testing begins. - For generic MCP clients, set
MCP_AUTH_TOKENbefore exposing the service URL. - For Claude.ai hosted connectors, validate OAuth-compatible auth or an approved no-auth/private access boundary before production.
Render
- Runtime: Python 3.11+.
- Build command:
pip install -e .. - Start command:
armls-mcp. - Set the same environment variables listed above.
- Ensure the public endpoint is HTTPS.
- Do not assume Claude.ai can pass a static bearer token; validate OAuth-compatible auth or an approved no-auth/private access boundary before production.
How To Add A New Tool
- Add a typed async function inside
register_tools()insrc/armls_mcp/tools.py. - Decorate it with
@mcp.tool(). - Keep inputs narrow and add Pydantic
Field()descriptions. - Use the Spark client abstraction instead of calling
httpxfrom the tool. - Compact large MLS responses before returning them to Claude.
- Add or update tests for filters, params, normalization, or mock output shape.
- Document any live Spark metadata assumptions.
Security Notes
- Keep all credentials in environment variables.
- Do not commit
.env, private planning material, or credential screenshots. - Use
MCP_AUTH_TOKENonly with clients or gateways that can send custom bearer headers. - For Claude.ai hosted connectors, implement an OAuth-compatible auth path or explicitly validate that no-auth mode is acceptable for the client's deployment boundary.
- Keep tool outputs read-only and compact.
- Do not expose private remarks, agent-only data, showing instructions, or other restricted MLS fields unless the client's ARMLS license explicitly permits it.
- Review ARMLS/FBS rules before enabling any consumer-facing or IDX-like use.
- Add rate limiting or gateway controls before broad team rollout.
Questions And Assumptions For Client Validation
- Which Spark product/access level will be used, and does it allow the required listing, sold, market statistics, and open-house endpoints?
- Which ARMLS Standard Fields should be used for status, MLS number, property type, address search, close date, close price, DOM, and ZIP/city filtering?
- Are closed sales and market statistics available under the client's credentials?
- Which fields are approved for internal Claude responses, and which must be suppressed?
- Should comparable-sale search resolve addresses from MLS data only, or should a licensed geocoding service be added later?
- What Claude connector auth mode should be used for production: OAuth/DCR/CIMD, Anthropic-held credentials, gateway-level controls, or a no-auth server behind an approved boundary?
- What token rotation, access logging, and team access controls are required before production rollout?
Additional Documentation
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。