secedgar-mcp-server

v0.11.0 pre-1.0

Query SEC EDGAR filings, XBRL financials, and company data through MCP. STDIO & Streamable HTTP.

secedgar.caseyjhand.com/mcp
claude mcp add --transport http secedgar-mcp-server https://secedgar.caseyjhand.com/mcp
codex mcp add secedgar-mcp-server --url https://secedgar.caseyjhand.com/mcp
{
  "mcpServers": {
    "secedgar-mcp-server": {
      "url": "https://secedgar.caseyjhand.com/mcp"
    }
  }
}
gemini mcp add --transport http secedgar-mcp-server https://secedgar.caseyjhand.com/mcp
{
  "mcpServers": {
    "secedgar-mcp-server": {
      "command": "bunx",
      "args": [
        "mcp-remote",
        "https://secedgar.caseyjhand.com/mcp"
      ]
    }
  }
}
{
  "mcpServers": {
    "secedgar-mcp-server": {
      "type": "http",
      "url": "https://secedgar.caseyjhand.com/mcp"
    }
  }
}
curl -X POST https://secedgar.caseyjhand.com/mcp \
  -H "Content-Type: application/json" \
  -H "MCP-Protocol-Version: 2025-11-25" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"curl","version":"1.0.0"}}}'

Tools

10

secedgar_search_filings

open-world

Search the full-text index of EDGAR filings since 1993. Supports exact phrases, boolean operators, wildcards, and entity targeting (ticker:AAPL or cik:320193 in query).

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "secedgar_search_filings",
    "arguments": {
      "query": "<query>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "query": {
      "type": "string",
      "minLength": 1,
      "description": "Full-text search query. Supports: exact phrases (\"material weakness\"), boolean operators (revenue OR income), exclusion (-preliminary), wildcard suffix (account*), entity targeting (ticker:AAPL or cik:320193 in the query). Terms are AND'd by default."
    },
    "forms": {
      "description": "Filter to specific form types (e.g., [\"10-K\", \"10-Q\", \"8-K\"]). Without this, searches all form types. Note: \"10-K\" also matches amendments filed as 10-K/A. Ownership forms (3, 4, 5) are indexed by the reporting person (e.g., \"LEVINSON ARTHUR D\"), not the issuer — rows carry no transaction code, share count, or price. Use secedgar_get_insider_transactions to retrieve parsed ownership XML with person, relationship, transaction code, shares, and price.",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "start_date": {
      "description": "Start of date range (YYYY-MM-DD). Both start_date and end_date must be provided for date filtering.",
      "anyOf": [
        {
          "type": "string",
          "const": ""
        },
        {
          "type": "string",
          "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
          "description": "YYYY-MM-DD"
        }
      ]
    },
    "end_date": {
      "description": "End of date range (YYYY-MM-DD). Both start_date and end_date must be provided for date filtering.",
      "anyOf": [
        {
          "type": "string",
          "const": ""
        },
        {
          "type": "string",
          "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
          "description": "YYYY-MM-DD"
        }
      ]
    },
    "limit": {
      "default": 20,
      "description": "Results per page. Max 100.",
      "type": "integer",
      "minimum": 1,
      "maximum": 100
    },
    "offset": {
      "default": 0,
      "description": "Pagination offset. For sort=relevance, EDGAR pages server-side up to its 10,000-result cap. For date sorts (the default) and entity targeting, the tool fetches a single 100-row window and slices it client-side — offsets at or past the window return nothing; switch to sort=relevance for deep pagination, or narrow the search (forms, dates, entity targeting).",
      "type": "integer",
      "minimum": 0,
      "maximum": 9999
    },
    "sort": {
      "default": "filing_date_desc",
      "description": "Result ordering. \"filing_date_desc\" (default) returns most recent first. \"filing_date_asc\" returns oldest first. \"relevance\" returns SEC's native search-score order, which weights term match strength over recency. Date sorts re-order the top 100 hits returned by the search index — for broad queries with more than 100 matches and no entity targeting, date-newest filings may sit outside that window. Entity targeting (ticker:/cik:) or a narrower query keeps matches inside the window when absolute recency matters.",
      "type": "string",
      "enum": [
        "filing_date_desc",
        "filing_date_asc",
        "relevance"
      ]
    }
  },
  "required": [
    "query",
    "limit",
    "offset",
    "sort"
  ],
  "additionalProperties": false
}
view source ↗

