{"name":"io.github.cyanheads/secedgar-mcp-server","slug":"cyanheads-secedgar-mcp-server","title":null,"description":"Query SEC EDGAR filings, XBRL financials, and company data through MCP. STDIO & Streamable HTTP.","url":"https://mcp.market/server/cyanheads-secedgar-mcp-server","rating":null,"grade":"A","score":86,"certified":false,"status":"active","category":"other","tags":[],"presence":{"score":45,"stars":10,"forks":4,"downloads_week":902,"last_push_at":"2026-09-16T12:17:05.000Z","license":"Apache-2.0"},"uptime":{"percent":100,"checks":1,"ok":1,"last_checked_at":"2026-09-19T17:30:24.644Z","last_ok_at":"2026-09-19T17:30:24.644Z","latency_ms":661},"claimed":false,"transport":"mixed","callable_via_gateway":true,"default_price_micros":0,"repository":"https://github.com/cyanheads/secedgar-mcp-server","website":null,"version":"0.15.6","remotes":[{"type":"streamable-http","url":"https://secedgar.caseyjhand.com/mcp"}],"packages":[{"registryType":"npm","registryBaseUrl":"https://registry.npmjs.org","identifier":"@cyanheads/secedgar-mcp-server","version":"0.15.6","runtimeHint":"bun","transport":{"type":"stdio"},"environmentVariables":[{"description":"User-Agent header for SEC compliance. Format: \"AppName contact@email.com\".","isRequired":true,"format":"string","name":"EDGAR_USER_AGENT"},{"description":"Sets the minimum log level for output (e.g., 'debug', 'info', 'warn').","format":"string","default":"info","name":"MCP_LOG_LEVEL"}]},{"registryType":"npm","registryBaseUrl":"https://registry.npmjs.org","identifier":"@cyanheads/secedgar-mcp-server","version":"0.15.6","runtimeHint":"bun","transport":{"type":"streamable-http","url":"http://localhost:3010/mcp"},"environmentVariables":[{"description":"User-Agent header for SEC compliance. Format: \"AppName contact@email.com\".","isRequired":true,"format":"string","name":"EDGAR_USER_AGENT"},{"description":"The hostname for the HTTP server.","format":"string","default":"127.0.0.1","name":"MCP_HTTP_HOST"},{"description":"The port to run the HTTP server on.","format":"string","default":"3010","name":"MCP_HTTP_PORT"},{"description":"The endpoint path for the MCP server.","format":"string","default":"/mcp","name":"MCP_HTTP_ENDPOINT_PATH"},{"description":"Public-facing origin override for TLS-terminating proxies (e.g., https://mcp.example.com). Leave unset for direct deployments.","format":"string","name":"MCP_PUBLIC_URL"},{"description":"Authentication mode to use: 'none', 'jwt', or 'oauth'.","format":"string","default":"none","name":"MCP_AUTH_MODE"},{"description":"Sets the minimum log level for output (e.g., 'debug', 'info', 'warn').","format":"string","default":"info","name":"MCP_LOG_LEVEL"}]}],"tools":[{"name":"secedgar_company_search","description":"Find companies and retrieve entity info with optional recent filings. Entry point for most EDGAR workflows — resolves tickers, names, or CIKs to entity details, with accession numbers in the result feeding secedgar_get_filing for document content. When a date or form filter carries the scan past the recent submissions window, the full filtered filing history is also staged as df_<id> — inspect it with secedgar_dataframe_describe, then analyze it with secedgar_dataframe_query.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"query":{"type":"string","minLength":1,"description":"Company ticker symbol (e.g., \"AAPL\", \"VOO\"), name (e.g., \"Apple\"), or CIK number (e.g., \"320193\"). Ticker is the fastest lookup and works for equities, ETFs, and mutual funds; a multi-class share ticker resolves in either form (\"BRK-B\" or \"BRK.B\"). Name search matches current and former names, and the corporate suffix does not have to match the registry's form (\"Beacon Financial Corporation\" finds \"Beacon Financial Corp\") — but Corp, Inc, Co, and Ltd stay distinct from each other, since separate registrants differ only by which one they use."},"include_filings":{"default":true,"description":"Include recent filings in the response. Set to false for entity-info-only lookups.","type":"boolean"},"form_types":{"description":"Filter filings to specific form types (e.g., [\"10-K\", \"10-Q\", \"8-K\"]). Without this, returns all form types.","type":"array","items":{"type":"string"}},"filing_limit":{"default":10,"description":"Maximum number of filings to return in the inline list.","type":"integer","minimum":1,"maximum":50},"filed_after":{"description":"Only include filings filed on or after this date (YYYY-MM-DD). A date filter routes the scan into the older submissions archive pages, so it reaches filings that predate the ~1000-filing recent window (e.g. a company's 2005 10-K).","anyOf":[{"type":"string","const":""},{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"YYYY-MM-DD"}]},"filed_before":{"description":"Only include filings filed on or before this date (YYYY-MM-DD). Use alone or with filed_after; together they bound the archive-page scan.","anyOf":[{"type":"string","const":""},{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"YYYY-MM-DD"}]}},"required":["query"],"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false}},{"name":"secedgar_compare_companies","description":"Compare 2-10 named companies across 1-8 XBRL concepts, aligned on calendar periods. This is the middle shape between secedgar_get_financials (one company, one concept, full history) and secedgar_fetch_frames (one concept, one period, every reporting company) — reach for it when the question names the companies. One companyfacts read per company, resolved through the same frame dedup and tag priority as secedgar_get_financials so the numbers agree. Balance-sheet and entity-info concepts are filed as point-in-time values and align on the calendar year (annual) or quarter (quarterly) their snapshot falls in, so they sit in the same matrix as income-statement lines. The inline matrix covers the most recent periods up to `periods`, trimmed further when companies x concepts x periods is too large to return in one response; the full aligned series is materialized as df_<id> for growth rates and spreads — inspect it with secedgar_dataframe_describe, then analyze it with secedgar_dataframe_query. A company that fails to resolve is reported in failed_companies and the comparison proceeds with the rest, and a company that does not report a concept is reported in gaps with the tags that were tried — never interpolated or zero-filled. Off-calendar filers and unit mismatches are surfaced in caveats rather than silently mixed.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"companies":{"minItems":2,"maxItems":10,"type":"array","items":{"type":"string","minLength":1,"description":"Ticker symbol or CIK number."},"description":"Companies to compare, as ticker symbols (preferred) or CIK numbers. A company that does not resolve is reported in failed_companies and the rest of the comparison still runs."},"concepts":{"minItems":1,"maxItems":8,"type":"array","items":{"type":"string","minLength":1,"description":"Friendly concept name or raw XBRL tag."},"description":"Concepts to compare — friendly names like \"revenue\" or \"net_income\" (discover them with secedgar_search_concepts) or raw XBRL tags."},"taxonomy":{"default":"us-gaap","description":"XBRL taxonomy to resolve concepts under. Use ifrs-full only when every company in the list reports under IFRS; mixing IFRS and US GAAP filers in one call resolves them all under the same taxonomy.","type":"string","enum":["us-gaap","ifrs-full"]},"period_type":{"default":"annual","description":"Align on full calendar years (annual) or calendar quarters (quarterly). Quarterly comparisons of off-calendar filers are missing at least one calendar quarter per year — see caveats.","type":"string","enum":["annual","quarterly"]},"periods":{"default":4,"description":"Upper bound on how many recent periods the inline matrix covers, newest first — not a guarantee. The matrix is companies x concepts x periods cells, and the inline window drops further older periods when that product is too large to return in one response. The full aligned series is always registered to the dataframe, so dropped periods stay queryable via secedgar_dataframe_query.","type":"integer","minimum":1,"maximum":12}},"required":["companies","concepts"],"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false}},{"name":"secedgar_dataframe_describe","description":"List the dataframes (df_XXXXX_XXXXX) registered by the data-returning secedgar_* tools — any tool whose response carries a `dataset` handle stages its full result set here. 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 the column schema here before writing SQL for secedgar_dataframe_query.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"name":{"description":"Optional table name (df_XXXXX_XXXXX) to describe a single dataframe. Omit to list all dataframes.","type":"string"}},"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false}},{"name":"secedgar_dataframe_query","description":"Run a single-statement SELECT against the canvas dataframes registered by the data-returning secedgar_* tools — any tool whose response carries a `dataset` handle. Inspect a dataframe with secedgar_dataframe_describe first; its column schema is what the SQL has to match. 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.","write_action":true,"price_micros":0,"input_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. A query matching more rows than this stops at the cap and `row_count_capped` comes back true; the full result lives on-canvas under register_as when provided, so do not raise this to keep large results. One case is not detectable: a SQL LIMIT exactly equal to this cap reads identically to a result that genuinely holds that many rows, and is reported as exact.","type":"integer","minimum":1,"maximum":10000}},"required":["sql"],"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false}},{"name":"secedgar_fetch_frames","description":"Fetch SEC XBRL frames for one concept × one period across all reporting companies. Inline response returns a page of the ranked companies — start at the top or pass offset/next_offset to walk further down the ranking; the full frames response (all reporters) is materialized as df_<id> when a canvas is available — inspect it with secedgar_dataframe_describe, then analyze it with 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.","write_action":false,"price_micros":0,"input_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},"offset":{"default":0,"description":"Rank to start the page at, 0-based, over the sorted frame. Pass the next_offset from the previous response to read the next page — the ranked list is fetched whole and sliced, so paging is stable and gap-free. An offset at or past total_companies returns an empty page.","type":"integer","minimum":0,"maximum":9007199254740991},"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"],"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false}},{"name":"secedgar_find_holders","description":"Find which institutional managers reported holding an issuer, by searching 13F-HR information tables for one reporting quarter. This is the reverse direction of secedgar_get_institutional_holdings: that tool takes a manager and returns its portfolio, this one takes an issuer and returns its managers — pass a returned filer_cik plus the same quarter to read the actual position. Searching by cusip is the precise path, matching the identifier the information table itself carries; without it the issuer name is matched as a phrase against the filing text, which both over-matches (unrelated issuers sharing a word) and under-matches (managers writing the name differently), so prefer cusip whenever one is known. A CUSIP cannot be derived from a ticker here — read one off any 13F information table returned by secedgar_get_institutional_holdings. The returned list is unranked: the search index scores by text relevance, which carries no signal about position size, and no ordering by shares or market value is available without opening each filing. Managers holding under $100M in 13(f) securities are exempt from filing at all. When more managers match than fit inline, the full fetched set is staged as df_<id> — inspect it with secedgar_dataframe_describe, then analyze it with secedgar_dataframe_query.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"issuer":{"type":"string","minLength":1,"description":"The portfolio company whose holders you want — a ticker (\"AAPL\"), a 10-digit CIK (\"0000320193\"), or a company name. Without cusip, this resolves to the company's EDGAR-conformed name and that name is phrase-matched against 13F information tables, so it must identify one company. With cusip supplied, it is used only to label the result."},"cusip":{"description":"The issuer's 9-character CUSIP (e.g. \"037833100\" for Apple common stock; foreign issuers use a CINS starting with a letter, e.g. \"H1467J104\"). The precise match key — information tables identify every position by CUSIP, so this avoids the name-phrase misses. Each share class has its own CUSIP, so a multi-class issuer needs one call per class. Read a CUSIP off the holdings returned by secedgar_get_institutional_holdings.","anyOf":[{"type":"string","const":""},{"type":"string","pattern":"^[0-9A-Za-z]{9}$","description":"9-character CUSIP/CINS"}]},"quarter":{"description":"Reporting quarter to search, \"YYYY-QN\" (e.g. \"2026-Q1\"). Omit for the newest quarter whose 45-day filing deadline has passed — the applied quarter and its filing window are echoed in the response. A quarter still inside its deadline returns nothing, because the filings do not exist yet.","anyOf":[{"type":"string","const":""},{"type":"string","pattern":"^\\d{4}-Q[1-4]$","description":"YYYY-QN"}]},"limit":{"default":20,"description":"Filer rows returned inline. The full fetched set (up to 500 rows) is materialized as a dataframe when a canvas is available. Default 20.","type":"integer","minimum":1,"maximum":100}},"required":["issuer"],"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false}},{"name":"secedgar_get_beneficial_owners","description":"List the 5%-and-over beneficial owners of a public company, parsed from the structured SCHEDULE 13D and SCHEDULE 13G filings made about it. The input is the ISSUER — the company being held — which is the opposite direction from secedgar_get_institutional_holdings, where the input is the manager. 13D is the activist form and carries the filer's stated purpose of the transaction; 13G is the passive form and has no purpose field at all, which is the substantive difference between a stake that intends to influence control and one that does not. Every filing is returned with each reporting person listed separately, because voting power, dispositive power, and percent of class are reported per person even on a joint filing where several funds and their controlling principal report overlapping shares — summing those percentages double-counts the same position. Coverage starts at 2024-12-18, when SEC replaced the legacy SC 13D / SC 13G text filings with this XML format; earlier stakes are readable but not parseable, and the response reports how many of them the issuer has. The full parsed set is materialized as df_<id> when a canvas is available, one row per reporting person, so it joins against the insider and 13F dataframes on issuer CIK — inspect it with secedgar_dataframe_describe, then analyze it with secedgar_dataframe_query.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"issuer":{"type":"string","minLength":1,"description":"The company whose blockholders you want — a ticker (\"AAPL\"), a 10-digit CIK (\"0000320193\"), or a company name. This is the subject company of the schedule, not the investor filing it; passing an investment manager here returns the schedules filed about that manager, which is almost always empty."},"form_kind":{"default":"all","description":"Which schedule to return. \"13D\" is the activist form, filed by a holder that may seek to influence control and carrying a stated purpose of transaction. \"13G\" is the passive form, available to institutions and holders under 20% that certify no control intent. \"all\" (default) returns both, newest first.","type":"string","enum":["all","13D","13G"]},"include_amendments":{"default":true,"description":"Whether to include amendments (SCHEDULE 13D/A, SCHEDULE 13G/A). Amendments carry the current position and are how an ongoing stake is tracked, so they are included by default. Set false to see only filings that opened a new position.","type":"boolean"},"limit":{"default":10,"description":"Number of filings to fetch and parse, newest first. Each filing is a separate document fetch, so this is the cost of the call as well as its depth. Default 10; a widely-held company can have dozens of blockholder filings a year.","type":"integer","minimum":1,"maximum":20}},"required":["issuer"],"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false}},{"name":"secedgar_get_filing","description":"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.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"accession_number":{"type":"string","pattern":"^(?:\\d{10}-\\d{2}-\\d{6}|\\d{18})$","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, digits only (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","pattern":"^\\d{1,10}$"},"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 are listed in the response metadata under documents; entries marked binary hold no text and are rejected.","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'). Matching also ignores whitespace and quote-style differences, so a heading copied from the outline resolves whether it carries the filing's non-breaking spaces and curly quotes or plain ones. Takes precedence over offset when both are provided. On a miss, the error message includes the detected outline so you can pick the correct heading.","type":"string","minLength":1}},"required":["accession_number"],"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false}},{"name":"secedgar_get_financials","description":"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. The full series is also staged as df_<id> when a canvas is available — inspect it with secedgar_dataframe_describe, then analyze it with secedgar_dataframe_query.","write_action":false,"price_micros":0,"input_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"],"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false}},{"name":"secedgar_get_fund_holdings","description":"List what an ETF or mutual fund holds, parsed from the NPORT-P portfolio report it files with the SEC every quarter. The input is the fund — a ticker like VOO, a fund series ID, or the registrant trust — which is the opposite direction from the ownership tools: secedgar_get_institutional_holdings and secedgar_find_holders answer who owns a company, this answers what a fund owns. Each position carries the security name, CUSIP/ISIN/LEI where the filer reports them, share balance, market value in USD, and percent of the fund's net assets, alongside fund-level net assets and total assets. Positions are returned largest-first by percent of net assets, one page of limit rows starting at offset; the full report registers as df_<id> when a canvas is available — inspect it with secedgar_dataframe_describe, then analyze it with secedgar_dataframe_query, which is how a fund running to thousands of positions is aggregated or joined against the 13F and insider dataframes. An NPORT-P covers exactly one fund series and a registrant trust files one report per series, so a trust with several funds needs the specific fund named — pass its ticker or series_id. Reports publish roughly two months after the period they cover, so every result is dated: the holdings are the portfolio as of report_period_date, not as of today.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"fund":{"type":"string","minLength":1,"description":"The fund whose portfolio you want — a fund ticker (\"VOO\", \"SCHD\"), an SEC fund series ID (\"S000002839\"), or a 10-digit CIK. A ticker names one share class of one series and routes directly; a CIK names the registrant, which files a separate report per series and needs series_id when it runs more than one fund. Fund trusts are indexed by ticker and series, not by name, so a trust name only resolves for a fund that trades under its own name (\"SPDR S&P 500 ETF Trust\") — pass the CIK otherwise."},"series_id":{"description":"SEC fund series identifier (\"S000002839\"), naming which fund of the registrant to report. Takes precedence over any series the fund input implies. Series IDs come back on fund results from secedgar_company_search and in the series list of a series_required error.","type":"string","pattern":"^S\\d{9}$"},"report_date":{"description":"Target a specific reporting period by its last day (YYYY-MM-DD), e.g. \"2025-12-31\". Omit for the most recent report. Period ends follow the fund's own fiscal quarters, which are not always calendar quarters — Direxion funds report to February, May, August, and November. available_report_periods in the response lists the ones this call identified; a period missing from that list is still worth requesting directly, since a report the submissions window no longer dates is dated by reading it.","type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"limit":{"default":20,"description":"Number of positions to return inline, largest first by percent of net assets. Default 20. A broad index fund reports thousands of positions, so the inline list is a preview — read the whole portfolio from the dataframe, or page it with offset.","type":"integer","minimum":1,"maximum":100},"offset":{"default":0,"description":"Position to start the page at, 0-based, over the full ordered holdings list. Pass the returned next_offset to read the next page — the report is parsed whole and sliced, so paging is stable and gap-free.","type":"integer","minimum":0,"maximum":9007199254740991}},"required":["fund"],"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false}},{"name":"secedgar_get_insider_transactions","description":"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) — inspect it with secedgar_dataframe_describe, then 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.","write_action":false,"price_micros":0,"input_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"],"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false}},{"name":"secedgar_get_institutional_holdings","description":"Fetch 13F-HR quarterly institutional holdings by parsing the SEC EDGAR information table XML. ticker_or_cik is the institutional filer — its 10-digit CIK (e.g. 0000102909), or an entity name resolved through EDGAR entity search — and the tool returns what that institution holds. A name that matches several EDGAR filers (some legal names are shared across entities) returns those candidates so you can retry with the exact CIK, rather than guessing. For the reverse direction — which institutions hold a given portfolio company — use secedgar_find_holders, whose filer_cik results feed straight back into this tool. 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 inline holdings list is one page of limit rows starting at offset — pass the returned next_offset to walk further down a large information table. The full parsed holdings set is also materialized as df_<id> when a canvas is available — inspect it with secedgar_dataframe_describe, then 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.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"ticker_or_cik":{"type":"string","minLength":1,"description":"The institutional filer whose 13F to fetch — a 10-digit CIK (e.g. \"0000102909\" for VANGUARD GROUP INC, the most reliable form) or an entity name. Names resolve through EDGAR entity search, which covers institutional managers absent from the ticker file; a name matching several filers (some legal names are shared across entities) returns those candidates so you can retry with the exact CIK. This is NOT the portfolio company — passing an issuer ticker like \"AAPL\" finds that operating company's own filings (it files no 13F), not who holds it; use secedgar_find_holders for that direction."},"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},"offset":{"default":0,"description":"Row to start the page at, 0-based, over the ordered position list. Pass the next_offset from the previous response to read the next page — the filing is parsed whole and sliced, so paging is stable and gap-free. An offset at or past the position count returns an empty page.","type":"integer","minimum":0,"maximum":9007199254740991},"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"],"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false}},{"name":"secedgar_get_material_events","description":"Retrieve a company's 8-K filings with their item codes decoded, optionally filtered to specific items. 8-K item codes are how material events are actually scoped — 1.01 material agreements, 2.02 results of operations, 4.02 non-reliance on previously issued financials, 5.02 officer and director departures — and filtering by them is narrower than any form-level filter in secedgar_search_filings or secedgar_company_search, neither of which can see items. Each row carries the accession number and primary document for secedgar_get_filing; press releases usually ride as EX-99 exhibits rather than in the primary document. Two numbering regimes exist: filings from 2004-08-23 onward use the x.xx codes, earlier ones use single integers (12 was the old results-of-operations item, 9 the old Regulation FD item), and both are accepted as filters and decoded in the response. A date window reaches filings older than the recent submissions window by paging into the archive. The full filtered set is materialized as df_<id> for item-distribution analysis over time — inspect it with secedgar_dataframe_describe, then analyze it with secedgar_dataframe_query.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"company":{"type":"string","minLength":1,"description":"Company ticker symbol (e.g. \"AAPL\"), name (e.g. \"Apple\"), or CIK number (e.g. \"320193\"). Ticker is the exact lookup; name search matches current and former names."},"items":{"description":"Item codes to filter to; a filing matches when it reports any of them. Omit to return every 8-K. Current-regime codes are dotted (\"2.02\"), pre-2004-08-23 codes are bare integers (\"12\"), and the two vocabularies do not overlap — filtering on \"2.02\" alone returns nothing from a pre-2004 window, so pair them (\"2.02\", \"12\") when the window spans the changeover. Full decode table: the secedgar://filing-types resource.","maxItems":20,"type":"array","items":{"type":"string","enum":["1","2","3","4","5","6","7","8","9","10","11","12","1.01","1.02","1.03","1.04","1.05","2.01","2.02","2.03","2.04","2.05","2.06","3.01","3.02","3.03","4.01","4.02","5.01","5.02","5.03","5.04","5.05","5.06","5.07","5.08","6.01","6.02","6.03","6.04","6.05","6.06","7.01","8.01","9.01"]}},"filed_after":{"description":"Only include filings filed on or after this date (YYYY-MM-DD). A date filter routes the scan into the older submissions archive pages, so it reaches 8-K filings that predate the ~1000-filing recent window.","anyOf":[{"type":"string","const":""},{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"YYYY-MM-DD"}]},"filed_before":{"description":"Only include filings filed on or before this date (YYYY-MM-DD). Use alone or with filed_after; together they bound the archive-page scan.","anyOf":[{"type":"string","const":""},{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"YYYY-MM-DD"}]},"limit":{"default":20,"description":"Filings returned inline, newest first. The full filtered set is materialized as a dataframe when it exceeds this and a canvas is available. Default 20.","type":"integer","minimum":1,"maximum":100}},"required":["company"],"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false}},{"name":"secedgar_get_snapshot","description":"Build a company financial profile in one call: the latest value of every supported XBRL concept, grouped by statement. Reads the filer's complete companyfacts payload once rather than one request per concept, so it replaces a run of secedgar_get_financials calls when the question is \"what do this company's financials look like right now\". Values use the same frame dedup and tag priority as secedgar_get_financials, so the two agree for any concept they both cover. Duration concepts (income statement, cash flow, per-share) report their latest full year and latest single quarter; balance-sheet and entity-info concepts report their latest point-in-time value, since that is the only form they are filed in. A concept the filer does not report is listed under gaps with the XBRL tags that were tried — never zero-filled or interpolated. Use secedgar_get_financials for a full time series of one concept, and secedgar_compare_companies to put several companies side by side.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"company":{"type":"string","minLength":1,"description":"Ticker symbol (e.g. \"AAPL\") or CIK number. Ticker is preferred."},"taxonomy":{"default":"us-gaap","description":"XBRL taxonomy to resolve concepts under. Every concept is looked up in this one taxonomy, so ifrs-full covers only the concepts with confirmed IFRS tag variants and the rest — including the dei entity-info concepts — come back under gaps. Leave at us-gaap for domestic filers, where each concept uses its own preferred taxonomy.","type":"string","enum":["us-gaap","ifrs-full"]},"period_type":{"default":"both","description":"Which duration periods to report per concept: the latest full year, the latest single quarter, or both (default). Balance-sheet and entity-info concepts are point-in-time and always report their latest instant value regardless of this setting.","type":"string","enum":["annual","quarterly","both"]}},"required":["company"],"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false}},{"name":"secedgar_search_concepts","description":"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.","write_action":false,"price_micros":0,"input_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"]}},"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false}},{"name":"secedgar_search_filings","description":"Search EDGAR filings since 1993. Full-text search covers 2001-present (the EFTS index floor); pre-2001 date ranges (to 1993) are served from the archives by form and entity/date. Pre-2001 free text needs entity scope (ticker:/cik:) — with it, the tool reads the entity's matching filings and matches the terms locally, which costs a few seconds (SEC's request rate caps the scan at roughly 5s for the 50-document maximum). A range crossing 2001-01-01 is split at the boundary and the two eras merged, each row tagged with its source. Supports exact phrases, boolean operators, wildcards, and entity targeting (ticker:AAPL or cik:320193 in query). When the match set outruns the inline list it is also staged as df_<id> — inspect it with secedgar_dataframe_describe, then analyze it with secedgar_dataframe_query.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"query":{"description":"Full-text search query. Optional — omit (or pass \"\") to browse by form type and/or entity instead, e.g. every S-1 in a date window, or a company's filings via ticker:/cik:. A date range alone is not a valid search; pair it with forms or entity targeting. The EFTS index that serves free text starts at 2001-01-01; a date range reaching earlier needs ticker:/cik: entity scope, which lets the tool read that entity's filings and match the terms locally (bounded to 50 documents, a few seconds at SEC's request rate), or drop the text terms to browse by form and date. When present, supports exact phrases (\"material weakness\"), boolean operators (revenue OR income), exclusion (-preliminary), wildcard suffix (account*), and entity targeting (ticker:AAPL or cik:320193 in the query); terms are AND'd by default. A multi-class share ticker resolves in either form — ticker:BRK-B and ticker:BRK.B scope to the same issuer. The pre-2001 local scan honors the same phrase / OR / exclusion / wildcard syntax.","anyOf":[{"type":"string","const":""},{"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. SEC renamed the blockholder schedules on 2024-12-18 — filings before that date are \"SC 13D\"/\"SC 13G\", filings after are \"SCHEDULE 13D\"/\"SCHEDULE 13G\" — so a filter spanning that boundary must list both spellings. 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 on a 2001-onward search, EDGAR pages server-side up to its 10,000-result cap. Everywhere else the offset indexes the rows this call assembled and sorted: a single 100-row window for date sorts and entity targeting, the full matched set on a pre-2001 archive path, or both together on a range that crosses 2001-01-01. Offsets at or past those rows return nothing even when total is larger — switch to sort=relevance for deep pagination on a 2001-onward search, narrow the search (forms, dates, entity targeting), or query the dataframe. On a crossing range the two sides are assembled unevenly — the archive side contributes every row it matched, the full-text side one window of its total — so once the window runs out the rows jump to the pre-2001 era with the remaining full-text matches absent from the middle; search the 2001-onward era on its own to page through those.","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. On the no-query browse path (forms/entity only), EFTS has no relevance signal — every hit scores null — and returns filings in natural date-descending order, so all sort modes effectively yield newest-first. Pre-2001 archive results carry no relevance score either, so relevance collapses to date-descending there.","type":"string","enum":["filing_date_desc","filing_date_asc","relevance"]}},"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false}}],"scan":{"score":86,"grade":"A","scanned_at":"2026-09-19T19:46:45.604Z","report":{"scannerVersion":"0.1.5","scannedAt":"2026-09-19T19:46:45.529Z","components":{"code":{"score":25,"max":25,"notes":["87 source files scanned","87 source files scanned"]},"reliability":{"score":20,"max":20,"notes":["remote reachable in 1293ms"]},"poisoning":{"score":15,"max":15,"notes":["16 tool descriptions checked"]},"auth":{"score":3,"max":15,"notes":["open endpoint exposes 1 write-action tools with no auth"]},"maintenance":{"score":15,"max":15,"notes":["last push 3 days ago"]},"identity":{"score":8,"max":10,"notes":["registry namespace matches repository owner","GitHub account older than a year"]}},"findings":[{"id":"auth.open-write","severity":"high","component":"auth","title":"Write-action tools reachable without authentication"}],"inputs":{"probes":[{"url":"https://secedgar.caseyjhand.com/mcp","reachable":true,"authRequired":false,"latencyMs":1293,"serverInfo":{"name":"secedgar-mcp-server","version":"0.15.6"}}],"packages":[{"registryType":"npm","identifier":"@cyanheads/secedgar-mcp-server","version":"0.15.6","found":true,"license":"Apache-2.0","hasInstallScripts":false,"dependencyCount":11,"publishedAt":"2026-09-16T12:18:17.204Z","repositoryUrl":"git+https://github.com/cyanheads/secedgar-mcp-server.git","weeklyDownloads":451},{"registryType":"npm","identifier":"@cyanheads/secedgar-mcp-server","version":"0.15.6","found":true,"license":"Apache-2.0","hasInstallScripts":false,"dependencyCount":11,"publishedAt":"2026-09-16T12:18:17.204Z","repositoryUrl":"git+https://github.com/cyanheads/secedgar-mcp-server.git","weeklyDownloads":451}],"repo":{"found":true,"owner":"cyanheads","repo":"secedgar-mcp-server","archived":false,"pushedAt":"2026-09-16T12:17:05Z","stars":10,"forks":4,"openIssues":3,"ownerType":"User","ownerAvatarUrl":"https://avatars.githubusercontent.com/u/10339515?v=4","ownerCreatedAt":"2014-12-29T13:01:12Z","license":"Apache-2.0"},"icon":{"url":"https://avatars.githubusercontent.com/u/10339515?v=4&s=128","source":"registry"},"presence":{"stars":10,"forks":4,"downloadsWeek":902,"license":"Apache-2.0","lastPushAt":"2026-09-16T12:17:05.000Z","score":45}}}},"grade_history":[],"reviews":[]}