zillow-mcp 0.1.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +7 -7
- package/dist/bundle.js +119 -58
- package/package.json +1 -1
- package/server.json +3 -3
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
},
|
|
8
8
|
"metadata": {
|
|
9
9
|
"description": "MCP server for Zillow — search listings, fetch property details, Zestimate history, saved searches & homes, market reports. Routes through the user's signed-in zillow.com tab via the fetchproxy browser extension to dodge bot detection.",
|
|
10
|
-
"version": "0.1
|
|
10
|
+
"version": "0.2.1"
|
|
11
11
|
},
|
|
12
12
|
"plugins": [
|
|
13
13
|
{
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"displayName": "Zillow",
|
|
16
16
|
"source": "./",
|
|
17
17
|
"description": "MCP server for Zillow — search listings, get property details, Zestimate history, saved searches & homes, market reports",
|
|
18
|
-
"version": "0.1
|
|
18
|
+
"version": "0.2.1",
|
|
19
19
|
"author": {
|
|
20
20
|
"name": "Chris Hall"
|
|
21
21
|
},
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zillow-mcp",
|
|
3
3
|
"displayName": "Zillow",
|
|
4
|
-
"version": "0.1
|
|
4
|
+
"version": "0.2.1",
|
|
5
5
|
"description": "Zillow real-estate access for Claude — search listings, get property details, Zestimate history, your saved searches & homes, market reports",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Chris Hall",
|
package/README.md
CHANGED
|
@@ -17,13 +17,13 @@ None of them can see what *you* have saved, favorited, or recently viewed — be
|
|
|
17
17
|
|
|
18
18
|
| Tool | Purpose | Auth-scoped |
|
|
19
19
|
| --- | --- | :---: |
|
|
20
|
-
| `zillow_search_properties` | Search listings by location
|
|
21
|
-
| `zillow_get_property` | Full record for a zpid (price, Zestimate, beds, schools, history) | |
|
|
22
|
-
| `zillow_get_zestimate_history` | Time series of Zestimate values | |
|
|
23
|
-
| `zillow_get_saved_searches` | Your saved searches with new-listing counts | ✓ |
|
|
24
|
-
| `zillow_get_saved_homes` | Your favorited homes | ✓ |
|
|
25
|
-
| `zillow_get_market_report` | Median
|
|
26
|
-
| `zillow_calculate_mortgage` | Local PITI calculator (no network) | |
|
|
20
|
+
| `zillow_search_properties` | Search listings by location, status, price band, beds/baths, home type | |
|
|
21
|
+
| `zillow_get_property` | Full record for a zpid (price, Zestimate, beds, schools, neighborhood, price history) | |
|
|
22
|
+
| `zillow_get_zestimate_history` | Time series of Zestimate values (and rent Zestimate where available) | |
|
|
23
|
+
| `zillow_get_saved_searches` | Your saved searches with new-listing counts and notification frequency | ✓ |
|
|
24
|
+
| `zillow_get_saved_homes` | Your favorited homes with current price + Zestimate | ✓ |
|
|
25
|
+
| `zillow_get_market_report` | Median sale/list/rent, days on market, inventory, ZHVI for a region | |
|
|
26
|
+
| `zillow_calculate_mortgage` | Local PITI calculator — principal+interest, taxes, insurance, HOA, PMI (no network) | |
|
|
27
27
|
|
|
28
28
|
## Install
|
|
29
29
|
|
package/dist/bundle.js
CHANGED
|
@@ -34704,10 +34704,7 @@ var ZillowClient = class {
|
|
|
34704
34704
|
);
|
|
34705
34705
|
}
|
|
34706
34706
|
throwIfSignInPage(result) {
|
|
34707
|
-
const
|
|
34708
|
-
const looksLikeSignIn = /\/user\/login/.test(result.url) || /[?&]login=true/.test(result.url) || signInMarkers.some(
|
|
34709
|
-
(m) => result.body.includes(m) && result.body.length < 8e4
|
|
34710
|
-
);
|
|
34707
|
+
const looksLikeSignIn = /\/user\/login/.test(result.url) || /[?&]login=true/.test(result.url) || result.body.includes("captcha-delivery") && result.body.length < 8e4;
|
|
34711
34708
|
if (looksLikeSignIn) throw new SessionNotAuthenticatedError();
|
|
34712
34709
|
}
|
|
34713
34710
|
};
|
|
@@ -36763,8 +36760,14 @@ function registerSearchTools(server2, client2) {
|
|
|
36763
36760
|
server2.registerTool(
|
|
36764
36761
|
"zillow_search_properties",
|
|
36765
36762
|
{
|
|
36766
|
-
|
|
36767
|
-
|
|
36763
|
+
title: "Search Zillow listings",
|
|
36764
|
+
description: "Search Zillow listings by location (city, ZIP, neighborhood, or address) and optional filters (status, price band, beds/baths minimums, home types). Returns matching properties with price, beds/baths, sqft, Zestimate, status, image, and homedetails URL. Does NOT return Zestimate history \u2014 use zillow_get_zestimate_history for that. Read-only; safe to call repeatedly.",
|
|
36765
|
+
annotations: {
|
|
36766
|
+
title: "Search Zillow listings",
|
|
36767
|
+
readOnlyHint: true,
|
|
36768
|
+
idempotentHint: true,
|
|
36769
|
+
openWorldHint: true
|
|
36770
|
+
},
|
|
36768
36771
|
inputSchema: {
|
|
36769
36772
|
location: external_exports.string().describe(
|
|
36770
36773
|
'Free-text location: city, ZIP, neighborhood, or address (e.g. "Brooklyn, NY", "94110", "Park Slope")'
|
|
@@ -36833,6 +36836,16 @@ function getPageProps(nextData) {
|
|
|
36833
36836
|
return pageProps ?? {};
|
|
36834
36837
|
}
|
|
36835
36838
|
|
|
36839
|
+
// src/url.ts
|
|
36840
|
+
function urlToPath(input) {
|
|
36841
|
+
try {
|
|
36842
|
+
const u = new URL(input);
|
|
36843
|
+
return `${u.pathname}${u.search}`;
|
|
36844
|
+
} catch {
|
|
36845
|
+
return input.startsWith("/") ? input : `/${input}`;
|
|
36846
|
+
}
|
|
36847
|
+
}
|
|
36848
|
+
|
|
36836
36849
|
// src/tools/properties.ts
|
|
36837
36850
|
function findPropertyInPageProps(pageProps) {
|
|
36838
36851
|
const cacheRaw = pageProps.gdpClientCache ?? pageProps.componentProps?.gdpClientCache;
|
|
@@ -36843,23 +36856,19 @@ function findPropertyInPageProps(pageProps) {
|
|
|
36843
36856
|
} catch {
|
|
36844
36857
|
return null;
|
|
36845
36858
|
}
|
|
36859
|
+
for (const [key, v] of Object.entries(cache)) {
|
|
36860
|
+
if (key.startsWith("Property:") && v && typeof v === "object" && v.property) {
|
|
36861
|
+
return v.property;
|
|
36862
|
+
}
|
|
36863
|
+
}
|
|
36846
36864
|
for (const v of Object.values(cache)) {
|
|
36847
36865
|
if (v && typeof v === "object" && v.property) return v.property;
|
|
36848
36866
|
}
|
|
36849
36867
|
return null;
|
|
36850
36868
|
}
|
|
36851
36869
|
function buildPath(args) {
|
|
36852
|
-
if (args.url)
|
|
36853
|
-
|
|
36854
|
-
const u = new URL(args.url);
|
|
36855
|
-
return `${u.pathname}${u.search}`;
|
|
36856
|
-
} catch {
|
|
36857
|
-
return args.url.startsWith("/") ? args.url : `/${args.url}`;
|
|
36858
|
-
}
|
|
36859
|
-
}
|
|
36860
|
-
if (args.zpid !== void 0) {
|
|
36861
|
-
return `/homedetails/${args.zpid}_zpid/`;
|
|
36862
|
-
}
|
|
36870
|
+
if (args.url) return urlToPath(args.url);
|
|
36871
|
+
if (args.zpid !== void 0) return `/homedetails/${args.zpid}_zpid/`;
|
|
36863
36872
|
throw new Error("zillow_get_property: must provide either zpid or url");
|
|
36864
36873
|
}
|
|
36865
36874
|
function format(raw) {
|
|
@@ -36869,6 +36878,7 @@ function format(raw) {
|
|
|
36869
36878
|
zpid,
|
|
36870
36879
|
url: url2,
|
|
36871
36880
|
address: raw.address,
|
|
36881
|
+
neighborhood: raw.address?.neighborhood,
|
|
36872
36882
|
price: raw.price,
|
|
36873
36883
|
zestimate: raw.zestimate,
|
|
36874
36884
|
rent_zestimate: raw.rentZestimate,
|
|
@@ -36895,8 +36905,14 @@ function registerPropertyTools(server2, client2) {
|
|
|
36895
36905
|
server2.registerTool(
|
|
36896
36906
|
"zillow_get_property",
|
|
36897
36907
|
{
|
|
36898
|
-
|
|
36899
|
-
|
|
36908
|
+
title: "Get Zillow property details",
|
|
36909
|
+
description: "Fetch a property's full Zillow record by zpid (numeric Zillow Property ID, e.g. 12345) or by homedetails URL. Returns address, neighborhood, price, Zestimate, rent Zestimate, beds/baths, square footage, year built, schools, and price history. Provide exactly one of zpid or url. Read-only; safe to call repeatedly.",
|
|
36910
|
+
annotations: {
|
|
36911
|
+
title: "Get Zillow property details",
|
|
36912
|
+
readOnlyHint: true,
|
|
36913
|
+
idempotentHint: true,
|
|
36914
|
+
openWorldHint: true
|
|
36915
|
+
},
|
|
36900
36916
|
inputSchema: {
|
|
36901
36917
|
zpid: external_exports.union([external_exports.number().int().positive(), external_exports.string()]).optional().describe("Zillow Property ID (numeric)"),
|
|
36902
36918
|
url: external_exports.string().optional().describe("A Zillow homedetails URL (or path beginning with /homedetails/)")
|
|
@@ -36949,48 +36965,76 @@ function registerZestimateTools(server2, client2) {
|
|
|
36949
36965
|
server2.registerTool(
|
|
36950
36966
|
"zillow_get_zestimate_history",
|
|
36951
36967
|
{
|
|
36952
|
-
|
|
36953
|
-
|
|
36968
|
+
title: "Get Zestimate history for a property",
|
|
36969
|
+
description: "Historical Zestimate values for a property by zpid or homedetails URL. Returns a time series of {date, value, rent?} entries (rent included when Zillow has a rent Zestimate for the property). Note: zillow_get_property returns only the *current* Zestimate as a scalar \u2014 call this tool when you need the trend. Read-only; safe to call repeatedly.",
|
|
36970
|
+
annotations: {
|
|
36971
|
+
title: "Get Zestimate history for a property",
|
|
36972
|
+
readOnlyHint: true,
|
|
36973
|
+
idempotentHint: true,
|
|
36974
|
+
openWorldHint: true
|
|
36975
|
+
},
|
|
36954
36976
|
inputSchema: {
|
|
36955
|
-
zpid: external_exports.union([external_exports.number().int().positive(), external_exports.string()]).describe("Zillow Property ID")
|
|
36977
|
+
zpid: external_exports.union([external_exports.number().int().positive(), external_exports.string()]).optional().describe("Zillow Property ID. Provide either zpid or url."),
|
|
36978
|
+
url: external_exports.string().optional().describe(
|
|
36979
|
+
"Zillow homedetails URL (or path). Provide either zpid or url."
|
|
36980
|
+
)
|
|
36956
36981
|
}
|
|
36957
36982
|
},
|
|
36958
|
-
async ({ zpid }) => {
|
|
36959
|
-
const
|
|
36983
|
+
async ({ zpid, url: url2 }) => {
|
|
36984
|
+
const path = url2 ? urlToPath(url2) : zpid !== void 0 ? `/homedetails/${zpid}_zpid/` : null;
|
|
36985
|
+
if (!path) {
|
|
36986
|
+
throw new Error(
|
|
36987
|
+
"zillow_get_zestimate_history: must provide either zpid or url"
|
|
36988
|
+
);
|
|
36989
|
+
}
|
|
36990
|
+
const html = await client2.fetchHtml(path);
|
|
36960
36991
|
const nextData = extractNextData(html);
|
|
36961
36992
|
const pageProps = getPageProps(nextData);
|
|
36962
36993
|
const property = findPropertyInPageProps(pageProps);
|
|
36963
36994
|
if (!property) {
|
|
36964
36995
|
throw new Error(
|
|
36965
|
-
`Could not locate property data in __NEXT_DATA__
|
|
36996
|
+
`Could not locate property data in __NEXT_DATA__ at ${path}.`
|
|
36966
36997
|
);
|
|
36967
36998
|
}
|
|
36968
36999
|
const series = extractZestimateHistory(property);
|
|
36969
|
-
return textResult({
|
|
37000
|
+
return textResult({
|
|
37001
|
+
zpid: String(property.zpid ?? zpid ?? ""),
|
|
37002
|
+
points: series
|
|
37003
|
+
});
|
|
36970
37004
|
}
|
|
36971
37005
|
);
|
|
36972
37006
|
}
|
|
36973
37007
|
|
|
36974
|
-
// src/
|
|
36975
|
-
function
|
|
36976
|
-
const
|
|
36977
|
-
|
|
37008
|
+
// src/page-props.ts
|
|
37009
|
+
function findArrayByShape(pageProps, directKeys, shapeMatches) {
|
|
37010
|
+
for (const key of directKeys) {
|
|
37011
|
+
const candidate = pageProps[key];
|
|
37012
|
+
if (Array.isArray(candidate)) return candidate;
|
|
37013
|
+
}
|
|
36978
37014
|
for (const v of Object.values(pageProps)) {
|
|
36979
|
-
if (Array.isArray(v) && v.length > 0 && typeof v[0] === "object" && v[0] !== null && (
|
|
37015
|
+
if (Array.isArray(v) && v.length > 0 && typeof v[0] === "object" && v[0] !== null && shapeMatches(v[0])) {
|
|
36980
37016
|
return v;
|
|
36981
37017
|
}
|
|
36982
37018
|
}
|
|
36983
37019
|
return [];
|
|
36984
37020
|
}
|
|
37021
|
+
|
|
37022
|
+
// src/tools/saved.ts
|
|
37023
|
+
var SAVED_SEARCH_KEYS = ["savedSearches", "userSavedSearches"];
|
|
37024
|
+
var SAVED_HOME_KEYS = ["savedHomes", "userSavedHomes", "favoriteHomes"];
|
|
37025
|
+
function findSavedSearches(pageProps) {
|
|
37026
|
+
return findArrayByShape(
|
|
37027
|
+
pageProps,
|
|
37028
|
+
SAVED_SEARCH_KEYS,
|
|
37029
|
+
(el) => "searchQueryState" in el || "filterState" in el
|
|
37030
|
+
);
|
|
37031
|
+
}
|
|
36985
37032
|
function findSavedHomes(pageProps) {
|
|
36986
|
-
|
|
36987
|
-
|
|
36988
|
-
|
|
36989
|
-
|
|
36990
|
-
|
|
36991
|
-
}
|
|
36992
|
-
}
|
|
36993
|
-
return [];
|
|
37033
|
+
return findArrayByShape(
|
|
37034
|
+
pageProps,
|
|
37035
|
+
SAVED_HOME_KEYS,
|
|
37036
|
+
(el) => "zpid" in el && ("hdpUrl" in el || "savedAt" in el)
|
|
37037
|
+
);
|
|
36994
37038
|
}
|
|
36995
37039
|
function formatSearch(raw) {
|
|
36996
37040
|
return {
|
|
@@ -37025,8 +37069,14 @@ function registerSavedTools(server2, client2) {
|
|
|
37025
37069
|
server2.registerTool(
|
|
37026
37070
|
"zillow_get_saved_searches",
|
|
37027
37071
|
{
|
|
37028
|
-
|
|
37029
|
-
|
|
37072
|
+
title: "Get my saved Zillow searches",
|
|
37073
|
+
description: "The signed-in user's saved searches on zillow.com (name, filters, new-listing count, notification frequency). Requires the user to be signed in at zillow.com in the bridged browser tab \u2014 throws SessionNotAuthenticatedError otherwise. Read-only; safe to call repeatedly.",
|
|
37074
|
+
annotations: {
|
|
37075
|
+
title: "Get my saved Zillow searches",
|
|
37076
|
+
readOnlyHint: true,
|
|
37077
|
+
idempotentHint: true,
|
|
37078
|
+
openWorldHint: true
|
|
37079
|
+
},
|
|
37030
37080
|
inputSchema: {}
|
|
37031
37081
|
},
|
|
37032
37082
|
async () => {
|
|
@@ -37040,8 +37090,14 @@ function registerSavedTools(server2, client2) {
|
|
|
37040
37090
|
server2.registerTool(
|
|
37041
37091
|
"zillow_get_saved_homes",
|
|
37042
37092
|
{
|
|
37043
|
-
|
|
37044
|
-
|
|
37093
|
+
title: "Get my saved (favorited) Zillow homes",
|
|
37094
|
+
description: "The signed-in user's saved (favorited) homes on zillow.com. Returns address, price, Zestimate, status, and when each home was saved. Requires the user to be signed in. Read-only; safe to call repeatedly.",
|
|
37095
|
+
annotations: {
|
|
37096
|
+
title: "Get my saved (favorited) Zillow homes",
|
|
37097
|
+
readOnlyHint: true,
|
|
37098
|
+
idempotentHint: true,
|
|
37099
|
+
openWorldHint: true
|
|
37100
|
+
},
|
|
37045
37101
|
inputSchema: {}
|
|
37046
37102
|
},
|
|
37047
37103
|
async () => {
|
|
@@ -37087,17 +37143,10 @@ function format2(raw) {
|
|
|
37087
37143
|
};
|
|
37088
37144
|
}
|
|
37089
37145
|
function pathFromInput(args) {
|
|
37090
|
-
if (args.url)
|
|
37091
|
-
try {
|
|
37092
|
-
const u = new URL(args.url);
|
|
37093
|
-
return `${u.pathname}${u.search}`;
|
|
37094
|
-
} catch {
|
|
37095
|
-
return args.url.startsWith("/") ? args.url : `/${args.url}`;
|
|
37096
|
-
}
|
|
37097
|
-
}
|
|
37146
|
+
if (args.url) return urlToPath(args.url);
|
|
37098
37147
|
if (args.region_path) {
|
|
37099
|
-
const p = args.region_path
|
|
37100
|
-
return p.includes("/home-values/") ? p : `/home-values${p
|
|
37148
|
+
const p = urlToPath(args.region_path);
|
|
37149
|
+
return p.includes("/home-values/") ? p : `/home-values${p}`;
|
|
37101
37150
|
}
|
|
37102
37151
|
throw new Error(
|
|
37103
37152
|
'zillow_get_market_report: provide either region_path (e.g. "/home-values/6181/brooklyn-ny/") or url.'
|
|
@@ -37107,8 +37156,14 @@ function registerMarketTools(server2, client2) {
|
|
|
37107
37156
|
server2.registerTool(
|
|
37108
37157
|
"zillow_get_market_report",
|
|
37109
37158
|
{
|
|
37110
|
-
|
|
37111
|
-
|
|
37159
|
+
title: "Get Zillow market report for a region",
|
|
37160
|
+
description: 'Market report for a Zillow region: median sale/list/rent prices, days on market, inventory, Zillow Home Value Index (ZHVI), year-over-year ZHVI change, and buyer/seller balance. Provide either a `region_path` (e.g. "/home-values/6181/brooklyn-ny/") or a full Zillow home-values URL. Read-only; safe to call repeatedly.',
|
|
37161
|
+
annotations: {
|
|
37162
|
+
title: "Get Zillow market report for a region",
|
|
37163
|
+
readOnlyHint: true,
|
|
37164
|
+
idempotentHint: true,
|
|
37165
|
+
openWorldHint: true
|
|
37166
|
+
},
|
|
37112
37167
|
inputSchema: {
|
|
37113
37168
|
region_path: external_exports.string().optional().describe(
|
|
37114
37169
|
'Path under /home-values/, e.g. "/home-values/6181/brooklyn-ny/" or "6181/brooklyn-ny/"'
|
|
@@ -37185,8 +37240,14 @@ function registerMortgageTools(server2) {
|
|
|
37185
37240
|
server2.registerTool(
|
|
37186
37241
|
"zillow_calculate_mortgage",
|
|
37187
37242
|
{
|
|
37188
|
-
|
|
37189
|
-
|
|
37243
|
+
title: "Calculate mortgage payment (local)",
|
|
37244
|
+
description: "Local-only mortgage payment calculator. Returns a full PITI breakdown (principal + interest, property tax, insurance, HOA, PMI) and total interest over the life of the loan. No network call \u2014 fully deterministic, safe to use for scenario comparison without burning a fetch. Provide either down_payment OR down_payment_percent; defaults to 20%. Property tax can be given as property_tax_annual or property_tax_rate (% of home price). PMI applies automatically when LTV > 80% and pmi_rate is provided.",
|
|
37245
|
+
annotations: {
|
|
37246
|
+
title: "Calculate mortgage payment (local)",
|
|
37247
|
+
readOnlyHint: true,
|
|
37248
|
+
idempotentHint: true,
|
|
37249
|
+
openWorldHint: false
|
|
37250
|
+
},
|
|
37190
37251
|
inputSchema: {
|
|
37191
37252
|
home_price: external_exports.number().positive(),
|
|
37192
37253
|
down_payment: external_exports.number().nonnegative().optional(),
|
|
@@ -37205,7 +37266,7 @@ function registerMortgageTools(server2) {
|
|
|
37205
37266
|
}
|
|
37206
37267
|
|
|
37207
37268
|
// src/index.ts
|
|
37208
|
-
var VERSION = "0.1
|
|
37269
|
+
var VERSION = "0.2.1";
|
|
37209
37270
|
var port = process.env.ZILLOW_WS_PORT ? Number(process.env.ZILLOW_WS_PORT) : void 0;
|
|
37210
37271
|
var transport = new FetchproxyTransport({ port, version: VERSION });
|
|
37211
37272
|
var client = new ZillowClient({ transport });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zillow-mcp",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"mcpName": "io.github.chrischall/zillow-mcp",
|
|
5
5
|
"description": "Zillow MCP server for Claude — developed and maintained by AI (Claude Code)",
|
|
6
6
|
"author": "Claude Code (AI) <https://www.anthropic.com/claude>",
|
package/server.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
|
|
3
3
|
"name": "io.github.chrischall/zillow-mcp",
|
|
4
|
-
"description": "Zillow real-estate
|
|
4
|
+
"description": "Zillow real-estate for Claude — search, property details, Zestimates, saved searches & homes",
|
|
5
5
|
"repository": {
|
|
6
6
|
"url": "https://github.com/chrischall/zillow-mcp",
|
|
7
7
|
"source": "github"
|
|
8
8
|
},
|
|
9
|
-
"version": "0.1
|
|
9
|
+
"version": "0.2.1",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
12
|
"registryType": "npm",
|
|
13
13
|
"identifier": "zillow-mcp",
|
|
14
|
-
"version": "0.1
|
|
14
|
+
"version": "0.2.1",
|
|
15
15
|
"transport": {
|
|
16
16
|
"type": "stdio"
|
|
17
17
|
},
|