DEV Community

Sergey Ermakovich for HasData

Posted on

Zillow MCP Server Comparison: 6 Tested, 3 Actually Work

The task was small. An agent in Claude Code that, given "two-bedroom rentals in Denver under $2,500", lists what is on Zillow right now and pulls the full record for anything we like. Zillow has no API for that and no MCP server of its own, so the work is choosing a third-party MCP server. We wired up six of them on 2026-09-09, ran the same rental search through each three times, and kept notes. The setup for each, what came back, and what broke.

The test

One search, rentals in Denver, CO, three calls per server, from the official MCP TypeScript SDK as a client with a 240 second timeout. We counted a call as failed when the tool returned an error, when it returned an error dressed as a normal result, or when it returned an empty list. Latency is the median of the successful calls.

| Server                  | Setup            | Denver rentals, 3 calls                      | p50    |
|-------------------------|------------------|----------------------------------------------|--------|
| HasData Zillow MCP      | hosted, API key  | 3/3, 41 rentals x 21 fields, 159 KB JSON     | 5.4 s  |
| Apify, afanasenko actor | hosted, token    | 3/3, 15 rentals x 77 fields, 42 KB JSON      | 7.2 s  |
| Apify, maxcopell actor  | hosted, token    | 3/3 in two calls, 40 rentals x 17 fields, 168 KB | 13.0 s |
| APIllow                 | local, uvx, key  | 3/3 answered, 5 results with sale prices     | 16.5 s |
| @striderlabs/mcp-zillow | local, from src  | 3/3 answered, total_found: 0                 | 4.2 s  |
| chrischall/zillow-mcp   | local, npx       | 0/6, needs your logged-in browser            | n/a    |
Enter fullscreen mode Exit fullscreen mode

1. HasData

HasData's Zillow server is hosted, streamable HTTP, two tools. Add it to Claude Code with the key in a header:

claude mcp add --transport http zillow "https://mcp.hasdata.com/api/mcp?apis=zillow" \
  --header "x-api-key: $HASDATA_API_KEY"
Enter fullscreen mode Exit fullscreen mode

The search tool takes a place name and a type, so the benchmark call was {"keyword": "Denver, CO", "type": "forRent"} with no translation step, the same broad query every server got. It came back in 3.5 to 8.7 seconds with 41 rentals and 21 fields each, price, beds, baths, area, address, days on Zillow, home type, the listing URL, and a total-results count. The tool also has the filters the agent needs, so the real task is one call with beds_min_ and price_max_ set, and Zillow does the narrowing:

// request
{"keyword": "Denver, CO", "type": "forRent", "beds_min_": 2, "price_max_": 2500}

// response, first listing of 41 (3,647 total)
{"id": "465129302", "price": 1595, "beds": 2, "baths": 1, "area": 805,
 "addressRaw": "975-979 S Lowell Blvd #977, Denver, CO 80219", "daysOnZillow": 0, "homeType": "APARTMENT"}
Enter fullscreen mode Exit fullscreen mode

Every listing that carried a price was two bedrooms or more and $2,500 or less. Some rows are apartment buildings rather than units, with price, beds and baths as null and only an address, so the agent has to skip those or open them. The three calls returned byte-identical payloads within a minute, which reads like a short server-side cache. The property tool takes the listing URL from the search result, so the "pull the full record" half of the task is one more call, 33 fields.

The payload is the largest of the working servers, 159 KB for the page. That is the whole listing object per rental. If the agent only needs price and address it is reading more than it uses, and there is no field selector on the search tool.

Billing is one call per page whatever the page returns, 200 calls a month free and renewing, then $59 a month for 40,000 calls. For this agent that is one call per search plus one per record you open.

2. Apify, the afanasenko Zillow actor

Apify exposes any actor in its store as an MCP tool through one hosted endpoint. You pick the actors in the URL:

claude mcp add --transport http apify-zillow "https://mcp.apify.com/?tools=afanasenko/zillow-mcp-server" \
  --header "Authorization: Bearer $APIFY_TOKEN"
Enter fullscreen mode Exit fullscreen mode

This actor has three tools, search by ZIP or place, search by any Zillow URL, and lookup by zpid. Denver rentals went in as a Zillow rentals URL. It returned 15 rentals with 77 fields each, the richest per-listing record of the set, 42 KB, in 6.7 to 13.4 seconds. The first fields on a Denver result were price, status, home type, coordinates, a description with the floor plans and the listing URL, and the tool's own description promises agent contact, Zestimates, HOA, tax and price history further down the record. Each call is a fresh actor run on Apify's side, so the latency floor is the run spin-up. On a ZIP search the same actor took 25 and 45 seconds for two calls and the third ran into a 120 second wall and errored.

