fdic-mcp-server 1.24.0 → 1.25.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/dist/index.js +718 -477
- package/dist/server.js +722 -479
- package/package.json +4 -2
package/dist/index.js
CHANGED
|
@@ -32,7 +32,7 @@ var import_types = require("@modelcontextprotocol/sdk/types.js");
|
|
|
32
32
|
var import_express2 = __toESM(require("express"));
|
|
33
33
|
|
|
34
34
|
// src/constants.ts
|
|
35
|
-
var VERSION = true ? "1.
|
|
35
|
+
var VERSION = true ? "1.25.1" : process.env.npm_package_version ?? "0.0.0-dev";
|
|
36
36
|
var FDIC_API_BASE_URL = "https://banks.data.fdic.gov/api";
|
|
37
37
|
var CHARACTER_LIMIT = 5e4;
|
|
38
38
|
var DEFAULT_FDIC_MAX_RESPONSE_BYTES = 5 * 1024 * 1024;
|
|
@@ -31846,13 +31846,96 @@ function formatLookupResultText(label, record, preferredKeys) {
|
|
|
31846
31846
|
return `${label}
|
|
31847
31847
|
${summarizeRecord(record, preferredKeys, 8)}`;
|
|
31848
31848
|
}
|
|
31849
|
-
|
|
31849
|
+
var ERROR_CODE_FROM_MESSAGE = [
|
|
31850
|
+
{ pattern: /Bad request to FDIC API/, code: "FDIC_BAD_FILTER", retryable: false },
|
|
31851
|
+
{ pattern: /rate limit/i, code: "FDIC_RATE_LIMIT", retryable: true },
|
|
31852
|
+
{ pattern: /server error/i, code: "FDIC_UPSTREAM_ERROR", retryable: true },
|
|
31853
|
+
{
|
|
31854
|
+
pattern: /response-size limit|maxContentLength/,
|
|
31855
|
+
code: "FDIC_RESPONSE_TOO_LARGE",
|
|
31856
|
+
retryable: false
|
|
31857
|
+
},
|
|
31858
|
+
{ pattern: /canceled/i, code: "FDIC_CANCELED", retryable: true },
|
|
31859
|
+
{ pattern: /No (institution|failure|financial)/i, code: "FDIC_NOT_FOUND", retryable: false },
|
|
31860
|
+
{ pattern: /quarter-end date/i, code: "FDIC_BAD_DATE", retryable: false }
|
|
31861
|
+
];
|
|
31862
|
+
function inferErrorCode(message) {
|
|
31863
|
+
for (const entry of ERROR_CODE_FROM_MESSAGE) {
|
|
31864
|
+
if (entry.pattern.test(message)) {
|
|
31865
|
+
return { code: entry.code, retryable: entry.retryable };
|
|
31866
|
+
}
|
|
31867
|
+
}
|
|
31868
|
+
return { code: "FDIC_UNKNOWN", retryable: false };
|
|
31869
|
+
}
|
|
31870
|
+
function formatToolError(err, override) {
|
|
31850
31871
|
const message = err instanceof Error ? err.message : String(err);
|
|
31872
|
+
const inferred = inferErrorCode(message);
|
|
31873
|
+
const payload = {
|
|
31874
|
+
code: override?.code ?? inferred.code,
|
|
31875
|
+
message: override?.message ?? message,
|
|
31876
|
+
retryable: override?.retryable ?? inferred.retryable,
|
|
31877
|
+
hint: override?.hint
|
|
31878
|
+
};
|
|
31851
31879
|
return {
|
|
31852
|
-
content: [{ type: "text", text: `Error: ${message}` }],
|
|
31880
|
+
content: [{ type: "text", text: `Error: ${payload.message}` }],
|
|
31881
|
+
structuredContent: payload,
|
|
31853
31882
|
isError: true
|
|
31854
31883
|
};
|
|
31855
31884
|
}
|
|
31885
|
+
var DEFAULT_STRUCTURED_BYTE_LIMIT = 2e5;
|
|
31886
|
+
function capStructuredContent(output, recordKey, byteLimit = DEFAULT_STRUCTURED_BYTE_LIMIT) {
|
|
31887
|
+
const records = output[recordKey];
|
|
31888
|
+
if (!Array.isArray(records)) {
|
|
31889
|
+
return output;
|
|
31890
|
+
}
|
|
31891
|
+
const initialBytes = Buffer.byteLength(JSON.stringify(output), "utf8");
|
|
31892
|
+
if (initialBytes <= byteLimit) {
|
|
31893
|
+
return output;
|
|
31894
|
+
}
|
|
31895
|
+
let lo = 0;
|
|
31896
|
+
let hi = records.length;
|
|
31897
|
+
let best = 0;
|
|
31898
|
+
while (lo <= hi) {
|
|
31899
|
+
const mid = Math.floor((lo + hi) / 2);
|
|
31900
|
+
const candidate = buildTruncatedPayload(output, recordKey, records, mid);
|
|
31901
|
+
const bytes = Buffer.byteLength(JSON.stringify(candidate), "utf8");
|
|
31902
|
+
if (bytes <= byteLimit) {
|
|
31903
|
+
best = mid;
|
|
31904
|
+
lo = mid + 1;
|
|
31905
|
+
} else {
|
|
31906
|
+
hi = mid - 1;
|
|
31907
|
+
}
|
|
31908
|
+
}
|
|
31909
|
+
if (best === 0) {
|
|
31910
|
+
throw new Error(
|
|
31911
|
+
"FDIC API response exceeded the configured response-size limit before parsing: a single record exceeded the structured-content byte cap. Request fewer fields with `fields=`, lower `limit`, or raise the cap."
|
|
31912
|
+
);
|
|
31913
|
+
}
|
|
31914
|
+
return buildTruncatedPayload(output, recordKey, records, best);
|
|
31915
|
+
}
|
|
31916
|
+
function buildTruncatedPayload(output, recordKey, records, slicedLength) {
|
|
31917
|
+
const sliced = records.slice(0, slicedLength);
|
|
31918
|
+
const result = {
|
|
31919
|
+
...output,
|
|
31920
|
+
[recordKey]: sliced,
|
|
31921
|
+
truncated: true
|
|
31922
|
+
};
|
|
31923
|
+
const offset = typeof output.offset === "number" ? output.offset : void 0;
|
|
31924
|
+
const upstreamCount = typeof output.count === "number" ? output.count : void 0;
|
|
31925
|
+
const upstreamNextOffset = typeof output.next_offset === "number" ? output.next_offset : void 0;
|
|
31926
|
+
if (offset !== void 0) {
|
|
31927
|
+
result.count = slicedLength;
|
|
31928
|
+
result.next_offset = offset + slicedLength;
|
|
31929
|
+
result.has_more = true;
|
|
31930
|
+
}
|
|
31931
|
+
if (upstreamCount !== void 0 || upstreamNextOffset !== void 0) {
|
|
31932
|
+
result.upstream = {
|
|
31933
|
+
...upstreamCount !== void 0 ? { count: upstreamCount } : {},
|
|
31934
|
+
...upstreamNextOffset !== void 0 ? { next_offset: upstreamNextOffset } : {}
|
|
31935
|
+
};
|
|
31936
|
+
}
|
|
31937
|
+
return result;
|
|
31938
|
+
}
|
|
31856
31939
|
|
|
31857
31940
|
// src/schemas/common.ts
|
|
31858
31941
|
var import_zod = require("zod");
|
|
@@ -31877,6 +31960,91 @@ var CertSchema = import_zod.z.object({
|
|
|
31877
31960
|
fields: import_zod.z.string().optional().describe("Comma-separated list of fields to return")
|
|
31878
31961
|
});
|
|
31879
31962
|
|
|
31963
|
+
// src/schemas/output.ts
|
|
31964
|
+
var import_zod2 = require("zod");
|
|
31965
|
+
var FdicRecord = import_zod2.z.record(import_zod2.z.unknown());
|
|
31966
|
+
var Pagination = {
|
|
31967
|
+
total: import_zod2.z.number().int(),
|
|
31968
|
+
offset: import_zod2.z.number().int(),
|
|
31969
|
+
count: import_zod2.z.number().int(),
|
|
31970
|
+
has_more: import_zod2.z.boolean(),
|
|
31971
|
+
next_offset: import_zod2.z.number().int().optional()
|
|
31972
|
+
};
|
|
31973
|
+
function paginatedSearchSchema(recordKey) {
|
|
31974
|
+
return import_zod2.z.object({
|
|
31975
|
+
...Pagination,
|
|
31976
|
+
[recordKey]: import_zod2.z.array(FdicRecord),
|
|
31977
|
+
truncated: import_zod2.z.boolean().optional()
|
|
31978
|
+
});
|
|
31979
|
+
}
|
|
31980
|
+
var FdicInstitutionsSearchOutputSchema = paginatedSearchSchema(
|
|
31981
|
+
"institutions"
|
|
31982
|
+
);
|
|
31983
|
+
var FdicFailuresSearchOutputSchema = paginatedSearchSchema("failures");
|
|
31984
|
+
var FdicLocationsSearchOutputSchema = paginatedSearchSchema("locations");
|
|
31985
|
+
var FdicHistorySearchOutputSchema = paginatedSearchSchema("events");
|
|
31986
|
+
var FdicFinancialsSearchOutputSchema = paginatedSearchSchema(
|
|
31987
|
+
"financials"
|
|
31988
|
+
);
|
|
31989
|
+
var FdicSummarySearchOutputSchema = paginatedSearchSchema("summary");
|
|
31990
|
+
var FdicSodSearchOutputSchema = paginatedSearchSchema("deposits");
|
|
31991
|
+
var FdicDemographicsSearchOutputSchema = paginatedSearchSchema(
|
|
31992
|
+
"demographics"
|
|
31993
|
+
);
|
|
31994
|
+
var FdicInstitutionLookupOutputSchema = import_zod2.z.object({}).passthrough();
|
|
31995
|
+
var FdicFailureLookupOutputSchema = import_zod2.z.object({}).passthrough();
|
|
31996
|
+
var ChatGptSearchResultSchema = import_zod2.z.object({
|
|
31997
|
+
results: import_zod2.z.array(
|
|
31998
|
+
import_zod2.z.object({
|
|
31999
|
+
id: import_zod2.z.string(),
|
|
32000
|
+
title: import_zod2.z.string(),
|
|
32001
|
+
url: import_zod2.z.string()
|
|
32002
|
+
})
|
|
32003
|
+
)
|
|
32004
|
+
});
|
|
32005
|
+
var ChatGptFetchResultSchema = import_zod2.z.object({
|
|
32006
|
+
id: import_zod2.z.string(),
|
|
32007
|
+
title: import_zod2.z.string(),
|
|
32008
|
+
text: import_zod2.z.string(),
|
|
32009
|
+
url: import_zod2.z.string(),
|
|
32010
|
+
metadata: import_zod2.z.record(import_zod2.z.unknown()).optional()
|
|
32011
|
+
});
|
|
32012
|
+
var Source = import_zod2.z.object({ title: import_zod2.z.string(), url: import_zod2.z.string() });
|
|
32013
|
+
var FdicBankDeepDiveOutputSchema = import_zod2.z.object({
|
|
32014
|
+
institution: import_zod2.z.object({
|
|
32015
|
+
cert: import_zod2.z.number().int(),
|
|
32016
|
+
name: import_zod2.z.string(),
|
|
32017
|
+
city: import_zod2.z.string(),
|
|
32018
|
+
state: import_zod2.z.string(),
|
|
32019
|
+
active: import_zod2.z.boolean(),
|
|
32020
|
+
asset_thousands: import_zod2.z.number().optional(),
|
|
32021
|
+
deposit_thousands: import_zod2.z.number().optional(),
|
|
32022
|
+
offices: import_zod2.z.number().optional(),
|
|
32023
|
+
charter_class: import_zod2.z.string(),
|
|
32024
|
+
regulator: import_zod2.z.string(),
|
|
32025
|
+
established: import_zod2.z.string(),
|
|
32026
|
+
report_date: import_zod2.z.string()
|
|
32027
|
+
}),
|
|
32028
|
+
assessment: import_zod2.z.object({
|
|
32029
|
+
official_rating: import_zod2.z.boolean(),
|
|
32030
|
+
proxy_band: import_zod2.z.string(),
|
|
32031
|
+
caveat: import_zod2.z.string()
|
|
32032
|
+
}),
|
|
32033
|
+
metrics: import_zod2.z.object({
|
|
32034
|
+
roa: import_zod2.z.string().optional(),
|
|
32035
|
+
roe: import_zod2.z.string().optional(),
|
|
32036
|
+
tier1_leverage: import_zod2.z.string().optional(),
|
|
32037
|
+
noncurrent_loans: import_zod2.z.string().optional(),
|
|
32038
|
+
loan_to_deposit: import_zod2.z.string().optional(),
|
|
32039
|
+
net_interest_margin: import_zod2.z.string().optional(),
|
|
32040
|
+
efficiency_ratio: import_zod2.z.string().optional()
|
|
32041
|
+
}),
|
|
32042
|
+
risk_signals: import_zod2.z.array(import_zod2.z.string()),
|
|
32043
|
+
warnings: import_zod2.z.array(import_zod2.z.string()),
|
|
32044
|
+
sources: import_zod2.z.array(Source)
|
|
32045
|
+
});
|
|
32046
|
+
var FdicAnalysisOutputSchema = import_zod2.z.object({}).passthrough();
|
|
32047
|
+
|
|
31880
32048
|
// src/tools/institutions.ts
|
|
31881
32049
|
function registerInstitutionTools(server) {
|
|
31882
32050
|
server.registerTool(
|
|
@@ -31885,6 +32053,7 @@ function registerInstitutionTools(server) {
|
|
|
31885
32053
|
title: "Search FDIC Institutions",
|
|
31886
32054
|
description: "Use this when the user needs FDIC-insured institution search results by name, state, CERT, asset size, charter class, or regulatory status. Returns institution profile rows with pagination; use fdic://schemas/institutions for the full field catalog.",
|
|
31887
32055
|
inputSchema: CommonQuerySchema,
|
|
32056
|
+
outputSchema: FdicInstitutionsSearchOutputSchema,
|
|
31888
32057
|
annotations: {
|
|
31889
32058
|
readOnlyHint: true,
|
|
31890
32059
|
destructiveHint: false,
|
|
@@ -31901,7 +32070,10 @@ function registerInstitutionTools(server) {
|
|
|
31901
32070
|
params.offset ?? 0,
|
|
31902
32071
|
records.length
|
|
31903
32072
|
);
|
|
31904
|
-
const output =
|
|
32073
|
+
const output = capStructuredContent(
|
|
32074
|
+
{ ...pagination, institutions: records },
|
|
32075
|
+
"institutions"
|
|
32076
|
+
);
|
|
31905
32077
|
const text = truncateIfNeeded(
|
|
31906
32078
|
formatSearchResultText("institutions", records, pagination, [
|
|
31907
32079
|
"CERT",
|
|
@@ -31927,8 +32099,9 @@ function registerInstitutionTools(server) {
|
|
|
31927
32099
|
"fdic_get_institution",
|
|
31928
32100
|
{
|
|
31929
32101
|
title: "Get Institution by Certificate Number",
|
|
31930
|
-
description: "Use this when the user knows an exact FDIC Certificate Number and needs one institution profile. To discover a CERT first, call fdic_search_institutions or
|
|
32102
|
+
description: "Use this when the user knows an exact FDIC Certificate Number and needs one institution profile. To discover a CERT first, call fdic_search_institutions or fdic_search.",
|
|
31931
32103
|
inputSchema: CertSchema,
|
|
32104
|
+
outputSchema: FdicInstitutionLookupOutputSchema,
|
|
31932
32105
|
annotations: {
|
|
31933
32106
|
readOnlyHint: true,
|
|
31934
32107
|
destructiveHint: false,
|
|
@@ -31983,43 +32156,9 @@ function registerFailureTools(server) {
|
|
|
31983
32156
|
"fdic_search_failures",
|
|
31984
32157
|
{
|
|
31985
32158
|
title: "Search Bank Failures",
|
|
31986
|
-
description:
|
|
31987
|
-
|
|
31988
|
-
Returns data on bank failures including failure date, resolution type, estimated cost to the FDIC Deposit Insurance Fund, and acquiring institution info.
|
|
31989
|
-
|
|
31990
|
-
Common filter examples:
|
|
31991
|
-
- By state: STALP:CA (two-letter state code)
|
|
31992
|
-
- By year range: FAILDATE:[2008-01-01 TO 2010-12-31]
|
|
31993
|
-
- Recent failures: FAILDATE:[2020-01-01 TO *]
|
|
31994
|
-
- By resolution type: RESTYPE:PAYOFF or RESTYPE:"PURCHASE AND ASSUMPTION"
|
|
31995
|
-
- Large failures by cost: COST:[100000 TO *] (cost in $thousands)
|
|
31996
|
-
- By name: NAME:"Washington Mutual"
|
|
31997
|
-
|
|
31998
|
-
Resolution types (RESTYPE):
|
|
31999
|
-
PAYOFF = depositors paid directly, no acquirer
|
|
32000
|
-
PURCHASE AND ASSUMPTION = acquirer buys assets and assumes deposits
|
|
32001
|
-
PAYOUT = variant of payoff with insured-deposit transfer
|
|
32002
|
-
|
|
32003
|
-
Key returned fields:
|
|
32004
|
-
- CERT: FDIC Certificate Number
|
|
32005
|
-
- NAME: Institution name
|
|
32006
|
-
- CITY, STALP (two-letter state code), STNAME (full state name): Location
|
|
32007
|
-
- FAILDATE: Date of failure (YYYY-MM-DD)
|
|
32008
|
-
- SAVR: Savings association flag (SA) or bank (BK)
|
|
32009
|
-
- RESTYPE: Resolution type (see above)
|
|
32010
|
-
- QBFASSET: Total assets at failure ($thousands)
|
|
32011
|
-
- COST: Estimated cost to FDIC Deposit Insurance Fund ($thousands)
|
|
32012
|
-
|
|
32013
|
-
Args:
|
|
32014
|
-
- filters (string, optional): ElasticSearch query filter
|
|
32015
|
-
- fields (string, optional): Comma-separated field names
|
|
32016
|
-
- limit (number): Records to return (default: 20)
|
|
32017
|
-
- offset (number): Pagination offset (default: 0)
|
|
32018
|
-
- sort_by (string, optional): Field to sort by (e.g., FAILDATE, COST)
|
|
32019
|
-
- sort_order ('ASC'|'DESC'): Sort direction (default: 'ASC')
|
|
32020
|
-
|
|
32021
|
-
Prefer concise human-readable summaries or tables when answering users. Structured fields are available for totals, pagination, and failure records.`,
|
|
32159
|
+
description: "Use this when the user wants details on failed FDIC-insured institutions filtered by name, state, date range, resolution type, or cost. Returns failure records with pagination; see fdic://schemas/failures for the full field catalog.",
|
|
32022
32160
|
inputSchema: CommonQuerySchema,
|
|
32161
|
+
outputSchema: FdicFailuresSearchOutputSchema,
|
|
32023
32162
|
annotations: {
|
|
32024
32163
|
readOnlyHint: true,
|
|
32025
32164
|
destructiveHint: false,
|
|
@@ -32036,7 +32175,10 @@ Prefer concise human-readable summaries or tables when answering users. Structur
|
|
|
32036
32175
|
params.offset ?? 0,
|
|
32037
32176
|
records.length
|
|
32038
32177
|
);
|
|
32039
|
-
const output =
|
|
32178
|
+
const output = capStructuredContent(
|
|
32179
|
+
{ ...pagination, failures: records },
|
|
32180
|
+
"failures"
|
|
32181
|
+
);
|
|
32040
32182
|
const text = truncateIfNeeded(
|
|
32041
32183
|
formatSearchResultText("failures", records, pagination, [
|
|
32042
32184
|
"CERT",
|
|
@@ -32063,16 +32205,9 @@ Prefer concise human-readable summaries or tables when answering users. Structur
|
|
|
32063
32205
|
"fdic_get_institution_failure",
|
|
32064
32206
|
{
|
|
32065
32207
|
title: "Get Failure Details by Certificate Number",
|
|
32066
|
-
description:
|
|
32067
|
-
|
|
32068
|
-
Use this when you know the CERT of a failed institution to get its specific failure record.
|
|
32069
|
-
|
|
32070
|
-
Args:
|
|
32071
|
-
- cert (number): FDIC Certificate Number of the failed institution
|
|
32072
|
-
- fields (string, optional): Comma-separated list of fields to return
|
|
32073
|
-
|
|
32074
|
-
Returns detailed failure information suitable for concise summaries, with structured fields available for exact values when needed.`,
|
|
32208
|
+
description: "Use this when the user knows the CERT of a failed institution and needs its specific failure record. Returns failure details (date, resolution type, cost, acquirer); responds with `found: false` if the institution did not fail.",
|
|
32075
32209
|
inputSchema: CertSchema,
|
|
32210
|
+
outputSchema: FdicFailureLookupOutputSchema,
|
|
32076
32211
|
annotations: {
|
|
32077
32212
|
readOnlyHint: true,
|
|
32078
32213
|
destructiveHint: false,
|
|
@@ -32122,7 +32257,7 @@ Returns detailed failure information suitable for concise summaries, with struct
|
|
|
32122
32257
|
}
|
|
32123
32258
|
|
|
32124
32259
|
// src/tools/locations.ts
|
|
32125
|
-
var
|
|
32260
|
+
var import_zod3 = require("zod");
|
|
32126
32261
|
|
|
32127
32262
|
// src/tools/shared/queryUtils.ts
|
|
32128
32263
|
var CHUNK_SIZE = 25;
|
|
@@ -32218,7 +32353,7 @@ async function mapWithConcurrency(values, limit, mapper) {
|
|
|
32218
32353
|
|
|
32219
32354
|
// src/tools/locations.ts
|
|
32220
32355
|
var LocationQuerySchema = CommonQuerySchema.extend({
|
|
32221
|
-
cert:
|
|
32356
|
+
cert: import_zod3.z.number().int().positive().optional().describe(
|
|
32222
32357
|
"Filter by FDIC Certificate Number to get all branches of a specific institution"
|
|
32223
32358
|
)
|
|
32224
32359
|
});
|
|
@@ -32227,53 +32362,9 @@ function registerLocationTools(server) {
|
|
|
32227
32362
|
"fdic_search_locations",
|
|
32228
32363
|
{
|
|
32229
32364
|
title: "Search Institution Locations / Branches",
|
|
32230
|
-
description:
|
|
32231
|
-
|
|
32232
|
-
Returns branch/office data including address, city, state, coordinates, branch type, and establishment date.
|
|
32233
|
-
|
|
32234
|
-
Common filter examples:
|
|
32235
|
-
- All branches of a bank: CERT:3511
|
|
32236
|
-
- By state: STALP:TX (two-letter state code)
|
|
32237
|
-
- By city: CITY:"Austin"
|
|
32238
|
-
- Main offices only: BRNUM:0
|
|
32239
|
-
- By county: COUNTY:"Travis"
|
|
32240
|
-
- Active branches only: ENDEFYMD:[9999-01-01 TO *] (sentinel date 9999-12-31 means still open)
|
|
32241
|
-
- By metro area (CBSA): CBSA_METRO_NAME:"New York-Newark-Jersey City"
|
|
32242
|
-
|
|
32243
|
-
Branch service types (BRSERTYP):
|
|
32244
|
-
11 = Full service brick and mortar
|
|
32245
|
-
12 = Full service retail
|
|
32246
|
-
21 = Limited service administrative
|
|
32247
|
-
22 = Limited service military
|
|
32248
|
-
23 = Limited service drive-through
|
|
32249
|
-
24 = Limited service loan production
|
|
32250
|
-
25 = Limited service consumer/trust
|
|
32251
|
-
26 = Limited service Internet/mobile
|
|
32252
|
-
29 = Limited service other
|
|
32253
|
-
|
|
32254
|
-
Key returned fields:
|
|
32255
|
-
- CERT: FDIC Certificate Number
|
|
32256
|
-
- UNINAME: Institution name
|
|
32257
|
-
- NAMEFULL: Full branch name
|
|
32258
|
-
- ADDRESS, CITY, STALP (two-letter state code), ZIP: Branch address
|
|
32259
|
-
- COUNTY: County name
|
|
32260
|
-
- BRNUM: Branch number (0 = main office)
|
|
32261
|
-
- BRSERTYP: Branch service type code (see above)
|
|
32262
|
-
- LATITUDE, LONGITUDE: Geographic coordinates
|
|
32263
|
-
- ESTYMD: Branch established date (YYYY-MM-DD)
|
|
32264
|
-
- ENDEFYMD: Branch end date (9999-12-31 if still active)
|
|
32265
|
-
|
|
32266
|
-
Args:
|
|
32267
|
-
- cert (number, optional): Filter by institution CERT number
|
|
32268
|
-
- filters (string, optional): Additional ElasticSearch query filters
|
|
32269
|
-
- fields (string, optional): Comma-separated field names
|
|
32270
|
-
- limit (number): Records to return (default: 20)
|
|
32271
|
-
- offset (number): Pagination offset (default: 0)
|
|
32272
|
-
- sort_by (string, optional): Field to sort by
|
|
32273
|
-
- sort_order ('ASC'|'DESC'): Sort direction (default: 'ASC')
|
|
32274
|
-
|
|
32275
|
-
Prefer concise human-readable summaries or tables when answering users. Structured fields are available for totals, pagination, and branch location records.`,
|
|
32365
|
+
description: "Use this when the user wants branch/office locations for FDIC-insured institutions, filtered by CERT, state, city, county, metro area, or branch type. Returns address, coordinates, branch number, and service-type rows; see fdic://schemas/locations for the full field catalog.",
|
|
32276
32366
|
inputSchema: LocationQuerySchema,
|
|
32367
|
+
outputSchema: FdicLocationsSearchOutputSchema,
|
|
32277
32368
|
annotations: {
|
|
32278
32369
|
readOnlyHint: true,
|
|
32279
32370
|
destructiveHint: false,
|
|
@@ -32297,7 +32388,10 @@ Prefer concise human-readable summaries or tables when answering users. Structur
|
|
|
32297
32388
|
params.offset ?? 0,
|
|
32298
32389
|
records.length
|
|
32299
32390
|
);
|
|
32300
|
-
const output =
|
|
32391
|
+
const output = capStructuredContent(
|
|
32392
|
+
{ ...pagination, locations: records },
|
|
32393
|
+
"locations"
|
|
32394
|
+
);
|
|
32301
32395
|
const text = truncateIfNeeded(
|
|
32302
32396
|
formatSearchResultText("locations", records, pagination, [
|
|
32303
32397
|
"CERT",
|
|
@@ -32322,9 +32416,9 @@ Prefer concise human-readable summaries or tables when answering users. Structur
|
|
|
32322
32416
|
}
|
|
32323
32417
|
|
|
32324
32418
|
// src/tools/history.ts
|
|
32325
|
-
var
|
|
32419
|
+
var import_zod4 = require("zod");
|
|
32326
32420
|
var HistoryQuerySchema = CommonQuerySchema.extend({
|
|
32327
|
-
cert:
|
|
32421
|
+
cert: import_zod4.z.number().int().positive().optional().describe(
|
|
32328
32422
|
"Filter by FDIC Certificate Number to get history for a specific institution"
|
|
32329
32423
|
)
|
|
32330
32424
|
});
|
|
@@ -32333,57 +32427,9 @@ function registerHistoryTools(server) {
|
|
|
32333
32427
|
"fdic_search_history",
|
|
32334
32428
|
{
|
|
32335
32429
|
title: "Search Institution History / Structure Changes",
|
|
32336
|
-
description:
|
|
32337
|
-
|
|
32338
|
-
Returns records on mergers, acquisitions, name changes, charter conversions, failures, and other significant structural events.
|
|
32339
|
-
|
|
32340
|
-
Common filter examples:
|
|
32341
|
-
- History for a specific bank: CERT:3511
|
|
32342
|
-
- Mergers: TYPE:merger
|
|
32343
|
-
- Failures: TYPE:failure
|
|
32344
|
-
- Name changes: CHANGECODE:CO
|
|
32345
|
-
- By date range: PROCDATE:[2008-01-01 TO 2009-12-31]
|
|
32346
|
-
- By state: PSTALP:CA (two-letter state code)
|
|
32347
|
-
|
|
32348
|
-
Event types (TYPE):
|
|
32349
|
-
merger = institution was merged into another
|
|
32350
|
-
failure = institution failed
|
|
32351
|
-
assistance = received FDIC assistance transaction
|
|
32352
|
-
insurance = insurance-related event (new coverage, termination)
|
|
32353
|
-
|
|
32354
|
-
Common change codes (CHANGECODE):
|
|
32355
|
-
CO = name change
|
|
32356
|
-
CR = charter conversion
|
|
32357
|
-
DC = deposit assumption change
|
|
32358
|
-
MA = merger/acquisition (absorbed by another institution)
|
|
32359
|
-
NI = new institution insured
|
|
32360
|
-
TC = trust company conversion
|
|
32361
|
-
|
|
32362
|
-
Key returned fields:
|
|
32363
|
-
- CERT: FDIC Certificate Number
|
|
32364
|
-
- INSTNAME: Institution name
|
|
32365
|
-
- CLASS: Charter class at time of change
|
|
32366
|
-
- PCITY, PSTALP: Location (city, two-letter state code)
|
|
32367
|
-
- PROCDATE: Processing date of the change (YYYY-MM-DD)
|
|
32368
|
-
- EFFDATE: Effective date of the change (YYYY-MM-DD)
|
|
32369
|
-
- ENDEFYMD: End effective date
|
|
32370
|
-
- PCERT: Predecessor/successor CERT (for mergers)
|
|
32371
|
-
- TYPE: Type of structural change (see above)
|
|
32372
|
-
- CHANGECODE: Code for type of change (see above)
|
|
32373
|
-
- CHANGECODE_DESC: Human-readable description of the change code
|
|
32374
|
-
- INSDATE: Insurance date
|
|
32375
|
-
|
|
32376
|
-
Args:
|
|
32377
|
-
- cert (number, optional): Filter by institution CERT number
|
|
32378
|
-
- filters (string, optional): ElasticSearch query filters
|
|
32379
|
-
- fields (string, optional): Comma-separated field names
|
|
32380
|
-
- limit (number): Records to return (default: 20)
|
|
32381
|
-
- offset (number): Pagination offset (default: 0)
|
|
32382
|
-
- sort_by (string, optional): Field to sort by (e.g., PROCDATE)
|
|
32383
|
-
- sort_order ('ASC'|'DESC'): Sort direction (default: 'ASC')
|
|
32384
|
-
|
|
32385
|
-
Prefer concise human-readable summaries or tables when answering users. Structured fields are available for totals, pagination, and event records.`,
|
|
32430
|
+
description: "Use this when the user wants structural-change events (mergers, acquisitions, name changes, charter conversions, failures) for FDIC-insured institutions, filtered by CERT, type, change code, date range, or state. See fdic://schemas/history for the full field catalog.",
|
|
32386
32431
|
inputSchema: HistoryQuerySchema,
|
|
32432
|
+
outputSchema: FdicHistorySearchOutputSchema,
|
|
32387
32433
|
annotations: {
|
|
32388
32434
|
readOnlyHint: true,
|
|
32389
32435
|
destructiveHint: false,
|
|
@@ -32407,7 +32453,10 @@ Prefer concise human-readable summaries or tables when answering users. Structur
|
|
|
32407
32453
|
params.offset ?? 0,
|
|
32408
32454
|
records.length
|
|
32409
32455
|
);
|
|
32410
|
-
const output =
|
|
32456
|
+
const output = capStructuredContent(
|
|
32457
|
+
{ ...pagination, events: records },
|
|
32458
|
+
"events"
|
|
32459
|
+
);
|
|
32411
32460
|
const text = truncateIfNeeded(
|
|
32412
32461
|
formatSearchResultText("events", records, pagination, [
|
|
32413
32462
|
"CERT",
|
|
@@ -32432,63 +32481,30 @@ Prefer concise human-readable summaries or tables when answering users. Structur
|
|
|
32432
32481
|
}
|
|
32433
32482
|
|
|
32434
32483
|
// src/tools/financials.ts
|
|
32435
|
-
var
|
|
32484
|
+
var import_zod5 = require("zod");
|
|
32436
32485
|
var FinancialQuerySchema = CommonQuerySchema.extend({
|
|
32437
|
-
sort_order:
|
|
32486
|
+
sort_order: import_zod5.z.enum(["ASC", "DESC"]).default("DESC").describe(
|
|
32438
32487
|
"Sort direction: DESC (descending, default for most recent first) or ASC (ascending)"
|
|
32439
32488
|
),
|
|
32440
|
-
cert:
|
|
32489
|
+
cert: import_zod5.z.number().int().positive().optional().describe(
|
|
32441
32490
|
"Filter by FDIC Certificate Number to get financials for a specific institution"
|
|
32442
32491
|
),
|
|
32443
|
-
repdte:
|
|
32444
|
-
"Filter by Report Date (REPDTE) in YYYYMMDD format
|
|
32492
|
+
repdte: import_zod5.z.string().optional().describe(
|
|
32493
|
+
"Filter by Report Date (REPDTE) in YYYYMMDD format (quarter-end: 0331, 0630, 0930, 1231). If omitted, returns all available dates (sorted most recent first)."
|
|
32445
32494
|
)
|
|
32446
32495
|
});
|
|
32447
32496
|
var SummaryQuerySchema = CommonQuerySchema.extend({
|
|
32448
|
-
cert:
|
|
32449
|
-
year:
|
|
32497
|
+
cert: import_zod5.z.number().int().positive().optional().describe("Filter by FDIC Certificate Number"),
|
|
32498
|
+
year: import_zod5.z.number().int().min(1934).optional().describe("Filter by specific year (e.g., 2022)")
|
|
32450
32499
|
});
|
|
32451
32500
|
function registerFinancialTools(server) {
|
|
32452
32501
|
server.registerTool(
|
|
32453
32502
|
"fdic_search_financials",
|
|
32454
32503
|
{
|
|
32455
32504
|
title: "Search Institution Financial Data",
|
|
32456
|
-
description:
|
|
32457
|
-
|
|
32458
|
-
Returns balance sheet, income statement, capital, and performance ratio data from FDIC Call Reports.
|
|
32459
|
-
|
|
32460
|
-
Common filter examples:
|
|
32461
|
-
- Financials for a specific bank: CERT:3511
|
|
32462
|
-
- By report date: REPDTE:20231231
|
|
32463
|
-
- High-profit banks in Q4 2023: REPDTE:20231231 AND ROA:[1.5 TO *]
|
|
32464
|
-
- Large banks most recent: ASSET:[10000000 TO *]
|
|
32465
|
-
- Negative net income: NETINC:[* TO 0]
|
|
32466
|
-
|
|
32467
|
-
Key returned fields:
|
|
32468
|
-
- CERT: FDIC Certificate Number
|
|
32469
|
-
- REPDTE: Report Date \u2014 the last day of the quarterly reporting period (YYYYMMDD)
|
|
32470
|
-
- ASSET: Total assets ($thousands)
|
|
32471
|
-
- DEP: Total deposits ($thousands)
|
|
32472
|
-
- DEPDOM: Domestic deposits ($thousands)
|
|
32473
|
-
- INTINC: Total interest income ($thousands)
|
|
32474
|
-
- EINTEXP: Total interest expense ($thousands)
|
|
32475
|
-
- NETINC: Net income ($thousands)
|
|
32476
|
-
- ROA: Return on assets (%)
|
|
32477
|
-
- ROE: Return on equity (%)
|
|
32478
|
-
- NETNIM: Net interest margin (%)
|
|
32479
|
-
|
|
32480
|
-
Args:
|
|
32481
|
-
- cert (number, optional): Filter by institution CERT number
|
|
32482
|
-
- repdte (string, optional): Report Date in YYYYMMDD format (quarter-end dates: 0331, 0630, 0930, 1231)
|
|
32483
|
-
- filters (string, optional): Additional ElasticSearch query filters
|
|
32484
|
-
- fields (string, optional): Comma-separated field names (the full set has 1,100+ fields)
|
|
32485
|
-
- limit (number): Records to return (default: 20)
|
|
32486
|
-
- offset (number): Pagination offset (default: 0)
|
|
32487
|
-
- sort_by (string, optional): Field to sort by
|
|
32488
|
-
- sort_order ('ASC'|'DESC'): Sort direction (default: 'DESC' recommended for most recent first)
|
|
32489
|
-
|
|
32490
|
-
Prefer concise human-readable summaries or tables when answering users. Structured fields are available for totals, pagination, and quarterly financial records.`,
|
|
32505
|
+
description: "Use this when the user wants quarterly Call Report data (balance sheet, income, capital, performance ratios) for FDIC-insured institutions. Filter by CERT and/or REPDTE plus optional ElasticSearch filters. See fdic://schemas/financials for the full 1,100+ field catalog.",
|
|
32491
32506
|
inputSchema: FinancialQuerySchema,
|
|
32507
|
+
outputSchema: FdicFinancialsSearchOutputSchema,
|
|
32492
32508
|
annotations: {
|
|
32493
32509
|
readOnlyHint: true,
|
|
32494
32510
|
destructiveHint: false,
|
|
@@ -32513,7 +32529,10 @@ Prefer concise human-readable summaries or tables when answering users. Structur
|
|
|
32513
32529
|
params.offset ?? 0,
|
|
32514
32530
|
records.length
|
|
32515
32531
|
);
|
|
32516
|
-
const output =
|
|
32532
|
+
const output = capStructuredContent(
|
|
32533
|
+
{ ...pagination, financials: records },
|
|
32534
|
+
"financials"
|
|
32535
|
+
);
|
|
32517
32536
|
const text = truncateIfNeeded(
|
|
32518
32537
|
formatSearchResultText("financial records", records, pagination, [
|
|
32519
32538
|
"CERT",
|
|
@@ -32539,40 +32558,9 @@ Prefer concise human-readable summaries or tables when answering users. Structur
|
|
|
32539
32558
|
"fdic_search_summary",
|
|
32540
32559
|
{
|
|
32541
32560
|
title: "Search Annual Financial Summary Data",
|
|
32542
|
-
description:
|
|
32543
|
-
|
|
32544
|
-
Returns annual snapshots of key financial metrics \u2014 useful for tracking an institution's growth over time.
|
|
32545
|
-
|
|
32546
|
-
Common filter examples:
|
|
32547
|
-
- Annual history for a bank: CERT:3511
|
|
32548
|
-
- Specific year: YEAR:2022
|
|
32549
|
-
- Year range: YEAR:[2010 TO 2020]
|
|
32550
|
-
- Large banks in 2022: YEAR:2022 AND ASSET:[10000000 TO *]
|
|
32551
|
-
- Profitable in 2023: YEAR:2023 AND ROE:[10 TO *]
|
|
32552
|
-
|
|
32553
|
-
Key returned fields:
|
|
32554
|
-
- CERT: FDIC Certificate Number
|
|
32555
|
-
- YEAR: Report year
|
|
32556
|
-
- ASSET: Total assets ($thousands)
|
|
32557
|
-
- DEP: Total deposits ($thousands)
|
|
32558
|
-
- NETINC: Net income ($thousands)
|
|
32559
|
-
- ROA: Return on assets (%)
|
|
32560
|
-
- ROE: Return on equity (%)
|
|
32561
|
-
- OFFICES: Number of branch offices
|
|
32562
|
-
- REPDTE: Report Date \u2014 the last day of the reporting period (YYYYMMDD)
|
|
32563
|
-
|
|
32564
|
-
Args:
|
|
32565
|
-
- cert (number, optional): Filter by institution CERT number
|
|
32566
|
-
- year (number, optional): Filter by specific year (1934-present)
|
|
32567
|
-
- filters (string, optional): Additional ElasticSearch query filters
|
|
32568
|
-
- fields (string, optional): Comma-separated field names
|
|
32569
|
-
- limit (number): Records to return (default: 20)
|
|
32570
|
-
- offset (number): Pagination offset (default: 0)
|
|
32571
|
-
- sort_by (string, optional): Field to sort by (e.g., YEAR, ASSET)
|
|
32572
|
-
- sort_order ('ASC'|'DESC'): Sort direction (default: 'ASC')
|
|
32573
|
-
|
|
32574
|
-
Prefer concise human-readable summaries or tables when answering users. Structured fields are available for totals, pagination, and annual summary records.`,
|
|
32561
|
+
description: "Use this when the user wants annual financial-summary snapshots (assets, deposits, ROA, ROE, offices) for FDIC-insured institutions, filtered by CERT and/or year. See fdic://schemas/summary for the full field catalog.",
|
|
32575
32562
|
inputSchema: SummaryQuerySchema,
|
|
32563
|
+
outputSchema: FdicSummarySearchOutputSchema,
|
|
32576
32564
|
annotations: {
|
|
32577
32565
|
readOnlyHint: true,
|
|
32578
32566
|
destructiveHint: false,
|
|
@@ -32597,7 +32585,10 @@ Prefer concise human-readable summaries or tables when answering users. Structur
|
|
|
32597
32585
|
params.offset ?? 0,
|
|
32598
32586
|
records.length
|
|
32599
32587
|
);
|
|
32600
|
-
const output =
|
|
32588
|
+
const output = capStructuredContent(
|
|
32589
|
+
{ ...pagination, summary: records },
|
|
32590
|
+
"summary"
|
|
32591
|
+
);
|
|
32601
32592
|
const text = truncateIfNeeded(
|
|
32602
32593
|
formatSearchResultText("annual summary records", records, pagination, [
|
|
32603
32594
|
"CERT",
|
|
@@ -32622,10 +32613,10 @@ Prefer concise human-readable summaries or tables when answering users. Structur
|
|
|
32622
32613
|
}
|
|
32623
32614
|
|
|
32624
32615
|
// src/tools/sod.ts
|
|
32625
|
-
var
|
|
32616
|
+
var import_zod6 = require("zod");
|
|
32626
32617
|
var SodQuerySchema = CommonQuerySchema.extend({
|
|
32627
|
-
cert:
|
|
32628
|
-
year:
|
|
32618
|
+
cert: import_zod6.z.number().int().positive().optional().describe("Filter by FDIC Certificate Number"),
|
|
32619
|
+
year: import_zod6.z.number().int().min(1994).optional().describe(
|
|
32629
32620
|
"Filter by specific year (1994-present). SOD data is annual."
|
|
32630
32621
|
)
|
|
32631
32622
|
});
|
|
@@ -32634,40 +32625,9 @@ function registerSodTools(server) {
|
|
|
32634
32625
|
"fdic_search_sod",
|
|
32635
32626
|
{
|
|
32636
32627
|
title: "Search Summary of Deposits (SOD)",
|
|
32637
|
-
description:
|
|
32638
|
-
|
|
32639
|
-
The SOD report provides annual deposit data at the branch level, showing deposit balances for each office of every FDIC-insured institution as of June 30 each year.
|
|
32640
|
-
|
|
32641
|
-
Common filter examples:
|
|
32642
|
-
- All branches for a bank: CERT:3511
|
|
32643
|
-
- SOD for specific year: YEAR:2022
|
|
32644
|
-
- Branches in a state: STALPBR:CA
|
|
32645
|
-
- Branches in a city: CITYBR:"Austin"
|
|
32646
|
-
- High-deposit branches: DEPSUMBR:[1000000 TO *]
|
|
32647
|
-
- By metro area (MSA code): MSABR:19100
|
|
32648
|
-
|
|
32649
|
-
Key returned fields:
|
|
32650
|
-
- YEAR: Report year (as of June 30)
|
|
32651
|
-
- CERT: FDIC Certificate Number
|
|
32652
|
-
- BRNUM: Branch number (0 = main office)
|
|
32653
|
-
- NAMEFULL: Branch or institution name
|
|
32654
|
-
- ADDRESBR, CITYBR, STALPBR, ZIPBR: Branch address
|
|
32655
|
-
- DEPSUMBR: Total deposits at branch ($thousands)
|
|
32656
|
-
- MSABR: Metropolitan Statistical Area code (numeric; 0 = non-MSA)
|
|
32657
|
-
- LATITUDE, LONGITUDE: Coordinates
|
|
32658
|
-
|
|
32659
|
-
Args:
|
|
32660
|
-
- cert (number, optional): Filter by institution CERT number
|
|
32661
|
-
- year (number, optional): SOD report year (1994-present)
|
|
32662
|
-
- filters (string, optional): Additional ElasticSearch query filters
|
|
32663
|
-
- fields (string, optional): Comma-separated field names
|
|
32664
|
-
- limit (number): Records to return (default: 20)
|
|
32665
|
-
- offset (number): Pagination offset (default: 0)
|
|
32666
|
-
- sort_by (string, optional): Field to sort by (e.g., DEPSUMBR, YEAR)
|
|
32667
|
-
- sort_order ('ASC'|'DESC'): Sort direction (default: 'ASC')
|
|
32668
|
-
|
|
32669
|
-
Prefer concise human-readable summaries or tables when answering users. Structured fields are available for totals, pagination, and deposit records.`,
|
|
32628
|
+
description: "Use this when the user wants annual branch-level deposit data (SOD, as of June 30 each year) \u2014 branch deposits, MSAs, geographic distribution. Filter by CERT and/or year. See fdic://schemas/sod for the full field catalog.",
|
|
32670
32629
|
inputSchema: SodQuerySchema,
|
|
32630
|
+
outputSchema: FdicSodSearchOutputSchema,
|
|
32671
32631
|
annotations: {
|
|
32672
32632
|
readOnlyHint: true,
|
|
32673
32633
|
destructiveHint: false,
|
|
@@ -32692,7 +32652,10 @@ Prefer concise human-readable summaries or tables when answering users. Structur
|
|
|
32692
32652
|
params.offset ?? 0,
|
|
32693
32653
|
records.length
|
|
32694
32654
|
);
|
|
32695
|
-
const output =
|
|
32655
|
+
const output = capStructuredContent(
|
|
32656
|
+
{ ...pagination, deposits: records },
|
|
32657
|
+
"deposits"
|
|
32658
|
+
);
|
|
32696
32659
|
const text = truncateIfNeeded(
|
|
32697
32660
|
formatSearchResultText("deposit records", records, pagination, [
|
|
32698
32661
|
"CERT",
|
|
@@ -32717,11 +32680,11 @@ Prefer concise human-readable summaries or tables when answering users. Structur
|
|
|
32717
32680
|
}
|
|
32718
32681
|
|
|
32719
32682
|
// src/tools/demographics.ts
|
|
32720
|
-
var
|
|
32683
|
+
var import_zod7 = require("zod");
|
|
32721
32684
|
var DemographicsQuerySchema = CommonQuerySchema.extend({
|
|
32722
|
-
cert:
|
|
32723
|
-
repdte:
|
|
32724
|
-
"Filter by Report Date (REPDTE) in YYYYMMDD format
|
|
32685
|
+
cert: import_zod7.z.number().int().positive().optional().describe("Filter by FDIC Certificate Number"),
|
|
32686
|
+
repdte: import_zod7.z.string().optional().describe(
|
|
32687
|
+
"Filter by Report Date (REPDTE) in YYYYMMDD format (quarter-end: 0331, 0630, 0930, 1231)."
|
|
32725
32688
|
)
|
|
32726
32689
|
});
|
|
32727
32690
|
function registerDemographicsTools(server) {
|
|
@@ -32729,43 +32692,9 @@ function registerDemographicsTools(server) {
|
|
|
32729
32692
|
"fdic_search_demographics",
|
|
32730
32693
|
{
|
|
32731
32694
|
title: "Search Institution Demographics Data",
|
|
32732
|
-
description:
|
|
32733
|
-
|
|
32734
|
-
Returns quarterly demographic and market-structure attributes such as office counts, territory assignments, metro classification, county/country codes, and selected geographic reference data.
|
|
32735
|
-
|
|
32736
|
-
Common filter examples:
|
|
32737
|
-
- Demographics for a specific bank: CERT:3511
|
|
32738
|
-
- By report date: REPDTE:20251231
|
|
32739
|
-
- Institutions in metro areas: METRO:1
|
|
32740
|
-
- Institutions with out-of-state offices: OFFSTATE:[1 TO *]
|
|
32741
|
-
- Minority status date present: MNRTYDTE:[19000101 TO 99991231]
|
|
32742
|
-
|
|
32743
|
-
Key returned fields:
|
|
32744
|
-
- CERT: FDIC Certificate Number
|
|
32745
|
-
- REPDTE: Report Date \u2014 the last day of the quarterly reporting period (YYYYMMDD)
|
|
32746
|
-
- QTRNO: Quarter number
|
|
32747
|
-
- OFFTOT: Total offices
|
|
32748
|
-
- OFFSTATE: Offices in other states
|
|
32749
|
-
- OFFNDOM: Offices in non-domestic territories
|
|
32750
|
-
- OFFOTH: Other offices
|
|
32751
|
-
- OFFSOD: Offices included in Summary of Deposits
|
|
32752
|
-
- METRO, MICRO: Metro/micro area flags
|
|
32753
|
-
- CBSANAME, CSA: Core-based statistical area data
|
|
32754
|
-
- FDICTERR, RISKTERR: FDIC and risk territory assignments
|
|
32755
|
-
- SIMS_LAT, SIMS_LONG: Geographic coordinates
|
|
32756
|
-
|
|
32757
|
-
Args:
|
|
32758
|
-
- cert (number, optional): Filter by institution CERT number
|
|
32759
|
-
- repdte (string, optional): Report Date in YYYYMMDD format (quarter-end dates: 0331, 0630, 0930, 1231)
|
|
32760
|
-
- filters (string, optional): Additional ElasticSearch query filters
|
|
32761
|
-
- fields (string, optional): Comma-separated field names
|
|
32762
|
-
- limit (number): Records to return (default: 20)
|
|
32763
|
-
- offset (number): Pagination offset (default: 0)
|
|
32764
|
-
- sort_by (string, optional): Field to sort by
|
|
32765
|
-
- sort_order ('ASC'|'DESC'): Sort direction (default: 'ASC')
|
|
32766
|
-
|
|
32767
|
-
Prefer concise human-readable summaries or tables when answering users. Structured fields are available for totals, pagination, and demographic records.`,
|
|
32695
|
+
description: "Use this when the user wants quarterly demographic and market-structure attributes (office counts, metro classification, county/territory codes, geographic reference data) for FDIC-insured institutions. Filter by CERT and/or REPDTE. See fdic://schemas/demographics for the full field catalog.",
|
|
32768
32696
|
inputSchema: DemographicsQuerySchema,
|
|
32697
|
+
outputSchema: FdicDemographicsSearchOutputSchema,
|
|
32769
32698
|
annotations: {
|
|
32770
32699
|
readOnlyHint: true,
|
|
32771
32700
|
destructiveHint: false,
|
|
@@ -32790,7 +32719,10 @@ Prefer concise human-readable summaries or tables when answering users. Structur
|
|
|
32790
32719
|
params.offset ?? 0,
|
|
32791
32720
|
records.length
|
|
32792
32721
|
);
|
|
32793
|
-
const output =
|
|
32722
|
+
const output = capStructuredContent(
|
|
32723
|
+
{ ...pagination, demographics: records },
|
|
32724
|
+
"demographics"
|
|
32725
|
+
);
|
|
32794
32726
|
const text = truncateIfNeeded(
|
|
32795
32727
|
formatSearchResultText("demographic records", records, pagination, [
|
|
32796
32728
|
"CERT",
|
|
@@ -32815,7 +32747,7 @@ Prefer concise human-readable summaries or tables when answering users. Structur
|
|
|
32815
32747
|
}
|
|
32816
32748
|
|
|
32817
32749
|
// src/tools/analysis.ts
|
|
32818
|
-
var
|
|
32750
|
+
var import_zod8 = require("zod");
|
|
32819
32751
|
|
|
32820
32752
|
// src/tools/shared/progress.ts
|
|
32821
32753
|
function asProgressToken(value) {
|
|
@@ -32841,7 +32773,7 @@ async function sendProgressNotification(sender, progressToken, progress, message
|
|
|
32841
32773
|
}
|
|
32842
32774
|
|
|
32843
32775
|
// src/tools/analysis.ts
|
|
32844
|
-
var SortFieldSchema =
|
|
32776
|
+
var SortFieldSchema = import_zod8.z.enum([
|
|
32845
32777
|
"asset_growth",
|
|
32846
32778
|
"asset_growth_pct",
|
|
32847
32779
|
"dep_growth",
|
|
@@ -32855,35 +32787,35 @@ var SortFieldSchema = import_zod7.z.enum([
|
|
|
32855
32787
|
"deposits_per_office_change",
|
|
32856
32788
|
"deposits_to_assets_change"
|
|
32857
32789
|
]);
|
|
32858
|
-
var AnalysisModeSchema =
|
|
32859
|
-
var SnapshotAnalysisSchema =
|
|
32860
|
-
state:
|
|
32790
|
+
var AnalysisModeSchema = import_zod8.z.enum(["snapshot", "timeseries"]);
|
|
32791
|
+
var SnapshotAnalysisSchema = import_zod8.z.object({
|
|
32792
|
+
state: import_zod8.z.string().optional().describe(
|
|
32861
32793
|
'State name for the institution roster filter. Example: "North Carolina"'
|
|
32862
32794
|
),
|
|
32863
|
-
certs:
|
|
32795
|
+
certs: import_zod8.z.array(import_zod8.z.number().int().positive()).max(100).optional().describe(
|
|
32864
32796
|
"Optional list of FDIC certificate numbers to compare directly. Max 100."
|
|
32865
32797
|
),
|
|
32866
|
-
institution_filters:
|
|
32798
|
+
institution_filters: import_zod8.z.string().optional().describe(
|
|
32867
32799
|
'Additional institution-level filter used when building the comparison set. Example: BKCLASS:N or CITY:"Charlotte"'
|
|
32868
32800
|
),
|
|
32869
|
-
active_only:
|
|
32870
|
-
start_repdte:
|
|
32801
|
+
active_only: import_zod8.z.boolean().default(true).describe("Limit the comparison set to currently active institutions."),
|
|
32802
|
+
start_repdte: import_zod8.z.string().regex(/^\d{8}$/).optional().describe(
|
|
32871
32803
|
"Starting Report Date (REPDTE) in YYYYMMDD format. Must be a quarter-end date: March 31 (0331), June 30 (0630), September 30 (0930), or December 31 (1231). Example: 20210331 for Q1 2021. If omitted, defaults to the same quarter one year before end_repdte."
|
|
32872
32804
|
),
|
|
32873
|
-
end_repdte:
|
|
32805
|
+
end_repdte: import_zod8.z.string().regex(/^\d{8}$/).optional().describe(
|
|
32874
32806
|
"Ending Report Date (REPDTE) in YYYYMMDD format. Must be a quarter-end date: March 31 (0331), June 30 (0630), September 30 (0930), or December 31 (1231). Must be later than start_repdte. Example: 20251231 for Q4 2025. If omitted, defaults to the most recent quarter-end date with published data (~90-day lag)."
|
|
32875
32807
|
),
|
|
32876
32808
|
analysis_mode: AnalysisModeSchema.default("snapshot").describe(
|
|
32877
32809
|
"Use snapshot for two-point comparison or timeseries for quarterly trend analysis across the date range."
|
|
32878
32810
|
),
|
|
32879
|
-
include_demographics:
|
|
32811
|
+
include_demographics: import_zod8.z.boolean().default(true).describe(
|
|
32880
32812
|
"Include office-count changes from the demographics dataset when available."
|
|
32881
32813
|
),
|
|
32882
|
-
limit:
|
|
32814
|
+
limit: import_zod8.z.number().int().min(1).max(100).default(10).describe("Maximum number of ranked comparisons to return."),
|
|
32883
32815
|
sort_by: SortFieldSchema.default("asset_growth").describe(
|
|
32884
32816
|
"Comparison field used to rank institutions. Valid options: asset_growth, asset_growth_pct, dep_growth, dep_growth_pct, netinc_change, netinc_change_pct, roa_change, roe_change, offices_change, assets_per_office_change, deposits_per_office_change, deposits_to_assets_change."
|
|
32885
32817
|
),
|
|
32886
|
-
sort_order:
|
|
32818
|
+
sort_order: import_zod8.z.enum(["ASC", "DESC"]).default("DESC").describe("Sort direction for the ranked comparisons.")
|
|
32887
32819
|
});
|
|
32888
32820
|
function resolveSnapshotDefaults(params) {
|
|
32889
32821
|
const end_repdte = params.end_repdte ?? getDefaultReportDate();
|
|
@@ -33434,6 +33366,7 @@ Inputs:
|
|
|
33434
33366
|
|
|
33435
33367
|
Returns concise comparison text plus structured deltas, derived metrics, and insight tags for each institution.`,
|
|
33436
33368
|
inputSchema: SnapshotAnalysisSchema,
|
|
33369
|
+
outputSchema: FdicAnalysisOutputSchema,
|
|
33437
33370
|
annotations: {
|
|
33438
33371
|
readOnlyHint: true,
|
|
33439
33372
|
destructiveHint: false,
|
|
@@ -33687,7 +33620,7 @@ Returns concise comparison text plus structured deltas, derived metrics, and ins
|
|
|
33687
33620
|
}
|
|
33688
33621
|
|
|
33689
33622
|
// src/tools/peerGroup.ts
|
|
33690
|
-
var
|
|
33623
|
+
var import_zod9 = require("zod");
|
|
33691
33624
|
|
|
33692
33625
|
// src/tools/shared/financialMetrics.ts
|
|
33693
33626
|
function safeRatio(numerator, denominator) {
|
|
@@ -33831,33 +33764,33 @@ var METRIC_DEFINITIONS = {
|
|
|
33831
33764
|
label: "Non-Interest Income Share"
|
|
33832
33765
|
}
|
|
33833
33766
|
};
|
|
33834
|
-
var PeerGroupInputSchema =
|
|
33835
|
-
cert:
|
|
33767
|
+
var PeerGroupInputSchema = import_zod9.z.object({
|
|
33768
|
+
cert: import_zod9.z.number().int().positive().optional().describe(
|
|
33836
33769
|
"Subject institution CERT number. When provided, auto-derives peer criteria and ranks this bank against peers."
|
|
33837
33770
|
),
|
|
33838
|
-
repdte:
|
|
33771
|
+
repdte: import_zod9.z.string().regex(/^\d{8}$/).optional().describe(
|
|
33839
33772
|
"Report Date (REPDTE) in YYYYMMDD format. FDIC data is published quarterly on: March 31, June 30, September 30, and December 31. Example: 20231231 for Q4 2023. If omitted, defaults to the most recent quarter-end date likely to have published data (~90-day lag)."
|
|
33840
33773
|
),
|
|
33841
|
-
asset_min:
|
|
33774
|
+
asset_min: import_zod9.z.number().positive().optional().describe(
|
|
33842
33775
|
"Minimum total assets ($thousands) for peer selection. Defaults to 50% of subject's report-date assets when cert is provided."
|
|
33843
33776
|
),
|
|
33844
|
-
asset_max:
|
|
33777
|
+
asset_max: import_zod9.z.number().positive().optional().describe(
|
|
33845
33778
|
"Maximum total assets ($thousands) for peer selection. Defaults to 200% of subject's report-date assets when cert is provided."
|
|
33846
33779
|
),
|
|
33847
|
-
charter_classes:
|
|
33780
|
+
charter_classes: import_zod9.z.array(import_zod9.z.string()).optional().describe(
|
|
33848
33781
|
`Charter class codes to include (e.g., ["N", "SM"]). Defaults to the subject's charter class when cert is provided.`
|
|
33849
33782
|
),
|
|
33850
|
-
state:
|
|
33851
|
-
raw_filter:
|
|
33783
|
+
state: import_zod9.z.string().regex(/^[A-Z]{2}$/).optional().describe('Two-letter state code (e.g., "NC", "TX").'),
|
|
33784
|
+
raw_filter: import_zod9.z.string().optional().describe(
|
|
33852
33785
|
"Advanced: raw ElasticSearch query string appended to peer selection criteria with AND."
|
|
33853
33786
|
),
|
|
33854
|
-
active_only:
|
|
33787
|
+
active_only: import_zod9.z.boolean().default(true).describe(
|
|
33855
33788
|
"Limit to institutions where ACTIVE:1 (currently operating, FDIC-insured)."
|
|
33856
33789
|
),
|
|
33857
|
-
extra_fields:
|
|
33790
|
+
extra_fields: import_zod9.z.array(import_zod9.z.string()).optional().describe(
|
|
33858
33791
|
"Additional FDIC field names to include as raw values in the response. Does not affect peer selection."
|
|
33859
33792
|
),
|
|
33860
|
-
limit:
|
|
33793
|
+
limit: import_zod9.z.number().int().min(1).max(500).default(50).describe(
|
|
33861
33794
|
"Max peer records returned in the response. All matched peers are used for ranking regardless of this limit."
|
|
33862
33795
|
)
|
|
33863
33796
|
});
|
|
@@ -33986,6 +33919,7 @@ Output includes:
|
|
|
33986
33919
|
|
|
33987
33920
|
Override precedence: cert derives defaults, then explicit params override them.`,
|
|
33988
33921
|
inputSchema: PeerGroupInputSchema,
|
|
33922
|
+
outputSchema: FdicAnalysisOutputSchema,
|
|
33989
33923
|
annotations: {
|
|
33990
33924
|
readOnlyHint: true,
|
|
33991
33925
|
destructiveHint: false,
|
|
@@ -34322,7 +34256,7 @@ Override precedence: cert derives defaults, then explicit params override them.`
|
|
|
34322
34256
|
}
|
|
34323
34257
|
|
|
34324
34258
|
// src/tools/bankHealth.ts
|
|
34325
|
-
var
|
|
34259
|
+
var import_zod10 = require("zod");
|
|
34326
34260
|
|
|
34327
34261
|
// src/tools/shared/camelsScoring.ts
|
|
34328
34262
|
var SCORING_RULES = {
|
|
@@ -35643,12 +35577,12 @@ function collectRiskSignals(metrics, components, trends) {
|
|
|
35643
35577
|
}
|
|
35644
35578
|
return signals;
|
|
35645
35579
|
}
|
|
35646
|
-
var BankHealthInputSchema =
|
|
35647
|
-
cert:
|
|
35648
|
-
repdte:
|
|
35580
|
+
var BankHealthInputSchema = import_zod10.z.object({
|
|
35581
|
+
cert: import_zod10.z.number().int().positive().describe("FDIC Certificate Number of the institution to analyze."),
|
|
35582
|
+
repdte: import_zod10.z.string().regex(/^\d{8}$/).optional().describe(
|
|
35649
35583
|
"Report Date (YYYYMMDD). Defaults to the most recent quarter likely to have published data."
|
|
35650
35584
|
),
|
|
35651
|
-
quarters:
|
|
35585
|
+
quarters: import_zod10.z.number().int().min(1).max(20).default(8).describe("Number of prior quarters to fetch for trend analysis (default 8).")
|
|
35652
35586
|
});
|
|
35653
35587
|
function registerBankHealthTools(server) {
|
|
35654
35588
|
server.registerTool(
|
|
@@ -35669,6 +35603,7 @@ Output includes:
|
|
|
35669
35603
|
|
|
35670
35604
|
NOTE: Management (M) is omitted from component scoring \u2014 cannot be assessed from public data. Sensitivity (S) uses proxy metrics (NIM trend, securities concentration). This is a public off-site analytical proxy, not an official CAMELS rating.`,
|
|
35671
35605
|
inputSchema: BankHealthInputSchema,
|
|
35606
|
+
outputSchema: FdicAnalysisOutputSchema,
|
|
35672
35607
|
annotations: {
|
|
35673
35608
|
readOnlyHint: true,
|
|
35674
35609
|
destructiveHint: false,
|
|
@@ -35810,7 +35745,7 @@ NOTE: Management (M) is omitted from component scoring \u2014 cannot be assessed
|
|
|
35810
35745
|
}
|
|
35811
35746
|
|
|
35812
35747
|
// src/tools/peerHealth.ts
|
|
35813
|
-
var
|
|
35748
|
+
var import_zod11 = require("zod");
|
|
35814
35749
|
|
|
35815
35750
|
// src/tools/shared/peerEngine.ts
|
|
35816
35751
|
function computeMedian2(values) {
|
|
@@ -35884,15 +35819,15 @@ function computePeerStats(subjectValue, peerValues, options) {
|
|
|
35884
35819
|
}
|
|
35885
35820
|
|
|
35886
35821
|
// src/tools/peerHealth.ts
|
|
35887
|
-
var PeerHealthInputSchema =
|
|
35888
|
-
cert:
|
|
35889
|
-
certs:
|
|
35890
|
-
state:
|
|
35891
|
-
asset_min:
|
|
35892
|
-
asset_max:
|
|
35893
|
-
repdte:
|
|
35894
|
-
sort_by:
|
|
35895
|
-
limit:
|
|
35822
|
+
var PeerHealthInputSchema = import_zod11.z.object({
|
|
35823
|
+
cert: import_zod11.z.number().int().positive().optional().describe("Subject institution CERT to highlight in the ranking. Optional."),
|
|
35824
|
+
certs: import_zod11.z.array(import_zod11.z.number().int().positive()).max(50).optional().describe("Explicit list of CERTs to compare (max 50)."),
|
|
35825
|
+
state: import_zod11.z.string().regex(/^[A-Z]{2}$/).optional().describe('Two-letter state code to select all active institutions (e.g., "WY").'),
|
|
35826
|
+
asset_min: import_zod11.z.number().positive().optional().describe("Minimum total assets ($thousands) for peer selection."),
|
|
35827
|
+
asset_max: import_zod11.z.number().positive().optional().describe("Maximum total assets ($thousands) for peer selection."),
|
|
35828
|
+
repdte: import_zod11.z.string().regex(/^\d{8}$/).optional().describe("Report Date (YYYYMMDD). Defaults to the most recent quarter."),
|
|
35829
|
+
sort_by: import_zod11.z.enum(["composite", "capital", "asset_quality", "earnings", "liquidity", "sensitivity"]).default("composite").describe("Sort results by composite or a specific CAMELS component rating."),
|
|
35830
|
+
limit: import_zod11.z.number().int().min(1).max(100).default(25).describe("Max institutions to return in the response.")
|
|
35896
35831
|
});
|
|
35897
35832
|
function sortKeyToComponent(key) {
|
|
35898
35833
|
const map = {
|
|
@@ -35922,6 +35857,7 @@ Output: Ranked list with per-institution proxy_score (1-4 scale) and proxy_band,
|
|
|
35922
35857
|
|
|
35923
35858
|
NOTE: Public off-site analytical proxy \u2014 not official supervisory ratings.`,
|
|
35924
35859
|
inputSchema: PeerHealthInputSchema,
|
|
35860
|
+
outputSchema: FdicAnalysisOutputSchema,
|
|
35925
35861
|
annotations: {
|
|
35926
35862
|
readOnlyHint: true,
|
|
35927
35863
|
destructiveHint: false,
|
|
@@ -36291,7 +36227,7 @@ NOTE: Public off-site analytical proxy \u2014 not official supervisory ratings.`
|
|
|
36291
36227
|
}
|
|
36292
36228
|
|
|
36293
36229
|
// src/tools/riskSignals.ts
|
|
36294
|
-
var
|
|
36230
|
+
var import_zod12 = require("zod");
|
|
36295
36231
|
function classifyRiskSignals(metrics, trends) {
|
|
36296
36232
|
const signals = [];
|
|
36297
36233
|
if (metrics.tier1_leverage !== null && metrics.tier1_leverage < 5) {
|
|
@@ -36362,15 +36298,15 @@ function classifyRiskSignals(metrics, trends) {
|
|
|
36362
36298
|
return signals;
|
|
36363
36299
|
}
|
|
36364
36300
|
var SEVERITY_ORDER = { critical: 0, warning: 1, info: 2 };
|
|
36365
|
-
var RiskSignalsInputSchema =
|
|
36366
|
-
state:
|
|
36367
|
-
certs:
|
|
36368
|
-
asset_min:
|
|
36369
|
-
asset_max:
|
|
36370
|
-
repdte:
|
|
36371
|
-
min_severity:
|
|
36372
|
-
quarters:
|
|
36373
|
-
limit:
|
|
36301
|
+
var RiskSignalsInputSchema = import_zod12.z.object({
|
|
36302
|
+
state: import_zod12.z.string().regex(/^[A-Z]{2}$/).optional().describe("Scan all active institutions in this state."),
|
|
36303
|
+
certs: import_zod12.z.array(import_zod12.z.number().int().positive()).max(50).optional().describe("Specific CERTs to scan (max 50)."),
|
|
36304
|
+
asset_min: import_zod12.z.number().positive().optional().describe("Minimum total assets ($thousands) filter."),
|
|
36305
|
+
asset_max: import_zod12.z.number().positive().optional().describe("Maximum total assets ($thousands) filter."),
|
|
36306
|
+
repdte: import_zod12.z.string().regex(/^\d{8}$/).optional().describe("Report Date (YYYYMMDD). Defaults to the most recent quarter."),
|
|
36307
|
+
min_severity: import_zod12.z.enum(["info", "warning", "critical"]).default("warning").describe("Minimum severity level to include in results (default: warning)."),
|
|
36308
|
+
quarters: import_zod12.z.number().int().min(1).max(12).default(4).describe("Prior quarters to fetch for trend analysis (default 4)."),
|
|
36309
|
+
limit: import_zod12.z.number().int().min(1).max(100).default(25).describe("Max flagged institutions to return.")
|
|
36374
36310
|
});
|
|
36375
36311
|
function registerRiskSignalTools(server) {
|
|
36376
36312
|
server.registerTool(
|
|
@@ -36393,6 +36329,7 @@ Output: Per-institution risk signals ranked by severity count. The proxy engine
|
|
|
36393
36329
|
|
|
36394
36330
|
NOTE: Public off-site analytical proxy \u2014 not official supervisory ratings.`,
|
|
36395
36331
|
inputSchema: RiskSignalsInputSchema,
|
|
36332
|
+
outputSchema: FdicAnalysisOutputSchema,
|
|
36396
36333
|
annotations: {
|
|
36397
36334
|
readOnlyHint: true,
|
|
36398
36335
|
destructiveHint: false,
|
|
@@ -36612,7 +36549,7 @@ NOTE: Public off-site analytical proxy \u2014 not official supervisory ratings.`
|
|
|
36612
36549
|
}
|
|
36613
36550
|
|
|
36614
36551
|
// src/tools/creditConcentration.ts
|
|
36615
|
-
var
|
|
36552
|
+
var import_zod13 = require("zod");
|
|
36616
36553
|
|
|
36617
36554
|
// src/tools/shared/creditConcentration.ts
|
|
36618
36555
|
var CREDIT_FIELDS = [
|
|
@@ -36728,9 +36665,9 @@ function formatCreditSummaryText(summary) {
|
|
|
36728
36665
|
}
|
|
36729
36666
|
return parts.join("\n");
|
|
36730
36667
|
}
|
|
36731
|
-
var CreditConcentrationSchema =
|
|
36732
|
-
cert:
|
|
36733
|
-
repdte:
|
|
36668
|
+
var CreditConcentrationSchema = import_zod13.z.object({
|
|
36669
|
+
cert: import_zod13.z.number().int().positive().describe("FDIC Certificate Number"),
|
|
36670
|
+
repdte: import_zod13.z.string().regex(/^\d{8}$/).optional().describe("Report date (YYYYMMDD). Defaults to most recent quarter.")
|
|
36734
36671
|
});
|
|
36735
36672
|
function registerCreditConcentrationTools(server) {
|
|
36736
36673
|
server.registerTool(
|
|
@@ -36748,6 +36685,7 @@ Output includes:
|
|
|
36748
36685
|
|
|
36749
36686
|
NOTE: This is an analytical tool based on public financial data.`,
|
|
36750
36687
|
inputSchema: CreditConcentrationSchema,
|
|
36688
|
+
outputSchema: FdicAnalysisOutputSchema,
|
|
36751
36689
|
annotations: {
|
|
36752
36690
|
readOnlyHint: true,
|
|
36753
36691
|
destructiveHint: false,
|
|
@@ -36834,7 +36772,7 @@ NOTE: This is an analytical tool based on public financial data.`,
|
|
|
36834
36772
|
}
|
|
36835
36773
|
|
|
36836
36774
|
// src/tools/fundingProfile.ts
|
|
36837
|
-
var
|
|
36775
|
+
var import_zod14 = require("zod");
|
|
36838
36776
|
|
|
36839
36777
|
// src/tools/shared/fundingProfile.ts
|
|
36840
36778
|
var FUNDING_FIELDS = "CERT,REPDTE,ASSET,DEP,DEPDOM,DEPFOR,COREDEP,BROR,FREPP,EFREPP,EINTEXP,DEPDASTR,CHBALR,LNLSDEPR";
|
|
@@ -36934,9 +36872,9 @@ function formatFundingSummaryText(summary) {
|
|
|
36934
36872
|
}
|
|
36935
36873
|
return parts.join("\n");
|
|
36936
36874
|
}
|
|
36937
|
-
var FundingProfileSchema =
|
|
36938
|
-
cert:
|
|
36939
|
-
repdte:
|
|
36875
|
+
var FundingProfileSchema = import_zod14.z.object({
|
|
36876
|
+
cert: import_zod14.z.number().int().positive().describe("FDIC Certificate Number"),
|
|
36877
|
+
repdte: import_zod14.z.string().regex(/^\d{8}$/).optional().describe("Report date (YYYYMMDD). Defaults to most recent quarter.")
|
|
36940
36878
|
});
|
|
36941
36879
|
function registerFundingProfileTools(server) {
|
|
36942
36880
|
server.registerTool(
|
|
@@ -36954,6 +36892,7 @@ Output includes:
|
|
|
36954
36892
|
|
|
36955
36893
|
NOTE: This is an analytical tool based on public financial data.`,
|
|
36956
36894
|
inputSchema: FundingProfileSchema,
|
|
36895
|
+
outputSchema: FdicAnalysisOutputSchema,
|
|
36957
36896
|
annotations: {
|
|
36958
36897
|
readOnlyHint: true,
|
|
36959
36898
|
destructiveHint: false,
|
|
@@ -37040,7 +36979,7 @@ NOTE: This is an analytical tool based on public financial data.`,
|
|
|
37040
36979
|
}
|
|
37041
36980
|
|
|
37042
36981
|
// src/tools/securitiesPortfolio.ts
|
|
37043
|
-
var
|
|
36982
|
+
var import_zod15 = require("zod");
|
|
37044
36983
|
|
|
37045
36984
|
// src/tools/shared/securitiesPortfolio.ts
|
|
37046
36985
|
var SECURITIES_FIELDS = "CERT,REPDTE,ASSET,EQTOT,SC,SCRES";
|
|
@@ -37125,9 +37064,9 @@ function formatSecuritiesSummaryText(summary) {
|
|
|
37125
37064
|
}
|
|
37126
37065
|
return parts.join("\n");
|
|
37127
37066
|
}
|
|
37128
|
-
var SecuritiesPortfolioSchema =
|
|
37129
|
-
cert:
|
|
37130
|
-
repdte:
|
|
37067
|
+
var SecuritiesPortfolioSchema = import_zod15.z.object({
|
|
37068
|
+
cert: import_zod15.z.number().int().positive().describe("FDIC Certificate Number"),
|
|
37069
|
+
repdte: import_zod15.z.string().regex(/^\d{8}$/).optional().describe("Report date (YYYYMMDD). Defaults to most recent quarter.")
|
|
37131
37070
|
});
|
|
37132
37071
|
function registerSecuritiesPortfolioTools(server) {
|
|
37133
37072
|
server.registerTool(
|
|
@@ -37145,6 +37084,7 @@ Output includes:
|
|
|
37145
37084
|
|
|
37146
37085
|
NOTE: This is an analytical tool based on public financial data. AFS/HTM breakdown is not currently available from the FDIC API.`,
|
|
37147
37086
|
inputSchema: SecuritiesPortfolioSchema,
|
|
37087
|
+
outputSchema: FdicAnalysisOutputSchema,
|
|
37148
37088
|
annotations: {
|
|
37149
37089
|
readOnlyHint: true,
|
|
37150
37090
|
destructiveHint: false,
|
|
@@ -37231,7 +37171,7 @@ NOTE: This is an analytical tool based on public financial data. AFS/HTM breakdo
|
|
|
37231
37171
|
}
|
|
37232
37172
|
|
|
37233
37173
|
// src/tools/ubprAnalysis.ts
|
|
37234
|
-
var
|
|
37174
|
+
var import_zod16 = require("zod");
|
|
37235
37175
|
|
|
37236
37176
|
// src/tools/shared/ubprRatios.ts
|
|
37237
37177
|
var UBPR_FIELDS = "CERT,REPDTE,ASSET,ROA,ROE,ROAPTX,NIMY,EEFFR,INTINC,EINTEXP,NONII,NONIX,NETINC,ELNATRY,LNLSNET,LNRE,LNCI,LNCON,LNAG,DEP,COREDEP,DEPDOM,DEPFOR,BROR,FREPP,IDT1CER,IDT1RWAJR,EQV,EQTOT,LNLSDEPR,DEPDASTR,CHBALR,NPERFV,NCLNLSR,NTLNLSR,LNATRESR,LNRESNCR,SC";
|
|
@@ -37342,9 +37282,9 @@ function formatUbprSummaryText(summary) {
|
|
|
37342
37282
|
parts.push("UBPR-equivalent calculations, not official FFIEC UBPR output.");
|
|
37343
37283
|
return parts.join("\n");
|
|
37344
37284
|
}
|
|
37345
|
-
var UbprAnalysisSchema =
|
|
37346
|
-
cert:
|
|
37347
|
-
repdte:
|
|
37285
|
+
var UbprAnalysisSchema = import_zod16.z.object({
|
|
37286
|
+
cert: import_zod16.z.number().int().positive().describe("FDIC Certificate Number"),
|
|
37287
|
+
repdte: import_zod16.z.string().length(8).optional().describe("Report date (YYYYMMDD). Defaults to most recent quarter.")
|
|
37348
37288
|
});
|
|
37349
37289
|
function registerUbprAnalysisTools(server) {
|
|
37350
37290
|
server.registerTool(
|
|
@@ -37363,6 +37303,7 @@ Output includes:
|
|
|
37363
37303
|
|
|
37364
37304
|
NOTE: This is an analytical tool based on public financial data.`,
|
|
37365
37305
|
inputSchema: UbprAnalysisSchema,
|
|
37306
|
+
outputSchema: FdicAnalysisOutputSchema,
|
|
37366
37307
|
annotations: {
|
|
37367
37308
|
readOnlyHint: true,
|
|
37368
37309
|
destructiveHint: false,
|
|
@@ -37463,7 +37404,7 @@ NOTE: This is an analytical tool based on public financial data.`,
|
|
|
37463
37404
|
}
|
|
37464
37405
|
|
|
37465
37406
|
// src/tools/marketShareAnalysis.ts
|
|
37466
|
-
var
|
|
37407
|
+
var import_zod17 = require("zod");
|
|
37467
37408
|
|
|
37468
37409
|
// src/tools/shared/marketShare.ts
|
|
37469
37410
|
function computeMarketShare(branches) {
|
|
@@ -37576,16 +37517,16 @@ function formatMarketShareText(summary) {
|
|
|
37576
37517
|
function getDefaultSodYear() {
|
|
37577
37518
|
return (/* @__PURE__ */ new Date()).getFullYear() - 1;
|
|
37578
37519
|
}
|
|
37579
|
-
var MarketShareInputSchema =
|
|
37580
|
-
msa:
|
|
37520
|
+
var MarketShareInputSchema = import_zod17.z.object({
|
|
37521
|
+
msa: import_zod17.z.number().int().positive().optional().describe(
|
|
37581
37522
|
"FDIC MSABR numeric code for the Metropolitan Statistical Area (e.g., 19100 for Dallas-Fort Worth-Arlington, 42660 for Seattle-Tacoma-Bellevue). Use fdic_search_sod with MSABR to look up codes."
|
|
37582
37523
|
),
|
|
37583
|
-
city:
|
|
37584
|
-
state:
|
|
37524
|
+
city: import_zod17.z.string().optional().describe('City name (e.g., "Austin"). Requires state.'),
|
|
37525
|
+
state: import_zod17.z.string().length(2).optional().describe(
|
|
37585
37526
|
"Two-letter state abbreviation (e.g., TX). Required when using city filter."
|
|
37586
37527
|
),
|
|
37587
|
-
year:
|
|
37588
|
-
cert:
|
|
37528
|
+
year: import_zod17.z.number().int().min(1994).optional().describe("SOD report year (1994-present). Defaults to most recent."),
|
|
37529
|
+
cert: import_zod17.z.number().int().positive().optional().describe("Highlight a specific institution in the results.")
|
|
37589
37530
|
});
|
|
37590
37531
|
function registerMarketShareAnalysisTools(server) {
|
|
37591
37532
|
server.registerTool(
|
|
@@ -37608,6 +37549,7 @@ Output includes:
|
|
|
37608
37549
|
|
|
37609
37550
|
Requires at least one of: msa (numeric MSABR code), or city + state.`,
|
|
37610
37551
|
inputSchema: MarketShareInputSchema,
|
|
37552
|
+
outputSchema: FdicAnalysisOutputSchema,
|
|
37611
37553
|
annotations: {
|
|
37612
37554
|
readOnlyHint: true,
|
|
37613
37555
|
destructiveHint: false,
|
|
@@ -37723,7 +37665,7 @@ Requires at least one of: msa (numeric MSABR code), or city + state.`,
|
|
|
37723
37665
|
}
|
|
37724
37666
|
|
|
37725
37667
|
// src/tools/franchiseFootprint.ts
|
|
37726
|
-
var
|
|
37668
|
+
var import_zod18 = require("zod");
|
|
37727
37669
|
var SOD_BRANCH_FIELDS = "CERT,NAMEFULL,DEPSUMBR,BRNUM,MSABR,STALPBR,YEAR";
|
|
37728
37670
|
var SOD_FETCH_LIMIT2 = 1e4;
|
|
37729
37671
|
var NON_MSA_LABEL = "Non-MSA / Rural";
|
|
@@ -37762,9 +37704,9 @@ function formatFranchiseFootprintText(summary) {
|
|
|
37762
37704
|
function getDefaultSodYear2() {
|
|
37763
37705
|
return (/* @__PURE__ */ new Date()).getFullYear() - 1;
|
|
37764
37706
|
}
|
|
37765
|
-
var FranchiseFootprintInputSchema =
|
|
37766
|
-
cert:
|
|
37767
|
-
year:
|
|
37707
|
+
var FranchiseFootprintInputSchema = import_zod18.z.object({
|
|
37708
|
+
cert: import_zod18.z.number().int().positive().describe("FDIC Certificate Number"),
|
|
37709
|
+
year: import_zod18.z.number().int().min(1994).optional().describe("SOD report year. Defaults to most recent.")
|
|
37768
37710
|
});
|
|
37769
37711
|
function registerFranchiseFootprintTools(server) {
|
|
37770
37712
|
server.registerTool(
|
|
@@ -37782,6 +37724,7 @@ Output includes:
|
|
|
37782
37724
|
|
|
37783
37725
|
Branches outside MSAs are grouped under "Non-MSA / Rural".`,
|
|
37784
37726
|
inputSchema: FranchiseFootprintInputSchema,
|
|
37727
|
+
outputSchema: FdicAnalysisOutputSchema,
|
|
37785
37728
|
annotations: {
|
|
37786
37729
|
readOnlyHint: true,
|
|
37787
37730
|
destructiveHint: false,
|
|
@@ -37902,7 +37845,7 @@ Branches outside MSAs are grouped under "Non-MSA / Rural".`,
|
|
|
37902
37845
|
}
|
|
37903
37846
|
|
|
37904
37847
|
// src/tools/holdingCompanyProfile.ts
|
|
37905
|
-
var
|
|
37848
|
+
var import_zod19 = require("zod");
|
|
37906
37849
|
|
|
37907
37850
|
// src/tools/shared/holdingCompany.ts
|
|
37908
37851
|
var INDEPENDENT_LABEL = "(Independent)";
|
|
@@ -38019,11 +37962,11 @@ function formatHoldingCompanyProfileText(result) {
|
|
|
38019
37962
|
}
|
|
38020
37963
|
return parts.join("\n");
|
|
38021
37964
|
}
|
|
38022
|
-
var HoldingCompanyProfileSchema =
|
|
38023
|
-
hc_name:
|
|
37965
|
+
var HoldingCompanyProfileSchema = import_zod19.z.object({
|
|
37966
|
+
hc_name: import_zod19.z.string().optional().describe(
|
|
38024
37967
|
'Holding company name (e.g., "JPMORGAN CHASE & CO"). Uses NAMEHCR field.'
|
|
38025
37968
|
),
|
|
38026
|
-
cert:
|
|
37969
|
+
cert: import_zod19.z.number().int().positive().optional().describe(
|
|
38027
37970
|
"CERT of any subsidiary \u2014 looks up its holding company, then profiles the entire HC."
|
|
38028
37971
|
)
|
|
38029
37972
|
});
|
|
@@ -38041,6 +37984,7 @@ Output includes:
|
|
|
38041
37984
|
|
|
38042
37985
|
NOTE: This is an analytical tool based on public financial data.`,
|
|
38043
37986
|
inputSchema: HoldingCompanyProfileSchema,
|
|
37987
|
+
outputSchema: FdicAnalysisOutputSchema,
|
|
38044
37988
|
annotations: {
|
|
38045
37989
|
readOnlyHint: true,
|
|
38046
37990
|
destructiveHint: false,
|
|
@@ -38211,7 +38155,7 @@ NOTE: This is an analytical tool based on public financial data.`,
|
|
|
38211
38155
|
}
|
|
38212
38156
|
|
|
38213
38157
|
// src/tools/regionalContext.ts
|
|
38214
|
-
var
|
|
38158
|
+
var import_zod20 = require("zod");
|
|
38215
38159
|
|
|
38216
38160
|
// src/services/fredClient.ts
|
|
38217
38161
|
var import_axios2 = __toESM(require("axios"));
|
|
@@ -38411,14 +38355,14 @@ function formatRegionalContextText(summary) {
|
|
|
38411
38355
|
parts.push("Note: Economic data from FRED (Federal Reserve Economic Data).");
|
|
38412
38356
|
return parts.join("\n");
|
|
38413
38357
|
}
|
|
38414
|
-
var RegionalContextSchema =
|
|
38415
|
-
cert:
|
|
38358
|
+
var RegionalContextSchema = import_zod20.z.object({
|
|
38359
|
+
cert: import_zod20.z.number().int().positive().optional().describe(
|
|
38416
38360
|
"FDIC Certificate Number \u2014 auto-detects state from institution record."
|
|
38417
38361
|
),
|
|
38418
|
-
state:
|
|
38362
|
+
state: import_zod20.z.string().length(2).optional().describe(
|
|
38419
38363
|
"Two-letter state abbreviation (e.g., TX). Alternative to cert-based lookup."
|
|
38420
38364
|
),
|
|
38421
|
-
repdte:
|
|
38365
|
+
repdte: import_zod20.z.string().regex(/^\d{8}$/).optional().describe(
|
|
38422
38366
|
"Reference report date (YYYYMMDD). FRED data fetched for 2 years before this date."
|
|
38423
38367
|
)
|
|
38424
38368
|
});
|
|
@@ -38437,6 +38381,7 @@ Output includes:
|
|
|
38437
38381
|
|
|
38438
38382
|
NOTE: Requires FRED_API_KEY environment variable for reliable data access. Degrades gracefully without it.`,
|
|
38439
38383
|
inputSchema: RegionalContextSchema,
|
|
38384
|
+
outputSchema: FdicAnalysisOutputSchema,
|
|
38440
38385
|
annotations: {
|
|
38441
38386
|
readOnlyHint: true,
|
|
38442
38387
|
destructiveHint: false,
|
|
@@ -38575,7 +38520,7 @@ NOTE: Requires FRED_API_KEY environment variable for reliable data access. Degra
|
|
|
38575
38520
|
}
|
|
38576
38521
|
|
|
38577
38522
|
// src/tools/chatgptRetrieval.ts
|
|
38578
|
-
var
|
|
38523
|
+
var import_zod21 = require("zod");
|
|
38579
38524
|
|
|
38580
38525
|
// src/tools/shared/chatgptUrls.ts
|
|
38581
38526
|
var FDIC_BANKFIND_BASE_URL = "https://banks.data.fdic.gov/bankfind-suite";
|
|
@@ -38595,11 +38540,11 @@ function getBranchCitationUrl() {
|
|
|
38595
38540
|
}
|
|
38596
38541
|
|
|
38597
38542
|
// src/tools/chatgptRetrieval.ts
|
|
38598
|
-
var SearchInputSchema =
|
|
38599
|
-
query:
|
|
38543
|
+
var SearchInputSchema = import_zod21.z.object({
|
|
38544
|
+
query: import_zod21.z.string().min(1).describe("Natural-language search query.")
|
|
38600
38545
|
});
|
|
38601
|
-
var FetchInputSchema =
|
|
38602
|
-
id:
|
|
38546
|
+
var FetchInputSchema = import_zod21.z.object({
|
|
38547
|
+
id: import_zod21.z.string().min(1).describe(
|
|
38603
38548
|
"Retrieval item id, such as institution:<CERT>, failure:<CERT>, branch:<UNINUM>, or schema:<endpoint>."
|
|
38604
38549
|
)
|
|
38605
38550
|
});
|
|
@@ -38946,13 +38891,39 @@ async function fetchById(id) {
|
|
|
38946
38891
|
}
|
|
38947
38892
|
throw new Error(`Unsupported fetch id kind: ${kind}.`);
|
|
38948
38893
|
}
|
|
38949
|
-
function
|
|
38894
|
+
async function runSearch(query) {
|
|
38895
|
+
const normalized = normalizeQuery(query);
|
|
38896
|
+
const shouldIncludeFailures = shouldSearchFailures(normalized);
|
|
38897
|
+
const shouldIncludeBranches = shouldSearchBranches(normalized);
|
|
38898
|
+
const shouldIncludeSchemas = shouldSearchSchemas(normalized);
|
|
38899
|
+
const [institutions, failures, branches] = await Promise.all([
|
|
38900
|
+
safeSearch(() => searchInstitutions(normalized)),
|
|
38901
|
+
shouldIncludeFailures ? safeSearch(() => searchFailures(normalized)) : Promise.resolve([]),
|
|
38902
|
+
shouldIncludeBranches ? safeSearch(() => searchBranches(normalized)) : Promise.resolve([])
|
|
38903
|
+
]);
|
|
38904
|
+
const fallbackFailures = failures.length === 0 && institutions.length === 0 ? await safeSearch(() => searchFailures(normalized)) : [];
|
|
38905
|
+
const fallbackBranches = branches.length === 0 && institutions.length === 0 ? await safeSearch(() => searchBranches(normalized)) : [];
|
|
38906
|
+
const schemas = shouldIncludeSchemas ? schemaSearchResults(normalized) : [];
|
|
38907
|
+
const results = dedupeResults([
|
|
38908
|
+
...institutions,
|
|
38909
|
+
...failures,
|
|
38910
|
+
...branches,
|
|
38911
|
+
...fallbackFailures,
|
|
38912
|
+
...fallbackBranches,
|
|
38913
|
+
...schemas
|
|
38914
|
+
]);
|
|
38915
|
+
return { results };
|
|
38916
|
+
}
|
|
38917
|
+
var SEARCH_DESCRIPTION = "Use this when the model needs citation-friendly FDIC BankFind search results for institutions, failed banks, branches, or schema documentation. Returns up to 8 results with id, title, and source URL.";
|
|
38918
|
+
var FETCH_DESCRIPTION = "Use this when the model needs the full citation text for a result returned by search. Pass the search result id (e.g. 'institution:3511', 'failure:1234', 'branch:<UNINUM>', 'schema:institutions').";
|
|
38919
|
+
function registerSearchTool(server, name) {
|
|
38950
38920
|
server.registerTool(
|
|
38951
|
-
|
|
38921
|
+
name,
|
|
38952
38922
|
{
|
|
38953
38923
|
title: "Search FDIC BankFind",
|
|
38954
|
-
description:
|
|
38924
|
+
description: SEARCH_DESCRIPTION,
|
|
38955
38925
|
inputSchema: SearchInputSchema,
|
|
38926
|
+
outputSchema: ChatGptSearchResultSchema,
|
|
38956
38927
|
annotations: {
|
|
38957
38928
|
readOnlyHint: true,
|
|
38958
38929
|
destructiveHint: false,
|
|
@@ -38961,37 +38932,22 @@ function registerChatGptRetrievalTools(server) {
|
|
|
38961
38932
|
}
|
|
38962
38933
|
},
|
|
38963
38934
|
async ({ query }) => {
|
|
38964
|
-
const
|
|
38965
|
-
const shouldIncludeFailures = shouldSearchFailures(normalized);
|
|
38966
|
-
const shouldIncludeBranches = shouldSearchBranches(normalized);
|
|
38967
|
-
const shouldIncludeSchemas = shouldSearchSchemas(normalized);
|
|
38968
|
-
const [institutions, failures, branches] = await Promise.all([
|
|
38969
|
-
safeSearch(() => searchInstitutions(normalized)),
|
|
38970
|
-
shouldIncludeFailures ? safeSearch(() => searchFailures(normalized)) : Promise.resolve([]),
|
|
38971
|
-
shouldIncludeBranches ? safeSearch(() => searchBranches(normalized)) : Promise.resolve([])
|
|
38972
|
-
]);
|
|
38973
|
-
const fallbackFailures = failures.length === 0 && institutions.length === 0 ? await safeSearch(() => searchFailures(normalized)) : [];
|
|
38974
|
-
const fallbackBranches = branches.length === 0 && institutions.length === 0 ? await safeSearch(() => searchBranches(normalized)) : [];
|
|
38975
|
-
const schemas = shouldIncludeSchemas ? schemaSearchResults(normalized) : [];
|
|
38976
|
-
const results = dedupeResults([
|
|
38977
|
-
...institutions,
|
|
38978
|
-
...failures,
|
|
38979
|
-
...branches,
|
|
38980
|
-
...fallbackFailures,
|
|
38981
|
-
...fallbackBranches,
|
|
38982
|
-
...schemas
|
|
38983
|
-
]);
|
|
38935
|
+
const payload = await runSearch(query);
|
|
38984
38936
|
return {
|
|
38985
|
-
content: [{ type: "text", text: jsonText(
|
|
38937
|
+
content: [{ type: "text", text: jsonText(payload) }],
|
|
38938
|
+
structuredContent: payload
|
|
38986
38939
|
};
|
|
38987
38940
|
}
|
|
38988
38941
|
);
|
|
38942
|
+
}
|
|
38943
|
+
function registerFetchTool(server, name) {
|
|
38989
38944
|
server.registerTool(
|
|
38990
|
-
|
|
38945
|
+
name,
|
|
38991
38946
|
{
|
|
38992
38947
|
title: "Fetch FDIC BankFind Result",
|
|
38993
|
-
description:
|
|
38948
|
+
description: FETCH_DESCRIPTION,
|
|
38994
38949
|
inputSchema: FetchInputSchema,
|
|
38950
|
+
outputSchema: ChatGptFetchResultSchema,
|
|
38995
38951
|
annotations: {
|
|
38996
38952
|
readOnlyHint: true,
|
|
38997
38953
|
destructiveHint: false,
|
|
@@ -39003,7 +38959,8 @@ function registerChatGptRetrievalTools(server) {
|
|
|
39003
38959
|
try {
|
|
39004
38960
|
const result = await fetchById(id);
|
|
39005
38961
|
return {
|
|
39006
|
-
content: [{ type: "text", text: jsonText(result) }]
|
|
38962
|
+
content: [{ type: "text", text: jsonText(result) }],
|
|
38963
|
+
structuredContent: result
|
|
39007
38964
|
};
|
|
39008
38965
|
} catch (err) {
|
|
39009
38966
|
return formatToolError(err);
|
|
@@ -39011,9 +38968,21 @@ function registerChatGptRetrievalTools(server) {
|
|
|
39011
38968
|
}
|
|
39012
38969
|
);
|
|
39013
38970
|
}
|
|
38971
|
+
function registerChatGptRetrievalTools(server, options = {}) {
|
|
38972
|
+
const includeCanonical = options.includeCanonicalNames ?? true;
|
|
38973
|
+
const includeAliases = options.includeNamespacedAliases ?? true;
|
|
38974
|
+
if (includeCanonical) {
|
|
38975
|
+
registerSearchTool(server, "search");
|
|
38976
|
+
registerFetchTool(server, "fetch");
|
|
38977
|
+
}
|
|
38978
|
+
if (includeAliases) {
|
|
38979
|
+
registerSearchTool(server, "fdic_search");
|
|
38980
|
+
registerFetchTool(server, "fdic_fetch");
|
|
38981
|
+
}
|
|
38982
|
+
}
|
|
39014
38983
|
|
|
39015
38984
|
// src/tools/chatgptBankDeepDive.ts
|
|
39016
|
-
var
|
|
38985
|
+
var import_zod22 = require("zod");
|
|
39017
38986
|
|
|
39018
38987
|
// src/resources/chatgptAppResources.ts
|
|
39019
38988
|
var BANK_DEEP_DIVE_WIDGET_URI = "ui://widget/fdic-bank-deep-dive-v1.html";
|
|
@@ -39274,9 +39243,9 @@ function registerChatGptAppResources(server) {
|
|
|
39274
39243
|
}
|
|
39275
39244
|
|
|
39276
39245
|
// src/tools/chatgptBankDeepDive.ts
|
|
39277
|
-
var BankDeepDiveInputSchema =
|
|
39278
|
-
cert:
|
|
39279
|
-
repdte:
|
|
39246
|
+
var BankDeepDiveInputSchema = import_zod22.z.object({
|
|
39247
|
+
cert: import_zod22.z.number().int().positive().describe("FDIC Certificate Number of the institution to render."),
|
|
39248
|
+
repdte: import_zod22.z.string().regex(/^\d{8}$/).optional().describe(
|
|
39280
39249
|
"Quarter-end report date in YYYYMMDD format. Defaults to the most recent likely published quarter."
|
|
39281
39250
|
)
|
|
39282
39251
|
});
|
|
@@ -39318,21 +39287,72 @@ function collectDashboardRiskSignals(financials) {
|
|
|
39318
39287
|
}
|
|
39319
39288
|
return signals;
|
|
39320
39289
|
}
|
|
39321
|
-
function
|
|
39322
|
-
|
|
39323
|
-
|
|
39324
|
-
|
|
39325
|
-
|
|
39326
|
-
|
|
39327
|
-
|
|
39328
|
-
|
|
39329
|
-
|
|
39330
|
-
|
|
39331
|
-
|
|
39332
|
-
|
|
39290
|
+
function formatDollarsInThousands(value) {
|
|
39291
|
+
if (value === void 0) {
|
|
39292
|
+
return "n/a";
|
|
39293
|
+
}
|
|
39294
|
+
if (Math.abs(value) >= 1e6) {
|
|
39295
|
+
return `$${(value / 1e6).toFixed(1)}B`;
|
|
39296
|
+
}
|
|
39297
|
+
if (Math.abs(value) >= 1e3) {
|
|
39298
|
+
return `$${(value / 1e3).toFixed(1)}M`;
|
|
39299
|
+
}
|
|
39300
|
+
return `$${value.toLocaleString()}k`;
|
|
39301
|
+
}
|
|
39302
|
+
function buildDashboardMarkdown(data) {
|
|
39303
|
+
const { institution: inst, assessment, metrics } = data;
|
|
39304
|
+
const status = inst.active ? "Active" : "Inactive or unknown";
|
|
39305
|
+
const lines = [];
|
|
39306
|
+
lines.push(`## FDIC Bank Deep Dive: ${inst.name}`);
|
|
39307
|
+
lines.push("");
|
|
39308
|
+
lines.push(
|
|
39309
|
+
`**CERT** ${inst.cert} \xB7 ${inst.city}, ${inst.state} \xB7 ${status} \xB7 **Report date** ${inst.report_date}`
|
|
39310
|
+
);
|
|
39311
|
+
lines.push("");
|
|
39312
|
+
lines.push(`> ${assessment.caveat}`);
|
|
39313
|
+
lines.push("");
|
|
39314
|
+
lines.push("### Headline metrics");
|
|
39315
|
+
lines.push("");
|
|
39316
|
+
lines.push("| Metric | Value |");
|
|
39317
|
+
lines.push("| --- | --- |");
|
|
39318
|
+
lines.push(`| Assets | ${formatDollarsInThousands(inst.asset_thousands)} |`);
|
|
39319
|
+
lines.push(
|
|
39320
|
+
`| Deposits | ${formatDollarsInThousands(inst.deposit_thousands)} |`
|
|
39321
|
+
);
|
|
39322
|
+
lines.push(`| Offices | ${inst.offices ?? "n/a"} |`);
|
|
39323
|
+
lines.push(`| Proxy band | ${assessment.proxy_band} |`);
|
|
39324
|
+
lines.push(`| ROA | ${metrics.roa ?? "n/a"} |`);
|
|
39325
|
+
lines.push(`| ROE | ${metrics.roe ?? "n/a"} |`);
|
|
39326
|
+
lines.push(`| Tier 1 leverage | ${metrics.tier1_leverage ?? "n/a"} |`);
|
|
39327
|
+
lines.push(`| Noncurrent loans | ${metrics.noncurrent_loans ?? "n/a"} |`);
|
|
39328
|
+
lines.push(`| Loan-to-deposit | ${metrics.loan_to_deposit ?? "n/a"} |`);
|
|
39329
|
+
lines.push(
|
|
39330
|
+
`| Net interest margin | ${metrics.net_interest_margin ?? "n/a"} |`
|
|
39331
|
+
);
|
|
39332
|
+
lines.push(`| Efficiency ratio | ${metrics.efficiency_ratio ?? "n/a"} |`);
|
|
39333
|
+
lines.push("");
|
|
39334
|
+
lines.push("### Risk signals");
|
|
39335
|
+
lines.push("");
|
|
39336
|
+
if (data.risk_signals.length === 0) {
|
|
39337
|
+
lines.push("_No risk signals returned for this dashboard._");
|
|
39338
|
+
} else {
|
|
39339
|
+
for (const signal of data.risk_signals) {
|
|
39340
|
+
lines.push(`- ${signal}`);
|
|
39341
|
+
}
|
|
39333
39342
|
}
|
|
39334
|
-
|
|
39335
|
-
|
|
39343
|
+
lines.push("");
|
|
39344
|
+
if (data.warnings.length > 0) {
|
|
39345
|
+
lines.push("### Warnings");
|
|
39346
|
+
lines.push("");
|
|
39347
|
+
for (const warning of data.warnings) {
|
|
39348
|
+
lines.push(`- ${warning}`);
|
|
39349
|
+
}
|
|
39350
|
+
lines.push("");
|
|
39351
|
+
}
|
|
39352
|
+
lines.push("### Sources");
|
|
39353
|
+
lines.push("");
|
|
39354
|
+
for (const source of data.sources) {
|
|
39355
|
+
lines.push(`- [${source.title}](${source.url})`);
|
|
39336
39356
|
}
|
|
39337
39357
|
return lines.join("\n");
|
|
39338
39358
|
}
|
|
@@ -39341,8 +39361,9 @@ function registerChatGptBankDeepDiveTool(server) {
|
|
|
39341
39361
|
"fdic_show_bank_deep_dive",
|
|
39342
39362
|
{
|
|
39343
39363
|
title: "Show Bank Deep Dive Dashboard",
|
|
39344
|
-
description: "Use this when the user wants a scannable
|
|
39364
|
+
description: "Use this when the user wants a scannable single-institution dashboard with identity, public financial metrics, risk signals, and source links. ChatGPT renders an interactive widget; Claude and other MCP clients render the same data as a Markdown table.",
|
|
39345
39365
|
inputSchema: BankDeepDiveInputSchema,
|
|
39366
|
+
outputSchema: FdicBankDeepDiveOutputSchema,
|
|
39346
39367
|
annotations: {
|
|
39347
39368
|
readOnlyHint: true,
|
|
39348
39369
|
destructiveHint: false,
|
|
@@ -39429,7 +39450,7 @@ function registerChatGptBankDeepDiveTool(server) {
|
|
|
39429
39450
|
{
|
|
39430
39451
|
type: "text",
|
|
39431
39452
|
text: truncateIfNeeded(
|
|
39432
|
-
|
|
39453
|
+
buildDashboardMarkdown(structuredContent),
|
|
39433
39454
|
CHARACTER_LIMIT
|
|
39434
39455
|
)
|
|
39435
39456
|
}
|
|
@@ -39522,36 +39543,218 @@ function registerSchemaResources(server) {
|
|
|
39522
39543
|
}
|
|
39523
39544
|
}
|
|
39524
39545
|
|
|
39546
|
+
// src/prompts/workflows.ts
|
|
39547
|
+
var import_zod23 = require("zod");
|
|
39548
|
+
var BankDeepDiveArgs = {
|
|
39549
|
+
bank: import_zod23.z.string().min(1).describe("Bank name or FDIC Certificate Number (CERT)."),
|
|
39550
|
+
repdte: import_zod23.z.string().regex(/^\d{8}$/).optional().describe(
|
|
39551
|
+
"Optional quarter-end report date in YYYYMMDD format (0331, 0630, 0930, or 1231)."
|
|
39552
|
+
)
|
|
39553
|
+
};
|
|
39554
|
+
var FailureForensicsArgs = {
|
|
39555
|
+
bank: import_zod23.z.string().min(1).describe("Failed bank name or FDIC Certificate Number (CERT)."),
|
|
39556
|
+
lookback_quarters: import_zod23.z.string().regex(/^\d+$/).optional().describe(
|
|
39557
|
+
"Number of pre-failure quarters to reconstruct (default 12 if omitted)."
|
|
39558
|
+
)
|
|
39559
|
+
};
|
|
39560
|
+
var PortfolioSurveillanceArgs = {
|
|
39561
|
+
scope: import_zod23.z.string().min(1).describe(
|
|
39562
|
+
"Universe to screen \u2014 e.g., 'state:NC', 'asset_min:1000000,asset_max:10000000', or a comma-separated CERT list ('certs:3511,29846,...')."
|
|
39563
|
+
),
|
|
39564
|
+
repdte: import_zod23.z.string().regex(/^\d{8}$/).optional().describe("Optional quarter-end report date in YYYYMMDD format.")
|
|
39565
|
+
};
|
|
39566
|
+
var ExaminerOverlayArgs = {
|
|
39567
|
+
bank: import_zod23.z.string().min(1).describe("Bank name or FDIC Certificate Number (CERT)."),
|
|
39568
|
+
qualitative_notes: import_zod23.z.string().optional().describe(
|
|
39569
|
+
"Optional qualitative analyst inputs (management quality, governance, exam findings) to overlay onto the public proxy assessment."
|
|
39570
|
+
)
|
|
39571
|
+
};
|
|
39572
|
+
function userText(text) {
|
|
39573
|
+
return {
|
|
39574
|
+
role: "user",
|
|
39575
|
+
content: { type: "text", text }
|
|
39576
|
+
};
|
|
39577
|
+
}
|
|
39578
|
+
function registerWorkflowPrompts(server) {
|
|
39579
|
+
server.registerPrompt(
|
|
39580
|
+
"bank_deep_dive",
|
|
39581
|
+
{
|
|
39582
|
+
title: "Comprehensive Bank Deep Dive",
|
|
39583
|
+
description: "Produce a comprehensive single-institution analysis report (health, financials, peer benchmarking, credit concentration, funding profile, securities, franchise footprint, regional context).",
|
|
39584
|
+
argsSchema: BankDeepDiveArgs
|
|
39585
|
+
},
|
|
39586
|
+
({ bank, repdte }) => ({
|
|
39587
|
+
messages: [
|
|
39588
|
+
userText(
|
|
39589
|
+
[
|
|
39590
|
+
`Run a comprehensive FDIC bank deep dive for "${bank}"${repdte ? ` as of ${repdte}` : ""}.`,
|
|
39591
|
+
"",
|
|
39592
|
+
"Steps:",
|
|
39593
|
+
"1. If a CERT was not given, call fdic_search_institutions to resolve the bank to a CERT.",
|
|
39594
|
+
"2. Call fdic_analyze_bank_health and fdic_ubpr_analysis for the resolved CERT.",
|
|
39595
|
+
"3. Call fdic_peer_group_analysis to benchmark the institution against peers.",
|
|
39596
|
+
"4. Call fdic_analyze_credit_concentration, fdic_analyze_funding_profile, and fdic_analyze_securities_portfolio.",
|
|
39597
|
+
"5. Call fdic_franchise_footprint for branch/deposit geography and fdic_regional_context for the home market.",
|
|
39598
|
+
"6. Synthesize into a narrative report with: identity & footprint, health summary, financial performance, peer position, credit concentration, funding profile, securities portfolio, regional context, and a public-data caveat.",
|
|
39599
|
+
"",
|
|
39600
|
+
"All output must be grounded in tool results. Treat any CAMELS-style scoring as a public off-site analytical proxy \u2014 not an official supervisory rating. Note unit conventions ($thousands) where relevant."
|
|
39601
|
+
].join("\n")
|
|
39602
|
+
)
|
|
39603
|
+
]
|
|
39604
|
+
})
|
|
39605
|
+
);
|
|
39606
|
+
server.registerPrompt(
|
|
39607
|
+
"failure_forensics",
|
|
39608
|
+
{
|
|
39609
|
+
title: "Failed Bank Forensics",
|
|
39610
|
+
description: "Reconstruct the pre-failure financial timeline of a failed FDIC institution and identify the earliest visible warning signals.",
|
|
39611
|
+
argsSchema: FailureForensicsArgs
|
|
39612
|
+
},
|
|
39613
|
+
({ bank, lookback_quarters }) => ({
|
|
39614
|
+
messages: [
|
|
39615
|
+
userText(
|
|
39616
|
+
[
|
|
39617
|
+
`Run a failure-forensics post-mortem for "${bank}" using the FDIC tools.`,
|
|
39618
|
+
"",
|
|
39619
|
+
"Steps:",
|
|
39620
|
+
"1. Resolve the bank to a CERT via fdic_search_institutions or fdic_search.",
|
|
39621
|
+
"2. Call fdic_get_institution_failure to confirm failure date, resolution type, and cost.",
|
|
39622
|
+
`3. Call fdic_search_financials with CERT and a sort_by:REPDTE DESC ordering to pull the prior ${lookback_quarters ?? "12"} quarters before the failure date.`,
|
|
39623
|
+
"4. Call fdic_analyze_credit_concentration, fdic_analyze_funding_profile, and fdic_analyze_securities_portfolio at the latest available pre-failure quarter.",
|
|
39624
|
+
"5. Call fdic_search_history for structural-change events (mergers, charter conversions, assistance) leading up to the failure.",
|
|
39625
|
+
"6. Synthesize a forensic timeline with: failure facts, the deterioration arc (capital, asset quality, earnings, liquidity), the earliest warning signals visible in public data, and likely drivers.",
|
|
39626
|
+
"",
|
|
39627
|
+
"Highlight inflection points (e.g. quarter ROA turned negative, when noncurrent loans exceeded reserves). Reference each finding to the report date that supports it."
|
|
39628
|
+
].join("\n")
|
|
39629
|
+
)
|
|
39630
|
+
]
|
|
39631
|
+
})
|
|
39632
|
+
);
|
|
39633
|
+
server.registerPrompt(
|
|
39634
|
+
"portfolio_surveillance",
|
|
39635
|
+
{
|
|
39636
|
+
title: "Portfolio Surveillance Watchlist",
|
|
39637
|
+
description: "Screen a universe of FDIC institutions and produce a decision-ready watchlist tiered Escalate / Monitor / No Immediate Concern.",
|
|
39638
|
+
argsSchema: PortfolioSurveillanceArgs
|
|
39639
|
+
},
|
|
39640
|
+
({ scope, repdte }) => ({
|
|
39641
|
+
messages: [
|
|
39642
|
+
userText(
|
|
39643
|
+
[
|
|
39644
|
+
`Run portfolio surveillance over scope: "${scope}"${repdte ? ` as of ${repdte}` : ""}.`,
|
|
39645
|
+
"",
|
|
39646
|
+
"Steps:",
|
|
39647
|
+
"1. Build the institution roster:",
|
|
39648
|
+
" - state:<XX> \u2192 fdic_search_institutions filters STALP:<XX> AND ACTIVE:1",
|
|
39649
|
+
" - asset_min:<n>,asset_max:<n> \u2192 ASSET range",
|
|
39650
|
+
" - certs:<csv> \u2192 use the comma-separated list directly",
|
|
39651
|
+
"2. Call fdic_detect_risk_signals across the roster.",
|
|
39652
|
+
"3. Call fdic_compare_peer_health to rank by composite proxy band.",
|
|
39653
|
+
"4. For the highest-risk subset, call fdic_analyze_bank_health for full proxy assessments.",
|
|
39654
|
+
"5. Tier institutions:",
|
|
39655
|
+
" - Escalate: critical risk signals or proxy band 'unsatisfactory'.",
|
|
39656
|
+
" - Monitor: warning signals or 'fair' band, especially deteriorating trends.",
|
|
39657
|
+
" - No Immediate Concern: no critical signals, satisfactory or strong band.",
|
|
39658
|
+
"6. Produce a watchlist table per tier (CERT, name, key signals, rationale).",
|
|
39659
|
+
"",
|
|
39660
|
+
"Treat all scoring as a public off-site analytical proxy. Surface data caveats explicitly."
|
|
39661
|
+
].join("\n")
|
|
39662
|
+
)
|
|
39663
|
+
]
|
|
39664
|
+
})
|
|
39665
|
+
);
|
|
39666
|
+
server.registerPrompt(
|
|
39667
|
+
"examiner_overlay",
|
|
39668
|
+
{
|
|
39669
|
+
title: "Examiner Overlay Assessment",
|
|
39670
|
+
description: "Layer qualitative analyst/examiner inputs on top of the public CAMELS proxy and produce a blended assessment with explicit provenance.",
|
|
39671
|
+
argsSchema: ExaminerOverlayArgs
|
|
39672
|
+
},
|
|
39673
|
+
({ bank, qualitative_notes }) => ({
|
|
39674
|
+
messages: [
|
|
39675
|
+
userText(
|
|
39676
|
+
[
|
|
39677
|
+
`Produce an examiner-overlay assessment for "${bank}".`,
|
|
39678
|
+
"",
|
|
39679
|
+
"Steps:",
|
|
39680
|
+
"1. Resolve to a CERT via fdic_search_institutions if needed.",
|
|
39681
|
+
"2. Call fdic_analyze_bank_health to get the public_camels_proxy_v1 baseline (capital, asset quality, earnings, liquidity, sensitivity).",
|
|
39682
|
+
"3. Call fdic_ubpr_analysis for performance ratios and fdic_analyze_funding_profile / fdic_analyze_credit_concentration for sub-component depth.",
|
|
39683
|
+
"4. Combine the public baseline with qualitative analyst inputs:",
|
|
39684
|
+
qualitative_notes ? ` Analyst notes: ${qualitative_notes}` : " (No qualitative inputs provided \u2014 produce the public baseline and clearly mark which factors would benefit from qualitative overlay.)",
|
|
39685
|
+
"5. Produce a blended assessment with two columns labeled exactly: 'Public-data finding' and 'Examiner overlay'. Never present overlay inputs as if they came from public data.",
|
|
39686
|
+
"6. Final composite must reconcile both columns and call out any divergence.",
|
|
39687
|
+
"",
|
|
39688
|
+
"Disclaimer: this overlay is not an official CAMELS rating or confidential supervisory conclusion."
|
|
39689
|
+
].join("\n")
|
|
39690
|
+
)
|
|
39691
|
+
]
|
|
39692
|
+
})
|
|
39693
|
+
);
|
|
39694
|
+
}
|
|
39695
|
+
|
|
39525
39696
|
// src/index.ts
|
|
39526
|
-
function
|
|
39697
|
+
function resolveProfile(raw) {
|
|
39698
|
+
const tokens = (raw ?? "all").split(",").map((token) => token.trim().toLowerCase()).filter((token) => token.length > 0);
|
|
39699
|
+
const has = (token) => tokens.includes(token);
|
|
39700
|
+
const all = has("all") || tokens.length === 0;
|
|
39701
|
+
const includeChatgpt = all || has("chatgpt");
|
|
39702
|
+
return {
|
|
39703
|
+
core: all || has("core"),
|
|
39704
|
+
analysis: all || has("analysis"),
|
|
39705
|
+
chatgptCanonical: all || includeChatgpt || has("chatgpt-canonical"),
|
|
39706
|
+
chatgptAliases: all || includeChatgpt || has("chatgpt-aliases"),
|
|
39707
|
+
chatgptDeepDive: all || includeChatgpt,
|
|
39708
|
+
prompts: all || has("prompts"),
|
|
39709
|
+
resources: all || has("resources")
|
|
39710
|
+
};
|
|
39711
|
+
}
|
|
39712
|
+
function createServer(options = {}) {
|
|
39527
39713
|
const server = new import_mcp.McpServer({
|
|
39528
39714
|
name: "fdic-mcp-server",
|
|
39529
39715
|
version: VERSION
|
|
39530
39716
|
});
|
|
39531
|
-
|
|
39532
|
-
|
|
39533
|
-
|
|
39534
|
-
|
|
39535
|
-
|
|
39536
|
-
|
|
39537
|
-
|
|
39538
|
-
|
|
39539
|
-
|
|
39540
|
-
|
|
39541
|
-
|
|
39542
|
-
|
|
39543
|
-
|
|
39544
|
-
|
|
39545
|
-
|
|
39546
|
-
|
|
39547
|
-
|
|
39548
|
-
|
|
39549
|
-
|
|
39550
|
-
|
|
39551
|
-
|
|
39552
|
-
|
|
39553
|
-
|
|
39554
|
-
|
|
39717
|
+
const profile = resolveProfile(options.profile ?? process.env.FDIC_MCP_PROFILE);
|
|
39718
|
+
if (profile.core) {
|
|
39719
|
+
registerInstitutionTools(server);
|
|
39720
|
+
registerFailureTools(server);
|
|
39721
|
+
registerLocationTools(server);
|
|
39722
|
+
registerHistoryTools(server);
|
|
39723
|
+
registerFinancialTools(server);
|
|
39724
|
+
registerSodTools(server);
|
|
39725
|
+
registerDemographicsTools(server);
|
|
39726
|
+
}
|
|
39727
|
+
if (profile.analysis) {
|
|
39728
|
+
registerAnalysisTools(server);
|
|
39729
|
+
registerPeerGroupTools(server);
|
|
39730
|
+
registerBankHealthTools(server);
|
|
39731
|
+
registerPeerHealthTools(server);
|
|
39732
|
+
registerRiskSignalTools(server);
|
|
39733
|
+
registerCreditConcentrationTools(server);
|
|
39734
|
+
registerFundingProfileTools(server);
|
|
39735
|
+
registerSecuritiesPortfolioTools(server);
|
|
39736
|
+
registerUbprAnalysisTools(server);
|
|
39737
|
+
registerMarketShareAnalysisTools(server);
|
|
39738
|
+
registerFranchiseFootprintTools(server);
|
|
39739
|
+
registerHoldingCompanyProfileTools(server);
|
|
39740
|
+
registerRegionalContextTools(server);
|
|
39741
|
+
}
|
|
39742
|
+
if (profile.chatgptCanonical || profile.chatgptAliases) {
|
|
39743
|
+
registerChatGptRetrievalTools(server, {
|
|
39744
|
+
includeCanonicalNames: profile.chatgptCanonical,
|
|
39745
|
+
includeNamespacedAliases: profile.chatgptAliases
|
|
39746
|
+
});
|
|
39747
|
+
}
|
|
39748
|
+
if (profile.chatgptDeepDive) {
|
|
39749
|
+
registerChatGptBankDeepDiveTool(server);
|
|
39750
|
+
registerChatGptAppResources(server);
|
|
39751
|
+
}
|
|
39752
|
+
if (profile.resources) {
|
|
39753
|
+
registerSchemaResources(server);
|
|
39754
|
+
}
|
|
39755
|
+
if (profile.prompts) {
|
|
39756
|
+
registerWorkflowPrompts(server);
|
|
39757
|
+
}
|
|
39555
39758
|
return server;
|
|
39556
39759
|
}
|
|
39557
39760
|
async function runStdio() {
|
|
@@ -39623,23 +39826,61 @@ function sendInvalidSessionResponse(res) {
|
|
|
39623
39826
|
}
|
|
39624
39827
|
function createApp(options = {}) {
|
|
39625
39828
|
const app = (0, import_express2.default)();
|
|
39626
|
-
const serverFactory = options.serverFactory ?? createServer;
|
|
39829
|
+
const serverFactory = options.serverFactory ?? (() => createServer());
|
|
39627
39830
|
const port = options.port ?? 3e3;
|
|
39628
39831
|
const allowedOrigins = options.allowedOrigins ?? parseAllowedOrigins(void 0, port);
|
|
39629
39832
|
const sessions = /* @__PURE__ */ new Map();
|
|
39630
39833
|
const chatSessions = /* @__PURE__ */ new Map();
|
|
39631
39834
|
const sessionIdleTimeoutMs = options.sessionIdleTimeoutMs ?? DEFAULT_SESSION_IDLE_TIMEOUT_MS;
|
|
39632
39835
|
const sessionSweepIntervalMs = options.sessionSweepIntervalMs ?? DEFAULT_SESSION_SWEEP_INTERVAL_MS;
|
|
39836
|
+
const stateless = options.stateless ?? process.env.FDIC_MCP_STATELESS_HTTP === "true";
|
|
39633
39837
|
app.use(import_express2.default.json());
|
|
39634
|
-
|
|
39635
|
-
|
|
39636
|
-
|
|
39637
|
-
|
|
39638
|
-
|
|
39838
|
+
if (!stateless) {
|
|
39839
|
+
const sessionSweepTimer = setInterval(() => {
|
|
39840
|
+
void sweepIdleSessions(sessions, sessionIdleTimeoutMs, Date.now());
|
|
39841
|
+
sweepIdleChatSessions(chatSessions, sessionIdleTimeoutMs, Date.now());
|
|
39842
|
+
}, sessionSweepIntervalMs);
|
|
39843
|
+
sessionSweepTimer.unref?.();
|
|
39844
|
+
}
|
|
39639
39845
|
app.get("/health", (_req, res) => {
|
|
39640
39846
|
res.json({ status: "ok", server: "fdic-mcp-server", version: VERSION });
|
|
39641
39847
|
});
|
|
39642
39848
|
app.all("/mcp", async (req, res) => {
|
|
39849
|
+
if (stateless) {
|
|
39850
|
+
let server;
|
|
39851
|
+
let transport;
|
|
39852
|
+
try {
|
|
39853
|
+
server = serverFactory();
|
|
39854
|
+
transport = new import_streamableHttp.StreamableHTTPServerTransport({
|
|
39855
|
+
sessionIdGenerator: void 0,
|
|
39856
|
+
enableJsonResponse: true,
|
|
39857
|
+
enableDnsRebindingProtection: true,
|
|
39858
|
+
allowedOrigins
|
|
39859
|
+
});
|
|
39860
|
+
res.on("close", () => {
|
|
39861
|
+
void transport?.close().catch(() => {
|
|
39862
|
+
});
|
|
39863
|
+
void server?.close().catch(() => {
|
|
39864
|
+
});
|
|
39865
|
+
});
|
|
39866
|
+
await server.connect(transport);
|
|
39867
|
+
await transport.handleRequest(req, res, req.body);
|
|
39868
|
+
} catch (error) {
|
|
39869
|
+
console.error("MCP request error:", error);
|
|
39870
|
+
if (!res.headersSent) {
|
|
39871
|
+
res.status(500).json({
|
|
39872
|
+
jsonrpc: "2.0",
|
|
39873
|
+
error: { code: -32603, message: "Internal server error" },
|
|
39874
|
+
id: null
|
|
39875
|
+
});
|
|
39876
|
+
}
|
|
39877
|
+
await transport?.close().catch(() => {
|
|
39878
|
+
});
|
|
39879
|
+
await server?.close().catch(() => {
|
|
39880
|
+
});
|
|
39881
|
+
}
|
|
39882
|
+
return;
|
|
39883
|
+
}
|
|
39643
39884
|
const sessionIdHeader = req.headers["mcp-session-id"];
|
|
39644
39885
|
const sessionId = typeof sessionIdHeader === "string" ? sessionIdHeader : void 0;
|
|
39645
39886
|
try {
|