@sfranalytics/mcp 0.6.3 → 0.6.5

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.

Potentially problematic release.


This version of @sfranalytics/mcp might be problematic. Click here for more details.

Files changed (44) hide show
  1. package/dist/http.js +69 -3
  2. package/dist/http.js.map +1 -1
  3. package/dist/landing.js +17 -4
  4. package/dist/landing.js.map +1 -1
  5. package/dist/server.js +5 -3
  6. package/dist/server.js.map +1 -1
  7. package/dist/tools/formatters.js +6 -1
  8. package/dist/tools/formatters.js.map +1 -1
  9. package/dist/tools/plr/borrowerProfile.js +5 -2
  10. package/dist/tools/plr/borrowerProfile.js.map +1 -1
  11. package/dist/tools/plr/borrowerSearch.js +1 -1
  12. package/dist/tools/plr/borrowerSearch.js.map +1 -1
  13. package/dist/tools/plr/loansNearby.js +100 -84
  14. package/dist/tools/plr/loansNearby.js.map +1 -1
  15. package/dist/tools/plr/transactionHistory.js +67 -50
  16. package/dist/tools/plr/transactionHistory.js.map +1 -1
  17. package/dist/tools/sfr/bestBuyers.js +58 -41
  18. package/dist/tools/sfr/bestBuyers.js.map +1 -1
  19. package/dist/tools/sfr/buyerProfile.js +12 -5
  20. package/dist/tools/sfr/buyerProfile.js.map +1 -1
  21. package/dist/tools/sfr/getProperty.js +147 -124
  22. package/dist/tools/sfr/getProperty.js.map +1 -1
  23. package/dist/tools/sfr/propertyBatch.js +3 -1
  24. package/dist/tools/sfr/propertyBatch.js.map +1 -1
  25. package/dist/tools/sfr/propertyComps.js +51 -34
  26. package/dist/tools/sfr/propertyComps.js.map +1 -1
  27. package/dist/tools/sfr/propertyTransactions.js +48 -31
  28. package/dist/tools/sfr/propertyTransactions.js.map +1 -1
  29. package/dist/tools/sfr/rentalComparables.js +83 -66
  30. package/dist/tools/sfr/rentalComparables.js.map +1 -1
  31. package/dist/tools/sfr/rentalMarketAnalysis.js +5 -2
  32. package/dist/tools/sfr/rentalMarketAnalysis.js.map +1 -1
  33. package/dist/tools/sfr/searchProperties.js +3 -1
  34. package/dist/tools/sfr/searchProperties.js.map +1 -1
  35. package/dist/tools/sfr/topBuyers.js +13 -10
  36. package/dist/tools/sfr/topBuyers.js.map +1 -1
  37. package/dist/tools/sfr/zipDetail.js +83 -72
  38. package/dist/tools/sfr/zipDetail.js.map +1 -1
  39. package/dist/tools/sfr/zipFinder.js +24 -15
  40. package/dist/tools/sfr/zipFinder.js.map +1 -1
  41. package/dist/tools/support.d.ts +3 -0
  42. package/dist/tools/support.js +60 -0
  43. package/dist/tools/support.js.map +1 -0
  44. package/package.json +1 -1
@@ -2,6 +2,7 @@ import { z } from "zod";
2
2
  import { structuredResult, kvSummary, truncatedJson } from "../formatters.js";
3
3
  import { action } from "../nextActions.js";
4
4
  import { registerToolSafe } from "../registerToolSafe.js";
5
+ import { ApiError } from "../../services/httpClient.js";
5
6
  const Input = z.object({
6
7
  zipCode: z.string().describe("5-digit zip code, e.g. '85281'"),
7
8
  });