Cost is Apify platform usage per run, and it differs a lot between actors. Six afanasenko searches across two scenarios consumed $5.25 of a $5 free month, about 87 cents a search, while three maxcopell two-step searches cost 28 cents together, about 9 cents each. The free tier is a demo for the first actor and a month of light use for the second. The afanasenko actor caps at 15 results per call in this configuration, so a 41-listing page is three calls.

3. Apify, the maxcopell Zillow scraper

Same endpoint, different actor, and a different shape. maxcopell/zillow-scraper takes a Zillow search URL that must contain searchQueryState, plus an extraction method, and returns run metadata, not listings. The listings land in a dataset that you fetch with the get-dataset-items tool in a second call, and the id for that call sits at storages.datasets.default.id in the first response. Our first attempt read the wrong field and the second call failed three times. With the right path the pair of calls completed three out of three in 12.4 to 14.5 seconds and returned 40 rentals with 17 fields each, 168 KB, the most listings per search of any server here. An agent using this actor has to know the two-step protocol, and the first response gives it nothing to reason about except a status line that says "scraped 40 items".

4. APIllow

A Zillow-only vendor with a PyPI package. The README's uvx apillow-mcp crashes on a current Python MCP SDK because the package imports FastMCP from a location that SDK 2.x renamed. Pin the SDK and it starts:

claude mcp add apillow -e APILLOW_API_KEY=$APILLOW_API_KEY -- uvx --with "mcp<2" apillow-mcp
Enter fullscreen mode Exit fullscreen mode

Ten tools, seven for data (search by city, ZIP, zpid, URL, address, batch, address check). The Denver call was search_properties with type: for_rent. It answered three out of three in 7 to 17 seconds with status: complete and five properties. The prices were $525,000 and $975,000, which are sale prices, and the records had last_sold_price fields, so the rental filter did not apply and the agent got five houses for sale. The server submits a job and polls, which is where the time goes, and one earlier search hit the vendor's own 120 second job timeout.

Fifty properties a month are free, then $9.99 for 3,333. It bills per property returned, including the five wrong ones. After the allowance it keeps answering 200 with {"error": "Rate limit or quota exceeded"} in the body.

5. @striderlabs/mcp-zillow

An open-source server with Playwright and a stealth plugin, no key. npx -y @striderlabs/mcp-zillow fails because the npm package ships src/index.ts and no dist. Cloned and built it starts in under a second with five tools, search_homes, search_rentals, get_listing, get_estimates, save_home. search_rentals for Denver returned in 3 to 5 seconds with total_found: 0 all three times, and the same for sales in Phoenix and a Miami Beach ZIP. Zillow is serving its headless Chromium an empty results page, so the server is free and so is its output.

6. chrischall/zillow-mcp

The most downloaded Zillow MCP package on npm, about 1,400 a month, with 20 tools including mortgage math and saved searches. It is in the table as six failures because it cannot run where Claude Code runs. Every tool goes through a WebSocket bridge to a browser extension that uses your logged-in zillow.com session, and without a signed-in Chrome next to the client every call fails with "no confirmed browser session". Six of six here. If you only ever run Claude Desktop on the laptop where you browse Zillow, it may be the most capable free option. For anything headless it is not an option.

The build-it-yourself path

HomeHarvest is a 739-star Python library that scrapes Zillow, Realtor.com and Redfin into a DataFrame, and it is the usual answer when someone asks how to get Zillow data without a vendor. It is not an MCP server. Wrapping it in one is an afternoon with the Python SDK, and then the anti-bot problem the striderlabs server hit is yours. That is the trade, and it is the same trade every hosted server above is charging for.

What we kept

For the rental agent, HasData. Place name in, 41 rentals out, one call, every time, and the property record is the same key and one more call. The Apify actor is the one to keep around for the record depth, 77 fields per listing, when the agent already knows what it wants and can afford seven seconds and a metered run per lookup. APIllow needs a fix to its rental filter before it belongs in a rental agent. The two open-source servers that show up next to these in the catalogs are, today, a package that does not install and a package that installs and returns nothing.

All of it is one afternoon's measurement from one machine, three calls per server, and vendors change. Rerun before you commit.

Top comments (1)

Collapse
 
jo-do profile image
Jo Do

Counting an error-shaped normal result as failure is the right benchmark choice. I would also separate transport success, semantic success, and freshness. A server can answer 3/3 with valid-looking stale listings, so each result needs an observed-at time and a small sample rechecked against the source. Otherwise reliability and correctness collapse into one misleading percentage.