# pequod-mcp — "the Gam" **SEC-primary-source ETF holdings + identifier crosswalk for agents.** An MCP (Model Context Protocol) server that gives AI agents the *complete* holdings of any US-registered ETF straight from SEC EDGAR N-PORT filings — not a top-10 scrape — plus a set of identifier-crosswalk tools (ticker, CUSIP/SEDOL, FIGI → resolved symbol) backed by OpenFIGI and SEC reference data. Runs locally over stdio; no vendor market-data subscriptions required. ## Tools | Tool | What it does | Sources | |---|---|---| | `lookup_cik` | Ticker → SEC CIK + entity metadata (name, SIC, exchanges, fiscal year end) | SEC `company_tickers.json` + submissions API | | `resolve_ticker` | Raw ticker + optional exchange code → Yahoo-convention symbol, verified | Exchange-suffix map (pure string mapping) + SEC + OpenFIGI | | `resolve_cusip` | CUSIP (or SEDOL) → symbol, with cross-source verification | OpenFIGI (one batched request) + SEC name/ticker agreement | | `resolve_figi` | Bloomberg FIGI → symbol, with cross-source verification | OpenFIGI + SEC name/ticker agreement | | `get_etf_holdings` | Any US ETF → **complete** holdings list from its latest monthly N-PORT filing (name, ticker, ISIN, FIGI, LEI, shares, USD value, % of net assets, country, currency) | SEC EDGAR N-PORT XML | All tools are read-only. ### How verification works Crosswalk results are verified without any market-data vendor: 1. **SEC registry check** — if the mapped ticker is a US SEC registrant, the entity title in `company_tickers.json` must agree with the OpenFIGI security name. A gross name mismatch **vetoes** the mapping (`verification: "name_veto"`) rather than returning a plausible-looking wrong symbol. 2. **OpenFIGI mapping** — non-US symbols (outside SEC's registry) verify on the OpenFIGI mapping itself, labeled `verification: "openfigi"` so you can tell the confidence tiers apart. Yahoo Finance *symbology* (`.SW`, `.T`, `.L`, … suffixes) is applied as a pure string convention — the default path makes **no network calls to Yahoo**. ## Install ```bash # with uv uv pip install pequod-mcp # or with pip pip install pequod-mcp ``` Run it directly (stdio): ```bash pequod-mcp ``` ### Optional: OpenFIGI API key The server works without a key (OpenFIGI anonymous rate limits apply). For heavier use, get a free key at and set: ```bash export API_OpenFIGI="your-key-here" ``` ### Optional: Yahoo enrichment extra An opt-in extra adds a live Yahoo quote block to crosswalk results. It is **off by default** and never used otherwise; enabling it means you accept the Yahoo Finance terms of use yourself. ```bash pip install 'pequod-mcp[yahoo]' export PEQUOD_YAHOO_VERIFY=1 ``` ## Configure in Claude **Claude Desktop** (`claude_desktop_config.json`) or any MCP client with a stdio transport: ```json { "mcpServers": { "pequod": { "command": "pequod-mcp", "env": { "API_OpenFIGI": "your-key-here" } } } } ``` **Claude Code:** ```bash claude mcp add pequod -e API_OpenFIGI=your-key-here -- pequod-mcp ``` ## Agent workflow examples **1. "What does SCHD actually hold?"** ```text Agent: lookup_cik("SCHD") → { cik: "0000884394", entity_name: "SCHWAB STRATEGIC TRUST", found: true } Agent: get_etf_holdings("SCHD", cik="0000884394") → { fund_name, report_date, source_url (the actual EDGAR filing), total_holdings: ~100, holdings: [ { name, ticker, isin, figi, balance, value_usd, pct_val, ... } ] } ``` The agent gets every position with weights, plus the EDGAR URL for citation — auditable back to the primary source. **2. "I have a CUSIP from a 13F — what stock is this?"** ```text Agent: resolve_cusip("594918104") → { yahoo_symbol: "MSFT", verified: true, verification: "openfigi+sec", company_name: "MICROSOFT CORP", cik: "0000789019", openfigi: { figi: "BBG000BPH459", ... } } ``` If OpenFIGI's mapping disagrees with SEC's registry on who the ticker belongs to, the tool refuses (`verification: "name_veto"`) instead of handing back a wrong symbol. **3. "Compare two dividend ETFs' overlap."** ```text Agent: get_etf_holdings("SCHD") → complete holdings A Agent: get_etf_holdings("VYM") → complete holdings B Agent: joins on isin (or ticker), computes overlap weight, reports the shared names — all from two tool calls, both citing SEC filings. ``` ## Data provenance - **All holdings data comes from SEC EDGAR primary sources** (Form N-PORT filings, the submissions API, and `company_tickers.json`). Identifier crosswalks come from the **OpenFIGI API** (FIGI is an open OMG standard). - **No CUSIPs in output.** Tool outputs carry ticker, ISIN, FIGI, and LEI; CUSIP fields present in the underlying filings are deliberately stripped. - **SEC fair access respected:** a declared User-Agent on every request, a throttle well under EDGAR's published rate limit, and an on-disk cache (`.cache/` next to the module, override with `PEQUOD_CACHE_DIR`) for `company_tickers.json` (24 h) and N-PORT documents (30 days — filed documents are immutable). - **Fail-loud policy:** if EDGAR is unreachable or a filing cannot be parsed, tools return an error. There is no degraded or partial fallback source — you either get filing-backed data or a clear failure. - N-PORT filings are published on a lag (holdings are typically ~1–2 months behind). The `report_date` and `source_url` fields tell you exactly which period you are looking at. - **Not investment advice.** This server relays public regulatory filings and open identifier mappings; verify independently before making investment decisions. ## Environment variables | Variable | Default | Purpose | |---|---|---| | `API_OpenFIGI` | *(unset)* | OpenFIGI API key (higher rate limits) | | `PEQUOD_CACHE_DIR` | `.cache/` next to the module | On-disk cache location | | `PEQUOD_YAHOO_VERIFY` | *(off)* | Opt-in Yahoo enrichment (needs the `[yahoo]` extra) | | `LOG_LEVEL` | `INFO` | Server log verbosity | ## Development ```bash pip install -e '.[dev]' pytest # fully offline — fixture filings, no live network ``` ## License Apache-2.0 — see [LICENSE](LICENSE). Copyright 2026 AB Evergreen Analytics LLC.