secedgar_get_filing

open-world

Fetch a specific filing's metadata and document content by accession number. Returns the primary document as readable text. Use offset/next_offset for multi-page access to large filings (10-K, S-1 can exceed 1M chars): pass the next_offset from a truncated response to read the next page. Use section to jump directly to a heading (e.g. 'risk factors', 'item 7') without needing an offset.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "secedgar_get_filing",
    "arguments": {
      "accession_number": "<accession_number>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "accession_number": {
      "type": "string",
      "description": "Filing accession number in either format: \"0000320193-23-000106\" (dashes) or \"000032019323000106\" (no dashes). Obtained from secedgar_company_search or secedgar_search_filings results."
    },
    "cik": {
      "description": "Company CIK (resolve via secedgar_company_search if you have a ticker or name). Optional but recommended — speeds up archive lookup. If omitted, likely filing CIKs are inferred from SEC search metadata and archive paths.",
      "type": "string"
    },
    "content_limit": {
      "default": 50000,
      "description": "Maximum characters of document text to return per page. 10-K filings can exceed 500,000 characters; S-1/A can exceed 1,000,000. Default 50,000 captures ~12,000 words (typically business overview, risk factors, and MD&A). Increase to 200,000 for full financial statements, or decrease for quick summaries. Use offset or section for subsequent pages.",
      "type": "integer",
      "minimum": 1000,
      "maximum": 200000
    },
    "document": {
      "description": "Specific document filename within the filing (e.g., \"ex-21.htm\" for subsidiaries list). Default: the primary document. Available documents listed in the response metadata.",
      "type": "string"
    },
    "include_xbrl": {
      "default": false,
      "description": "Include XBRL viewer artifacts and machine-readable taxonomy files (R*.htm fragments, *_cal/_def/_lab/_pre.xml linkbases, *_htm.xml inline instance, *.xsd schemas, MetaLinks.json, FilingSummary.xml, Show.js, report.css, *-xbrl.zip, Financial_Report.xlsx, EX-101.* technical exhibits) under documents.xbrl. Off by default — these dominate filing indexes (~100 entries on a typical 10-K) and are rarely relevant when reading filing content.",
      "type": "boolean"
    },
    "offset": {
      "default": 0,
      "description": "Character offset into the extracted document text. Pass next_offset from a truncated response to continue reading the next page. Default 0 reads from the beginning.",
      "type": "integer",
      "minimum": 0,
      "maximum": 9007199254740991
    },
    "section": {
      "description": "Jump to a named section by case-insensitive substring match against detected headings (e.g. 'risk factors', 'item 7', 'certain relationships'). Takes precedence over offset when both are provided. On a miss, the error data carries the detected outline so you can pick the correct heading.",
      "type": "string",
      "minLength": 1
    }
  },
  "required": [
    "accession_number",
    "content_limit",
    "include_xbrl",
    "offset"
  ],
  "additionalProperties": false
}
view source ↗

secedgar_get_financials

open-world

Get historical XBRL financial data for a company. Accepts friendly concept names (e.g., "revenue", "net_income", "assets") or raw XBRL tags. Discover available friendly names with secedgar_search_concepts. Handles historical tag changes and deduplicates data automatically.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "secedgar_get_financials",
    "arguments": {
      "company": "<company>",
      "concept": "<concept>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "company": {
      "type": "string",
      "minLength": 1,
      "description": "Ticker symbol (e.g., \"AAPL\") or CIK number. Ticker is preferred."
    },
    "concept": {
      "type": "string",
      "minLength": 1,
      "description": "Financial concept — friendly name (e.g., \"revenue\", \"net_income\", \"assets\", \"eps_diluted\") or raw XBRL tag (e.g., \"AccountsPayableCurrent\"). Friendly names auto-resolve to the correct XBRL tags and handle historical tag changes."
    },
    "taxonomy": {
      "default": "us-gaap",
      "description": "XBRL taxonomy. us-gaap for US companies, ifrs-full for foreign filers, dei for entity info (shares outstanding).",
      "type": "string",
      "enum": [
        "us-gaap",
        "ifrs-full",
        "dei"
      ]
    },
    "period_type": {
      "description": "Filter to annual (FY) or quarterly (Q1-Q4) data. \"all\" returns both. When omitted, defaults to \"annual\"; instant (balance-sheet) concepts automatically fall back to returning the full series on the first call when the annual filter yields nothing (#48).",
      "type": "string",
      "enum": [
        "annual",
        "quarterly",
        "all"
      ]
    },
    "limit": {
      "description": "Cap the inline data[] to the most-recent N periods (the series is newest-first). The full series is always registered to the dataframe, so older periods stay queryable via secedgar_dataframe_query. Omit to return every period inline.",
      "type": "integer",
      "minimum": 1,
      "maximum": 100
    }
  },
  "required": [
    "company",
    "concept",
    "taxonomy"
  ],
  "additionalProperties": false
}
view source ↗