@@ -13,80 +14,90 @@ export function registerZipDetailTool(server, sfr) {
13
14
  "More detailed than sfr_zip_finder which ranks many zips — this deep-dives into one.",
14
15
  inputSchema: Input,
15
16
  }, async (args) => {
16
- const data = await sfr.getZipDetail(args.zipCode);
17
- if (!data || typeof data !== "object") {
18
- return structuredResult(`## Zip Code Detail ${args.zipCode}\n\n_No data found._`, {});
17
+ try {
18
+ const data = await sfr.getZipDetail(args.zipCode);
19
+ if (!data || typeof data !== "object") {
20
+ return structuredResult(`## Zip Code Detail — ${args.zipCode}\n\n_No data found._`, {});
21
+ }
22
+ const fmt$ = (v) => v != null ? `$${Math.round(Number(v)).toLocaleString()}` : undefined;
23
+ const fmtPct01 = (v) => v != null ? `${(Number(v) * 100).toFixed(1)}%` : undefined;
24
+ const fmtNum = (v) => v != null ? Number(v).toLocaleString() : undefined;
25
+ const grossYieldRaw = data.grossYield ?? data.gross_yield;
26
+ const grossYieldCapped = grossYieldRaw != null && Number.isFinite(Number(grossYieldRaw)) && Number(grossYieldRaw) >= 0 && Number(grossYieldRaw) <= 0.4
27
+ ? Number(grossYieldRaw)
28
+ : null;
29
+ const grossYieldDisplay = grossYieldCapped != null
30
+ ? fmtPct01(grossYieldCapped)
31
+ : "— (no reliable rent data)";
32
+ const lines = [
33
+ `## Zip Code Detail — ${data.zipCode ?? args.zipCode}`,
34
+ "",
35
+ "### Demographics",
36
+ kvSummary([
37
+ ["Population", fmtNum(data.population)],
38
+ ["Population Density", data.populationDensity != null
39
+ ? `${Number(data.populationDensity).toFixed(0)}/sq mi` : undefined],
40
+ ["Housing Units", fmtNum(data.housingUnits)],
41
+ ["Median Household Income", fmt$(data.medianHouseholdIncome)],
42
+ ["Income vs MSA", fmtPct01(data.incomeRelativeToMsa)],
43
+ ]),
44
+ "",
45
+ "### Investment Metrics",
46
+ kvSummary([
47
+ ["Median Home Value", fmt$(data.medianHomeValue)],
48
+ ["Median Rent", data.medianRent != null ? `$${Math.round(Number(data.medianRent)).toLocaleString()}/mo` : undefined],
49
+ ["Gross Yield", grossYieldDisplay],
50
+ ["Inst. Ownership", fmtPct01(data.instOwnPercentage)],
51
+ ]),
52
+ ];
53
+ // Append any additional fields as raw JSON
54
+ const knownKeys = new Set([
55
+ "zipCode", "population", "populationDensity", "populationGrowthForecast",
56
+ "housingUnits", "medianHouseholdIncome", "medianHomeValue", "medianRent",
57
+ "instOwnPercentage", "grossYield", "incomeRelativeToMsa",
58
+ ]);
59
+ const extra = {};
60
+ for (const [k, v] of Object.entries(data)) {
61
+ if (!knownKeys.has(k) && v != null)
62
+ extra[k] = v;
63
+ }
64
+ if (Object.keys(extra).length > 0) {
65
+ lines.push("");
66
+ lines.push("### Additional Data");
67
+ lines.push("```json");
68
+ lines.push(truncatedJson(extra, 2000));
69
+ lines.push("```");
70
+ }
71
+ const zip = args.zipCode;
72
+ const actions = [
73
+ action("sfr_rental_stats", "Rental market stats", { search_type: "zip", zips: zip }),
74
+ action("sfr_top_buyers", "Active buyers in zip", { search_type: "zip", zips: zip }),
75
+ action("sfr_search_properties", "Browse transactions", { search_type: "zip", zips: zip }),
76
+ action("sfr_institutional_owners", "Institutional owners in zip", { search_type: "zip", zips: zip }),
77
+ ];
78
+ const structured = {
79
+ zipCode: data.zipCode,
80
+ population: data.population,
81
+ populationDensity: data.populationDensity,
82
+ populationGrowthForecast: data.populationGrowthForecast,
83
+ housingUnits: data.housingUnits,
84
+ medianHouseholdIncome: data.medianHouseholdIncome,
85
+ medianHomeValue: data.medianHomeValue,
86
+ medianRent: data.medianRent,
87
+ grossYield: grossYieldCapped,
88
+ instOwnPercentage: data.instOwnPercentage,
89
+ incomeRelativeToMsa: data.incomeRelativeToMsa,
90
+ };
91
+ return structuredResult(lines.join("\n"), structured, actions);
19
92
  }
20
- const fmt$ = (v) => v != null ? `$${Math.round(Number(v)).toLocaleString()}` : undefined;
21
- const fmtPct01 = (v) => v != null ? `${(Number(v) * 100).toFixed(1)}%` : undefined;
22
- const fmtNum = (v) => v != null ? Number(v).toLocaleString() : undefined;
23
- const grossYieldRaw = data.grossYield ?? data.gross_yield;
24
- const grossYieldCapped = grossYieldRaw != null && Number.isFinite(Number(grossYieldRaw)) && Number(grossYieldRaw) >= 0 && Number(grossYieldRaw) <= 0.4
25
- ? Number(grossYieldRaw)
26
- : null;
27
- const grossYieldDisplay = grossYieldCapped != null
28
- ? fmtPct01(grossYieldCapped)
29
- : "— (no reliable rent data)";
30
- const lines = [
31
- `## Zip Code Detail — ${data.zipCode ?? args.zipCode}`,
32
- "",
33
- "### Demographics",
34
- kvSummary([
35
- ["Population", fmtNum(data.population)],
36
- ["Population Density", data.populationDensity != null
37
- ? `${Number(data.populationDensity).toFixed(0)}/sq mi` : undefined],
38
- ["Housing Units", fmtNum(data.housingUnits)],
39
- ["Median Household Income", fmt$(data.medianHouseholdIncome)],
40
- ["Income vs MSA", fmtPct01(data.incomeRelativeToMsa)],
41
- ]),
42
- "",
43
- "### Investment Metrics",
44
- kvSummary([
45
- ["Median Home Value", fmt$(data.medianHomeValue)],
46
- ["Median Rent", data.medianRent != null ? `$${Math.round(Number(data.medianRent)).toLocaleString()}/mo` : undefined],
47
- ["Gross Yield", grossYieldDisplay],
48
- ["Inst. Ownership", fmtPct01(data.instOwnPercentage)],
49
- ]),
50
- ];
51
- // Append any additional fields as raw JSON
52
- const knownKeys = new Set([
53
- "zipCode", "population", "populationDensity", "populationGrowthForecast",
54
- "housingUnits", "medianHouseholdIncome", "medianHomeValue", "medianRent",
55
- "instOwnPercentage", "grossYield", "incomeRelativeToMsa",
56
- ]);
57
- const extra = {};
58
- for (const [k, v] of Object.entries(data)) {
59
- if (!knownKeys.has(k) && v != null)
60
- extra[k] = v;
93
+ catch (err) {
94
+ if (err instanceof ApiError && err.status === 404) {
95
+ return structuredResult(`## Zip Code Detail ${args.zipCode}\n\n` +
96
+ `_No data found for zip code "${args.zipCode}". Verify the 5-digit zip code is correct. ` +
97
+ `Use sfr_zip_finder to discover zip codes with investment data._`, { zipCode: args.zipCode, error: "not_found" }, [action("sfr_zip_finder", "Find valid zip codes", {})]);
98
+ }
99
+ throw err;
61
100
  }
62
- if (Object.keys(extra).length > 0) {
63
- lines.push("");
64
- lines.push("### Additional Data");
65
- lines.push("```json");
66
- lines.push(truncatedJson(extra, 2000));
67
- lines.push("```");
68
- }
69
- const zip = args.zipCode;
70
- const actions = [
71
- action("sfr_rental_stats", "Rental market stats", { search_type: "zip", zips: zip }),
72
- action("sfr_top_buyers", "Active buyers in zip", { search_type: "zip", zips: zip }),
73
- action("sfr_search_properties", "Browse transactions", { search_type: "zip", zips: zip }),
74
- action("sfr_institutional_owners", "Institutional owners in zip", { search_type: "zip", zips: zip }),
75
- ];
76
- const structured = {
77
- zipCode: data.zipCode,
78
- population: data.population,
79
- populationDensity: data.populationDensity,
80
- populationGrowthForecast: data.populationGrowthForecast,
81
- housingUnits: data.housingUnits,
82
- medianHouseholdIncome: data.medianHouseholdIncome,
83
- medianHomeValue: data.medianHomeValue,
84
- medianRent: data.medianRent,
85
- grossYield: grossYieldCapped,
86
- instOwnPercentage: data.instOwnPercentage,
87
- incomeRelativeToMsa: data.incomeRelativeToMsa,
88
- };
89
- return structuredResult(lines.join("\n"), structured, actions);
90
101
  });
91
102
  }
