Skip to main content
Glama
nathanaelhub

open-finance-mcp

by nathanaelhub
README.md
# open-finance-mcp

An MCP server that gives Claude **free, citable** financial data for comps and
DCF work: standardized financials from SEC EDGAR XBRL filings, filing links,
Treasury yields from FRED, and market prices and beta. Every number comes back
with its source: the XBRL concept, the filing accession and a URL to the filing.

## Why

Anthropic's [financial-services plugins](https://github.com/anthropics/financial-services)
ship `/comps`, `/dcf` and earnings workflows whose skills tell Claude to pull
data from MCP connectors first and to cite every hard-coded input. All of the
bundled connectors are paid terminals (FactSet, S&P Capital IQ, PitchBook,
Morningstar, …). Without a subscription, the skills fall back to web search,
which they explicitly warn against.

This server fills that gap with public sources, and it is built around the
skills' citation requirement instead of treating sources as an afterthought.

## Tools

| Tool | Returns |
|---|---|
| `lookup_company` | Ticker, name, CIK and exchange for a ticker or name search |
| `get_financials` | Annual + LTM income statement, cash flow and balance sheet; derived EBITDA, FCF, total debt, net debt; per-value citations |
| `get_filings` | Recent 10-K / 10-Q / 8-K (etc.) with document and index URLs |
| `get_market_data` | Price, cover-page shares outstanding, market cap, 5-year monthly beta vs the S&P 500 |
| `get_treasury_yield` | Latest constant-maturity Treasury yield (3M–30Y) from FRED |
| `get_comps` | Peer table: market cap, EV, LTM revenue/EBITDA/net income, EV/Revenue, EV/EBITDA, P/E, with median and mean |

All tools are read-only. Nothing needs an API key.

### Example: `get_comps(["KO", "PEP", "KDP", "MNST"])`, run 2026-09-29

| Ticker | Period | Mkt cap ($B) | EV ($B) | EV/Rev | EV/EBITDA | P/E | Beta |
|---|---|---:|---:|---:|---:|---:|---:|
| KO | LTM to 2026-04-03 | 374 | 407 | 8.26 | 26.23 | 27.27 | 0.34 |
| PEP | LTM to 2026-06-13 | 176 | 226 | 2.33 | 12.57 | 16.81 | 0.35 |
| KDP | LTM to 2026-06-30 | 42 | 71 | 3.52 | 18.51 | 29.59 | 0.40 |
| MNST | LTM to 2026-06-30 | 41 | — | — | — | 19.22 | 0.52 |

The notes that came back with those rows are the point of the design:

- **KO**: EDGAR lists a 10-Q filed 2026-07-29 that the XBRL API does not
  include yet, so the figures stop at Q1. The tool says so instead of passing
  stale LTM off as current.
- **KDP**: non-operating items of −1.3B exceed 25% of operating income, so the
  P/E is distorted and EV/EBITDA should carry more weight.
- **MNST**: no debt concepts are reported, so EV is left null rather than
  assuming zero debt. A separately labeled `enterprise_value_if_debt_free`
  (37B) is offered, to use once the balance sheet confirms it.

## Install