secedgar_get_insider_transactions

open-world

Fetch Form 4 insider transactions (purchases, sales, grants, exercises) for a company by parsing SEC EDGAR ownership XML. Returns the reporting person, their relationship to the issuer, transaction date, type, shares traded (absolute magnitude), direction (acquire/dispose), price per share, and shares owned after the transaction. Covers nonDerivative transactions (open-market buys/sells, gifts) and derivative transactions (option exercises, RSU vests). When a canvas is available, the full set of transactions parsed from the scanned recent filings is materialized as df_<id> (the inline list is a preview capped at limit) — query it with secedgar_dataframe_query to aggregate net buy/sell by insider: SUM(CASE WHEN direction='dispose' THEN -shares_traded ELSE shares_traded END). Use secedgar_search_filings with forms=["4"] for broader date-range queries or to search across all companies.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "secedgar_get_insider_transactions",
    "arguments": {
      "ticker_or_cik": "<ticker_or_cik>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "ticker_or_cik": {
      "type": "string",
      "minLength": 1,
      "description": "Company ticker symbol (e.g., \"AAPL\") or 10-digit CIK number (e.g., \"0000320193\"). The issuer, not the reporting person."
    },
    "transaction_type": {
      "default": "all",
      "description": "Filter by direction. \"purchase\" = open-market buys (code P). \"sale\" = open-market sells (code S). \"all\" includes grants, awards, exercises, gifts, and other coded transaction types as well.",
      "type": "string",
      "enum": [
        "purchase",
        "sale",
        "all"
      ]
    },
    "limit": {
      "default": 20,
      "description": "Maximum number of transactions to return across all Form 4 filings fetched. Filings are scanned newest-first. Default 20.",
      "type": "integer",
      "minimum": 1,
      "maximum": 100
    }
  },
  "required": [
    "ticker_or_cik",
    "transaction_type",
    "limit"
  ],
  "additionalProperties": false
}
view source ↗

secedgar_get_institutional_holdings

open-world

Fetch 13F-HR quarterly institutional holdings by parsing the SEC EDGAR information table XML. Use ticker_or_cik to look up an institution (e.g., "Vanguard Group" or its CIK) and see what it holds — or pass a company ticker/CIK to find which institutions filed 13Fs covering that period. The 13F information table lists each position: issuer name, CUSIP, shares held, market value (in whole USD), and put/call designation for options. Sub-lines for the same security are consolidated into distinct positions sorted by value by default (set consolidate=false for raw filing rows). The full parsed holdings set is materialized as df_<id> when a canvas is available — the inline holdings list is a preview capped at limit — so query it with secedgar_dataframe_query to aggregate the whole filing or self-join across quarters on cusip + reporting_period. Institutions with less than $100M in 13(f) securities are exempt and may not file. Use secedgar_search_filings with forms=["13F-HR"] for broader search.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "secedgar_get_institutional_holdings",
    "arguments": {
      "ticker_or_cik": "<ticker_or_cik>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "ticker_or_cik": {
      "type": "string",
      "minLength": 1,
      "description": "Ticker symbol or CIK of the institutional filer (e.g., \"0000102909\" for Vanguard) or a company name. For institution lookups, CIK or the full legal name resolves most reliably — tickers are typically for operating companies, not fund managers."
    },
    "quarter": {
      "description": "Reporting quarter to target, in \"YYYY-QN\" format (e.g., \"2025-Q4\"). When omitted, returns the most recent 13F-HR available. Quarters map to the filing window: Q4 2025 = filings submitted roughly Jan–Mar 2026.",
      "type": "string"
    },
    "limit": {
      "default": 20,
      "description": "Maximum number of holdings rows to return. 13F filings from large institutions can contain thousands of positions. Default 20.",
      "type": "integer",
      "minimum": 1,
      "maximum": 500
    },
    "consolidate": {
      "default": true,
      "description": "When true (default), info-table sub-lines for the same security (CUSIP + class + put/call) are summed into one position and results are sorted by market value descending, so `limit` returns the largest distinct holdings. Set false to return raw information-table rows in filing order (one per investment-discretion/manager sub-line), preserving investment_discretion.",
      "type": "boolean"
    }
  },
  "required": [
    "ticker_or_cik",
    "limit",
    "consolidate"
  ],
  "additionalProperties": false
}
view source ↗