92
103
  //# sourceMappingURL=zipDetail.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"zipDetail.js","sourceRoot":"","sources":["../../../src/tools/sfr/zipDetail.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"zipDetail.js","sourceRoot":"","sources":["../../../src/tools/sfr/zipDetail.ts"],"names":[],"mappings":"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"}
@@ -22,18 +22,6 @@ export function registerZipFinderTool(server, sfr) {
22
22
  "For detailed stats on a single zip, use sfr_zip_detail.",
23
23
  inputSchema: Input,
24
24
  }, async (args) => {
25
- const query = {
26
- search_type: args.search_type,
27
- page: args.page,
28
- page_size: args.page_size,
29
- };
30
- if (args.zips)
31
- query.zips = args.zips;
32
- if (args.sort)
33
- query.sort = args.sort;
34
- const data = await sfr.getZipFinder(query);
35
- const rawItems = data?.data ?? data?.results ?? (Array.isArray(data) ? data : []);
36
- const total = data?.total ?? data?.count ?? rawItems.length;
37
25
  const normalizedSort = (args.sort ?? "").toLowerCase();
38
26
  const isGrossYieldSort = normalizedSort.includes("gross_yield") || normalizedSort.includes("grossyield");
39
27
  // Workaround for upstream API bug: grossYield can be corrupt (>1.0) when rent is null.
@@ -46,6 +34,20 @@ export function registerZipFinderTool(server, sfr) {
46
34
  return null;
47
35
  return n;
48
36
  };
37
+ // When sorting by yield, over-fetch to compensate for corrupt data being filtered out.
38
+ // The top results from the API often have invalid yields (>40% from null rents).
39
+ const fetchPageSize = isGrossYieldSort ? Math.min(args.page_size * 4, 100) : args.page_size;
40
+ const query = {
41
+ search_type: args.search_type,
42
+ page: args.page,
43
+ page_size: fetchPageSize,
44
+ };
45
+ if (args.zips)
46
+ query.zips = args.zips;
47
+ if (args.sort)
48
+ query.sort = args.sort;
49
+ const data = await sfr.getZipFinder(query);
50
+ const rawItems = data?.data ?? data?.results ?? (Array.isArray(data) ? data : []);
49
51
  const sanitizedItems = rawItems.map((item) => {
50
52
  const normalizedGrossYield = normalizeGrossYield(item.grossYield ?? item.gross_yield);
51
53
  return {
@@ -54,12 +56,16 @@ export function registerZipFinderTool(server, sfr) {
54
56
  gross_yield: normalizedGrossYield,
55
57
  };
56
58
  });
57
- const items = isGrossYieldSort
59
+ const allValid = isGrossYieldSort
58
60
  ? sanitizedItems.filter((item) => item.grossYield != null || item.gross_yield != null)
59
61
  : sanitizedItems;
62
+ // Trim back to the requested page_size after filtering
63
+ const items = allValid.slice(0, args.page_size);
64
+ const filteredOut = sanitizedItems.length - allValid.length;
60
65
  const lines = [
61
66
  `## Zip Code Finder`,
62
- `**Total:** ${total} zips | **Page:** ${args.page}`,
67
+ `**Total:** ${items.length} zips | **Page:** ${args.page}`,
68
+ ...(filteredOut > 0 ? [`*${filteredOut} zips excluded due to missing or invalid yield data*`] : []),
63
69
  "",
64
70
  ];
65
71
  if (items.length > 0) {
@@ -81,6 +87,9 @@ export function registerZipFinderTool(server, sfr) {
81
87
  ]);
82
88
  lines.push(markdownTable(["Zip", "Pop", "Income", "Home Value", "Rent", "Yield", "Inst Own"], rows));
83
89
  }
90
+ else if (filteredOut > 0) {
91
+ lines.push("All results had invalid yield data and were excluded. Try removing the sort or sorting by a different field (e.g. `-median_home_value`).");
92
+ }
84
93
  else {
85
94
  lines.push("```json");
86
95
  lines.push(truncatedJson(data, 3000));
@@ -92,7 +101,7 @@ export function registerZipFinderTool(server, sfr) {
92
101
  ...(topZip ? [action("sfr_rental_stats", "Rental market for top zip", { search_type: "zip", zips: String(topZip) })] : []),
93
102
  ...(topZip ? [action("sfr_top_buyers", "Active buyers in top zip", { search_type: "zip", zips: String(topZip) })] : []),
94
103
  ];
95
- return structuredResult(lines.join("\n"), { items, total, page: args.page }, actions);
104
+ return structuredResult(lines.join("\n"), { items, total: items.length, page: args.page }, actions);
96
105
  });
