pequod-mcp
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@pequod-mcpWhat are the complete holdings of SCHD?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
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 |
| Ticker → SEC CIK + entity metadata (name, SIC, exchanges, fiscal year end) | SEC |
| Raw ticker + optional exchange code → Yahoo-convention symbol, verified | Exchange-suffix map (pure string mapping) + SEC + OpenFIGI |
| CUSIP (or SEDOL) → symbol, with cross-source verification | OpenFIGI (one batched request) + SEC name/ticker agreement |
| Bloomberg FIGI → symbol, with cross-source verification | OpenFIGI + SEC name/ticker agreement |
| 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:
SEC registry check — if the mapped ticker is a US SEC registrant, the entity title in
company_tickers.jsonmust agree with the OpenFIGI security name. A gross name mismatch vetoes the mapping (verification: "name_veto") rather than returning a plausible-looking wrong symbol.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.
Related MCP server: edgar-mcp
Install
# with uv
uv pip install pequod-mcp
# or with pip
pip install pequod-mcpRun it directly (stdio):
pequod-mcpOptional: OpenFIGI API key
The server works without a key (OpenFIGI anonymous rate limits apply). For heavier use, get a free key at https://www.openfigi.com/api and set:
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.
pip install 'pequod-mcp[yahoo]'
export PEQUOD_YAHOO_VERIFY=1Configure in Claude
Claude Desktop (claude_desktop_config.json) or any MCP client with a
stdio transport:
{
"mcpServers": {
"pequod": {
"command": "pequod-mcp",
"env": {
"API_OpenFIGI": "your-key-here"
}
}
}
}Claude Code:
claude mcp add pequod -e API_OpenFIGI=your-key-here -- pequod-mcpAgent workflow examples
1. "What does SCHD actually hold?"
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?"
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."
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 withPEQUOD_CACHE_DIR) forcompany_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_dateandsource_urlfields 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 |
| (unset) | OpenFIGI API key (higher rate limits) |
|
| On-disk cache location |
| (off) | Opt-in Yahoo enrichment (needs the |
|
| Server log verbosity |
Development
pip install -e '.[dev]'
pytest # fully offline — fixture filings, no live networkLicense
Apache-2.0 — see LICENSE. Copyright 2026 AB Evergreen Analytics LLC.
Available Tools
5 toolsget_etf_holdingsA
Get the complete holdings of any US-registered ETF via SEC EDGAR.
Uses Form N-PORT filings (filed monthly by all US ETFs) as the single, consistent primary source. Each holding includes name, ticker, ISIN, FIGI, LEI, shares, USD value, percent of net assets, country, and currency. (CUSIPs are deliberately not included in output.)
| Name | Required | Description | Default |
|---|---|---|---|
| cik | No | Optional 10-digit SEC CIK (from lookup_cik). Skips the ticker→CIK lookup if provided. | |
| ticker | Yes | The ETF ticker symbol (e.g. 'QQQ', 'SPY', 'SCHD', 'IHDG'). |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description takes on full disclosure responsibility. It specifies the data source (monthly N-PORT filings), the exact fields returned, and deliberately notes that CUSIPs are excluded. This adds meaningful behavioral context beyond the schema, though it does not mention potential limitations like filing delays.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two concise paragraphs, front-loaded with the core action in the first sentence, followed by essential context and output details. Every sentence provides value; there is no redundancy or filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Despite moderate complexity, the description covers the tool's purpose, data source, returned fields, and an explicit exclusion (no CUSIPs). With an output schema present, detailed return structure is unnecessary, making this description complete for an AI agent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, with both parameters well-documented: ticker has examples and cik explains its optional role and the lookup-cik shortcut. The description itself adds no further parameter-level semantics, so the baseline score of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with 'Get the complete holdings of any US-registered ETF via SEC EDGAR,' clearly stating the tool's specific action, resource, and scope. It distinguishes itself from sibling tools (lookup_cik, resolve_ticker, etc.) which are identifier-resolution utilities rather than data-retrieval tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides clear context about when the tool applies (any US-registered ETF, using Form N-PORT filings) but does not explicitly state when-not-to-use or compare with alternatives. It references lookup_cik only in the schema, not the description, so the guidance is contextually clear but lacks explicit exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
lookup_cikA
Look up a ticker's SEC Central Index Key (CIK) and entity metadata.
This is the first step before calling get_etf_holdings. The CIK is the SEC's unique identifier for every filing entity. The submissions endpoint also returns the entity name, SIC code, tickers, exchanges, fiscal year end, and addresses.
The ticker→CIK mapping comes from SEC's company_tickers.json (covers 10,000+ US tickers), cached on disk with a 24-hour freshness window.
| Name | Required | Description | Default |
|---|---|---|---|
| ticker | Yes | Stock or ETF ticker symbol (e.g. 'SCHD', 'QQQ', 'AAPL'). |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden of behavioral disclosure. It discloses the data source (SEC's company_tickers.json), coverage (10,000+ US tickers), cache freshness (24-hour window), and the metadata returned (entity name, SIC code, tickers, exchanges, fiscal year end, addresses). This is strong context, though it doesn't explicitly state the operation is read-only.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is six sentences, front-loaded with the core purpose. Each sentence adds value—explaining the CIK, the workflow, metadata, data source, and caching—though it could be slightly tightened without losing meaning.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Despite having no annotations and only one parameter, the description covers the tool's purpose, role in the pipeline, data source, freshness, and returned metadata. With an output schema present, it doesn't need to describe return values. Minor gaps like error handling or invalid ticker behavior are acceptable for this simple lookup tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% with a clear description for the 'ticker' parameter ('Stock or ETF ticker symbol'). The description adds context about US ticker coverage but does not meaningfully enrich the parameter beyond what the schema already provides, so the baseline score of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's function with a specific verb and resource: 'Look up a ticker's SEC Central Index Key (CIK) and entity metadata.' It distinguishes itself from sibling resolvers by focusing on SEC CIK and explicitly positions itself as a prerequisite step for get_etf_holdings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly says 'This is the first step before calling get_etf_holdings,' providing clear when-to-use context. However, it does not mention when not to use the tool or compare it directly with sibling tools like resolve_ticker, resolve_cusip, or resolve_figi.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
resolve_cusipA
Resolve a CUSIP (or SEDOL) identifier to a Yahoo-convention ticker symbol.
Queries OpenFIGI (one batched request trying both ID_CUSIP and ID_SEDOL), maps the result to a Yahoo-convention symbol via pure suffix mapping, and verifies the mapping against SEC company_tickers.json name/ticker agreement. A gross name mismatch between OpenFIGI and SEC vetoes the mapping.
Note: the CUSIP is accepted as INPUT only — tool outputs carry ticker/ISIN/FIGI identifiers, never CUSIPs.
| Name | Required | Description | Default |
|---|---|---|---|
| cusip | Yes | A 9-character CUSIP (or 7-character SEDOL) identifier. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries full burden. It transparently discloses the OpenFIGI batched query, suffix mapping, SEC verification, and veto on gross name mismatch. The note that CUSIP is input-only and outputs carry different identifiers is valuable. It stops short of 5 by not describing failure modes or error behavior, but it is unusually rich.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is three sentences, front-loaded with the core purpose, followed by concise process details and a critical input/output note. Every sentence earns its place with no fluff or repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the multi-step resolution process (OpenFIGI query, mapping, verification), the description covers the key behaviors and constraints. An output schema exists, so return-value details are not needed. Minor gaps like failure handling or rate limits keep it from a 5, but it is highly complete for a complex tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema covers 100% of parameter documentation with a clear description ('9-character CUSIP (or 7-character SEDOL) identifier'). The tool description adds no additional parameter-level meaning beyond what the schema provides, so the baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a clear, specific verb+resource+outcome: 'Resolve a CUSIP (or SEDOL) identifier to a Yahoo-convention ticker symbol.' This precisely states what the tool does and naturally distinguishes it from siblings like resolve_figi or lookup_cik by input type and output.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is strongly implied through the purpose statement and process details (e.g., handling both CUSIP and SEDOL, mapping to Yahoo ticker). However, it does not explicitly name alternatives or state when not to use it, so it falls short of a 5. The sibling tool names provide additional context but are not referenced.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
resolve_figiA
Resolve a Bloomberg FIGI (Financial Instrument Global Identifier) to a Yahoo-convention ticker symbol.
Queries OpenFIGI, maps the exchange code to a Yahoo suffix (pure string mapping), and verifies the mapping against SEC company_tickers.json name/ticker agreement.
| Name | Required | Description | Default |
|---|---|---|---|
| figi | Yes | A Bloomberg FIGI identifier (e.g. 'BBG000BVRVT1'). |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden. It discloses that the tool queries OpenFIGI, performs a pure string mapping, and verifies against SEC data, providing useful process context. It does not detail error handling or failure modes, but these are less critical for a lookup tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences long, front-loaded with the primary purpose, and each sentence adds meaningful process detail without redundancy. It is concise and well-structured.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description adequately covers the main process steps and external dependencies. Since an output schema exists, return values are likely documented there. Minor gaps include not mentioning what happens if the FIGI is not found or the mapping fails, but overall it is complete enough for most use cases.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema already provides a complete description of the 'figi' parameter, including an example. The description adds no additional semantic meaning or constraints beyond what the schema already states, so the baseline of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the verb 'Resolve' and the resource 'Bloomberg FIGI' to a 'Yahoo-convention ticker symbol'. It distinguishes itself from sibling tools like resolve_cusip and resolve_ticker by specifying the exact input and output format.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The usage context is implied by the description: if you have a FIGI and need a Yahoo ticker, you would use this tool. However, there is no explicit guidance on when to use this over alternatives or any when-not-to-use conditions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
resolve_tickerA
Resolve a raw ticker symbol to its Yahoo-convention equivalent.
Applies exchange suffix mapping and known manual fixes as a pure string transformation (no Yahoo network calls), then verifies the mapping against SEC company_tickers.json and/or OpenFIGI.
| Name | Required | Description | Default |
|---|---|---|---|
| symbol | Yes | Raw ticker symbol (e.g. 'AAPL', 'SCMN', 'BHP'). | |
| exchange_code | No | Optional exchange code — MIC format like 'XASX' or short format like 'AU', 'LN', 'SW', 'JP'. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are present, so the description carries the burden. It discloses important behaviors: the transformation is a 'pure string transformation (no Yahoo network calls)' and that it 'verifies against SEC company_tickers.json and/or OpenFIGI'. This adds meaningful context beyond the schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, zero waste, with the core purpose front-loaded. The second sentence provides valuable technical context without unnecessary elaboration.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-parameter tool with an output schema and no annotations, the description covers the core process, clarifies network usage, and mentions external verification sources. It lacks some edge-case behavior details but is reasonably complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema documents both parameters adequately. The description hints at 'exchange suffix mapping' but does not add significant detail beyond what the schema already provides, matching the baseline for full schema coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Resolve') and resource ('raw ticker symbol to its Yahoo-convention equivalent'), clearly identifying the tool's unique function. This distinguishes it from sibling tools that resolve other identifiers (CIK, CUSIP, FIGI).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The context is clear: use when a raw ticker needs conversion to Yahoo format. However, it does not explicitly contrast with sibling tools or provide exclusions, so it stops short of a full 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
5 tool updates
v0.2.2- First observed
get_etf_holdings - First observed
lookup_cik - First observed
resolve_cusip - First observed
resolve_figi - First observed
resolve_ticker
TDQS
Scored across 5 tools
Each tool targets a distinct input identifier or action: lookup_cik maps tickers to CIK, resolve_ticker/cusip/figi convert different identifier types to Yahoo tickers, and get_etf_holdings retrieves ETF data. Despite three resolve tools, their input types (ticker, CUSIP/SEDOL, FIGI) are clearly differentiated.
All tools follow a verb_noun pattern: lookup_cik, resolve_ticker, resolve_cusip, resolve_figi, get_etf_holdings. The verbs are simple and consistent, with 'resolve_' forming a clear subgroup for identifier conversion.
Five tools is well within the ideal 3-15 range for a focused server. Each tool has a distinct role, and the count neither feels thin nor bloated.
The core workflow (lookup CIK, then get ETF holdings) is covered, and the most common identifier types (ticker, CUSIP/SEDOL, FIGI) have resolvers. Minor gaps exist, such as missing ISIN or LEI resolvers, but these are edge cases rather than critical missing operations.
Maintenance
Related MCP Connectors
Real SEC, 13F, insider, congress & macro data your AI agent can cite. Hosted MCP, 24 tools.
The financial MCP for AI agents - 90+ financial tables, SEC filings, signals, alt-data.
MCP server connecting AI agents to non-custodial staking data across 130+ networks.
EDGAR MCP — SEC EDGAR public APIs (free, no auth)
Related MCP Servers
- AlicenseAqualityFmaintenanceAn MCP server that delivers crypto ETF flow data to power AI agents' decision-making.19MIT
- AlicenseAqualityBmaintenanceMCP server providing read-only access to SEC EDGAR filings, allowing LLMs to look up companies, search filings, and retrieve securities offering data.31MIT
- AlicenseCqualityBmaintenanceMCP server for accessing SEC EDGAR filings. Connects AI assistants to company filings, financial statements, and insider trading data with exact numeric precision.21355AGPL 3.0
- AlicenseNot gradedqualityDmaintenanceHosted MCP server that gives AI agents real-time access to SEC EDGAR filings search, 10-K/8-K reading, XBRL financial facts, and insider-trade (Form 4) alerts.151MIT