secedgar_fetch_frames

open-world

Fetch SEC XBRL frames for one concept × one period across all reporting companies. Inline response returns the top N ranked companies; the full frames response (all reporters) is materialized as df_<id> when a canvas is available, queryable via secedgar_dataframe_query. Accepts friendly names like "revenue" or "assets" (discover via secedgar_search_concepts) or raw XBRL tags. One call hits one XBRL tag — when a friendly name maps to multiple same-meaning tags, the response's `unqueried_tags` lists the others; call again per tag and UNION/COALESCE in SQL with an analysis-specific priority (e.g. SalesRevenueGoodsNet is goods-only). The response's `related_tags` separately flags alternate-DEFINITION tags a meaningful share of filers use as their primary line (e.g. cash incl. restricted cash, equity incl. noncontrolling interest) — a whole-universe screen on the base tag silently omits those filers; query them separately, but do not blindly union (the semantics differ). Response includes `value_distribution` and `period_end_range` to flag XBRL scale-factor anomalies and fiscal-year mixing.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "secedgar_fetch_frames",
    "arguments": {
      "concept": "<concept>",
      "period": "<period>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "concept": {
      "type": "string",
      "minLength": 1,
      "description": "Financial concept — same friendly names as secedgar_get_financials (e.g., \"revenue\", \"assets\", \"eps_basic\") or raw XBRL tag."
    },
    "period": {
      "type": "string",
      "minLength": 1,
      "pattern": "^CY\\d{4}(Q[1-4]I?)?$",
      "description": "Calendar period. Use duration periods (no I suffix) for income/cash-flow items: \"CY2023\" (full year), \"CY2024Q2\" (single quarter). Use instant periods (I suffix) for balance-sheet items: \"CY2023Q4I\" (snapshot at Q4 close)."
    },
    "unit": {
      "default": "USD",
      "description": "Unit of measure. Use \"USD-per-shares\" (or equivalently \"USD/shares\") for EPS, \"shares\" for share counts, \"pure\" for ratios. Ignored when concept resolves to a friendly name with a known unit.",
      "type": "string",
      "enum": [
        "USD",
        "USD-per-shares",
        "USD/shares",
        "shares",
        "pure"
      ]
    },
    "limit": {
      "default": 25,
      "description": "Number of companies to return.",
      "type": "integer",
      "minimum": 1,
      "maximum": 100
    },
    "sort": {
      "default": "desc",
      "description": "Sort direction. \"desc\" for highest values first (typical for revenue, assets). \"asc\" for lowest values.",
      "type": "string",
      "enum": [
        "desc",
        "asc"
      ]
    }
  },
  "required": [
    "concept",
    "period",
    "unit",
    "limit",
    "sort"
  ],
  "additionalProperties": false
}
view source ↗

secedgar_search_concepts

Search supported XBRL financial concepts by keyword, statement group, or taxonomy. Use before secedgar_get_financials or secedgar_fetch_frames to discover the right friendly name, or pass a raw XBRL tag (e.g., "NetIncomeLoss") to reverse-lookup which friendly names map to it. Empty search with no filters returns the full catalog.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "secedgar_search_concepts",
    "arguments": {}
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "search": {
      "description": "Case-insensitive substring matched against friendly name, label, and XBRL tags. Examples: \"cash\" finds cash and operating_cash_flow; \"earnings\" finds eps_basic and eps_diluted; \"NetIncomeLoss\" reverse-maps to net_income. Omit to list all concepts.",
      "type": "string"
    },
    "group": {
      "description": "Filter to a single financial statement group. income_statement covers P&L items; balance_sheet covers position items (use instant periods in secedgar_fetch_frames); cash_flow covers CF statement items; per_share covers EPS; entity_info covers DEI items like shares outstanding.",
      "type": "string",
      "enum": [
        "income_statement",
        "balance_sheet",
        "cash_flow",
        "per_share",
        "entity_info"
      ]
    },
    "taxonomy": {
      "description": "Filter to a single XBRL taxonomy. us-gaap for US filers, ifrs-full for foreign filers, dei for entity info.",
      "type": "string",
      "enum": [
        "us-gaap",
        "ifrs-full",
        "dei"
      ]
    }
  },
  "additionalProperties": false
}
view source ↗

