# realtystack-mcp

**Category:** 💻 Developer Tools  
**Repository:** https://github.com/IsaiahDupree/realtystack-mcp  
**Views:** 0  
**Installs:** 0  
**Upvotes:** 0  
**Directory Page:** https://allmcps.com/mcp/realtystack-mcp

## Description
U.S. real-estate data: property records, AVM value + rent estimates, sale/rental listings.

## Claude Desktop Quick Installation
Heuristic fallback — verify the package name and runner against the repository README before running it. Uses `npx` (confidence: low):

```json
"mcpServers": {
  "realtystack-mcp": {
    "command": "npx",
    "args": ["-y","realtystack-mcp"]
  }
}
```

## Documentation & README

# realtystack-mcp

A remote **MCP (Model Context Protocol)** connector for the **RealtyStack API** — U.S. real-estate data built on [RentCast](https://developers.rentcast.io/reference): property records search + single-record lookup, AVM sale-value and long-term-rent estimates with comparables, and active sale/rental listings, all in one flat `/v1` JSON contract.

**Upstream:** `https://realestate-api-kappa.vercel.app` (RealtyStack REST API) — 6 tools, one per `/v1` endpoint. Since the upstream deployment is metered (RapidAPI/Apify, and itself layered over RentCast's metered quota), this connector authenticates its own outbound calls with a server-side RapidAPI proxy secret (`REALTYSTACK_MCP_PROXY_SECRET`, sent as the `X-RapidAPI-Proxy-Secret` header) and applies a soft per-IP rate limit (`REALTYSTACK_MCP_RATE_LIMIT`, default 30 tool-calls/hour, in-memory) so this free MCP tier stays a discovery channel rather than an unmetered bypass of the paid listing — see `lib/ratelimit.js`.

## What this is, and why it's a separate connector

RealtyStack is a plain REST API. Any HTTP client can already call it directly. This repo exists because **MCP clients (Claude, ChatGPT, and other MCP-aware agents) don't consume arbitrary REST APIs — they consume MCP tools.** `realtystack-mcp` is a thin adapter layer that:

- Exposes each RealtyStack `/v1` endpoint as a discoverable, typed MCP **tool** (name, description, zod input schema, annotations) that an LLM can reason about and call directly, instead of having to be taught the REST surface out-of-band.
- Speaks the MCP **streamable-HTTP** transport at a single `/mcp` endpoint, so it can be registered as a connector in Claude, ChatGPT, or any other MCP client with one URL.
- Does nothing else. It has no business logic of its own — every tool call is a pass-through `fetch` to RealtyStack, and the JSON response RealtyStack returns is handed back verbatim as the tool result.

## Authentication: none on the MCP caller side (deliberate)

RealtyStack's data has **no per-user dimension** — it's objective real-estate data (property records, valuation estimates, listings). There is nothing to gate per-caller, so this connector intentionally ships with:

- No OAuth, no login, no bearer tokens from the MCP client
- No Supabase / database
- No demo-vs-real account split — every caller gets the same real, live data

`api/mcp.js` builds a fresh, stateless `McpServer` per request and serves it with zero MCP-caller auth checks.

### Upstream auth (outbound)

The *upstream* RealtyStack deployment gates every `/v1/*` route behind a RapidAPI proxy secret (see `realestate-api/src/guard.js`). This connector reaches real data by sending that same secret as the `X-RapidAPI-Proxy-Secret` header on its outbound `fetch` calls, read from the `REALTYSTACK_MCP_PROXY_SECRET` env var. Verified behavior: sending `X-RapidAPI-Proxy-Secret` passes the guard and returns real data; sending nothing returns `403 "This API is served through RapidAPI."`. This is an upstream monetization detail — it does not add any auth to *this* connector, which still has zero MCP-caller auth by design.

## Tool list

One tool per RealtyStack `/v1` endpoint (from `realestate-api/openapi.yaml`; `/api/health` is intentionally not wrapped):

| Tool | RealtyStack endpoint | Description |
|---|---|---|
| `search_properties` | `GET /v1/properties` | Search property records by address, city/state/zip, or lat/long radius, with structural filters. |
| `get_property` | `GET /v1/properties/{id}` | Full detail for one property record by its RentCast id. |
| `avm_value` | `GET /v1/avm/value` | AVM sale-value estimate (point + range) with scored comparable sales. |
| `avm_rent` | `GET /v1/avm/rent` | AVM long-term-rent estimate (point + range) with scored comparable rentals. |
| `search_sale_listings` | `GET /v1/listings/sale` | Active (or inactive) for-sale listings with MLS + agent/office contact. |
| `search_rental_listings` | `GET /v1/listings/rental` | Active (or inactive) long-term rental listings. |

All 6 tools are read-only GETs, annotated `{ readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true }` — none of them write anything, and all of them reflect live, externally-changing real-estate data.

## How it wraps realestate-api

Each tool handler does a plain `fetch(\`${REALTYSTACK_MCP_API_BASE_URL}${path}\`, ...)` against the real RealtyStack REST API (adding the `X-RapidAPI-Proxy-Secret` header when configured) and returns the parsed JSON as MCP tool-result content:

```js
{ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] }
```

Upstream HTTP errors (4xx/5xx) are caught and surfaced as a typed MCP error result via an `asError` helper rather than crashing the request.

### Environment variables

| Var | Purpose | Default |
|---|---|---|
| `REALTYSTACK_MCP_API_BASE_URL` | Upstream RealtyStack base URL | `https://realestate-api-kappa.vercel.app` |
| `REALTYSTACK_MCP_PROXY_SECRET` | Sent as `X-RapidAPI-Proxy-Secret` to pass the upstream guard | *(unset — 403 from guarded upstream)* |
| `REALTYSTACK_MCP_RATE_LIMIT` | Soft per-IP tools/call cap per hour | `30` |

## Project layout

```
api/mcp.js       MCP endpoint (StreamableHTTPServerTransport, stateless, no caller auth)
api/health.js    GET /api/health
lib/tools.js     All 6 tool definitions (zod schemas + fetch-and-forward handlers)
lib/ratelimit.js Soft in-memory per-IP tools/call cap
local-server.js  Plain-Node http server for local dev / smoke testing (not deployed)
test/smoke.mjs   Real end-to-end smoke test (initialize, tools/list, tools/call)
vercel.json      Routes /mcp -> api/mcp.js, /health -> api/health.js
server.json      MCP registry metadata
```

## Local development

```bash
npm install
npm run dev          # starts local-server.js on http://localhost:3900
```

Endpoints locally: `POST http://localhost:3900/mcp`, `GET http://localhost:3900/health`.

To hit real upstream data locally, set the proxy secret:

```bash
REALTYSTACK_MCP_PROXY_SECRET=<secret> npm run dev
```

## Smoke test

```bash
npm run dev &                 # terminal 1
npm run smoke                 # terminal 2
```

`test/smoke.mjs` drives the running server over real HTTP/JSON-RPC and verifies:

1. `GET /health` returns `{ ok: true, ... }`
2. `initialize` succeeds and reports `serverInfo.name === "realtystack"`
3. `tools/list` returns all 6 tools with their zod-derived JSON schemas
4. `tools/call` for `search_properties` exercises the tool end-to-end (when `REALTYSTACK_MCP_PROXY_SECRET` is set it asserts a real upstream result; without it, the tool-calling mechanics are still proven and the upstream's honest 403 guard response is accepted)

## Deploy

Not deployed by this build (verify first). Once verified:

```bash
cd /Users/isaiahdupree/Software/realtystack-mcp
npx vercel --yes --prod
```

After deploy, the MCP connector URL to register in Claude/ChatGPT/any MCP client is:

```
https://<deployment-domain>/mcp
```

