@sfranalytics/mcp 0.6.0

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.
Files changed (198) hide show
  1. package/LICENSE +24 -0
  2. package/README.md +147 -0
  3. package/dist/config.d.ts +28 -0
  4. package/dist/config.js +101 -0
  5. package/dist/config.js.map +1 -0
  6. package/dist/http.d.ts +2 -0
  7. package/dist/http.js +252 -0
  8. package/dist/http.js.map +1 -0
  9. package/dist/index.d.ts +2 -0
  10. package/dist/index.js +41 -0
  11. package/dist/index.js.map +1 -0
  12. package/dist/server.d.ts +3 -0
  13. package/dist/server.js +213 -0
  14. package/dist/server.js.map +1 -0
  15. package/dist/services/httpClient.d.ts +19 -0
  16. package/dist/services/httpClient.js +73 -0
  17. package/dist/services/httpClient.js.map +1 -0
  18. package/dist/services/plr.d.ts +26 -0
  19. package/dist/services/plr.js +75 -0
  20. package/dist/services/plr.js.map +1 -0
  21. package/dist/services/sfr.d.ts +33 -0
  22. package/dist/services/sfr.js +124 -0
  23. package/dist/services/sfr.js.map +1 -0
  24. package/dist/services/snowflake.d.ts +12 -0
  25. package/dist/services/snowflake.js +71 -0
  26. package/dist/services/snowflake.js.map +1 -0
  27. package/dist/tools/dateHelper.d.ts +26 -0
  28. package/dist/tools/dateHelper.js +86 -0
  29. package/dist/tools/dateHelper.js.map +1 -0
  30. package/dist/tools/formatters.d.ts +66 -0
  31. package/dist/tools/formatters.js +219 -0
  32. package/dist/tools/formatters.js.map +1 -0
  33. package/dist/tools/health.d.ts +5 -0
  34. package/dist/tools/health.js +38 -0
  35. package/dist/tools/health.js.map +1 -0
  36. package/dist/tools/nextActions.d.ts +10 -0
  37. package/dist/tools/nextActions.js +23 -0
  38. package/dist/tools/nextActions.js.map +1 -0
  39. package/dist/tools/plr/borrowerContacts.d.ts +3 -0
  40. package/dist/tools/plr/borrowerContacts.js +73 -0
  41. package/dist/tools/plr/borrowerContacts.js.map +1 -0
  42. package/dist/tools/plr/borrowerLoans.d.ts +3 -0
  43. package/dist/tools/plr/borrowerLoans.js +115 -0
  44. package/dist/tools/plr/borrowerLoans.js.map +1 -0
  45. package/dist/tools/plr/borrowerProfile.d.ts +3 -0
  46. package/dist/tools/plr/borrowerProfile.js +201 -0
  47. package/dist/tools/plr/borrowerProfile.js.map +1 -0
  48. package/dist/tools/plr/borrowerRankings.d.ts +3 -0
  49. package/dist/tools/plr/borrowerRankings.js +123 -0
  50. package/dist/tools/plr/borrowerRankings.js.map +1 -0
  51. package/dist/tools/plr/borrowerSearch.d.ts +3 -0
  52. package/dist/tools/plr/borrowerSearch.js +128 -0
  53. package/dist/tools/plr/borrowerSearch.js.map +1 -0
  54. package/dist/tools/plr/churnedBorrowers.d.ts +3 -0
  55. package/dist/tools/plr/churnedBorrowers.js +86 -0
  56. package/dist/tools/plr/churnedBorrowers.js.map +1 -0
  57. package/dist/tools/plr/lenderBorrowers.d.ts +3 -0
  58. package/dist/tools/plr/lenderBorrowers.js +71 -0
  59. package/dist/tools/plr/lenderBorrowers.js.map +1 -0
  60. package/dist/tools/plr/lenderRankings.d.ts +3 -0
  61. package/dist/tools/plr/lenderRankings.js +74 -0
  62. package/dist/tools/plr/lenderRankings.js.map +1 -0
  63. package/dist/tools/plr/loansNearby.d.ts +3 -0
  64. package/dist/tools/plr/loansNearby.js +113 -0
  65. package/dist/tools/plr/loansNearby.js.map +1 -0
  66. package/dist/tools/plr/marketTrends.d.ts +3 -0
  67. package/dist/tools/plr/marketTrends.js +95 -0
  68. package/dist/tools/plr/marketTrends.js.map +1 -0
  69. package/dist/tools/plr/msaRankings.d.ts +3 -0
  70. package/dist/tools/plr/msaRankings.js +74 -0
  71. package/dist/tools/plr/msaRankings.js.map +1 -0
  72. package/dist/tools/plr/negativeRemarks.d.ts +3 -0
  73. package/dist/tools/plr/negativeRemarks.js +94 -0
  74. package/dist/tools/plr/negativeRemarks.js.map +1 -0
  75. package/dist/tools/plr/ownerSearch.d.ts +3 -0
  76. package/dist/tools/plr/ownerSearch.js +57 -0
  77. package/dist/tools/plr/ownerSearch.js.map +1 -0
  78. package/dist/tools/plr/portfolioSummary.d.ts +3 -0
  79. package/dist/tools/plr/portfolioSummary.js +99 -0
  80. package/dist/tools/plr/portfolioSummary.js.map +1 -0
  81. package/dist/tools/plr/topBorrowers.d.ts +3 -0
  82. package/dist/tools/plr/topBorrowers.js +69 -0
  83. package/dist/tools/plr/topBorrowers.js.map +1 -0
  84. package/dist/tools/plr/topLenders.d.ts +3 -0
  85. package/dist/tools/plr/topLenders.js +75 -0
  86. package/dist/tools/plr/topLenders.js.map +1 -0
  87. package/dist/tools/plr/transactionHistory.d.ts +3 -0
  88. package/dist/tools/plr/transactionHistory.js +74 -0
  89. package/dist/tools/plr/transactionHistory.js.map +1 -0
  90. package/dist/tools/prompts.d.ts +7 -0
  91. package/dist/tools/prompts.js +157 -0
  92. package/dist/tools/prompts.js.map +1 -0
  93. package/dist/tools/registerToolSafe.d.ts +29 -0
  94. package/dist/tools/registerToolSafe.js +36 -0
  95. package/dist/tools/registerToolSafe.js.map +1 -0
  96. package/dist/tools/sfr/activityHighlights.d.ts +3 -0
  97. package/dist/tools/sfr/activityHighlights.js +70 -0
  98. package/dist/tools/sfr/activityHighlights.js.map +1 -0
  99. package/dist/tools/sfr/bestBuyers.d.ts +3 -0
  100. package/dist/tools/sfr/bestBuyers.js +60 -0
  101. package/dist/tools/sfr/bestBuyers.js.map +1 -0
  102. package/dist/tools/sfr/buyerGrowth.d.ts +3 -0
  103. package/dist/tools/sfr/buyerGrowth.js +68 -0
  104. package/dist/tools/sfr/buyerGrowth.js.map +1 -0
  105. package/dist/tools/sfr/buyerProfile.d.ts +3 -0
  106. package/dist/tools/sfr/buyerProfile.js +162 -0
  107. package/dist/tools/sfr/buyerProfile.js.map +1 -0
  108. package/dist/tools/sfr/distressSearch.d.ts +3 -0
  109. package/dist/tools/sfr/distressSearch.js +173 -0
  110. package/dist/tools/sfr/distressSearch.js.map +1 -0
  111. package/dist/tools/sfr/flipActivity.d.ts +3 -0
  112. package/dist/tools/sfr/flipActivity.js +110 -0
  113. package/dist/tools/sfr/flipActivity.js.map +1 -0
  114. package/dist/tools/sfr/flipStats.d.ts +3 -0
  115. package/dist/tools/sfr/flipStats.js +98 -0
  116. package/dist/tools/sfr/flipStats.js.map +1 -0
  117. package/dist/tools/sfr/getProperty.d.ts +3 -0
  118. package/dist/tools/sfr/getProperty.js +142 -0
  119. package/dist/tools/sfr/getProperty.js.map +1 -0
  120. package/dist/tools/sfr/institutionalOwners.d.ts +3 -0
  121. package/dist/tools/sfr/institutionalOwners.js +88 -0
  122. package/dist/tools/sfr/institutionalOwners.js.map +1 -0
  123. package/dist/tools/sfr/investorActivity.d.ts +3 -0
  124. package/dist/tools/sfr/investorActivity.js +130 -0
  125. package/dist/tools/sfr/investorActivity.js.map +1 -0
  126. package/dist/tools/sfr/marketHighlights.d.ts +3 -0
  127. package/dist/tools/sfr/marketHighlights.js +100 -0
  128. package/dist/tools/sfr/marketHighlights.js.map +1 -0
  129. package/dist/tools/sfr/msaResolver.d.ts +15 -0
  130. package/dist/tools/sfr/msaResolver.js +109 -0
  131. package/dist/tools/sfr/msaResolver.js.map +1 -0
  132. package/dist/tools/sfr/propertyBatch.d.ts +3 -0
  133. package/dist/tools/sfr/propertyBatch.js +73 -0
  134. package/dist/tools/sfr/propertyBatch.js.map +1 -0
  135. package/dist/tools/sfr/propertyComps.d.ts +3 -0
  136. package/dist/tools/sfr/propertyComps.js +56 -0
  137. package/dist/tools/sfr/propertyComps.js.map +1 -0
  138. package/dist/tools/sfr/propertyTransactions.d.ts +3 -0
  139. package/dist/tools/sfr/propertyTransactions.js +50 -0
  140. package/dist/tools/sfr/propertyTransactions.js.map +1 -0
  141. package/dist/tools/sfr/rentalComparables.d.ts +3 -0
  142. package/dist/tools/sfr/rentalComparables.js +91 -0
  143. package/dist/tools/sfr/rentalComparables.js.map +1 -0
  144. package/dist/tools/sfr/rentalMarketAnalysis.d.ts +3 -0
  145. package/dist/tools/sfr/rentalMarketAnalysis.js +134 -0
  146. package/dist/tools/sfr/rentalMarketAnalysis.js.map +1 -0
  147. package/dist/tools/sfr/rentalStats.d.ts +3 -0
  148. package/dist/tools/sfr/rentalStats.js +118 -0
  149. package/dist/tools/sfr/rentalStats.js.map +1 -0
  150. package/dist/tools/sfr/searchProperties.d.ts +3 -0
  151. package/dist/tools/sfr/searchProperties.js +157 -0
  152. package/dist/tools/sfr/searchProperties.js.map +1 -0
  153. package/dist/tools/sfr/topBuyers.d.ts +3 -0
  154. package/dist/tools/sfr/topBuyers.js +91 -0
  155. package/dist/tools/sfr/topBuyers.js.map +1 -0
  156. package/dist/tools/sfr/zipDetail.d.ts +3 -0
  157. package/dist/tools/sfr/zipDetail.js +85 -0
  158. package/dist/tools/sfr/zipDetail.js.map +1 -0
  159. package/dist/tools/sfr/zipFinder.d.ts +3 -0
  160. package/dist/tools/sfr/zipFinder.js +79 -0
  161. package/dist/tools/sfr/zipFinder.js.map +1 -0
  162. package/dist/tools/slugHelper.d.ts +2 -0
  163. package/dist/tools/slugHelper.js +5 -0
  164. package/dist/tools/slugHelper.js.map +1 -0
  165. package/dist/tools/snowflake/compareMarkets.d.ts +2 -0
  166. package/dist/tools/snowflake/compareMarkets.js +95 -0
  167. package/dist/tools/snowflake/compareMarkets.js.map +1 -0
  168. package/dist/tools/snowflake/hviTrend.d.ts +2 -0
  169. package/dist/tools/snowflake/hviTrend.js +77 -0
  170. package/dist/tools/snowflake/hviTrend.js.map +1 -0
  171. package/dist/tools/snowflake/investorActivity.d.ts +2 -0
  172. package/dist/tools/snowflake/investorActivity.js +138 -0
  173. package/dist/tools/snowflake/investorActivity.js.map +1 -0
  174. package/dist/tools/snowflake/marketSnapshot.d.ts +2 -0
  175. package/dist/tools/snowflake/marketSnapshot.js +185 -0
  176. package/dist/tools/snowflake/marketSnapshot.js.map +1 -0
  177. package/dist/tools/snowflake/marketTrends.d.ts +2 -0
  178. package/dist/tools/snowflake/marketTrends.js +81 -0
  179. package/dist/tools/snowflake/marketTrends.js.map +1 -0
  180. package/dist/tools/snowflake/rankRentalZips.d.ts +2 -0
  181. package/dist/tools/snowflake/rankRentalZips.js +94 -0
  182. package/dist/tools/snowflake/rankRentalZips.js.map +1 -0
  183. package/dist/tools/snowflake/rankZips.d.ts +2 -0
  184. package/dist/tools/snowflake/rankZips.js +86 -0
  185. package/dist/tools/snowflake/rankZips.js.map +1 -0
  186. package/dist/tools/snowflake/rentalMarket.d.ts +2 -0
  187. package/dist/tools/snowflake/rentalMarket.js +111 -0
  188. package/dist/tools/snowflake/rentalMarket.js.map +1 -0
  189. package/dist/tools/snowflake/rentalYield.d.ts +2 -0
  190. package/dist/tools/snowflake/rentalYield.js +143 -0
  191. package/dist/tools/snowflake/rentalYield.js.map +1 -0
  192. package/dist/tools/snowflake/zipProfile.d.ts +2 -0
  193. package/dist/tools/snowflake/zipProfile.js +110 -0
  194. package/dist/tools/snowflake/zipProfile.js.map +1 -0
  195. package/dist/version.d.ts +1 -0
  196. package/dist/version.js +5 -0
  197. package/dist/version.js.map +1 -0
  198. package/package.json +53 -0