Requires [uv](https://docs.astral.sh/uv/). SEC requires automated clients to
send a User-Agent with a contact, so you provide your name and email once.

**As a Claude Code plugin** (adds the server plus a skill on citing the data):

```bash
claude plugin marketplace add nathanaelhub/open-finance-mcp
claude plugin install open-finance@open-finance
# prompts for, or set with `claude plugin configure open-finance`: your SEC contact
```

It works alongside `financial-analysis@claude-for-financial-services`: the
`/comps` and `/dcf` skills find an MCP data source and use it.

**As a plain MCP server** (Claude Code, Claude Desktop or any MCP client):

```bash
claude mcp add open-finance \
  -e SEC_USER_AGENT="Your Name you@example.com" \
  -- uvx --from git+https://github.com/nathanaelhub/open-finance-mcp open-finance-mcp
```

Responses are cached on disk (`~/.cache/open-finance-mcp`, or
`$OPEN_FINANCE_MCP_CACHE`): company facts for a day, prices for 15 minutes.
SEC requests are spaced to stay under the 10 requests/second fair-access limit.

## How the numbers are built

XBRL data is messier than it looks. Each rule below exists because a real
filer broke the simple version:

- **Concepts resolve per period, not per company.** Tags change over time:
  Caterpillar's `NetIncomeLoss` stops in 2010 and continues as
  `NetIncomeLossAvailableToCommonStockholdersBasic`. Each metric has a priority
  list, the first concept with a value *for that period* wins, and the
  concept used is returned with the value.
- **Restatements win; labels come from the original 10-K.** A 10-K repeats
  prior years as comparatives and may restate them. Values come from the most
  recent filing, and each value cites it. The fiscal-year label comes from the
  period's original 10-K, because a year-end date misleads for retailers (Home
  Depot's fiscal 2025 ends 1 Feb 2026).
- **LTM = FY + YTD − prior-year YTD, from one concept.** JPMorgan tags annual
  revenue as `Revenues` and quarterly as `RevenuesNetOfInterestExpense`, so an
  LTM mixing concepts could combine different definitions. If no single
  concept covers all three periods, LTM is null. Labels give the exact end
  date, not "6M", because 52/53-week filers have 12- and 16-week quarters.
- **Total debt never double counts.** `DebtCurrent` already includes commercial
  paper and the current portion of long-term debt; `LongTermDebt` already
  includes its current portion. The formula used is returned (e.g.
  `ltd_noncurrent + ltd_current + commercial_paper`), and matches Apple's
  FY2024 10-K to the dollar ($106.629B). Operating leases are excluded.
- **Missing is null, never zero.** Caterpillar's 10-Qs tag debt only by
  segment, which the XBRL API omits, so LTM debt is null with a reason.
- **Share counts handle multiple classes.** The cover-page count is summed
  across classes. Alphabet reports its cover page only per class, which the API
  drops, so the server falls back to the balance-sheet total and says the
  price is for one class.
- **Beta uses completed months.** Yahoo's monthly series ends with the
  in-progress month; that partial "return" is dropped. Beta is OLS on the last
  60 completed monthly returns against `^GSPC` (a price index, no dividends).
- **Errors the model can act on.** The MCP SDK hides unexpected exceptions
  behind "Error executing tool", so every anticipated failure is a readable
  tool error: an unknown ticker points to `lookup_company`, and a new registrant
  with no history (ExxonMobil's new holding company, CIK 2115436) is explained
  rather than returned as empty tables.

## Limitations

- US-GAAP SEC filers only. IFRS filers (20-F/40-F) are not supported.
- The XBRL company-facts API excludes dimensional (segment/class) facts and
  can lag EDGAR by weeks. Both cases are flagged rather than hidden.
- Prices come from Yahoo Finance's unofficial chart endpoint. They are labeled
  as unofficial so a model citing them says so; verify before publishing.
- EBITDA is operating income + D&A as reported, not adjusted EBITDA.

## Development

```bash
uv sync
uv run pytest            # 39 tests, offline: real filings trimmed into tests/fixtures
SEC_USER_AGENT="Name you@example.com" uv run python scripts/make_fixtures.py   # refresh fixtures
```

Tests run the tools through an in-process MCP client with HTTP mocked, and
once over stdio as a subprocess, which is how Claude Code launches the server.
CI covers Python 3.11–3.14.

Data: [SEC EDGAR APIs](https://www.sec.gov/search-filings/edgar-application-programming-interfaces),
[FRED](https://fred.stlouisfed.org/). Not investment advice; outputs are
drafts for review by a qualified person.

MIT licensed.

TDQS

A3.7/5.0

Scored across 6 tools

Disambiguation5/5

Each tool serves a clearly distinct purpose: company lookup, market data, financial statements, SEC filings, Treasury yields, and trading comparables. Although get_market_data and get_comps both surface market cap, their scopes are well differentiated by the descriptions. No two tools appear to do the same thing.

Naming Consistency4/5

Most tools use a consistent get_<object> snake_case pattern, such as get_market_data, get_financials, and get_filings. lookup_company is the only deviation, using lookup_ instead of get_, but it still follows a readable verb_noun convention.

Tool Count5/5

Six tools is well-scoped for a focused open-finance data server. Each tool covers a distinct part of the financial-analysis workflow without redundancy. The count is neither bloated nor too thin.

Completeness4/5

The surface covers lookup, market data, financials, filings, risk-free rate, and comparables, which supports core fundamental workflows. Minor gaps remain, such as historical price series and quarterly financial statements, but agents can work around them with the available annual/LTM and current market data.

Maintenance

ActivityMaintained
ResponsivenessNo issues