AI编码
dev.to ·
@MonRiah Studio
为 AI Agent 接入 SEC EDGAR 数据:免费远程 MCP 服务器,覆盖内幕交易与 XBRL 财务数据
介绍一个 MIT 许可的免费远程 MCP 服务器,通过 Streamable HTTP 端点让 Claude、Cursor、VS Code 等 AI 客户端调用美国 SEC EDGAR 数据,覆盖内幕交易、10-K、8-K 和 XBRL 财务事实,无需安装或 API Key。文章说明 SEC 公平访问政策要求声明 User-Agent 并限制每秒请求数,并称将展示三次真实调用输出及局限,但摘要未包含实际输出。
AI推荐理由 提供可验证的免费 MIT 许可远程 MCP 服务器,封装 SEC EDGAR 的内幕交易与 XBRL 财务数据,含端点、GitHub 源码和 MCP Registry 名称,并说明 SEC User-Agent 与限速约束;作者自述会展示真实调用输出和局限,但正文片段未给出实际输出,实际效果仍需自行验证。
72
正文
MCP (Model Context Protocol) is an open standard that lets an AI client such as Claude, Cursor or VS Code call external tools through one common interface.
This post walks through a free, MIT-licensed MCP server for U.S. SEC EDGAR data. It runs remotely, so there's nothing to install and no API key. I'll show how to connect it, three real calls with their actual output, how it works inside, and where it falls short.
Endpoint (Streamable HTTP, no key): https://sec-edgar-api.kidriahx.workers.dev/mcp
Source: https://github.com/monriah-studio/sec-edgar-mcp-remote
MCP Registry name: io.github.monriah-studio/sec-edgar-mcp
Why EDGAR needs a wrapper
EDGAR is one of the best free financial datasets around: every insider trade, 10-K, 8-K and XBRL financial fact that U.S. public companies file. It's also awkward to use, especially for an agent:
The User-Agent rule. SEC's fair-access policy asks every client to send a declared User-Agent with a contact email and to stay under 10 requests per second. Requests that skip this get 403s. An LLM making fetches on its own won't know that.
CIK lookup. Most endpoints want a 10-digit Central Index Key (0000320193), not a ticker (AAPL). You have to look it up in a roughly 1 MB company_tickers.json file first.
Form 4 is XML. Insider trades come as one XML document per filing, full of transaction codes (P, S, A, M, F, G), derivative tables and footnotes.
XBRL is messy. The companyconcept JSON repeats the same period across many filings and mixes 3-month, 9-month and 12-month durations. Getting "net income by fiscal year" out of it means filtering and de-duplicating.
The server does all of this and returns compact JSON.
The seven tools
Tool
What it returns
get_insider_trades
Form 4 transactions for a company or an insider, with buy/sell totals and a 10b5-1 flag
get_market_insider_buys
Open-market insider purchases across the market, grouped by company, with cluster-buy detection (2+ insiders)
get_company_filings
Latest 10-K, 10-Q, 8-K (with item numbers) and other filings, with document links
get_company_snapshot
Revenue, margins, net income, EPS, cash flow, balance sheet and YoY growth from XBRL
get_company_concept
Annual or quarterly history of any XBRL tag
search_filings
EDGAR full-text search with phrase, form and date filters
resolve_company
Ticker ↔ CIK lookup
Every tool takes a ticker or a CIK, and all of them are marked read-only.
Connect a client
Cursor: add this to ~/.cursor/mcp.json (or .cursor/mcp.json in a project):
{
"mcpServers": {
"sec-edgar": {
"url": "https://sec-edgar-api.kidriahx.workers.dev/mcp"
}
}
}
Enter fullscreen mode
Exit fullscreen mode
VS Code (Copilot agent mode): add this to .vscode/mcp.json:
{
"servers": {
"sec-edgar": {
"type": "http",
"url": "https://sec-edgar-api.kidriahx.workers.dev/mcp"
}
}
}
Enter fullscreen mode
Exit fullscreen mode
Claude Desktop: on plans that support custom connectors, add the URL under Settings → Connectors. You can also bridge it through claude_desktop_config.json with the mcp-remote package (needs Node.js):
{
"mcpServers": {
"sec-edgar": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://sec-edgar-api.kidriahx.workers.dev/mcp"]
}
}
}
Enter fullscreen mode
Exit fullscreen mode
Claude Code: claude mcp add --transport http sec-edgar https://sec-edgar-api.kidriahx.workers.dev/mcp
Then try prompts like "Show NVIDIA's last insider sales and whether they were under 10b5-1 plans" or "Which companies had cluster insider buying this week?"
Three real calls with curl
The server is stateless, so you don't need an SDK to test it. Every request is a single JSON-RPC POST. Start with initialize:
URL=https://sec-edgar-api.kidriahx.workers.dev/mcp
curl -s $URL \
-H 'content-type: application/json' \
-H 'accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl","version":"1"}}}'
Enter fullscreen mode
Exit fullscreen mode
{"result":{"protocolVersion":"2025-06-18","capabilities":{"tools":{}},"serverInfo":{"name":"sec-edgar-mcp","title":"SEC EDGAR Insider Trades & Financials","version":"1.0.0"}, ...},"jsonrpc":"2.0","id":1}
Enter fullscreen mode
Exit fullscreen mode
Each tool result comes back as JSON text in result.content[0].text. The outputs below are pretty-printed and trimmed (...). I ran them on October 23, 2026, so your numbers will differ.
1. NVIDIA insider trades
curl -s $URL -H 'content-type: application/json' -H 'accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"get_insider_trades","arguments":{"ticker_or_cik":"NVDA","filings":5,"max_rows":5}}}'
Enter fullscreen mode
Exit fullscreen mode
{
"company": {"id": "NVDA", "cik": "0001045810", "ticker": "NVDA", "name": "NVIDIA CORP"},
"filingsParsed": 5,
"summary": {"transactions": 8, "openMarketBuys": 0, "openMarketSells": 5,
"sellShares": 1396460, "sellValueUsd": 306933627.99, "distinctInsiders": 5},
"returned": 5,
"transactions": [
{"date": "2026-09-21", "insider": "Teter Timothy S.", "role": "EVP, General Counsel and Sec",
"code": "S", "shares": 12483, "price": 222.1932, "valueUsd": 2773637.72,
"ownedAfter": 2705637, "plan10b51": true, "filed": "2026-09-23",
"url": "https://www.sec.gov/Archives/edgar/data/1045810/000169684126000014/wk-form4_1790196985.xml"},
...
]
}
Enter fullscreen mode
Exit fullscreen mode
On a cold cache, that call made 7 requests to SEC: the ticker map, the company's submissions index and five Form 4 XML files. The response header x-sec-requests: 7 reports the count.
2. Apple net income from XBRL
curl -s $URL -H 'content-type: application/json' -H 'accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"get_company_concept","arguments":{"ticker_or_cik":"AAPL","concept":"NetIncomeLoss","period":"annual","limit":4}}}'
Enter fullscreen mode
Exit fullscreen mode
{
"company": {"name": "Apple Inc.", "cik": "0000320193"},
"concept": "us-gaap:NetIncomeLoss",
"label": "Net Income (Loss) Attributable to Parent",
"unit": "USD", "period": "annual", "totalPeriods": 19,
"values": [
{"value": 112010000000, "start": "2024-09-29", "end": "2025-09-27", "fy": 2025, "form": "10-K", "filed": "2025-10-31"},
{"value": 93736000000, "start": "2023-10-01", "end": "2024-09-28", "fy": 2025, "form": "10-K", "filed": "2025-10-31"},
{"value": 96995000000, "start": "2022-09-25", "end": "2023-09-30", "fy": 2025, "form": "10-K", "filed": "2025-10-31"},
...
]
}
Enter fullscreen mode
Exit fullscreen mode
Look at fy. It's SEC's fiscal year of the filing that reported the value, not of the period, so the FY2024 figure shows fy: 2025. Use start/end to know which period a value belongs to.
3. Cluster buys across the market
curl -s $URL -H 'content-type: application/json' -H 'accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"get_market_insider_buys","arguments":{"days":7,"min_insiders":2,"limit":3}}}'
Enter fullscreen mode
Exit fullscreen mode
{
"window": {"days": 7, "from": "2026-10-17", "to": "2026-10-24"},
"dataUpdatedAt": "2026-10-24T04:40:38.877Z",
"issuers": 3, "clusterBuys": 3,
"results": [
{"ticker": "RAPP", "issuer": "Rapport Therapeutics, Inc.", "insiderCount": 6, "clusterBuy": true,
"totalValueUsd": 1664824.35, "totalShares": 61694, "avgPrice": 26.9852,
"firstDate": "2026-10-21", "lastDate": "2026-10-23",
"insiders": [{"name": "Ignelzi Troy A.", "role": "Chief Financial Officer", "valueUsd": 143550}, ...]},
{"ticker": "CHCO", "issuer": "CITY HOLDING CO", "insiderCount": 4, "totalValueUsd": 68222.4, ...},
{"ticker": "RENT", "issuer": "Rent the Runway, Inc.", "insiderCount": 3, "totalValueUsd": 6120515.95, ...}
],
"note": "Open-market, non-derivative purchases only. Not investment advice."
}
Enter fullscreen mode
Exit fullscreen mode
This call made zero SEC requests because it reads from a pre-built store (more on that below). Dates are UTC, which is why the window ends on the 24th.
How it works
The whole thing is one Cloudflare Worker on the free plan:
MCP transport. /mcp uses the official MCP TypeScript SDK's web-standard Streamable HTTP transport in stateless JSON mode. There are no sessions and no Durable Object per client. Each POST stands alone, and GET/DELETE return 405. Each tool maps to one REST endpoint, and a compact() function trims the REST JSON down to fewer fields and capped rows so it doesn't fill the model's context. The same Worker also serves that REST API (/v1/..., documented in openapi.yaml).
SEC etiquette. Every request to SEC carries a declared User-Agent with a contact email. Requests are spaced at least 115 ms apart, and a global Durable Object rate limiter hands out time slots so that all Worker isolates together stay near 8.7 req/s, under SEC's 10 req/s ceiling. On 429/5xx the Worker backs off (honoring Retry-After) and retries up to three times. A 403 gets one retry and then a clear error.
Caching. Lookups go through three layers: isolate memory, then the Cloudflare Cache API, then KV for selected keys. TTLs follow how often the data changes. The ticker map and resolutions are cached for 24 h, parsed Form 4s for 30 days (filings don't change), submissions for 10 min, XBRL snapshots and concepts for 6 h, and full-text search for 15 min.
Market-wide buys. A cron runs every 10 minutes. It queries EDGAR full-text search for new Form 4s, parses up to 40 per run, and keeps open-market purchases (code P, non-derivative) in a KV store. get_market_insider_buys groups that store by issuer.
Ticker resolution. The ticker file is searched with a regex instead of JSON.parse, which keeps it inside the free plan's CPU budget.
Limits and caveats
Shallow per-call history. get_insider_trades parses at most 25 recent Form 4 filings per call (default 5). The free plan allows about 50 subrequests per invocation, so this isn't a tool for pulling ten years of history.
Market scan coverage. The cluster-buy data covers at most 30 days and only starts from when the store was first populated. During a burst of filings the cron can fall behind.
XBRL is only as clean as the filings. Companies choose different tags (Revenues vs. RevenueFromContractWithCustomerExcludingAssessedTax), and some metrics will come back null. Check the tag field in the snapshot.
Shared free endpoint. The public instance has no key and no SLA. Under heavy load you'll queue behind the global SEC limit or get a 503 asking you to retry. For anything important, deploy your own copy (the README covers it: a KV namespace, your own SEC_USER_AGENT, then wrangler deploy). You can protect /mcp with MCP_API_KEYS.
Not investment advice, not affiliated with the SEC. The data is public domain and comes straight from EDGAR. Interpreting it is up to you. A 10b5-1 sale means something very different from a discretionary open-market buy.
Links
Source code (MIT): https://github.com/monriah-studio/sec-edgar-mcp-remote
For scheduled or bulk Form 4 pulls outside an agent loop, there's an Apify actor: https://apify.com/monriah-studio/sec-form4-insider-trades
Issues and pull requests are welcome on the repo.
Written with AI assistance and checked by a human.