About fdic-banks-mcp-server
fdic-banks-mcp-server exposes FDIC-insured institution data for financial researchers, analysts, and banking workflows. It combines institution search, historical Call Report data, peer comparisons, failures, deposits, and read-only dataframe queries without requiring an API key.
Key features
- 01Search insured institutions
- 02Query quarterly financials since 1984
- 03Compare metrics with peer banks
- 04Search failures since 1934
- 05Analyze branch deposits and market share
- 06Stage and query dataframes
Use cases
- 01Screen banks by location, size, or status
- 02Review a bank's financial history
- 03Benchmark a bank against peers
- 04Analyze failures or deposit-market concentration
MCP support
The server exposes ten FDIC data and dataframe tools over stdio or Streamable HTTP. A public hosted MCP endpoint is also available; no API key is required.
Configuration
Remote servers need no local install. Pick your client, then copy the config or install in one click.
https://fdic-banks.caseyjhand.com/mcpclaude mcp add --transport http cyanheads-fdic-banks https://fdic-banks.caseyjhand.com/mcp{"mcpServers":{"cyanheads-fdic-banks":{"type":"http","url":"https://fdic-banks.caseyjhand.com/mcp"}}}Open in Cursor{"servers":{"cyanheads-fdic-banks":{"type":"http","url":"https://fdic-banks.caseyjhand.com/mcp"}}}Open in VS Code{"mcpServers":{"cyanheads-fdic-banks":{"type":"http","url":"https://fdic-banks.caseyjhand.com/mcp"}}}{"mcpServers":{"cyanheads-fdic-banks":{"serverUrl":"https://fdic-banks.caseyjhand.com/mcp"}}}Run commands in a terminal; paste JSON into the client’s MCP config and restart. Servers that need sign-in will prompt on first connect.
Tools
9| Parameter | Type | Required | Description |
|---|---|---|---|
| city | string | No | Headquarters city as FDIC spells it (e.g. Seattle, St. Louis), up to 50 characters; matched exactly, as given or in title case, with a hyphen, apostrophe, or space between words also tried the other ways FDIC records it (Winston-Salem finds Winston Salem, Coeur d'Alene finds Coeur D Alene). |
| name | string | No | Institution name to match, up to 100 characters — current, former, or trade name, case-insensitive, every word required (e.g. "silicon valley"). Punctuation other than & ' . , - is ignored, and so is a standalone N.A. or NA, which then also matches "National Association". |
| sort | enum | No | relevance (active institutions whose current name holds every word of name first, then every other match, each by match score; default when name is given — without name it falls back to assets_desc), assets_desc (largest first; the default otherwise), or name (A–Z).relevance | assets_desc | name |
| certs | array | No | Nonempty CERT selection, at most 1000 raw items. Deduplicated first; the first 50 are queried and the rest returned as deferred_certs. missing_certs covers only processed_certs. |
| limit | integer | No | Institutions per page; accepts 1–10000, executes at most 100. effective_limit reports the applied count; use next_offset to continue. |
| state | string | No | Headquarters state: two-letter code in any case (wa) or full name (Washington); DC and territories accepted. |
| offset | integer | No | Matches to skip (0–100,000); pass next_offset from the previous page. |
| status | enum | No | active, inactive (merged, failed, or closed), or any. Default: any when name or certs is given, otherwise active. The applied value is echoed as status_filter.active | inactive | any |
| max_assets | number | No | Maximum latest reported total assets, in thousands of US dollars. |
| min_assets | number | No | Minimum latest reported total assets, in thousands of US dollars (1000000 = $1 billion). |
| bank_classes | array | No | Charter classes to include: N national bank, NM state nonmember bank, SM state member bank, SB federal savings bank, SI state savings bank, SL state savings and loan, OI insured branch of a foreign bank, NC noninsured non-deposit trust company. |
| holding_company_rssd | integer | No | Holding company RSSD ID from any result's holding_company.rssd; lists the institutions under that top holder. With status any, former subsidiaries are included under the holder they had at closing. |
Details
From the project README@cyanheads/fdic-banks-mcp-server
Search FDIC-insured banks, Call Report financials, peer rankings, failures, deposit market share via MCP. STDIO or Streamable HTTP.
Public Hosted Server: https://fdic-banks.caseyjhand.com/mcp
Overview
Every FDIC-insured bank and savings institution, open, merged, or failed, from the FDIC BankFind Suite API. Read quarterly Call Report financials back to 1984, rank a bank against peers, screen many at once, search failures since 1934, and map branch deposits and market share. Credit unions are NCUA-insured and not included. No API key required.
Tools
| Tool | Description |
|---|---|
fdic_search_institutions | Find institutions by name, CERT, location, size, charter class, or holding company; returns the CERT every other tool takes |
fdic_get_institution_financials | One institution's quarterly Call Report history, most recent first, with its profile |
fdic_compare_peers | One institution against a peer group for one quarter: peer median, quartiles, range, percentile, and rank per metric |
fdic_query_financials | Multi-bank, multi-quarter Call Report panel filtered by CERTs, state, asset range, and metric thresholds |
fdic_search_failures | Bank failures and assistance transactions since 1934, with totals, per-method subtotals, and optional grouping |
fdic_get_deposits | Summary of Deposits: an institution's branches and state market share, or a market ranked by deposits with HHI |
fdic_list_reference | Metric catalog, charter classes, failure methods, insurance funds, peer asset bands, and dataset coverage |
fdic_dataframe_describe | List staged dataframes, or describe one by name: provenance, columns, and units |
fdic_dataframe_query | Run one read-only DuckDB SELECT across staged dataframes |
fdic_dataframe_drop | Drop a staged dataframe before its TTL; off unless FDIC_DATAFRAME_DROP_ENABLED=true |
Dataframe workflow
fdic_query_financialsandfdic_get_depositsreturn an inline preview. When the full result is larger thanlimit, they also stage it as adf_XXXXX_XXXXXtable and name it in thedatasetfield.- Pass that name to
fdic_dataframe_describefor the table's columns, units, and basis. - Query it with
fdic_dataframe_query: joins, aggregates, window functions, and CTEs across every staged table.register_assaves a result as a new table. - Tables expire after
FDIC_DATASET_TTL_SECONDS(default 24 hours). The live tables hold 1,000,000 rows together, and the oldest are dropped past that.
Staging runs on DuckDB and is on by default; CANVAS_PROVIDER_TYPE=none turns it off. The Claude Desktop .mcpb bundle ships without DuckDB's native binding, so there the dataframe tools report an install hint and every other tool works normally.
Capability reference
fdic_search_institutions tool
- Filters:
name(up to 100 characters; every word must match a current, former, or trade name),certs(first 50 unique),state,city,bank_classes,min_assets/max_assets(thousands of US dollars),holding_company_rssd statusisactive,inactive, orany; it defaults toanywhennameorcertsis given andactiveotherwise, andstatus_filterreports the value applied- Up to 100 per page (default 20), paged with
offset/next_offset. Records carryactive,successor_certfor merged or failed banks,holding_company.rssd, andmatched_on; CERTs with no record land inmissing_certs
fdic_get_institution_financials tool
certrequired; up to 25metrics(default: a 15-metric health set);quartersaccepts 1–10,000 and queries at most 200 (default 8), bounded byfrom_date/to_dateas2025-03-31,20250331, or2025Q1- Rows run most recent first, each a
valuesmap of metric → number,nullwhen not reported;metric_definitionsgives each metric's FDIC field, unit, and basis quarters_availablecounts the quarters in the window; an unknown CERT fails ascert_not_found
fdic_compare_peers tool
certrequired;report_datedefaults to the latest published quarter (report_date_defaulted); up to 20metrics- Peer group:
peer_asset_band(sameby default,any,under_100m,100m_1b,1b_10b,10b_250b,over_250b) plus an optionalpeer_state, orpeer_certs(first 200 unique);peer_certscan't be combined with the band or state (conflicting_peer_filters) - Each comparison returns
value,peer_median,peer_p25/peer_p75,peer_min/peer_max,percentile, andrankofrank_of, over thepeer_count_with_valuepeers that reported the metric;peer_cohort_incompletemarks a peer group only partly processed
fdic_query_financials tool
- Filters: up to 100
certs,state,min_assets/max_assets, up to 5metric_filters(metricwithminand/ormax), and up to 30metrics;from_date/to_datedefault to the latest published quarter - Inline
limitdefaults to 50, ordered bysort_by/sort_order; a larger panel is staged whole as a dataframe - The panel is capped at
FDIC_PANEL_MAX_ROWS(default 50,000), keeping the newest quarters;total_matching,rows_fetched, andpanel_truncatedreport what was left out
fdic_search_failures tool
- Filters:
name,certs(first 50 unique; events before 1977 carry none),state,from_date/to_date(YYYY-MM-DD),methods,min_assets;resolutionisfailureby default, orassistanceorall summarytotals every matching event with aby_methodbreakdown;group_by(year,state,method,insurance_fund) addsgroupstotal_assets_missing_count,total_deposits_missing_count, andestimated_loss_missing_countcount unreported amounts, and a total isnullwhen no match has a recorded amount.sortby date, loss, or assets; up to 200 per page (default 25)
fdic_get_deposits tool
certalone returns the institution's branches and deposit share in each state (mode: "institution"); a geography (state,county,city,zip,msa_code) ranks every institution in that market withhhi(market); both together giveinstitution_in_market.countyandcityrequirestateyearfrom 1994 on, defaulting to the latest survey (year_defaulted); deposits are domestic branch deposits as of June 30, in thousands of US dollars- Inline
limitdefaults to 25; a larger set is staged as a dataframe, andtotal_rowsgives the full count
fdic_list_reference tool
- One
topicper call:metrics,bank_classes,failure_methods,insurance_funds,peer_asset_bands, orcoverage metricslists all 49 metric names with FDIC field, unit, basis, caveat, andin_default_set; served from built-in tables with no request to FDIC
fdic_dataframe_describe tool
name(adf_XXXXX_XXXXXfrom adatasetfield) returns that table's source tool, parameters, row count, expiry,column_schema, andcolumn_units- Without
name, lists live tables newest first, 50 per page, paged withoffset/next_offset; over HTTP withMCP_AUTH_MODE=nonelisting is off and fails aslisting_unavailable - Fails as
canvas_unavailablewhen dataframe staging is off
fdic_dataframe_query tool
- One
SELECTper call, up to 20,000 characters; writes, DDL, file-reading functions, and system catalogs are rejected with typed reasons (non_select_statement,denied_function,system_catalog_access, and others) row_limitaccepts 1–1,000,000 (default 1,000) and executes at most 10,000;row_count_cappedreports when more rows matched.previewsets the inline row countregister_assaves the result as a new dataframe, or fails asregister_as_too_largepast 1,000,000 rows;BIGINTresults such asCOUNT(*)come back as strings
fdic_dataframe_drop tool
nameof a staged dataframe; returnsdropped: true, ordropped: falsewhen nothing by that name was staged- Disabled unless
FDIC_DATAFRAME_DROP_ENABLED=true; otherwise tables expire on their TTL
Features
Built on @cyanheads/mcp-ts-core: stdio and Streamable HTTP transports, pluggable auth (none / jwt / oauth), swappable storage (in-memory, filesystem, Supabase, Cloudflare KV/R2/D1), structured logging with optional OpenTelemetry tracing.
FDIC-specific:
- Reads four BankFind datasets: institutions (every insured charter, active and inactive), quarterly Call Report financials from 1984, failures and assistance transactions from 1934, and the annual Summary of Deposits from 1994
- Paced requests (
FDIC_RATE_LIMIT_RPS, at most four in flight) with a response cache and a cooldown after an FDIC 429; each call has a 45-second budget (55 seconds for a panel) - A curated catalog of 49 Call Report metrics with FDIC field code, unit, and basis;
_ytdmetrics accumulate from January 1, and unsuffixed income and return metrics cover a single quarter - Handles BankFind's quirks: case-sensitive code values, string-typed report dates, absence sentinels, and ratios reported as
0when a bank did not report them - Array inputs are deduplicated in order and capped at 1,000 items; empty
certs,peer_certs,bank_classes, andmethodsare rejected
Agent-friendly output:
- Every data response carries
data_as_of,metric_definitions, andreport_date_defaulted/year_defaultedwhen the server picked the period - Unreported metrics come back
null; nothing is filled in - Typed errors with recovery text that names the next call (
cert_not_found,conflicting_peer_filters,no_report_for_period); rate-limit errors (pacer_shed,upstream_rate_limited) carryretryAfter processed_certs/deferred_certsandprocessed_metrics/deferred_metricsseparate what was queried from what to pass in a new call
Getting started
Public Hosted Instance
A public instance is available at https://fdic-banks.caseyjhand.com/mcp — no installation required. Point any MCP client at it via Streamable HTTP:
{
"mcpServers": {
"fdic-banks-mcp-server": {
"type": "streamable-http",
"url": "https://fdic-banks.caseyjhand.com/mcp"
}
}
}
Every caller of the hosted instance shares one FDIC request pacer and one dataframe workspace, so fdic_dataframe_describe takes a table's exact name there; listing is off.
Self-Hosted / Local
Add the following to your MCP client configuration file. No API key is needed.
{
"mcpServers": {
"fdic-banks-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/fdic-banks-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with npx (no Bun required):
{
"mcpServers": {
"fdic-banks-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/fdic-banks-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with Docker:
{
"mcpServers": {
"fdic-banks-mcp-server": {
"type": "stdio",
"command": "docker",
"args": ["run", "-i", "--rm", "-e", "MCP_TRANSPORT_TYPE=stdio", "ghcr.io/cyanheads/fdic-banks-mcp-server:latest"]
}
}
}
For Streamable HTTP, set the transport and start the server:
MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 bun run start:http
# Server listens at http://localhost:3010/mcp
Prerequisites
- Bun v1.4.0 or higher (or Node.js v24+).
- No account or API key: the FDIC BankFind Suite API is public.
Installation
- Clone the repository:
git clone https://github.com/cyanheads/fdic-banks-mcp-server.git
- Navigate into the directory:
cd fdic-banks-mcp-server
- Install dependencies:
bun install
- Configure environment:
cp .env.example .env
# every variable is optional; edit .env to override a default
Configuration
| Variable | Description | Default |
|---|---|---|
FDIC_RATE_LIMIT_RPS | Maximum request starts per second to api.fdic.gov (1–15), shared by every caller of the process. | 8 |
FDIC_CACHE_TTL_SECONDS | Lifetime of the in-process FDIC response cache, in seconds; 0 disables caching. | 3600 |
FDIC_PANEL_MAX_ROWS | Row cap for one fdic_query_financials panel (1,000–200,000); the newest quarters are kept when it binds. | 50000 |
FDIC_DATASET_TTL_SECONDS | Lifetime of each staged dataframe, in seconds (minimum 60). | 86400 |
FDIC_DATAFRAME_DROP_ENABLED | Set true to enable fdic_dataframe_drop. | false |
CANVAS_PROVIDER_TYPE | Dataframe engine: duckdb, or none to turn staging and the dataframe tools off. The server sets duckdb when unset. | duckdb |
MCP_TRANSPORT_TYPE | Transport: stdio or http. | stdio |
MCP_HTTP_PORT | HTTP server port. | 3010 |
MCP_SESSION_MODE | HTTP session mode: stateless, stateful, or auto. | stateless |
MCP_AUTH_MODE | Authentication: none, jwt, or oauth. | none |
MCP_LOG_LEVEL | Log level (debug, info, warning, error, etc.). | info |
LOGS_DIR | Directory for log files (Node.js only). | <app-root>/logs |
STORAGE_PROVIDER_TYPE | Storage backend: in-memory, filesystem, supabase, cloudflare-kv/r2/d1. | in-memory |
OTEL_ENABLED | Enable OpenTelemetry. | false |
See .env.example for the full list of optional overrides.
Running the server
Local development
-
Build and run the production version:
# One-time build bun run rebuild # Run the built server bun run start:http # or bun run start:stdio -
Run checks and tests:
bun run devcheck # Lints, formats, type-checks, and more bun run test # Runs the test suite
Project structure
| Directory | Purpose |
|---|---|
src/index.ts | createApp() entry point: registers the tools, sets the server instructions, and starts the FDIC service and canvas bridge. |
src/config | Server-specific environment variable parsing and validation with Zod. |
src/mcp-server/tools | Tool definitions (*.tool.ts), shared input schemas, and markdown helpers. Ten tools. |
src/services/fdic | FDIC BankFind client (request pacer, response cache, query builder, normalization), the metric catalog, and the reference tables. |
src/services/canvas-bridge | Adapter to the framework's DataCanvas: df_<id> table names, per-table TTL, and provenance. |
tests/ | Unit and integration tests, mirroring the src/ structure. |
Development guide
See CLAUDE.md for development guidelines and architectural rules. The short version:
- Handlers throw, framework catches — no
try/catchin tool logic - Use
ctx.logfor logging,ctx.statefor storage - Register new tools in
buildToolDefinitions()insrc/mcp-server/tools/definitions/index.ts - Wrap external API calls: validate raw → normalize to domain type → return output schema; never fabricate missing fields
Contributing
Issues are welcome. Run checks and tests before submitting:
bun run devcheck
bun run test
License
This project is licensed under the Apache 2.0 License. See the LICENSE file for details.
Comments
New to MCP?
From what the protocol is to installing your first server, these answers cover most first questions.
An open protocol that defines how AI applications connect to external tools and data in a uniform way. Clients talk to the model; MCP servers provide tools, resources and prompt templates. They exchange standard messages, so one server can be reused by many clients.