@@ -0,0 +1,95 @@
1
+ import { z } from "zod";
2
+ import { structuredResult, markdownTable, truncatedJson, fmtDollars, fmtPercent, fmtPeriod } from "../formatters.js";
3
+ import { registerToolSafe } from "../registerToolSafe.js";
4
+ import { autoFillPlrDates } from "../dateHelper.js";
5
+ import { action } from "../nextActions.js";
6
+ const Input = z.object({
7
+ granularity: z
8
+ .enum(["monthly", "quarterly", "yearly", "loan_type", "seasonal", "rolling"])
9
+ .default("monthly")
10
+ .describe("Time series granularity"),
11
+ startDate: z.string().optional().describe("Start date, e.g. '2023-01-01'"),
12
+ endDate: z.string().optional().describe("End date"),
13
+ loanTypes: z.string().optional().describe("Comma-separated loan types: DSCR, Bridge, Unknown"),
14
+ });
15
+ const granularityToEndpoint = {
16
+ monthly: "monthly_market_trends",
17
+ quarterly: "quarterly_trends",
18
+ yearly: "year_over_year_comparison",
19
+ loan_type: "loan_type_trends",
20
+ seasonal: "seasonal_analysis",
21
+ rolling: "rolling_averages",
22
+ };
23
+ export function registerMarketTrendsTool(server, plr) {
24
+ registerToolSafe(server, "plr_market_trends", {
25
+ title: "Private lending market trends — NATIONWIDE only (PLR)",
26
+ description: "Get NATIONWIDE private lending time series data with 6 granularity options: " +
27
+ "monthly, quarterly, yearly, loan_type breakdowns, seasonal analysis, and rolling averages. " +
28
+ "Returns loan counts, volumes, unique lender/borrower counts, and growth metrics. " +
29
+ "NOTE: This is nationwide data only — geographic filters (state/MSA) are NOT supported. " +
30
+ "For geographic rankings, use plr_msa_rankings. " +
31
+ "For a point-in-time market overview, use plr_portfolio_summary.",
32
+ inputSchema: Input,
33
+ }, async (args) => {
34
+ const endpoint = granularityToEndpoint[args.granularity];
35
+ const query = {};
36
+ if (args.startDate)
37
+ query.start_date = args.startDate;
38
+ if (args.endDate)
39
+ query.end_date = args.endDate;
40
+ if (args.loanTypes)
41
+ query.loan_types = args.loanTypes;
42
+ autoFillPlrDates(query);
43
+ const data = await plr.marketTrends(endpoint, query);
44
+ const items = data?.results ?? data?.data ?? (Array.isArray(data) ? data : []);
45
+ const lines = [
46
+ `## Private Lending Market Trends (${args.granularity})`,
47
+ "",
48
+ ];
49
+ if (items.length > 0) {
50
+ // Try to build a table from the first item's keys
51
+ const sampleKeys = Object.keys(items[0]).slice(0, 8);
52
+ const dollarKeys = new Set(sampleKeys.filter((k) => /amount|volume/i.test(k)));
53
+ const pctKeys = new Set(sampleKeys.filter((k) => /growth|percent|change/i.test(k)));
54
+ const dateKeys = new Set(sampleKeys.filter((k) => /^(month|quarter|period|year)$/i.test(k)));
55
+ // Detect if last row's period is incomplete (contains current month)
56
+ const now = new Date();
57
+ const isPartialPeriod = (v) => {
58
+ const d = new Date(v);
59
+ if (isNaN(d.getTime()))
60
+ return false;
61
+ return d.getFullYear() === now.getFullYear() && d.getMonth() === now.getMonth();
62
+ };
63
+ const sliced = items.slice(0, 36);
64
+ const rows = sliced.map((row, idx) => sampleKeys.map((k) => {
65
+ const v = row[k];
66
+ if (v == null)
67
+ return "—";
68
+ if (typeof v === "number" && dollarKeys.has(k) && v > 10000)
69
+ return fmtDollars(v);
70
+ if (typeof v === "number" && pctKeys.has(k))
71
+ return fmtPercent(v);
72
+ if (typeof v === "string" && dateKeys.has(k)) {
73
+ const label = fmtPeriod(k, v);
74
+ if (idx === sliced.length - 1 && isPartialPeriod(v))
75
+ return `${label} (partial)`;
76
+ return label;
77
+ }
78
+ return String(v);
79
+ }));
80
+ lines.push(markdownTable(sampleKeys, rows));
81
+ }
82
+ else {
83
+ lines.push("```json");
84
+ lines.push(truncatedJson(data, 4000));
85
+ lines.push("```");
86
+ }
87
+ const actions = [
88
+ action("plr_msa_rankings", "Geographic breakdown by MSA", {}),
89
+ action("plr_portfolio_summary", "Point-in-time market overview", {}),
90
+ action("plr_top_lenders", "Top lenders by volume", {}),
91
+ ];
92
+ return structuredResult(lines.join("\n"), { items, total: items.length, page: 1 }, actions);
93
+ });
94
+ }
95
+ //# sourceMappingURL=marketTrends.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"marketTrends.js","sourceRoot":"","sources":["../../../src/tools/plr/marketTrends.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { PlrClient } from "../../services/plr.js";
3
+ export declare function registerMsaRankingsTool(server: McpServer, plr: PlrClient): void;
@@ -0,0 +1,74 @@
1
+ import { z } from "zod";
2
+ import { structuredResult, markdownTable, truncatedJson, fmtDollars } from "../formatters.js";
3
+ import { registerToolSafe } from "../registerToolSafe.js";
4
+ import { autoFillPlrDates } from "../dateHelper.js";
5
+ import { action } from "../nextActions.js";
6
+ const Input = z.object({
7
+ search: z.string().optional().describe("Search MSA by name, e.g. 'Phoenix'"),
8
+ states: z.string().optional().describe("Comma-separated state abbreviations"),
9
+ startDate: z.string().optional().describe("Start date, e.g. '2024-01-01'"),
10
+ endDate: z.string().optional().describe("End date"),
11
+ loanTypes: z.string().optional().describe("Comma-separated: 'Bridge', 'DSCR', 'Unknown'"),
12
+ page: z.coerce.number().default(1).describe("Page number (default 1)"),
13
+ pageSize: z.coerce.number().default(25).describe("Results per page (default 25, max 25)"),
14
+ });
15
+ export function registerMsaRankingsTool(server, plr) {
16
+ registerToolSafe(server, "plr_msa_rankings", {
17
+ title: "Rank MSAs by lending activity (PLR)",
18
+ description: "Rank metropolitan statistical areas (MSAs) by private lending volume. " +
19
+ "Shows which metros have the most bridge/DSCR lending activity, loan counts, " +
20
+ "and period-over-period changes. Great for identifying hot markets. " +
21
+ "Defaults to last 1 year if no dates provided. " +
22
+ "Requires MSAs with 100+ loans in both the current and previous period.",
23
+ inputSchema: Input,
24
+ }, async (args) => {
25
+ const body = {
26
+ page: args.page,
27
+ page_size: Math.min(args.pageSize, 25),
28
+ };
29
+ if (args.search)
30
+ body.search = args.search;
31
+ if (args.states)
32
+ body.states = args.states.split(",").map((s) => s.trim());
33
+ if (args.startDate)
34
+ body.start_date = args.startDate;
35
+ if (args.endDate)
36
+ body.end_date = args.endDate;
37
+ if (args.loanTypes)
38
+ body.loan_types = args.loanTypes.split(",").map((s) => s.trim());
39
+ autoFillPlrDates(body);
40
+ const data = await plr.msaRankings(body);
41
+ const items = data?.results ?? data?.data ?? (Array.isArray(data) ? data : []);
42
+ const total = data?.count ?? items.length;
43
+ const lines = [
44
+ `## MSA Rankings by Lending Activity`,
45
+ `**Total:** ${total} | **Page:** ${args.page}`,
46
+ "",
47
+ ];
48
+ if (items.length > 0) {
49
+ const fmtPct = (v) => v != null ? `${(Number(v) * 100).toFixed(1)}%` : "—";
50
+ const rows = items.slice(0, 25).map((m, i) => [
51
+ i + 1 + (args.page - 1) * args.pageSize,
52
+ m.msa ?? "—",
53
+ m.recent_loan_count ?? "—",
54
+ fmtDollars(m.recent_total_amount),
55
+ fmtPct(m.loan_count_percent_change),
56
+ fmtPct(m.total_amount_percent_change),
57
+ ]);
58
+ lines.push(markdownTable(["#", "MSA", "Loans", "Volume", "Loan %Chg", "Vol %Chg"], rows));
59
+ }
60
+ else {
61
+ lines.push("```json");
62
+ lines.push(truncatedJson(data, 3000));
63
+ lines.push("```");
64
+ }
65
+ const firstMsa = items[0]?.msa;
66
+ const actions = [
67
+ ...(firstMsa ? [action("plr_top_lenders", "Top lenders in leading MSA", { msas: firstMsa })] : []),
68
+ ...(firstMsa ? [action("plr_borrower_rankings", "Top borrowers in leading MSA", { msas: firstMsa })] : []),
69
+ ...(firstMsa ? [action("sfr_top_buyers", "SFR buyers in leading MSA", { search_type: "msa", msa: firstMsa })] : []),
70
+ ];
71
+ return structuredResult(lines.join("\n"), { items, total, page: args.page }, actions);
72
+ });
73
+ }
74
+ //# sourceMappingURL=msaRankings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"msaRankings.js","sourceRoot":"","sources":["../../../src/tools/plr/msaRankings.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { PlrClient } from "../../services/plr.js";
3
+ export declare function registerNegativeRemarksTool(server: McpServer, plr: PlrClient): void;
@@ -0,0 +1,94 @@
1
+ import { z } from "zod";
2
+ import { structuredResult, markdownTable, fmtDollars } from "../formatters.js";
3
+ import { registerToolSafe } from "../registerToolSafe.js";
4
+ import { action } from "../nextActions.js";
5
+ const Input = z.object({
6
+ borrower_name: z.string().optional().describe("Borrower/entity name (partial match, ILIKE)"),
7
+ lender_name: z.string().optional().describe("Lender name (partial match on standardized name)"),
8
+ states: z.string().optional().describe("Comma-separated state codes (e.g. 'FL,TX')"),
9
+ event_types: z.string().optional().describe("Comma-separated event types (e.g. 'FORECLOSURE')"),
10
+ negative_event_date_start: z.string().optional().describe("Start date for events (YYYY-MM-DD)"),
11
+ negative_event_date_end: z.string().optional().describe("End date for events (YYYY-MM-DD)"),
12
+ page: z.coerce.number().default(1).describe("Page number (default 1)"),
13
+ pageSize: z.coerce.number().default(25).describe("Results per page (default 25, max 25)"),
14
+ });
15
+ export function registerNegativeRemarksTool(server, plr) {
16
+ registerToolSafe(server, "plr_negative_remarks", {
17
+ title: "Negative remarks / adverse events (PLR)",
18
+ description: "Search adverse loan events — foreclosures, defaults, and negative remarks from private lender originations. " +
19
+ "Filter by borrower name, lender, state, event type, and date range. " +
20
+ "Use to identify borrower credit risk and distress patterns. " +
21
+ "CHAIN: combine with plr_churned_borrowers to find churned borrowers with negative events, " +
22
+ "or with sfr_distress_search for property-level distress.",
23
+ inputSchema: Input,
24
+ }, async (args) => {
25
+ const body = {
26
+ page: args.page,
27
+ page_size: Math.min(args.pageSize, 25),
28
+ };
29
+ if (args.borrower_name)
30
+ body.borrower_name = args.borrower_name;
31
+ if (args.lender_name)
32
+ body.lender_name = args.lender_name;
33
+ if (args.states)
34
+ body.states = args.states.split(",").map((s) => s.trim());
35
+ if (args.event_types)
36
+ body.event_types = args.event_types.split(",").map((s) => s.trim());
37
+ if (args.negative_event_date_start)
38
+ body.negative_event_date_start = args.negative_event_date_start;
39
+ if (args.negative_event_date_end)
40
+ body.negative_event_date_end = args.negative_event_date_end;
41
+ const data = await plr.negativeRemarks(body);
42
+ const items = data?.results ?? data?.data ?? (Array.isArray(data) ? data : []);
43
+ const total = data?.count ?? items.length;
44
+ const filterDesc = [
45
+ args.borrower_name && `borrower="${args.borrower_name}"`,
46
+ args.lender_name && `lender="${args.lender_name}"`,
47
+ args.states && `states=${args.states}`,
48
+ args.event_types && `events=${args.event_types}`,
49
+ ].filter(Boolean).join(", ") || "all";
50
+ const lines = [
51
+ `## Negative Remarks — ${filterDesc}`,
52
+ `**Total:** ${total} | **Page:** ${args.page} | **Showing:** ${items.length}`,
53
+ "",
54
+ ];
55
+ if (items.length > 0) {
56
+ const rows = items.slice(0, 25).map((r) => [
57
+ r.borrower_name ?? "—",
58
+ r.lender_name ?? r.lender ?? "—",
59
+ fmtDollars(r.loan_amount),
60
+ r.negative_event_date ?? "—",
61
+ r.event_type ?? "—",
62
+ r.address ?? "—",
63
+ r.city ?? "—",
64
+ r.state ?? "—",
65
+ ]);
66
+ lines.push(markdownTable(["Borrower", "Lender", "Loan Amt", "Event Date", "Event Type", "Address", "City", "State"], rows));
67
+ }
68
+ else {
69
+ lines.push("_No negative remarks found._");
70
+ }
71
+ const slimItems = items.slice(0, 25).map((r) => ({
72
+ property_id: r.property_id,
73
+ borrower_name: r.borrower_name,
74
+ lender_name: r.lender_name ?? r.lender,
75
+ loan_date: r.loan_date,
76
+ loan_amount: r.loan_amount,
77
+ negative_event_date: r.negative_event_date,
78
+ event_type: r.event_type,
79
+ address: r.address,
80
+ city: r.city,
81
+ state: r.state,
82
+ zip_code: r.zip_code,
83
+ }));
84
+ const firstName = items[0]?.borrower_name;
85
+ const firstState = items[0]?.state;
86
+ const actions = [
87
+ ...(firstName ? [action("plr_borrower_loans", "Borrower loan history", { borrowerNames: firstName })] : []),
88
+ ...(firstName ? [action("plr_borrower_contacts", "Contact info", { borrowerNames: firstName })] : []),
89
+ ...(firstName && firstState ? [action("sfr_distress_search", "Property distress status", { owner_name: firstName, state: firstState })] : []),
90
+ ];
91
+ return structuredResult(lines.join("\n"), { items: slimItems, total, page: args.page }, actions);
92
+ });
93
+ }
94
+ //# sourceMappingURL=negativeRemarks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"negativeRemarks.js","sourceRoot":"","sources":["../../../src/tools/plr/negativeRemarks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { PlrClient } from "../../services/plr.js";
3
+ export declare function registerOwnerSearchTool(server: McpServer, plr: PlrClient): void;
@@ -0,0 +1,57 @@
1
+ import { z } from "zod";
2
+ import { structuredResult, markdownTable } from "../formatters.js";
3
+ import { registerToolSafe } from "../registerToolSafe.js";
4
+ import { action } from "../nextActions.js";
5
+ const Input = z.object({
6
+ search: z.string().describe("Person/owner name to search (partial match, ILIKE)"),
7
+ states: z.string().optional().describe("Comma-separated state codes for filtering (e.g. 'CA,TX')"),
8
+ page: z.coerce.number().default(1).describe("Page number (default 1)"),
9
+ pageSize: z.coerce.number().default(25).describe("Results per page (default 25, max 25)"),
10
+ });
11
+ export function registerOwnerSearchTool(server, plr) {
12
+ registerToolSafe(server, "plr_owner_search", {
13
+ title: "Principal/owner name search (PLR)",
14
+ description: "Search for principal/owner names (people, not LLCs). Returns person names and their loan counts. " +
15
+ "Use when a user asks about a specific person rather than an entity/LLC. " +
16
+ "Requires a state filter for best results. " +
17
+ "CHAIN: owner names → plr_borrower_contacts (to get linked LLCs and contact info) → " +
18
+ "plr_borrower_loans (loan history under associated entities).",
19
+ inputSchema: Input,
20
+ }, async (args) => {
21
+ const query = {
22
+ search: args.search,
23
+ page: args.page,
24
+ page_size: Math.min(args.pageSize, 25),
25
+ };
26
+ if (args.states)
27
+ query.states = args.states;
28
+ const data = await plr.ownersList(query);
29
+ const items = data?.results ?? data?.data ?? (Array.isArray(data) ? data : []);
30
+ const total = data?.count ?? items.length;
31
+ const lines = [
32
+ `## Owner Search — "${args.search}"${args.states ? ` (${args.states})` : ""}`,
33
+ `**Total:** ${total} | **Page:** ${args.page} | **Showing:** ${items.length}`,
34
+ "",
35
+ ];
36
+ if (items.length > 0) {
37
+ const rows = items.slice(0, 25).map((r, i) => [
38
+ i + 1 + (args.page - 1) * args.pageSize,
39
+ r.owner_name ?? "—",
40
+ r.loans_count ?? "—",
41
+ ]);
42
+ lines.push(markdownTable(["#", "Owner Name", "Loans"], rows));
43
+ }
44
+ else {
45
+ lines.push("_No owners found._ " +
46
+ (!args.states ? "Try adding a states filter — person name search works best with a state (e.g. states='TX'). " : "") +
47
+ "Check spelling and try partial names (first + last only, no middle name).");
48
+ }
49
+ const firstName = items[0]?.owner_name;
50
+ const actions = [
51
+ ...(firstName ? [action("plr_borrower_contacts", "Contact info + linked LLCs", { borrowerNames: firstName })] : []),
52
+ ...(firstName ? [action("plr_negative_remarks", "Check for negative events", { borrower_name: firstName })] : []),
53
+ ];
54
+ return structuredResult(lines.join("\n"), { items, total, page: args.page }, actions);
55
+ });
56
+ }
57
+ //# sourceMappingURL=ownerSearch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ownerSearch.js","sourceRoot":"","sources":["../../../src/tools/plr/ownerSearch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { PlrClient } from "../../services/plr.js";
3
+ export declare function registerPortfolioSummaryTool(server: McpServer, plr: PlrClient): void;
@@ -0,0 +1,99 @@
1
+ import { z } from "zod";
2
+ import { structuredResult, kvSummary, markdownTable, truncatedJson, fmtDollars } from "../formatters.js";
3
+ import { registerToolSafe } from "../registerToolSafe.js";
4
+ import { autoFillPlrDates } from "../dateHelper.js";
5
+ import { action } from "../nextActions.js";
6
+ const Input = z.object({
7
+ startDate: z.string().optional().describe("Start date, e.g. '2024-01-01'"),
8
+ endDate: z.string().optional().describe("End date"),
9
+ });
10
+ export function registerPortfolioSummaryTool(server, plr) {
11
+ registerToolSafe(server, "plr_portfolio_summary", {
12
+ title: "Nationwide private lending summary — totals & distributions (PLR)",
13
+ description: "Get a NATIONWIDE summary of the private lending market: total loans, total volume, " +
14
+ "unique lenders, unique borrowers, MSA count, state count, plus loan type and " +
15
+ "land use distributions. NOTE: This is nationwide only — no geographic filters. " +
16
+ "Use this to set context before deeper analysis. " +
17
+ "For geographic breakdowns, use plr_msa_rankings.",
18
+ inputSchema: Input,
19
+ }, async (args) => {
20
+ const query = {};
21
+ if (args.startDate)
22
+ query.start_date = args.startDate;
23
+ if (args.endDate)
24
+ query.end_date = args.endDate;
25
+ autoFillPlrDates(query);
26
+ const data = await plr.portfolioSummary(query);
27
+ const lines = [`## Private Lending Market Summary`, ""];
28
+ if (data && typeof data === "object") {
29
+ // API returns {date_range, overall_metrics: {...}, loan_type_distribution, land_use_distribution}
30
+ const metrics = data.overall_metrics ?? data;
31
+ const dateRange = data.date_range;
32
+ if (dateRange) {
33
+ lines.push(`**Period:** ${dateRange.start_date} to ${dateRange.end_date}`, "");
34
+ }
35
+ lines.push(kvSummary([
36
+ ["Total Loans", metrics.total_loans != null ? Number(metrics.total_loans).toLocaleString() : undefined],
37
+ ["Total Volume", metrics.total_amount ? fmtDollars(metrics.total_amount) : undefined],
38
+ ["Average Loan", metrics.avg_amount ? fmtDollars(metrics.avg_amount) : undefined],
39
+ ["Unique Lenders", metrics.unique_lenders != null ? Number(metrics.unique_lenders).toLocaleString() : undefined],
40
+ ["Unique Borrowers", metrics.unique_borrowers != null ? Number(metrics.unique_borrowers).toLocaleString() : undefined],
41
+ ["MSAs", metrics.unique_msas ?? metrics.msa_count],
42
+ ["States", metrics.unique_states ?? metrics.state_count],
43
+ ]));
44
+ const loanTypes = data.loan_type_distribution ?? data.loan_types;
45
+ if (Array.isArray(loanTypes) && loanTypes.length > 0) {
46
+ lines.push("", "### Loan Type Distribution");
47
+ const rows = loanTypes.map((lt) => [
48
+ lt.loan_type ?? "—",
49
+ lt.loan_count != null ? Number(lt.loan_count).toLocaleString() : "—",
50
+ fmtDollars(lt.total_amount),
51
+ ]);
52
+ lines.push(markdownTable(["Type", "Loans", "Volume"], rows));
53
+ }
54
+ const landUse = data.land_use_distribution ?? data.land_use;
55
+ if (Array.isArray(landUse) && landUse.length > 0) {
56
+ lines.push("", "### Land Use Distribution");
57
+ const rows = landUse.map((lu) => [
58
+ lu.land_use_category ?? "—",
59
+ lu.loan_count != null ? Number(lu.loan_count).toLocaleString() : "—",
60
+ fmtDollars(lu.total_amount),
61
+ ]);
62
+ lines.push(markdownTable(["Category", "Loans", "Volume"], rows));
63
+ }
64
+ }
65
+ else {
66
+ lines.push("```json");
67
+ lines.push(truncatedJson(data, 4000));
68
+ lines.push("```");
69
+ }
70
+ const actions = [
71
+ action("plr_market_trends", "Time series trends", { granularity: "monthly" }),
72
+ action("plr_msa_rankings", "Geographic breakdown by MSA", {}),
73
+ action("plr_top_lenders", "Top lenders by volume", {}),
74
+ ];
75
+ const metrics2 = data?.overall_metrics ?? data ?? {};
76
+ const loanTypes2 = data?.loan_type_distribution ?? data?.loan_types;
77
+ const landUse2 = data?.land_use_distribution ?? data?.land_use;
78
+ const structured = {
79
+ date_range: data?.date_range,
80
+ overall_metrics: {
81
+ total_loans: metrics2.total_loans,
82
+ total_amount: metrics2.total_amount,
83
+ avg_amount: metrics2.avg_amount,
84
+ unique_lenders: metrics2.unique_lenders,
85
+ unique_borrowers: metrics2.unique_borrowers,
86
+ unique_msas: metrics2.unique_msas ?? metrics2.msa_count,
87
+ unique_states: metrics2.unique_states ?? metrics2.state_count,
88
+ },
89
+ loan_type_distribution: Array.isArray(loanTypes2)
90
+ ? loanTypes2.map((lt) => ({ loan_type: lt.loan_type, loan_count: lt.loan_count, total_amount: lt.total_amount }))
91
+ : undefined,
92
+ land_use_distribution: Array.isArray(landUse2)
93
+ ? landUse2.map((lu) => ({ land_use_category: lu.land_use_category, loan_count: lu.loan_count, total_amount: lu.total_amount }))
94
+ : undefined,
95
+ };
96
+ return structuredResult(lines.join("\n"), structured, actions);
97
+ });
98
+ }
99
+ //# sourceMappingURL=portfolioSummary.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"portfolioSummary.js","sourceRoot":"","sources":["../../../src/tools/plr/portfolioSummary.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { PlrClient } from "../../services/plr.js";
3
+ export declare function registerTopBorrowersTool(server: McpServer, plr: PlrClient): void;
@@ -0,0 +1,69 @@
1
+ import { z } from "zod";
2
+ import { structuredResult, markdownTable, truncatedJson, fmtDollars } from "../formatters.js";
3
+ import { registerToolSafe } from "../registerToolSafe.js";
4
+ import { autoFillPlrDates } from "../dateHelper.js";
5
+ import { action } from "../nextActions.js";
6
+ const Input = z.object({
7
+ state: z.string().optional().describe("Optional state filter, e.g. 'CA'"),
8
+ startDate: z.string().optional().describe("Start date, e.g. '2024-01-01'"),
9
+ endDate: z.string().optional().describe("End date"),
10
+ page: z.coerce.number().default(1).describe("Page number (default 1)"),
11
+ pageSize: z.coerce.number().default(25).describe("Results per page (default 25, max 25)"),
12
+ });
13
+ export function registerTopBorrowersTool(server, plr) {
14
+ registerToolSafe(server, "plr_top_borrowers", {
15
+ title: "Nationwide borrower leaderboard (PLR)",
16
+ description: "Simple nationwide leaderboard of the largest private lending borrowers by loan volume. " +
17
+ "State filter only — NO MSA/city filter. For borrowers in a specific metro/MSA, use plr_borrower_search. " +
18
+ "Returns borrower name, loan count, total volume, avg loan size, and number of lenders. " +
19
+ "Best for quick 'who are the biggest borrowers nationally?' or 'top borrowers in FL' questions. " +
20
+ "Use plr_borrower_profile for full details on any borrower. " +
21
+ "CHAIN: Pass borrower names to sfr_distress_search (as owner_name + state) to find distressed properties they own.",
22
+ inputSchema: Input,
23
+ }, async (args) => {
24
+ const body = {
25
+ page: args.page,
26
+ page_size: Math.min(args.pageSize, 25),
27
+ };
28
+ if (args.state)
29
+ body.state = args.state;
30
+ if (args.startDate)
31
+ body.start_date = args.startDate;
32
+ if (args.endDate)
33
+ body.end_date = args.endDate;
34
+ autoFillPlrDates(body);
35
+ const data = await plr.nationwideLargestBorrowers(body);
36
+ const items = data?.results ?? data?.data ?? (Array.isArray(data) ? data : []);
37
+ const total = data?.count ?? items.length;
38
+ const lines = [
39
+ `## Top Borrowers Nationwide${args.state ? ` (${args.state})` : ""}`,
40
+ `**Total:** ${total} | **Page:** ${args.page}`,
41
+ "",
42
+ ];
43
+ if (items.length > 0) {
44
+ // API returns {borrower, loan_count, total_amount, avg_loan_amount, lenders}
45
+ const rows = items.slice(0, 30).map((b, i) => [
46
+ i + 1 + (args.page - 1) * args.pageSize,
47
+ b.borrower ?? b.borrower_name ?? b.name ?? "—",
48
+ b.loan_count ?? b.total_loans ?? "—",
49
+ fmtDollars(b.total_amount),
50
+ b.avg_loan_amount ? fmtDollars(b.avg_loan_amount) : "—",
51
+ b.lenders ? String(b.lenders).split(";").length : "—",
52
+ ]);
53
+ lines.push(markdownTable(["#", "Borrower", "Loans", "Volume", "Avg Loan", "Lenders"], rows));
54
+ }
55
+ else {
56
+ lines.push("```json");
57
+ lines.push(truncatedJson(data, 3000));
58
+ lines.push("```");
59
+ }
60
+ const firstName = items[0]?.borrower ?? items[0]?.borrower_name ?? items[0]?.name;
61
+ const actions = [
62
+ ...(firstName ? [action("plr_borrower_profile", "Full profile for top borrower", { borrowerName: firstName })] : []),
63
+ ...(firstName ? [action("plr_borrower_loans", "Loan history for top borrower", { borrowerNames: firstName })] : []),
64
+ ...(firstName ? [action("plr_borrower_contacts", "Contact info for top borrower", { borrowerNames: firstName })] : []),
65
+ ];
66
+ return structuredResult(lines.join("\n"), { items, total, page: args.page }, actions);
67
+ });
68
+ }
69
+ //# sourceMappingURL=topBorrowers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"topBorrowers.js","sourceRoot":"","sources":["../../../src/tools/plr/topBorrowers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { PlrClient } from "../../services/plr.js";
3
+ export declare function registerTopLendersTool(server: McpServer, plr: PlrClient): void;