97
106
  }
98
107
  //# sourceMappingURL=zipFinder.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"zipFinder.js","sourceRoot":"","sources":["../../../src/tools/sfr/zipFinder.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"zipFinder.js","sourceRoot":"","sources":["../../../src/tools/sfr/zipFinder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { AppConfig } from "../config.js";
3
+ export declare function registerSupportTool(server: McpServer, config: AppConfig): void;
@@ -0,0 +1,60 @@
1
+ import { z } from "zod";
2
+ import { structuredResult } from "./formatters.js";
3
+ import { registerToolSafe } from "./registerToolSafe.js";
4
+ const SUPPORT_EMAIL = "support@sfranalytics.com";
5
+ const CHAT_URL = "https://mcp.sfranalytics.com";
6
+ const CALENDLY_URL = "https://calendly.com/d/ckd7-sw4-g46";
7
+ const Input = z.object({
8
+ topic: z
9
+ .enum(["general", "contacts", "address", "keys"])
10
+ .default("general")
11
+ .describe("Help topic: 'general' (overview + contact), 'contacts' (getting investor contact data), 'address' (address format issues), 'keys' (API key setup)"),
12
+ });
13
+ export function registerSupportTool(server, config) {
14
+ const hasSfr = config.sfr !== null;
15
+ const hasPlr = config.plr !== null;
16
+ registerToolSafe(server, "sfra_support", {
17
+ title: "Help, troubleshooting & support (SFRA)",
18
+ description: "Get help with common issues: API key setup, accessing investor contact data, " +
19
+ "address format problems, or general guidance. " +
20
+ "Includes direct support contact info (email, chat, booking link). " +
21
+ "Call this when a user is stuck, confused, or asks about getting access to more data.",
22
+ inputSchema: Input,
23
+ }, async (args) => {
24
+ const lines = [];
25
+ const topic = args.topic;
26
+ if (topic === "general" || topic === "keys") {
27
+ lines.push("## API Keys & Data Access", "");
28
+ lines.push("SFR Analytics has two APIs, each with its own key:", "", "| API | What it covers | Tools |", "|-----|---------------|-------|", `| **SFR** | Property transactions, buyer rankings, rental stats, zip screening, flip activity | 21 tools (sfr_*) ${hasSfr ? "— **connected**" : "— not configured"} |`, `| **PLR** | Private lending: borrower search, loan history, **contact info** (phone/email), lender intelligence | 17 tools (plr_*) ${hasPlr ? "— **connected**" : "— not configured"} |`, "");
29
+ if (!hasSfr || !hasPlr) {
30
+ lines.push(`You currently have ${hasSfr && hasPlr ? "both" : hasSfr ? "SFR only" : hasPlr ? "PLR only" : "no"} API key(s) configured.`, !hasPlr ? "Add a PLR key to unlock investor contact info, lending history, and borrower intelligence." : "", !hasSfr ? "Add an SFR key to unlock property data, buyer rankings, and market analytics." : "", "");
31
+ }
32
+ lines.push("### Setup", "**Recommended (HTTP — auto-updates):**", "```", "claude mcp add sfranalytics --transport http https://mcp.sfranalytics.com/mcp \\", ' -H "Api-Token: <YOUR_KEY>"', "```", "A single Api-Token works if your key covers one API. For both APIs, use separate headers:", "```", ' -H "SFR-Api-Token: <SFR_KEY>" -H "PLR-Api-Token: <PLR_KEY>"', "```", "");
33
+ }
34
+ if (topic === "general" || topic === "contacts") {
35
+ lines.push("## Investor Contact Data", "");
36
+ lines.push("Contact information (phone, email, principal names) is available through **PLR API tools**:", "- `plr_borrower_profile` — Full profile including contacts, lending history, and lender relationships", "- `plr_borrower_contacts` — Direct contact lookup (phone, email, social links)", "- `plr_borrower_search` — Find borrowers by geography, loan type, and contact availability", "");
37
+ if (hasPlr) {
38
+ lines.push("You have a PLR key configured — these tools are available to you now.", "**Workflow:** sfr_top_buyers (find investors) -> plr_borrower_profile (contacts + lending activity)", "");
39
+ }
40
+ else {
41
+ lines.push("**You need a PLR API key to access contact data.** The SFR API shows which buyers have contacts " +
42
+ "(Contact* column in sfr_top_buyers) but cannot expose the actual phone/email fields.", "", "Get a PLR key to unlock investor contacts, lending history, and borrower intelligence.", "");
43
+ }
44
+ }
45
+ if (topic === "general" || topic === "address") {
46
+ lines.push("## Address Format Troubleshooting", "");
47
+ lines.push("Address-based tools require **exact matches** against the recorded dataset. Common issues:", "", "- **Directional prefixes matter:** '123 University Dr' vs '123 **E** University Dr'", "- **Abbreviations matter:** 'Street' vs 'St', 'Avenue' vs 'Ave', 'Boulevard' vs 'Blvd'", "- **Unit numbers:** Include or exclude exactly as recorded", "- **Format:** '123 Main St, Phoenix, AZ 85004' (street, city, state zip)", "", "**If a property lookup fails:** Use `sfr_search_properties` with the zip code to browse " +
48
+ "recent transactions and find the exact recorded address.", "");
49
+ }
50
+ // Always include contact info
51
+ lines.push("---", "### Get Help", `- **Chat:** ${CHAT_URL} (bottom-right chat widget)`, `- **Email:** ${SUPPORT_EMAIL}`, `- **Book a call:** ${CALENDLY_URL}`);
52
+ return structuredResult(lines.join("\n"), {
53
+ topic,
54
+ sfrConnected: hasSfr,
55
+ plrConnected: hasPlr,
56
+ support: { email: SUPPORT_EMAIL, chat: CHAT_URL, calendly: CALENDLY_URL },
57
+ });
58
+ });
59
+ }
60
+ //# sourceMappingURL=support.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"support.js","sourceRoot":"","sources":["../../src/tools/support.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sfranalytics/mcp",
3
- "version": "0.6.3",
3
+ "version": "0.6.5",
4
4
  "description": "MCP server for SFR Analytics — single-family residential property data, buyer intelligence, and private lending insights",
5
5
  "type": "module",
6
6
  "license": "SEE LICENSE IN LICENSE",