secedgar_dataframe_describe

List dataframes (df_XXXXX_XXXXX) materialized by secedgar_fetch_frames, secedgar_search_filings, secedgar_get_financials, secedgar_get_insider_transactions, and secedgar_get_institutional_holdings. Each entry surfaces source tool, query parameters, creation/expiry timestamps, row count, column schema, and whether the dataframe is truncated relative to the upstream source.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "secedgar_dataframe_describe",
    "arguments": {}
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "name": {
      "description": "Optional table name (df_XXXXX_XXXXX) to describe a single dataframe. Omit to list all dataframes.",
      "type": "string"
    }
  },
  "additionalProperties": false
}
view source ↗

secedgar_dataframe_query

Run a single-statement SELECT against the canvas dataframes registered by secedgar_fetch_frames, secedgar_search_filings, and secedgar_get_financials. Read-only: writes, DDL, DROP, COPY, PRAGMA, ATTACH, and external-file table functions are rejected. System catalogs (information_schema, pg_catalog, sqlite_master, duckdb_*) are denied — list dataframes via secedgar_dataframe_describe. Optional register_as chains the result as a new dataframe with a fresh TTL.

read
invocation
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "secedgar_dataframe_query",
    "arguments": {
      "sql": "<sql>"
    }
  }
}
schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "sql": {
      "type": "string",
      "minLength": 1,
      "description": "Single-statement SELECT against df_<id> tables on the shared canvas. Standard DuckDB SQL — joins, aggregates, window functions, CTEs all supported. Reference dataframes by the names returned in fetch/search responses or listed by secedgar_dataframe_describe. BIGINT columns (e.g., XBRL `value`, COUNT/SUM results) serialize as JSON strings to preserve precision past 2^53 — CAST(col AS DOUBLE) in projections for inline arithmetic."
    },
    "register_as": {
      "description": "When set, persist the result as a new dataframe under this name (must match df_XXXXX_XXXXX shape, or pass a fresh df_<id> generated by the agent). Fresh TTL window — not inherited from the parents in the SELECT. Use to chain analyses without re-running the source SQL.",
      "type": "string",
      "pattern": "^df_[A-Z0-9]{5}_[A-Z0-9]{5}$"
    },
    "preview": {
      "description": "Rows to include in the immediate response. Defaults to the row limit. Set lower (e.g., 50) when chaining via register_as and only a sample is needed inline.",
      "type": "integer",
      "minimum": 0,
      "maximum": 10000
    },
    "row_limit": {
      "default": 1000,
      "description": "Hard cap on rows materialized in the response. Default 1000, max 10000. The full result lives on-canvas under register_as when provided — do not raise this to keep large results.",
      "type": "integer",
      "minimum": 1,
      "maximum": 10000
    }
  },
  "required": [
    "sql",
    "row_limit"
  ],
  "additionalProperties": false
}
view source ↗

Resources

2

Reference list of common XBRL financial concepts grouped by financial statement, mapping friendly names accepted by secedgar_get_financials and secedgar_fetch_frames to their XBRL tags.

uri secedgar://concepts mime text/markdown

Reference list of common SEC filing types with descriptions, cadence, and typical use cases. Helps choose the forms parameter for secedgar_search_filings or the form_types filter for secedgar_company_search.

uri secedgar://filing-types mime text/markdown

Prompts

1

Guide a structured analysis of a public company's SEC filings: identify recent filings, extract financial trends, surface risk factors, and note material events.

  • companyrequired — Company name, ticker symbol, or CIK number to analyze.
  • focus_areas — Specific areas to focus on (e.g., "revenue growth, debt levels, insider activity"). If omitted, performs a general analysis.