@cyanheads/secedgar-mcp-server 0.15.4 → 0.15.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +412 -0
- package/CLAUDE.md +412 -0
- package/README.md +179 -151
- package/changelog/0.1.x/0.1.0.md +33 -0
- package/changelog/0.1.x/0.1.1.md +27 -0
- package/changelog/0.1.x/0.1.10.md +27 -0
- package/changelog/0.1.x/0.1.11.md +15 -0
- package/changelog/0.1.x/0.1.2.md +28 -0
- package/changelog/0.1.x/0.1.3.md +20 -0
- package/changelog/0.1.x/0.1.4.md +13 -0
- package/changelog/0.1.x/0.1.5.md +19 -0
- package/changelog/0.1.x/0.1.6.md +20 -0
- package/changelog/0.1.x/0.1.7.md +20 -0
- package/changelog/0.1.x/0.1.8.md +14 -0
- package/changelog/0.1.x/0.1.9.md +14 -0
- package/changelog/0.10.x/0.10.0.md +18 -0
- package/changelog/0.10.x/0.10.1.md +21 -0
- package/changelog/0.10.x/0.10.2.md +23 -0
- package/changelog/0.10.x/0.10.3.md +21 -0
- package/changelog/0.10.x/0.10.4.md +12 -0
- package/changelog/0.10.x/0.10.5.md +18 -0
- package/changelog/0.11.x/0.11.0.md +41 -0
- package/changelog/0.11.x/0.11.1.md +30 -0
- package/changelog/0.11.x/0.11.2.md +27 -0
- package/changelog/0.11.x/0.11.3.md +15 -0
- package/changelog/0.12.x/0.12.0.md +16 -0
- package/changelog/0.12.x/0.12.1.md +29 -0
- package/changelog/0.12.x/0.12.2.md +23 -0
- package/changelog/0.12.x/0.12.3.md +24 -0
- package/changelog/0.12.x/0.12.4.md +19 -0
- package/changelog/0.12.x/0.12.5.md +42 -0
- package/changelog/0.13.x/0.13.0.md +29 -0
- package/changelog/0.13.x/0.13.1.md +27 -0
- package/changelog/0.14.x/0.14.0.md +30 -0
- package/changelog/0.15.x/0.15.0.md +20 -0
- package/changelog/0.15.x/0.15.1.md +38 -0
- package/changelog/0.15.x/0.15.2.md +28 -0
- package/changelog/0.15.x/0.15.3.md +22 -0
- package/changelog/0.15.x/0.15.4.md +14 -0
- package/changelog/0.15.x/0.15.5.md +21 -0
- package/changelog/0.15.x/0.15.6.md +42 -0
- package/changelog/0.2.x/0.2.0.md +25 -0
- package/changelog/0.3.x/0.3.0.md +17 -0
- package/changelog/0.4.x/0.4.0.md +24 -0
- package/changelog/0.4.x/0.4.1.md +34 -0
- package/changelog/0.4.x/0.4.2.md +14 -0
- package/changelog/0.4.x/0.4.3.md +28 -0
- package/changelog/0.4.x/0.4.4.md +19 -0
- package/changelog/0.4.x/0.4.5.md +17 -0
- package/changelog/0.5.x/0.5.0.md +35 -0
- package/changelog/0.5.x/0.5.1.md +13 -0
- package/changelog/0.5.x/0.5.2.md +13 -0
- package/changelog/0.6.x/0.6.0.md +24 -0
- package/changelog/0.6.x/0.6.1.md +21 -0
- package/changelog/0.6.x/0.6.2.md +34 -0
- package/changelog/0.6.x/0.6.3.md +23 -0
- package/changelog/0.7.x/0.7.0.md +25 -0
- package/changelog/0.7.x/0.7.1.md +12 -0
- package/changelog/0.7.x/0.7.2.md +23 -0
- package/changelog/0.7.x/0.7.3.md +12 -0
- package/changelog/0.7.x/0.7.4.md +16 -0
- package/changelog/0.8.x/0.8.0.md +20 -0
- package/changelog/0.8.x/0.8.1.md +17 -0
- package/changelog/0.8.x/0.8.2.md +14 -0
- package/changelog/0.8.x/0.8.3.md +20 -0
- package/changelog/0.8.x/0.8.4.md +12 -0
- package/changelog/0.9.x/0.9.0.md +20 -0
- package/changelog/template.md +151 -0
- package/dist/index.js +17 -39
- package/dist/index.js.map +1 -1
- package/dist/mcp-server/tools/definitions/company-search.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/company-search.tool.js +6 -4
- package/dist/mcp-server/tools/definitions/company-search.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/compare-companies.tool.d.ts +1 -0
- package/dist/mcp-server/tools/definitions/compare-companies.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/compare-companies.tool.js +24 -6
- package/dist/mcp-server/tools/definitions/compare-companies.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/dataframe-describe.tool.js +1 -1
- package/dist/mcp-server/tools/definitions/dataframe-describe.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/dataframe-query.tool.d.ts +1 -0
- package/dist/mcp-server/tools/definitions/dataframe-query.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/dataframe-query.tool.js +48 -13
- package/dist/mcp-server/tools/definitions/dataframe-query.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/fetch-frames.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/fetch-frames.tool.js +22 -10
- package/dist/mcp-server/tools/definitions/fetch-frames.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/find-holders.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/find-holders.tool.js +8 -6
- package/dist/mcp-server/tools/definitions/find-holders.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/get-beneficial-owners.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/get-beneficial-owners.tool.js +8 -4
- package/dist/mcp-server/tools/definitions/get-beneficial-owners.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/get-financials.tool.d.ts +1 -0
- package/dist/mcp-server/tools/definitions/get-financials.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/get-financials.tool.js +19 -4
- package/dist/mcp-server/tools/definitions/get-financials.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/get-fund-holdings.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/get-fund-holdings.tool.js +18 -7
- package/dist/mcp-server/tools/definitions/get-fund-holdings.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/get-insider-transactions.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/get-insider-transactions.tool.js +11 -4
- package/dist/mcp-server/tools/definitions/get-insider-transactions.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/get-institutional-holdings.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/get-institutional-holdings.tool.js +18 -7
- package/dist/mcp-server/tools/definitions/get-institutional-holdings.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/get-material-events.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/get-material-events.tool.js +4 -4
- package/dist/mcp-server/tools/definitions/get-material-events.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/index.d.ts +1034 -0
- package/dist/mcp-server/tools/definitions/index.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/index.js +63 -0
- package/dist/mcp-server/tools/definitions/index.js.map +1 -0
- package/dist/mcp-server/tools/definitions/search-filings.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/search-filings.tool.js +25 -10
- package/dist/mcp-server/tools/definitions/search-filings.tool.js.map +1 -1
- package/dist/services/canvas-bridge/canvas-bridge.d.ts +16 -0
- package/dist/services/canvas-bridge/canvas-bridge.d.ts.map +1 -1
- package/dist/services/canvas-bridge/canvas-bridge.js +15 -0
- package/dist/services/canvas-bridge/canvas-bridge.js.map +1 -1
- package/dist/services/edgar/mirror/index.d.ts +6 -0
- package/dist/services/edgar/mirror/index.d.ts.map +1 -1
- package/dist/services/edgar/mirror/index.js +12 -0
- package/dist/services/edgar/mirror/index.js.map +1 -1
- package/package.json +13 -9
- package/server.json +3 -3
package/README.md
CHANGED
|
@@ -27,9 +27,11 @@
|
|
|
27
27
|
|
|
28
28
|
---
|
|
29
29
|
|
|
30
|
-
##
|
|
30
|
+
## Overview
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
SEC EDGAR filings, XBRL financials, and company ownership data, keyless aside from a required SEC User-Agent header. Resolve companies by ticker, name, or CIK, search filings back to 1993, pull XBRL financials and cross-company comparisons by concept, and trace ownership — insider transactions, 13F institutional holdings, 13D/13G blockholders, and fund holdings — from any MCP client. Runs as a stdio process, a local Streamable HTTP server, or the public hosted endpoint above.
|
|
33
|
+
|
|
34
|
+
### Tools
|
|
33
35
|
|
|
34
36
|
| Tool | Description |
|
|
35
37
|
|:---|:---|
|
|
@@ -49,238 +51,241 @@ Fourteen tools for querying SEC EDGAR data, plus three for SQL analytics over th
|
|
|
49
51
|
| `secedgar_search_concepts` | Discover supported XBRL concept names or reverse-lookup a raw tag |
|
|
50
52
|
| `secedgar_dataframe_describe` | List canvas dataframes with provenance, TTL, and schema |
|
|
51
53
|
| `secedgar_dataframe_query` | Run a single-statement SELECT across dataframes |
|
|
52
|
-
| `secedgar_dataframe_drop` | Drop a canvas dataframe by name. Opt-in via `EDGAR_DATAFRAME_DROP_ENABLED=true` — off by default since TTL already handles cleanup |
|
|
54
|
+
| `secedgar_dataframe_drop` | Drop a canvas dataframe by name. Opt-in via `EDGAR_DATAFRAME_DROP_ENABLED=true` — off by default since TTL already handles cleanup, and uncallable until the flag is set |
|
|
53
55
|
|
|
54
|
-
###
|
|
56
|
+
### Resources
|
|
55
57
|
|
|
56
|
-
|
|
58
|
+
| Resource | Description |
|
|
59
|
+
|:---|:---|
|
|
60
|
+
| `secedgar://concepts` | Common XBRL financial concepts grouped by statement, mapping friendly names to XBRL tags |
|
|
61
|
+
| `secedgar://filing-types` | Common SEC filing types with descriptions, cadence, and use cases, plus the full 8-K item-code decode tables for both numbering regimes |
|
|
57
62
|
|
|
58
|
-
|
|
59
|
-
- ETFs and mutual funds resolve by ticker via `company_tickers_mf.json`; fund results include `series_id` and `class_id` for downstream scoping
|
|
60
|
-
- Current and former company names both resolve (`Facebook` → Meta Platforms, `Square` → Block)
|
|
61
|
-
- Corporate suffix form does not have to match the registry (`Beacon Financial Corporation` → `Beacon Financial Corp`); `Corp`, `Inc`, `Co`, and `Ltd` stay distinct from one another, since separate registrants differ only by which one they use (`TORO CO` vs `TORO CORP.`)
|
|
62
|
-
- Near-match suggestions on a zero-result name or ticker search (e.g. `Microsfot` → `MICROSOFT CORP / MSFT`, `CSWI` → `CSW INDUSTRIALS, INC. / CSW`)
|
|
63
|
-
- Optionally includes recent filings with form type filtering
|
|
64
|
-
- Date filtering (`filed_after` / `filed_before`) and under-filled form filters page into the older submissions archive, reaching filings that predate the ~1000-entry recent window (e.g. a 2005 10-K); `history_scanned_through` discloses the scan depth, and the full filtered history materializes as a `df_<id>` dataframe when it exceeds the inline `filing_limit`
|
|
65
|
-
- Returns entity metadata: SIC code, exchanges, fiscal year end, state of incorporation
|
|
63
|
+
### Prompts
|
|
66
64
|
|
|
67
|
-
|
|
65
|
+
| Prompt | Description |
|
|
66
|
+
|:---|:---|
|
|
67
|
+
| `secedgar_company_analysis` | Guides a structured analysis of a public company's SEC filings: identify recent filings, extract financial trends, surface risk factors, and note material events |
|
|
68
68
|
|
|
69
|
-
|
|
69
|
+
## Capability reference
|
|
70
70
|
|
|
71
|
-
|
|
71
|
+
### `secedgar_company_search` <sub>tool</sub>
|
|
72
72
|
|
|
73
|
-
-
|
|
74
|
-
-
|
|
75
|
-
-
|
|
76
|
-
-
|
|
77
|
-
-
|
|
78
|
-
-
|
|
79
|
-
- Date range filtering, form type filtering, pagination up to 10,000 results
|
|
80
|
-
- Returns form distribution for narrowing follow-up searches
|
|
81
|
-
- When the entity-scoped window exceeds the inline limit, the already-fetched EFTS window is materialized as a `df_<id>` dataframe — query it with `secedgar_dataframe_query`
|
|
73
|
+
- Resolves ticker symbols, company names, or CIK numbers; a multi-class share ticker matches either form (`BRK-B` or `BRK.B`), and current/former names both resolve (`Facebook` → Meta Platforms, `Square` → Block)
|
|
74
|
+
- ETFs and mutual funds resolve by ticker via `company_tickers_mf.json`; fund results carry `series_id` and `class_id`
|
|
75
|
+
- Corporate suffix form need not match the registry (`Beacon Financial Corporation` → `Beacon Financial Corp`), but `Corp`/`Inc`/`Co`/`Ltd` stay distinct — separate registrants can differ only by which one they use
|
|
76
|
+
- Near-match suggestions on a zero-result name or ticker search (e.g. `Microsfot` → `MICROSOFT CORP / MSFT`)
|
|
77
|
+
- Optional recent filings inline with form-type filtering; `filed_after`/`filed_before` and under-filled form filters page into the older submissions archive, reaching filings past the ~1000-entry recent window — `history_scanned_through` reports the scan depth, and the full filtered history stages as `df_<id>` when it exceeds `filing_limit`
|
|
78
|
+
- Returns entity metadata — SIC code, exchanges, fiscal year end, state of incorporation
|
|
82
79
|
|
|
83
80
|
---
|
|
84
81
|
|
|
85
|
-
### `
|
|
82
|
+
### `secedgar_search_filings` <sub>tool</sub>
|
|
86
83
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
-
|
|
90
|
-
-
|
|
91
|
-
-
|
|
92
|
-
-
|
|
93
|
-
- Binary entries — scanned pages, PDF exhibits, packaged archives and spreadsheets — are marked `binary` in the document catalog and rejected with a `binary_document` error instead of being returned as decoded bytes
|
|
94
|
-
- **Offset paging** for large documents (10-K, S-1/A can exceed 1M chars): pass `next_offset` from a truncated response as `offset` on the next call to continue reading; first-page truncated responses include a detected `outline` (headings with offsets) for targeted navigation
|
|
95
|
-
- **Section targeting** via the `section` param: jumps directly to a named heading by substring match that ignores case, whitespace style, and quote style (e.g. `"risk factors"`, `"item 7"`, `"certain relationships"`), so a heading copied from the outline resolves whether it carries the filing's non-breaking spaces and curly quotes or plain ones; on a miss, the error carries the detected outline so you can pick the correct heading
|
|
96
|
-
- Extracted text is cached per `accession + document` (bounded LRU, 8 entries), making subsequent paged calls cheap
|
|
84
|
+
- Full-text search (2001–present, the EFTS index floor) with exact phrases, boolean operators, wildcards, and inline entity targeting (`cik:320193` / `ticker:AAPL`, either share-class form for multi-class tickers) — server-side scoped by CIK, so former-name filings on the same entity are included
|
|
85
|
+
- Browse mode (omit `query`) lists by form type and/or entity, optionally narrowed by date; a bare date range must pair with forms or entity targeting
|
|
86
|
+
- Pre-2001 date ranges (back to 1993) route to the archives — entity-scoped reads the filer's full submissions history, unscoped browses the quarterly full-index; pre-2001 free-text search needs `ticker:`/`cik:` entity scope, since it works by reading up to 50 candidate documents (`scan` reports candidates/scanned/matched, costing ~5s for a full scan)
|
|
87
|
+
- A range crossing 2001-01-01 is split at the boundary and merged, each row tagged with its `source` (`efts`/`submissions`/`full-index`); `period_ending`, `ticker`, `file_description`, `sic`, and `location` exist only on `efts` rows
|
|
88
|
+
- Date range and form-type filtering, pagination up to 10,000 results; response includes form distribution for narrowing follow-up searches
|
|
89
|
+
- The full result set stages as `df_<id>` when it exceeds the inline limit
|
|
97
90
|
|
|
98
91
|
---
|
|
99
92
|
|
|
100
|
-
### `
|
|
101
|
-
|
|
102
|
-
Get historical XBRL financial data for a company with friendly concept name resolution.
|
|
93
|
+
### `secedgar_get_filing` <sub>tool</sub>
|
|
103
94
|
|
|
104
|
-
-
|
|
105
|
-
-
|
|
106
|
-
-
|
|
107
|
-
-
|
|
108
|
-
-
|
|
109
|
-
-
|
|
110
|
-
- A further `caveats` entry when the concept resolved to an XBRL tag SEC has retired from the taxonomy — that only happens when no current tag reports for the filer, and the series can stop years short
|
|
111
|
-
- See `secedgar://concepts` resource for the full mapping
|
|
95
|
+
- Accepts accession numbers in dash or no-dash format; fetches the primary document or a specific exhibit by name
|
|
96
|
+
- Converts HTML filings to plain text; pre-2005 filings produce noisier output
|
|
97
|
+
- Configurable `content_limit` (1K–200K characters, default 50K)
|
|
98
|
+
- Binary entries (scanned pages, PDF exhibits, packaged archives/spreadsheets) are marked `binary` in the document catalog and rejected with a `binary_document` error rather than returned as decoded bytes
|
|
99
|
+
- Offset paging for large documents (10-K, S-1/A can exceed 1M chars) — pass a truncated response's `next_offset` as `offset` to continue; first-page truncated responses include a detected `outline` (headings + offsets)
|
|
100
|
+
- `section` jumps directly to a named heading by substring match ignoring case, whitespace style, and quote style (`"risk factors"`, `"item 7"`) — a miss returns the detected outline; extracted text is cached per `accession + document` (bounded LRU, 8 entries) so paged calls are cheap
|
|
112
101
|
|
|
113
102
|
---
|
|
114
103
|
|
|
115
|
-
### `
|
|
104
|
+
### `secedgar_get_financials` <sub>tool</sub>
|
|
105
|
+
|
|
106
|
+
- Friendly names (`"revenue"`, `"net_income"`, `"eps_diluted"`) auto-resolve to XBRL tags, including historical tag changes (e.g. ASC 606 revenue recognition) — see `secedgar://concepts` for the full mapping
|
|
107
|
+
- Automatic deduplication to one value per standard calendar period; filter by `period_type` (`annual`/`quarterly`/`all`)
|
|
108
|
+
- Optional `limit` caps the inline series to the most-recent N periods; the full series stays queryable via `df_<id>`
|
|
109
|
+
- `caveats` names every calendar quarter absent from the frame-tagged series — SEC reports fiscal Q4 as the 10-K residual, so the calendar quarter it spans carries no discrete quarterly value (calendar-year filers included), and a filer whose other fiscal quarters span non-calendar durations can lose a second quarter the same way
|
|
110
|
+
- A separate `caveats` entry appears when the concept resolved to an XBRL tag SEC has retired from the taxonomy — that only happens when no current tag reports for the filer, and the series can then stop years short
|
|
111
|
+
|
|
112
|
+
---
|
|
116
113
|
|
|
117
|
-
|
|
114
|
+
### `secedgar_get_snapshot` <sub>tool</sub>
|
|
118
115
|
|
|
119
|
-
- Reads the filer's complete companyfacts payload once
|
|
116
|
+
- Reads the filer's complete companyfacts payload once and resolves every supported concept against it — one call instead of a run of `secedgar_get_financials` calls
|
|
120
117
|
- Same frame dedup and tag priority as `secedgar_get_financials`, so the two agree for any concept they both cover
|
|
121
118
|
- 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
|
|
122
119
|
- Concepts the filer does not report are listed under `gaps` with the XBRL tags that were tried — never zero-filled or interpolated
|
|
123
|
-
- IFRS filers resolve through the mapped IFRS tag variants via `taxonomy: "ifrs-full"`,
|
|
124
|
-
- Compact single-record profile
|
|
120
|
+
- IFRS filers resolve through the mapped IFRS tag variants via `taxonomy: "ifrs-full"`, covering the income statement, balance sheet, cash flow, and per-share concepts; each line reports the taxonomy its value came from
|
|
121
|
+
- Compact single-record profile, no dataframe — reach for `secedgar_get_financials` when a time series is needed
|
|
125
122
|
|
|
126
123
|
---
|
|
127
124
|
|
|
128
|
-
### `
|
|
125
|
+
### `secedgar_get_material_events` <sub>tool</sub>
|
|
126
|
+
|
|
127
|
+
- Filter with `items` (e.g. `["2.02"]` results of operations, `["5.02"]` officer departures, `["4.02"]` non-reliance) — the only surface that scopes by what the event actually was, since `secedgar_search_filings` and `secedgar_company_search` cannot see item codes
|
|
128
|
+
- Two numbering regimes are both accepted and decoded: the dotted scheme in force since 2004-08-23, and single integers before it (legacy `12` is the ancestor of `2.02`, `9` of `7.01`); decoding keys off the code's shape so a filing straddling the changeover is never mis-decoded
|
|
129
|
+
- `item_distribution` counts every code across the scanned window before the filter, so a zero-hit filter still surfaces the items that are present
|
|
130
|
+
- A date window pages into the older submissions archive, reaching 8-K filings older than the ~1000-filing recent window; `history_scanned_through` discloses the scan depth
|
|
131
|
+
- The full decode table is in the `secedgar://filing-types` resource
|
|
132
|
+
- The full filtered set materializes as `df_<id>` with item codes on every row — item frequency over time is one `secedgar_dataframe_query` away
|
|
133
|
+
|
|
134
|
+
---
|
|
129
135
|
|
|
130
|
-
|
|
136
|
+
### `secedgar_get_insider_transactions` <sub>tool</sub>
|
|
131
137
|
|
|
138
|
+
- Parses Form 4 / 4-A insider transactions from ownership XML; Form 3 initial statements and Form 5 annual statements are not covered — reach those with `secedgar_search_filings` (`forms: ["3", "5"]`) plus `secedgar_get_filing`
|
|
132
139
|
- Reporting person, relationship to issuer (director, officer + title, 10% owner), and transaction date
|
|
133
|
-
- Transaction code mapped to a readable type (purchase, sale, gift, award, exercise, …); shares signed by acquired/disposed
|
|
134
|
-
- Price per share and shares owned after each transaction; covers non-derivative (open-market) and derivative (option/RSU) lines
|
|
140
|
+
- Transaction code mapped to a readable type (purchase, sale, gift, award, exercise, …); shares signed by acquired/disposed, price per share, and shares owned after each transaction; covers non-derivative (open-market) and derivative (option/RSU) lines
|
|
135
141
|
- Filter by `transaction_type` (`purchase`, `sale`, `all`); scans newest filings first
|
|
136
|
-
- The full set
|
|
142
|
+
- The full set parsed from the scanned recent filings materializes as `df_<id>` (the inline list is a preview capped at `limit`) — query it to aggregate net buy/sell by insider
|
|
137
143
|
|
|
138
144
|
---
|
|
139
145
|
|
|
140
|
-
### `secedgar_get_institutional_holdings`
|
|
141
|
-
|
|
142
|
-
Surface 13F-HR quarterly institutional holdings by parsing the information table.
|
|
146
|
+
### `secedgar_get_institutional_holdings` <sub>tool</sub>
|
|
143
147
|
|
|
144
148
|
- Pass the institutional filer (CIK or full legal name, e.g. `0000102909` for Vanguard) to see what it holds; for the reverse direction — which managers hold a given company — use `secedgar_find_holders`, whose `filer_cik` results feed straight back into this tool
|
|
145
149
|
- Each holding: issuer name, CUSIP, market value (whole USD), shares/principal, and put/call; raw rows also carry investment discretion
|
|
146
|
-
- Sub-lines for the same security
|
|
150
|
+
- Sub-lines for the same security are consolidated into distinct positions sorted by value by default — pass `consolidate: false` for raw filing rows
|
|
147
151
|
- Resolves the filing-manager name and reporting quarter from the cover page; target a specific quarter with `quarter` (e.g. `"2025-Q4"`)
|
|
148
|
-
- `total_holdings_in_filing` counts raw info-table rows
|
|
149
|
-
-
|
|
150
|
-
- The full parsed holdings set is materialized as a `df_<id>` dataframe (the inline list is one page of `limit` rows) — query it with `secedgar_dataframe_query` for full-filing aggregation or cross-quarter joins on `cusip` + `reporting_period`
|
|
152
|
+
- `total_holdings_in_filing` counts raw info-table rows, `total_positions` counts distinct positions after consolidation (both before `limit`); page with `offset`, which returns `next_offset` while rows remain
|
|
153
|
+
- The full parsed holdings set materializes as `df_<id>` for full-filing aggregation or cross-quarter joins on `cusip` + `reporting_period`
|
|
151
154
|
|
|
152
155
|
---
|
|
153
156
|
|
|
154
|
-
### `secedgar_find_holders`
|
|
157
|
+
### `secedgar_find_holders` <sub>tool</sub>
|
|
155
158
|
|
|
156
|
-
Reverse 13F lookup
|
|
157
|
-
|
|
158
|
-
- Searching by `cusip` matches the identifier the 13F information table itself carries — the precise path. Louisiana-Pacific Q1 2026 returns 451 filings by CUSIP `546347105` against 43 by the phrase `"LOUISIANA-PACIFIC CORP"`; the name path both under-matches (managers write the name differently) and over-matches (an unrelated issuer sharing a word)
|
|
159
|
+
- Reverse 13F lookup — which institutional managers reported a position in an issuer, for one reporting quarter. Searching by `cusip` matches the identifier the 13F information table itself carries (the precise path); the name path both under-matches (managers write names differently) and over-matches (unrelated issuers sharing a word)
|
|
159
160
|
- A CUSIP is not derivable from a ticker anywhere in EDGAR — read one off any `secedgar_get_institutional_holdings` result, or fall back to the name path
|
|
160
|
-
- `quarter` targets a reporting period (`"2026-Q1"`); omit it for the newest quarter whose 45-day filing deadline has passed
|
|
161
|
-
- Filings are kept by the period they report, not the date they were filed, so amendments restating an older quarter (roughly 6% of any window)
|
|
161
|
+
- `quarter` targets a reporting period (`"2026-Q1"`); omit it for the newest quarter whose 45-day filing deadline has passed — the applied quarter and its filing window are echoed back
|
|
162
|
+
- Filings are kept by the period they report, not the date they were filed, so amendments restating an older quarter (roughly 6% of any window) don't land in the wrong quarter's holder list
|
|
162
163
|
- Up to 500 filer rows are fetched per call; `total_filings` reports the full count and `dataset.truncated` flags when more exist
|
|
163
|
-
- **The list is unranked
|
|
164
|
+
- **The list is unranked** — EDGAR search relevance carries no signal about position size; read a manager's actual position by passing its `filer_cik` to `secedgar_get_institutional_holdings`
|
|
164
165
|
|
|
165
166
|
---
|
|
166
167
|
|
|
167
|
-
### `secedgar_get_beneficial_owners`
|
|
168
|
-
|
|
169
|
-
The 5%-and-over stakes in an issuer — the blockholder layer between Form 4 insiders and 13F portfolios. Input is the issuer, the company being held.
|
|
168
|
+
### `secedgar_get_beneficial_owners` <sub>tool</sub>
|
|
170
169
|
|
|
171
|
-
-
|
|
172
|
-
-
|
|
173
|
-
-
|
|
170
|
+
- The 5%-and-over stakes in an issuer — the blockholder layer between Form 4 insiders and 13F portfolios; input is the issuer, the company being held
|
|
171
|
+
- 13D is the activist form and carries the filer's stated purpose of the transaction; 13G is the passive form and has no purpose item at all — filter with `form_kind`
|
|
172
|
+
- Every reporting person is listed separately — 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 the same underlying shares, so summing those percentages double-counts the position
|
|
173
|
+
- Coverage starts **2024-12-18**, when SEC replaced the legacy `SC 13D` / `SC 13G` text filings with structured XML; earlier stakes are readable but not parseable, and `legacy_filings_before_coverage` reports how many the issuer has
|
|
174
174
|
- Amendments carry the current position and are included by default; `include_amendments=false` leaves only the filings that opened a position
|
|
175
|
-
- The full parsed set registers as
|
|
175
|
+
- The full parsed set registers as `df_<id>`, one row per reporting person, so it joins the insider and 13F dataframes on issuer CIK
|
|
176
176
|
|
|
177
177
|
---
|
|
178
178
|
|
|
179
|
-
### `secedgar_get_fund_holdings`
|
|
179
|
+
### `secedgar_get_fund_holdings` <sub>tool</sub>
|
|
180
180
|
|
|
181
|
-
What an ETF or mutual fund owns, from the NPORT-P portfolio report it files each quarter — the inverse of the ownership tools, which answer who owns a company.
|
|
182
|
-
|
|
183
|
-
-
|
|
184
|
-
- An NPORT-P covers exactly one fund series and a registrant trust files one report per series per period, so a trust running several funds needs the specific fund named. A registrant that resolves to more than one series comes back with the series listed, each with its ticker; one whose series carry no ticker is routed by reading the series off its newest report, because a trust's own filing history interleaves funds whose fiscal quarters end on different months
|
|
185
|
-
- Every result is dated to `report_period_date`. Reports publish roughly two months after the period they cover, so the holdings are the portfolio as of that date, not as of today; `publication_lag_days` states the gap. Target an earlier period with `report_date`, chosen from the `available_report_periods` in any response
|
|
181
|
+
- What an ETF or mutual fund owns, from the NPORT-P portfolio report it files each quarter — the inverse of the ownership tools, which answer who owns a company. Input is the fund: a ticker (`VOO`), a fund series ID (`S000002839`), or a CIK — name the registrant by CIK unless the fund itself trades under that name
|
|
182
|
+
- An NPORT-P covers exactly one fund series and a registrant trust files one report per series per period, so a trust running several funds needs the specific fund named; a registrant resolving to more than one series returns the series list with tickers, and one whose series carry no ticker is routed by reading the series off its newest report
|
|
183
|
+
- Every result is dated to `report_period_date` — reports publish roughly two months after the period they cover, so holdings are the portfolio as of that date, not as of today; `publication_lag_days` states the gap, and `report_date` targets an earlier period from `available_report_periods`
|
|
186
184
|
- Positions carry the security name, CUSIP/ISIN/LEI where the filer reports them, share balance, USD value, and percent of net assets, alongside fund-level net assets, total assets, and total liabilities
|
|
187
|
-
- Positions come back largest
|
|
188
|
-
|
|
189
|
-
---
|
|
190
|
-
|
|
191
|
-
### `secedgar_get_material_events`
|
|
192
|
-
|
|
193
|
-
A company's 8-K history with item codes decoded and filterable — the only surface that can scope by what the event actually was rather than by form.
|
|
194
|
-
|
|
195
|
-
- Filter with `items` (e.g. `["2.02"]` for results of operations, `["5.02"]` for officer departures, `["4.02"]` for non-reliance); `secedgar_search_filings` and `secedgar_company_search` cannot see items at all
|
|
196
|
-
- Two numbering regimes are both accepted and decoded: the dotted scheme in force since 2004-08-23, and the single integers before it (legacy `12` is the ancestor of `2.02`, `9` of `7.01`). Decoding keys off the code's shape, so a filing straddling the changeover is never mis-decoded, and a window spanning it needs both codes in the filter
|
|
197
|
-
- `item_distribution` counts every code across the scanned window before the filter, so a zero-hit filter comes back with the items that *are* present rather than a dead end
|
|
198
|
-
- A date window pages into the older submissions archive, reaching 8-K filings that predate the ~1000-filing recent window; `history_scanned_through` discloses the scan depth
|
|
199
|
-
- The full decode table is in the `secedgar://filing-types` resource
|
|
200
|
-
- The full filtered set materializes as a `df_<id>` dataframe with item codes on every row — item frequency over time is one `secedgar_dataframe_query` away
|
|
185
|
+
- Positions come back largest-first by percent of net assets, one page of `limit` rows from `offset`; the full report registers as `df_<id>` for aggregation and for joining the 13F and insider dataframes on CUSIP
|
|
201
186
|
|
|
202
187
|
---
|
|
203
188
|
|
|
204
|
-
### `secedgar_fetch_frames`
|
|
205
|
-
|
|
206
|
-
Fetch SEC XBRL frames for one concept × one period across all reporting companies.
|
|
189
|
+
### `secedgar_fetch_frames` <sub>tool</sub>
|
|
207
190
|
|
|
208
|
-
- Same friendly concept names as `secedgar_get_financials
|
|
191
|
+
- Same friendly concept names as `secedgar_get_financials`, or a raw XBRL tag
|
|
209
192
|
- Supports annual (`CY2023`), quarterly (`CY2024Q2`), and instant (`CY2023Q4I`) periods
|
|
210
|
-
- Inline response returns one page of the ranked companies (sort + limit), with ticker enrichment
|
|
211
|
-
-
|
|
212
|
-
- The full frames response (all reporters, typically 2k–10k rows) is materialized as a `df_<id>` dataframe — query it with `secedgar_dataframe_query`
|
|
193
|
+
- Inline response returns one page of the ranked companies (sort + limit), with ticker enrichment; walk further down the ranking with `offset`, which returns `next_offset` while companies remain
|
|
194
|
+
- The full frames response (all reporters, typically 2k–10k rows) materializes as `df_<id>`
|
|
213
195
|
- `related_tags` flags alternate-definition tags some filers use as their primary line (e.g. `cash` → restricted-cash-inclusive total, `equity` → NCI-inclusive total), so a whole-universe screen on the base tag isn't silently under-inclusive — query those separately
|
|
196
|
+
- One call hits one XBRL tag; when a friendly name maps to multiple same-meaning tags, `unqueried_tags` lists the others to query and combine with an analysis-specific priority
|
|
214
197
|
|
|
215
198
|
---
|
|
216
199
|
|
|
217
|
-
### `secedgar_compare_companies`
|
|
218
|
-
|
|
219
|
-
Compare 2-10 named companies across 1-8 concepts, aligned on calendar periods — the middle shape between `secedgar_get_financials` (one company over time) and `secedgar_fetch_frames` (one period across the market).
|
|
200
|
+
### `secedgar_compare_companies` <sub>tool</sub>
|
|
220
201
|
|
|
202
|
+
- Compares 2-10 named companies across 1-8 concepts, aligned on calendar periods — the middle shape between `secedgar_get_financials` (one company over time) and `secedgar_fetch_frames` (one period across the market)
|
|
221
203
|
- One companyfacts read per company, resolved through the same frame dedup and tag priority as `secedgar_get_financials`
|
|
222
204
|
- Balance-sheet and entity-info concepts align on the calendar year or quarter their point-in-time snapshot falls in, so they sit in the same matrix as income-statement lines; each cell keeps its underlying XBRL frame
|
|
223
|
-
- `periods` bounds the inline matrix (1-12, default 4)
|
|
224
|
-
- A company that fails to resolve is reported in `failed_companies` with a
|
|
225
|
-
-
|
|
226
|
-
- `caveats` surface a filer missing one or two calendar quarters, a concept that resolved to a retired XBRL tag for one company, period ends that differ inside one aligned period, and concepts whose unit differs across companies
|
|
205
|
+
- `periods` bounds the inline matrix (1-12, default 4), shrinking further when companies × concepts × periods is too large for one response; the full aligned series always materializes as `df_<id>`
|
|
206
|
+
- A company that fails to resolve is reported in `failed_companies` and the comparison proceeds with the rest; a company that does not report a concept is reported in `gaps` with the tags that were tried — never interpolated
|
|
207
|
+
- `caveats` surface a filer missing calendar quarters, a concept that resolved to a retired tag for one company, differing period ends inside one aligned period, and unit mismatches across companies
|
|
227
208
|
|
|
228
209
|
---
|
|
229
210
|
|
|
230
|
-
### `secedgar_search_concepts`
|
|
231
|
-
|
|
232
|
-
Discover supported XBRL concept names before querying financials or cross-company comparisons.
|
|
211
|
+
### `secedgar_search_concepts` <sub>tool</sub>
|
|
233
212
|
|
|
234
|
-
- Search by friendly name, label, or raw XBRL tag
|
|
213
|
+
- Search by friendly name, label, or raw XBRL tag; an empty search with no filters returns the full catalog
|
|
235
214
|
- Filter by statement group (`income_statement`, `balance_sheet`, `cash_flow`, `per_share`, `entity_info`) or taxonomy
|
|
236
215
|
- Reverse-lookup raw tags like `NetIncomeLoss` to the supported friendly names
|
|
237
216
|
- Surfaces `related_tags` for concepts with a high-coverage alternate-definition tag (e.g. restricted-cash-inclusive cash) so callers can discover them before screening
|
|
238
|
-
- Filtering by `taxonomy: "ifrs-full"` narrows the catalog to concepts with an IFRS tag confirmed against live 20-F
|
|
217
|
+
- Filtering by `taxonomy: "ifrs-full"` narrows the catalog to concepts with an IFRS tag confirmed against live 20-F filers — a concept with no IFRS equivalent is left out rather than mapped to a guess
|
|
239
218
|
- Returns the same catalog used by `secedgar_get_financials`, `secedgar_fetch_frames`, and `secedgar://concepts`
|
|
240
219
|
|
|
241
220
|
---
|
|
242
221
|
|
|
243
|
-
### `secedgar_dataframe_describe`
|
|
222
|
+
### `secedgar_dataframe_describe` <sub>tool</sub>
|
|
244
223
|
|
|
245
|
-
|
|
224
|
+
- Lists every dataframe (`df_XXXXX_XXXXX`) registered by the data-returning `secedgar_*` tools — any response carrying a `dataset` field holds one
|
|
225
|
+
- Optional `name` describes a single dataframe; omit to list every dataframe for the tenant
|
|
226
|
+
- 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
|
|
227
|
+
- Read the column schema here before writing SQL for `secedgar_dataframe_query`
|
|
246
228
|
|
|
247
|
-
|
|
248
|
-
- **Per-table TTL.** Each dataframe ages on its own clock (default 24h, override with `EDGAR_DATASET_TTL_SECONDS`). The canvas itself uses the framework's sliding TTL.
|
|
249
|
-
- **`register_as` chaining.** `secedgar_dataframe_query` can persist its result as a new dataframe (`df_XXXXX_XXXXX`) with a fresh TTL — pipe analyses without re-running the source query.
|
|
229
|
+
---
|
|
250
230
|
|
|
251
|
-
|
|
231
|
+
### `secedgar_dataframe_query` <sub>tool</sub>
|
|
252
232
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
233
|
+
- Runs a single-statement SELECT (standard DuckDB SQL — joins, aggregates, window functions, CTEs) against the dataframes registered by the data-returning `secedgar_*` tools
|
|
234
|
+
- Read-only: writes, DDL, DROP, COPY, PRAGMA, ATTACH, and external-file table functions are rejected by the framework SQL gate; system catalogs (`information_schema`, `pg_catalog`, `sqlite_master`, `duckdb_*`) are denied at the bridge layer so callers can't enumerate dataframes they don't already hold a handle for
|
|
235
|
+
- `row_limit` caps rows materialized in the response (default 1000, max 10000); a capped result reports `row_count_capped: true` with `row_count` as that cap rather than a total — a SQL `LIMIT` exactly equal to the cap is indistinguishable from an exact result and reported as such
|
|
236
|
+
- `register_as` persists the result as a new dataframe (`df_XXXXX_XXXXX`) with a fresh TTL, to chain analyses without re-running the source query
|
|
237
|
+
- BIGINT columns (XBRL `value`, COUNT/SUM results) serialize as JSON strings to preserve precision past 2^53 — cast to `DOUBLE` in projections for inline arithmetic
|
|
257
238
|
|
|
258
|
-
|
|
239
|
+
---
|
|
259
240
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
241
|
+
### `secedgar_dataframe_drop` <sub>tool</sub>
|
|
242
|
+
|
|
243
|
+
- Drops a canvas dataframe by name; idempotent — returns `dropped: false` when nothing matched
|
|
244
|
+
- Opt-in via `EDGAR_DATAFRAME_DROP_ENABLED=true` — off by default since the per-table TTL already reclaims canvas tables, and this is the only destructive tool on the server
|
|
245
|
+
- Off, the tool is registered through `disabledTool()`: absent from `tools/list` and uncallable, but shown on the HTTP landing page in a `disabled` group naming the reason and the flag that enables it
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
### `secedgar://concepts` <sub>resource</sub>
|
|
250
|
+
|
|
251
|
+
- XBRL financial concepts grouped by statement (Income Statement, Balance Sheet, Cash Flow, Per Share, Entity Info), returned as `text/markdown`
|
|
252
|
+
- Maps the friendly names accepted by `secedgar_get_financials` and `secedgar_fetch_frames` to their underlying XBRL tags
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
### `secedgar://filing-types` <sub>resource</sub>
|
|
257
|
+
|
|
258
|
+
- Common SEC filing types with descriptions, cadence, and typical use cases, returned as `text/markdown`
|
|
259
|
+
- Includes the full 8-K item-code decode tables for both numbering regimes (the current dotted scheme and the pre-2004-08-23 legacy integers)
|
|
260
|
+
- Helps choose the `forms` parameter for `secedgar_search_filings`, the `form_types` filter for `secedgar_company_search`, or the `items` filter for `secedgar_get_material_events`
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
### `secedgar_company_analysis` <sub>prompt</sub>
|
|
265
|
+
|
|
266
|
+
- Arguments: `company` (name, ticker, or CIK) required; `focus_areas` free-text optional (e.g. `"revenue growth, debt levels, insider activity"`) — omitted, it performs a general analysis
|
|
267
|
+
- Baseline workflow: company identification, financial trends, recent-filing review, and material events, each routed through the corresponding `secedgar_*` tool, closing with a peer comparison via `secedgar_fetch_frames`
|
|
268
|
+
- `focus_areas` mentioning insider, institutional, or blockholder/activist terms adds the matching ownership step — insider transactions (Form 4/4-A), institutional holdings (`secedgar_find_holders` then `secedgar_get_institutional_holdings`), or 5%+ blockholders (13D/13G) — the generic word "ownership" adds all three
|
|
269
|
+
- Returns a single user-role message carrying the numbered workflow and a findings template to fill in
|
|
263
270
|
|
|
264
271
|
## Features
|
|
265
272
|
|
|
266
|
-
Built on [`@cyanheads/mcp-ts-core`](https://github.com/cyanheads/mcp-ts-core):
|
|
273
|
+
Built on [`@cyanheads/mcp-ts-core`](https://github.com/cyanheads/mcp-ts-core): stdio and Streamable HTTP transports, pluggable auth (`none` / `jwt` / `oauth`), swappable storage (`in-memory`, `filesystem`, `Supabase`, `Cloudflare KV/R2/D1`), structured logging with optional OpenTelemetry tracing.
|
|
274
|
+
|
|
275
|
+
EDGAR-specific:
|
|
267
276
|
|
|
268
|
-
-
|
|
269
|
-
-
|
|
270
|
-
-
|
|
271
|
-
-
|
|
272
|
-
-
|
|
273
|
-
- Runs locally (stdio/HTTP) from the same codebase
|
|
277
|
+
- Rate-limited HTTP client honoring SEC's 10 req/s limit with automatic inter-request delay; a 429 fails fast with a cool-down hint instead of retrying, since SEC's own block window outlasts any retry budget
|
|
278
|
+
- CIK resolution from tickers (including ETFs and mutual funds via `company_tickers_mf.json`), current and former company names, or raw CIK numbers, with local caching, corporate-suffix normalization, and near-match trigram suggestions on zero-result queries
|
|
279
|
+
- Friendly XBRL concept name mapping with historical tag-change handling and a searchable, reverse-lookupable concept catalog
|
|
280
|
+
- HTML-to-text conversion for filing documents, with heading detection and offset-based paging for oversized filings
|
|
281
|
+
- Opt-in local SQLite mirror of `company_tickers` + XBRL company-facts (`EDGAR_MIRROR_ENABLED`) serves CIK resolution and financials from disk instead of the live API
|
|
274
282
|
|
|
275
|
-
|
|
283
|
+
Agent-friendly output:
|
|
276
284
|
|
|
277
|
-
-
|
|
278
|
-
-
|
|
279
|
-
-
|
|
280
|
-
-
|
|
281
|
-
- HTML-to-text conversion for filing documents via `html-to-text`
|
|
282
|
-
- In-conversation SQL analytics: `secedgar_fetch_frames`, `secedgar_compare_companies`, `secedgar_search_filings`, `secedgar_get_financials`, `secedgar_get_material_events`, `secedgar_get_insider_transactions`, `secedgar_get_institutional_holdings`, and `secedgar_find_holders` materialize their full result as a DuckDB-backed canvas dataframe queryable via `secedgar_dataframe_query`
|
|
283
|
-
- No API keys required — SEC EDGAR is a free, public API
|
|
285
|
+
- In-conversation SQL analytics — data-returning tools materialize their full result as a DuckDB-backed canvas dataframe (`df_<id>`); inspect its columns with `secedgar_dataframe_describe`, then query with `secedgar_dataframe_query`
|
|
286
|
+
- Discriminated outputs — `source` fields on merged filing-search rows (`efts`/`submissions`/`full-index`), typed `caveats` entries for series staleness and fiscal-Q4 gaps, and `gaps`/`failed_companies` rows instead of silent omission
|
|
287
|
+
- Graceful partial failure — `secedgar_compare_companies` returns every resolved company alongside `failed_companies` and per-concept `gaps` rather than failing the whole request
|
|
288
|
+
- Provenance on scan and staleness — `history_scanned_through`, `publication_lag_days`, and `dataset.truncated` let agents reason about scan depth, report lag, and completeness
|
|
284
289
|
|
|
285
290
|
## Getting started
|
|
286
291
|
|
|
@@ -337,6 +342,25 @@ Or with npx (no Bun required):
|
|
|
337
342
|
}
|
|
338
343
|
```
|
|
339
344
|
|
|
345
|
+
Or with Docker:
|
|
346
|
+
|
|
347
|
+
```json
|
|
348
|
+
{
|
|
349
|
+
"mcpServers": {
|
|
350
|
+
"secedgar-mcp-server": {
|
|
351
|
+
"type": "stdio",
|
|
352
|
+
"command": "docker",
|
|
353
|
+
"args": [
|
|
354
|
+
"run", "-i", "--rm",
|
|
355
|
+
"-e", "MCP_TRANSPORT_TYPE=stdio",
|
|
356
|
+
"-e", "EDGAR_USER_AGENT=YourAppName your-email@example.com",
|
|
357
|
+
"ghcr.io/cyanheads/secedgar-mcp-server:latest"
|
|
358
|
+
]
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
```
|
|
363
|
+
|
|
340
364
|
For Streamable HTTP, set the transport and start the server:
|
|
341
365
|
|
|
342
366
|
```sh
|
|
@@ -346,7 +370,8 @@ MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 bun run start:http
|
|
|
346
370
|
|
|
347
371
|
### Prerequisites
|
|
348
372
|
|
|
349
|
-
- [Bun v1.3.0](https://bun.sh/) or higher.
|
|
373
|
+
- [Bun v1.3.0](https://bun.sh/) or higher (or Node.js v24+).
|
|
374
|
+
- A SEC EDGAR User-Agent string — any `"AppName contact@email.com"` format works; no account or key required.
|
|
350
375
|
|
|
351
376
|
### Installation
|
|
352
377
|
|
|
@@ -384,18 +409,20 @@ All configuration is validated at startup via Zod schemas in `src/config/server-
|
|
|
384
409
|
| `EDGAR_RATE_LIMIT_RPS` | Max requests/second to SEC APIs. Do not exceed 10. | `10` |
|
|
385
410
|
| `EDGAR_TICKER_CACHE_TTL` | Seconds to cache the company tickers lookup file. | `3600` |
|
|
386
411
|
| `EDGAR_DATASET_TTL_SECONDS` | Per-table TTL for canvas-registered dataframes. Sliding window touched on every dataframe op. | `86400` |
|
|
387
|
-
| `EDGAR_DATAFRAME_DROP_ENABLED` | Set to `true` to expose `secedgar_dataframe_drop` — the only destructive tool on this server. Off by default; TTL handles cleanup. | `false` |
|
|
412
|
+
| `EDGAR_DATAFRAME_DROP_ENABLED` | Set to `true` to expose `secedgar_dataframe_drop` — the only destructive tool on this server. Off by default; TTL handles cleanup, and the tool is still listed on the HTTP landing page as disabled, with the flag that enables it. | `false` |
|
|
388
413
|
| `EDGAR_MIRROR_ENABLED` | Enable the local SQLite mirror of `company_tickers` + XBRL company-facts so CIK resolution and financials read from disk instead of the live API. Node/Bun only (skipped on Workers). Bootstrap once with `bun run mirror:init`. | `false` |
|
|
389
414
|
| `EDGAR_MIRROR_PATH` | Directory holding the mirror SQLite databases. | `./data/edgar-mirror` |
|
|
390
415
|
| `EDGAR_MIRROR_REFRESH_CRON` | Cron for the in-process nightly refresh (HTTP transport only). Recommended `0 9 * * *`. Omit to refresh out-of-band via `bun run mirror:refresh`. | — |
|
|
391
416
|
| `EDGAR_MIRROR_FALLBACK_LIVE` | When the mirror misses (not yet synced, or a filing newer than the last refresh), fall back to the live SEC API. Set `false` for strict mirror-only reads. | `true` |
|
|
392
|
-
| `CANVAS_PROVIDER_TYPE` | Canvas engine. Defaults to `duckdb`; set to `none` to disable the canvas
|
|
417
|
+
| `CANVAS_PROVIDER_TYPE` | Canvas engine. Defaults to `duckdb`; set to `none` to disable the canvas. | `duckdb` |
|
|
393
418
|
| `MCP_TRANSPORT_TYPE` | Transport: `stdio` or `http` | `stdio` |
|
|
394
419
|
| `MCP_HTTP_PORT` | HTTP server port | `3010` |
|
|
395
420
|
| `MCP_AUTH_MODE` | Authentication: `none`, `jwt`, or `oauth` | `none` |
|
|
396
421
|
| `MCP_LOG_LEVEL` | Log level (`debug`, `info`, `warning`, `error`, etc.) | `info` |
|
|
397
422
|
| `LOGS_DIR` | Directory for log files (Node.js only). | `<project-root>/logs` |
|
|
398
423
|
|
|
424
|
+
See [`.env.example`](./.env.example) for the full list of optional overrides.
|
|
425
|
+
|
|
399
426
|
## Running the server
|
|
400
427
|
|
|
401
428
|
### Local development
|
|
@@ -432,7 +459,7 @@ docker exec <container> bun run mirror:refresh # re-ingest when the archive ha
|
|
|
432
459
|
|
|
433
460
|
| Directory | Purpose |
|
|
434
461
|
|:---|:---|
|
|
435
|
-
| `src/mcp-server/tools/definitions/` | Tool definitions (`*.tool.ts`).
|
|
462
|
+
| `src/mcp-server/tools/definitions/` | Tool definitions (`*.tool.ts`). Fourteen SEC EDGAR tools plus three `dataframe_*` tools for SQL analytics. |
|
|
436
463
|
| `src/mcp-server/resources/definitions/` | Resource definitions. XBRL concepts and filing types. |
|
|
437
464
|
| `src/mcp-server/prompts/definitions/` | Prompt definitions. Company analysis prompt. |
|
|
438
465
|
| `src/services/edgar/` | SEC EDGAR API client, XBRL concept mapping, HTML-to-text conversion. |
|
|
@@ -447,10 +474,11 @@ See [`CLAUDE.md`](./CLAUDE.md) and [`AGENTS.md`](./AGENTS.md) for development gu
|
|
|
447
474
|
- Handlers throw, framework catches — no `try/catch` in tool logic
|
|
448
475
|
- Use `ctx.log` for logging, `ctx.state` for storage
|
|
449
476
|
- Register new tools and resources in the `createApp()` arrays
|
|
477
|
+
- Wrap external SEC EDGAR calls: validate the raw response → normalize to a domain type → return the output schema; never fabricate a missing XBRL field — report it under `gaps` instead
|
|
450
478
|
|
|
451
479
|
## Contributing
|
|
452
480
|
|
|
453
|
-
Issues
|
|
481
|
+
Issues are welcome. Run checks and tests before submitting:
|
|
454
482
|
|
|
455
483
|
```sh
|
|
456
484
|
bun run devcheck
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "Initial release. MCP server for SEC EDGAR — company lookups, filing search/retrieval, XBRL financial data, and cross-company comparison."
|
|
3
|
+
breaking: false
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 0.1.0 — 2026-03-24
|
|
7
|
+
|
|
8
|
+
Initial release. MCP server for SEC EDGAR — company lookups, filing search/retrieval, XBRL financial data, and cross-company comparison.
|
|
9
|
+
|
|
10
|
+
## Added
|
|
11
|
+
|
|
12
|
+
- **Tools**
|
|
13
|
+
- `secedgar_company_search` — find companies and retrieve entity info with optional recent filings
|
|
14
|
+
- `secedgar_search_filings` — full-text search across all EDGAR filing documents since 1993
|
|
15
|
+
- `secedgar_get_filing` — fetch a specific filing's metadata and document content
|
|
16
|
+
- `secedgar_get_financials` — get historical XBRL financial data for a company (friendly concept names supported)
|
|
17
|
+
- `secedgar_compare_metric` — compare a financial metric across all reporting companies for a period
|
|
18
|
+
- **Resources**
|
|
19
|
+
- `secedgar://concepts` — XBRL financial concepts grouped by statement, mapping friendly names to tags
|
|
20
|
+
- `secedgar://filing-types` — common SEC filing types with descriptions, cadence, and use cases
|
|
21
|
+
- **Prompts**
|
|
22
|
+
- `secedgar_company_analysis` — guided structured analysis of a company's SEC filings
|
|
23
|
+
- **Services**
|
|
24
|
+
- `EdgarApiService` — rate-limited HTTP client with CIK resolution and ticker caching
|
|
25
|
+
- `concept-map` — static friendly name → XBRL tag mapping (handles ASC 606 historical tag changes)
|
|
26
|
+
- `filing-to-text` — HTML → readable plain text conversion via `html-to-text`
|
|
27
|
+
- **Infrastructure**
|
|
28
|
+
- Dockerfile and `.dockerignore` for containerized deployment
|
|
29
|
+
- Biome for linting and formatting
|
|
30
|
+
- Vitest test scaffolding
|
|
31
|
+
- Build scripts (build, clean, rebuild, devcheck, tree, lint-mcp)
|
|
32
|
+
- Stdio and HTTP transport support
|
|
33
|
+
- Design document (`docs/sec-edgar-mcp-design.md`)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "Metadata, documentation, and packaging polish — no functional changes."
|
|
3
|
+
breaking: false
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 0.1.1 — 2026-03-24
|
|
7
|
+
|
|
8
|
+
Metadata, documentation, and packaging polish — no functional changes.
|
|
9
|
+
|
|
10
|
+
## Added
|
|
11
|
+
|
|
12
|
+
- `README.md` with full tool/resource/prompt docs, configuration, and getting started guide
|
|
13
|
+
- `LICENSE` file (Apache 2.0)
|
|
14
|
+
- `bunfig.toml` for Bun runtime configuration
|
|
15
|
+
- `docs/tree.md` directory structure
|
|
16
|
+
|
|
17
|
+
## Changed
|
|
18
|
+
|
|
19
|
+
- `.env.example` — replaced template placeholders with SEC EDGAR env vars
|
|
20
|
+
- `CLAUDE.md` — added `lint:mcp` command, fixed import example to use real service path
|
|
21
|
+
- `Dockerfile` — added OCI description and source labels
|
|
22
|
+
- `package.json` — filled in description, mcpName, keywords, repository URLs, author, bun engine, packageManager
|
|
23
|
+
- `server.json` — filled in name/description/repo URL, set runtimeHint to bun, added `EDGAR_USER_AGENT` env var
|
|
24
|
+
|
|
25
|
+
## Removed
|
|
26
|
+
|
|
27
|
+
- Template echo tests (`echo.tool.test.ts`, `echo.resource.test.ts`, `echo.prompt.test.ts`)
|