stoop
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@stoopFind me a one-bedroom under $3,500 within ten minutes of the Bedford L, cats allowed."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
stoop
Your AI agent hunts NYC apartments. Tell it where you want to live (a neighborhood, a subway stop, ten minutes from the office), your budget and what you can't live without, and it searches live StreetEasy rentals, checks each building's public record for violations, heat complaints, bedbugs and evictions, and brings back the ones worth touring. This Worker makes that happen: deploy it to your own Cloudflare account and any MCP agent gets seven tools, with a daily cap on the requests that cost money.
Unofficial. Not affiliated with StreetEasy. Listing data comes from the private endpoints the StreetEasy website uses; they can change without notice, and you are responsible for your own use and for StreetEasy's terms. Building records come from NYC Open Data and FEMA and describe the whole building, not the unit. The software is provided as is, without warranty of any kind, and its authors are not responsible for how anyone uses it. See LICENSE.
Get started
1. Deploy.
The button clones this repo into your GitHub, creates the storage it needs, asks for the three required secrets (an admin password, a cookie signing key and a Zyte API key), and deploys. Or from a terminal:
git clone https://github.com/jitpal/stoop.git && cd stoop && npm install
npx wrangler login
npm run deploy # creates the KV namespace and the Durable Object
npx wrangler secret put ADMIN_PASSWORD # your sign-in for the admin pages
npx wrangler secret put COOKIE_SIGNING_KEY # openssl rand -hex 32
npx wrangler secret put ZYTE_API_KEY # or another provider, see belowTo check the provider before deploying, ZYTE_API_KEY=... npm run smoke sends one search and one listing lookup (2 requests) and prints PASS or what came back. Open https://<your-worker>/healthz afterwards: ok: true means config, secrets and storage are in place.
2. Give your agent access. Open https://<your-worker>/admin, sign in, create an API key on /admin/keys, and add the server:
claude mcp add --transport http stoop https://<your-worker>/mcp \
--header "Authorization: Bearer stoop_..."Or use OAuth instead of a key. Run the same command without the header and approve it in the browser with the same password. claude.ai, ChatGPT and other hosted connectors only support OAuth.
3. Ask. "Find me a one-bedroom under $3,500 within ten minutes of the Bedford L, cats allowed." "Anything no-fee in Greenpoint available by November 1?" "Pull the building record for the second one before I go see it."
Related MCP server: Idealista7 MCP Server
What the agent can do
Tool | What it does | Cost |
| Rentals by | 1 upstream request per StreetEasy page (usually 1–3), cached 15 min |
| Everything about one listing: description, features, pet policy, price history, days on market, neighborhood median, photos, floor plans, nearest stations, building-record summary. | 1 upstream request, cached 6 h |
| Full public record for a listing or any NYC address: overview (PLUTO), HPD violations, 311 complaints with heat by season, bedbugs, evictions, DOB violations, permits and scaffolding, owner and managing agent, FEMA flood zone. | Free with an address |
| "the Bedford L", "Atlantic Terminal", "14th St Union Square" → station, lines, neighborhood. | Free |
| Reference lookups. | Free |
| Provider in use and today's upstream request count. | Free |
Safety
An agent with access to this spends paid proxy requests on your behalf, so the defaults keep that small and visible.
A hard daily cap.
MAX_UPSTREAM_REQUESTS_PER_DAY(default 300, retries included) is counted in a Durable Object before every attempt, so it holds even when searches run at once. One search scans at mostMAX_PAGES_PER_SEARCHpages, and repeat questions come from the cache for free.Read-only. No tool contacts a landlord or broker, applies, or books a tour. The agent gets the listing URL and you take it from there.
Keys are revocable. Revoke any key with one click on
/admin/keys. Only a hash of each key is stored.Your provider key never reaches the model. It lives in Cloudflare secrets and is used only by the Worker.
An audit log. Every tool call is recorded on
/admin/auditwith who made it, the arguments, the outcome and how many paid requests it spent./adminshows today's usage.Facts, not verdicts. Building reports give counts with dates and sources. A flag of
nullmeans it could not be checked, not that the building is clean, and the agent is told so.
How it works
You deploy the Worker to your own Cloudflare account. The agent authenticates to the Worker, and every tool call becomes requests to StreetEasy through your provider and to the city's open data, with keys, caps, the cache and the audit log in a Durable Object.
sequenceDiagram
participant A as Agent
participant W as Worker
participant D as Durable Object
participant P as Provider
participant S as StreetEasy
participant O as NYC Open Data
A->>W: tool call with API key or OAuth token
W->>D: key check, daily cap, cache
W->>P: search or listing request
P->>S: from an IP StreetEasy accepts
W->>O: building records (free)
W->>D: audit row
W-->>A: listings, distances, building flagsStreetEasy only filters by neighborhood, so location search is stoop's own: it finds the point (station table, landmark table or NYC Geosearch), searches every neighborhood the radius could touch in one request, and keeps listings whose own coordinates are inside the radius. Walking time is estimated from straight-line distance (× 1.3, 80 m/min). Design and trade-offs are in docs/DESIGN.md.
Reaching StreetEasy: providers
StreetEasy blocks datacenter IPs, so the Worker sends its StreetEasy requests through a provider. Switch with one var, UPSTREAM_PROVIDER:
Provider | Secrets | Notes |
|
| Zyte API with a custom POST body and headers. Verified live. |
|
| Web Unlocker REST API. POST pass-through untested; run the smoke test first. |
|
| Your own relay on a home connection: |
| none | Plain fetch. Only works from a residential IP, e.g. |
Adding another provider is one function in src/upstream/providers.ts.
Configuration
Vars live in wrangler.jsonc, secrets in wrangler secret put (or .dev.vars for npm run dev; see .dev.vars.example). For your own deployment, copy wrangler.jsonc to wrangler.local.jsonc (gitignored); every npm run script prefers it, so a custom domain (routes plus PUBLIC_BASE_URL) or tuned limits never touch the committed file.
Name | Kind | Default | Purpose |
| var |
|
|
| var |
| Daily cap on provider attempts (UTC day), or |
| var |
| Retries after a bot challenge |
| var |
| Pages one location search may scan (50 listings each) |
| var |
| Web Unlocker zone |
| var | empty | Custom domain, if any |
| secret | required | Signs you in at |
| secret | required | Signs the admin cookie and approval forms (32 bytes, hex) |
| secret | per provider | |
| secret | optional | Higher NYC Open Data rate limits |
Plan note: a search can make up to ~40 outbound requests (StreetEasy pages, one geocode per new building, a few Open Data queries). The free Workers plan allows 50 subrequests per request, which covers light personal use; the $5 paid plan raises it. Cache fills and audit rows are Durable Object SQLite writes, which the free plan allows by the hundred thousand a day.
What it does not do
Contact landlords or brokers, apply, or book tours. By design.
Sales listings. Rentals only.
Anywhere outside the five boroughs.
Transit routing. Walk times are estimated from straight-line distance, and "near the L" means near a station on it, not a commute time.
Promise a listing is still available or accurate. It is what StreetEasy showed at the time, cached for up to 15 minutes.
Development
npm run dev # local Worker on :8787 (UPSTREAM_PROVIDER=direct works from home)
npm run check # biome + tsc + vitest (tests never touch the network)
npm run check-datasets # confirm every public dataset and column still existsBundled data is regenerated by scripts; see docs/DATA.md.
Docs
Design · Data sources · Security policy
A personal project
This is built for my own use and shared as is. Bug reports are welcome as issues. Pull requests are not accepted and are closed automatically; fork it and change whatever you like, the license allows it. Security problems can be reported privately, see SECURITY.md.
Thanks
The StreetEasy query shapes are adapted from evandcoleman/streeteasy-api and Alec2435/streeteasy-mcp (both MIT). Building records come from NYC Open Data, addresses from NYC Geosearch, flood zones from FEMA's National Flood Hazard Layer, stations from the MTA's GTFS feed, and neighborhood shapes from HodgesWardElliott/custom-nyc-neighborhoods. None are affiliated with this project.
MIT. See LICENSE.
This server cannot be deployed
Maintenance
Related MCP Connectors
Search NYC rentals and sales, property details, building data, and market analytics
Building intelligence for NYC, LA, Chicago rentals: violations, 311, reviews, rents, landlords.
Pull property listings, prices, and details from real-estate sites as structured JSON.
Agent-ready NYC public records. Hosted, source-backed civic data organized around durable anchors.
Related MCP Servers
- FlicenseBqualityNot gradedmaintenanceEnables AI assistants to search and analyze Swedish real estate data from Booli.se using natural language queries. Supports property searches with comprehensive filtering options and location discovery through GraphQL API integration.31-
- AlicenseCqualityDmaintenanceEnables access to Idealista API for searching and retrieving property listings across Spain, Portugal, and Italy. Supports various property types including homes, apartments, garages, commercial properties, offices, and land with detailed filtering options.143MIT
- FlicenseAqualityDmaintenanceA remote MCP server that wraps the StreetEasy GraphQL API to enable LLM agents to search and parse NYC rental listings.41-
- AlicenseAqualityBmaintenanceEnables AI agents to search Dutch housing listings on Kamernet.nl, retrieve full listing details, and optionally reply to landlords; designed for personal use in finding rooms, studios, and apartments.31MIT