edgar-mcp
An MCP server that enables models to access SEC EDGAR filings, filing text, and XBRL financial facts with caching, rate limiting, and iXBRL stripping.
README
edgar-mcp
An MCP server that gives a model working access to SEC EDGAR — company filings, filing text, and XBRL financial facts.
Verification launch kit
| Inspect | Published evidence |
|---|---|
| Strongest result | Warm 10-K reads reach 1.1 ms / 0.00 MB, measured at 138x the cold fetch |
| Verification | Wire-level request windows, transferred-byte counters, offline fixtures, and burst tests |
| Failure boundary | Public EDGAR data only; not an investment recommendation or a complete accounting model |
| Reproduce | make test && make bench |
| Interactive replay | Replay the burst and false cache hit |
Evidence contract: a class named
RateLimiterorCacheproves nothing by itself. The benchmark measures grants inside a real one-second window and bytes transferred on the wire.
→ Interactive results page — fire a burst of tool calls and watch a full token bucket sail through the limit it was written to enforce, then see what each EDGAR host can actually validate.
EDGAR will happily hand you a 9 MB filing and then throttle you for asking twice. The interesting part of this server is everything between the model and the wire.
What is actually implemented
- ticker, CIK, or company name resolves to an EDGAR identity, with ambiguous names returning candidates instead of a silent wrong guess;
- filing history spans EDGAR's overflow files, so companies past ~1000 filings don't get silently truncated to the recent page;
- filing text arrives windowed with a
next_offsetcursor — a 10-K is ~206K characters and does not belong in a context window whole; - inline-XBRL scaffolding is stripped, so extracted text starts at the prose
and not at 11K characters of
false2025FY0000320193...; - XBRL concepts come back as a time series, with a tag-discovery tool because nobody knows the right us-gaap tag name off the top of their head;
- one metric can be ranked across every filer for a period via the frames API;
- full-text search covers filings from 2001 onward;
- requests are paced under SEC's 10 req/s ceiling even when a model fires a parallel burst of tool calls;
- responses are cached per-host by the freshness rule that host actually supports.
flowchart LR
M["model tool call"] --> R["resolve ticker / CIK / name"]
R --> C{"cached?"}
C -->|"Archives: immutable"| D["disk, no network"]
C -->|"data.sec.gov: TTL fresh"| D
C -->|"stale or absent"| P["pacer @ 9 req/s"]
P --> E["EDGAR"]
E -->|"429 / 5xx"| P
E --> W["cache write"]
W --> X["iXBRL strip + window"]
D --> X
X --> M
Measured, not implied
Apple M-series, macOS, Python 3.13, live EDGAR. Reproduce with make bench.
| Check | Result |
|---|---|
| Tests passing | 32 |
companyfacts cold fetch |
3.75 MB / 97 ms |
companyfacts warm read |
0.00 MB / 1.4 ms (68×) |
| 10-K document cold fetch | 1.52 MB / 154 ms |
| 10-K document warm read | 0.00 MB / 1.1 ms (138×) |
submissions warm read |
0.00 MB / 0.2 ms (755×) |
| Sustained request rate | 9.2 req/s |
| Peak requests in any 1s window | 10 (SEC ceiling: 10) |
| iXBRL scaffolding removed from a 10-K | 11,303 chars |
| Text extraction throughput | 23.4 MB/s |
| Windows to read a full 10-K @ 40K | 6 |
Both the cache and pacer numbers above are post-fix. The first benchmark run reported a 3.75 MB "cache hit" that was really a full re-download, and 19 requests inside a one-second window against a 10 req/s limit. See DESIGN.md.
Where it loses
- Freshness on
data.sec.govis a guess. That host sends noETagand noLast-Modified, so conditional requests are impossible and freshness falls back to a 1-hour TTL. A filing that lands mid-TTL is invisible until it expires. Passttl=0if you need read-your-writes. - Windowing re-reads, it doesn't range-read. EDGAR honors HTTP
Rangeon Archives (verified:206,accept-ranges: bytes), but partial HTML can't be parsed reliably, so the whole document is fetched once and windowed from cache. The first call on a large filing pays the full download. - Search is never cached. Results are query-shaped and EDGAR's full-text endpoint offers no validators, so every search is a live round trip against the 9 req/s budget.
- The pacer is global. Ten companies queried in parallel serialize at ~9 req/s. Correct, but not fast.
- XBRL values are consolidated totals. Dimensional breakdowns (by segment, by geography) exist in the data and this does not surface them.
- Full-text search starts at 2001. Older filings are reachable through
list_filings, notsearch_filings.
Verify it
make test # 32 tests, no network
make bench # live EDGAR, prints the table above
Setup
SEC requires a User-Agent carrying a real contact address and blocks requests without one. The server refuses to start rather than letting you discover that as a confusing 403 later.
export EDGAR_USER_AGENT="your-project you@example.com"
Build and run the local container over stdio:
docker build -t edgar-mcp:local .
docker run --rm -i \
-e EDGAR_USER_AGENT="your-project you@example.com" \
edgar-mcp:local
The image runs as an unprivileged user and writes its EDGAR cache under that
user's home directory. Mount /home/edgar/.cache/edgar-mcp if the cache should
survive container restarts.
Add to claude_desktop_config.json or .mcp.json:
{
"mcpServers": {
"edgar": {
"command": "uv",
"args": ["run", "--directory", "/path/to/edgar-mcp", "edgar-mcp"],
"env": { "EDGAR_USER_AGENT": "your-project you@example.com" }
}
}
}
Tools
| Tool | Purpose |
|---|---|
lookup_company |
ticker / CIK / name → EDGAR identity |
list_filings |
filing history, filtered by form and date |
get_filing_text |
windowed document text, follow next_offset |
list_concepts |
which XBRL tags a company actually reports |
get_concept |
time series for one tag |
compare_concept |
one tag ranked across all filers for a period |
search_filings |
full-text search, 2001→ |
cache_stats |
hit rate, requests, bytes downloaded |
A typical chain is lookup_company → list_filings → get_filing_text, or
list_concepts → get_concept when you want numbers rather than prose.
License
MIT
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。
mcp-server-qdrant
这个仓库展示了如何为向量搜索引擎 Qdrant 创建一个 MCP (Managed Control Plane) 服务器的示例。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。