sec-filings
Allows serving document retrieval from MongoDB Atlas as an optional backend. The server can upload parsed document chunks to Atlas, create vector and text indexes, and run searches using $vectorSearch and Atlas Search with ticker and fiscal_year filters, fusing results with reciprocal rank fusion.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@sec-filingsWhat was Nike's headcount in their latest 10-K?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Ask your documents: an MCP server with citations, and the numbers to prove it
An MCP server that lets Claude (or ChatGPT, or any MCP client) answer questions from a set of long, messy documents, and cite the exact passage every answer comes from. The documents here are eight SEC annual reports (10-K) from Costco, Nike, Delta Air Lines and Netflix, about 360,000 words of HTML with tables, footnotes and no real headings.
Most RAG demos stop at "it answered my question". This one also ships the part that decides whether it works on real questions: a retrieval eval that compares chunking strategies, embedding models and search modes against a fixed question set, so changes are made on evidence, not on vibes.
Results
37 real-world questions, each with a known answer in the filings. "Right passage in top 5" is what the model actually gets to read; "right passage first" is how often the best hit is on top.
Setup | Right passage in top 5 | Right passage first | Latency (laptop CPU) |
Tutorial default: 300-word windows + all-MiniLM-L6-v2 | 70% | 30% | 9 ms |
Keyword search only (BM25) | 54% | 41% | 4 ms |
Structure-aware chunks + bge-base, vector search (default) | 81% | 46% | 41 ms |
Structure-aware chunks + bge-base, hybrid | 68% | 59% | 46 ms |
… plus a cross-encoder reranker | 81% | 54% | 3,839 ms |
Full grid of 12 configurations: eval/results.md.
What the numbers said, and what a gut call would have got wrong:
Chunking mattered more than the model. Swapping to the bigger embedding model alone left top-5 accuracy at 70%; cutting along the filing's sections with that same model took it to 81%. The first version of structure-aware chunking actually lost to plain windows. It produced 800+ fragments under 40 words (signature lines, footnotes), and short chunks win searches on length alone. Merging fragments and keeping sub-headings in the text fixed it.
The small default model truncates. all-MiniLM-L6-v2 reads at most 256 tokens, so the end of a 300-word chunk is invisible to it. bge-base reads 512.
Hybrid search is a trade, not an upgrade. Adding keyword search puts the right passage first more often (46% → 59%) but pushes it out of the top five more often too (81% → 68%). Since the model reads all five, the server defaults to vector search; set
DOCS_MODE=hybridif your users ask for exact figures and codes.The reranker didn't pay for itself. A popular off-the-shelf cross-encoder (ms-marco MiniLM, trained on web search) recovered hybrid's top-5 losses, but only back to the 81% plain vector search already gets, at about 90× the latency on CPU. On fixed-window chunks it made results worse. On a GPU, or with a reranker tuned for financial text, that may change; the eval is how you'd know.
Graded on the fact, not the paragraph. A first pass graded on exact sentences and marked correct answers wrong when a filing stated the same number in a table and in the text. The eval now checks for the answer itself (e.g. "103,000" employees).
The misses are the hardest paraphrases, e.g. "What was Nike's headcount?" when the filing says "employees", or "How exposed is Costco to a single US state?" when it says "California operations comprised 26%". In a chat the model can rephrase and search again; the eval scores the first try only.
Related MCP server: edgar-mcp
What Claude can do with it
Tool | What it does |
| Lists the filings available, with fiscal year and SEC link |
| Searches one company and year, or all filings; returns passages with section and SEC link |
| Reads a passage in full with the passages around it, to check context before answering |
Every result carries the company, fiscal year, section path (Item 7 > Membership Fees) and the
SEC URL, and the server instructions tell the model to cite them and say so when the passages
don't contain the answer.
Run it in five minutes
Requires Python 3.11+. No API keys, no GPU: embeddings run locally on CPU.
git clone https://github.com/mariacparra/mcp-docs-demo
cd mcp-docs-demo
python -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e .
cp .env.example .env # put your email in SEC_USER_AGENT
python -m docsdemo.fetch_sec # downloads the 8 filings from SEC EDGAR (~17 MB)
python -m docsdemo.ingest # parses, chunks and embeds them (a few minutes on a laptop)
python eval/run_eval.py # reproduces the table above
python tests/smoke_test.py # starts the server and calls every toolConnect it to Claude Desktop
Add this to claude_desktop_config.json (Settings > Developer > Edit Config), with your own paths:
{
"mcpServers": {
"sec-filings": {
"command": "C:\\path\\to\\mcp-docs-demo\\.venv\\Scripts\\python.exe",
"args": ["-m", "docsdemo.server"]
}
}
}Or in Claude Code: claude mcp add sec-filings -- /path/to/.venv/bin/python -m docsdemo.server.
For a remote client, python -m docsdemo.server --http serves streamable HTTP at http://localhost:8000/mcp.
How it works
SEC EDGAR ──> fetch_sec ──> parse ──> chunking ──> embeddings ──┬──> local index (numpy + BM25)
└──> MongoDB Atlas ($vectorSearch + Atlas Search)
│
Claude ──MCP──> server: list_filings / search_filings / get_passageParsing. 10-K filings are inline XBRL: thousands of nested divs and styled spans, hidden
XBRL metadata, and headings that are just bold text. The parser strips the hidden blocks, finds
"Item 7" style section breaks, treats short bold lines as headings, and turns tables into
label | 2026 | 2025 rows, re-joining the $, number and % cells that XBRL splits apart.
Two chunking strategies, so the eval has something to compare:
fixed: 300-word sliding windows with 50 words of overlap. The common default.structure: paragraphs packed within one section up to 350 words, tables kept whole, and every chunk prefixed with a context line likeCostco 10-K FY2026 > Item 7 > Membership Fees, so a chunk that says "increased 11%" still knows what increased.
Two embedding models, both free and local through fastembed:
all-MiniLM-L6-v2 (the most common default) and BAAI/bge-base-en-v1.5.
Four search modes: BM25 keyword search, dense vector search, hybrid (reciprocal rank fusion of both), and hybrid followed by a cross-encoder reranker over the top 20. Dense search understands "how many people work at Costco"; keyword search nails "$7.4 billion" and "SkyMiles". Which mix wins is an empirical question, answered in the results above.
The eval
eval/questions.jsonl holds 37 questions written the way a person would
ask them ("Does Delta produce any of its own jet fuel?"), each with a snippet of the passage that
answers it ("operate the Trainer refinery"). A question counts as answered at rank r when the
r-th result is from the right company and contains the snippet. Matching on text rather than
chunk ids means the same questions grade any chunking strategy.
Hit@1: the first result is the right passage.
Hit@5: the right passage is somewhere in the top five (what the model actually sees).
MRR: mean reciprocal rank; 1.0 means always first.
Full results: eval/results.md.
MongoDB Atlas (optional)
The local index is enough to run everything. To serve from Atlas instead (the free M0 tier works):
Create a free cluster at mongodb.com/atlas, add a database user and allow your IP.
Put the connection string in
.envasMONGODB_URI.python -m docsdemo.ingest --mongouploads the chunks and creates a vector index (withtickerandfiscal_yearas filters) and a text index.DOCS_BACKEND=mongo python -m docsdemo.server.
Search then runs $vectorSearch and $search in Atlas and fuses them with the same RRF as locally.
Adapting this to your documents
The SEC part is two files (fetch_sec.py, parse.py). The rest (chunking, hybrid search,
citations, the eval, the MCP server) works the same for contracts, policies, manuals, research
or support tickets. The step that matters most is the one people skip: write 30 to 50 real
questions with known answers before tuning anything, then let the numbers pick the configuration.
Layout
src/docsdemo/
fetch_sec.py download filings from SEC EDGAR
parse.py 10-K HTML -> blocks with section paths
chunking.py fixed and structure-aware chunking
retrieval.py embeddings, BM25, hybrid search (local)
mongo_store.py the same search on MongoDB Atlas
ingest.py build every index
server.py the MCP server
eval/ questions, runner, results
tests/ end-to-end smoke test over stdioLicense
MIT. The filings are public documents from SEC EDGAR.
This server cannot be deployed
Maintenance
Related MCP Connectors
Access SEC filings efficiently (10-K, 10-Q, etc), save time and tokens, and get cited answers.
SEC & financial-data MCP: filings, financials, ownership, factors, fund letters, prompts.
Search SEC filings, read 10-K/8-K, query XBRL facts, track Form 4 insider trades.
SEC EDGAR 10-K/10-Q/8-K filings and XBRL company facts by ticker, CIK or company name.
Related MCP Servers
- -licenseNot gradedqualityNot gradedmaintenanceEnables deep analysis of SEC EDGAR filings through universal company search, document content extraction, and advanced filing search capabilities. Provides AI-ready access to business descriptions, risk factors, financial statements, and full-text search across any public company's SEC documents.-
- AlicenseAqualityBmaintenanceMCP server providing read-only access to SEC EDGAR filings, allowing LLMs to look up companies, search filings, and retrieve securities offering data.364 PyPI2MIT
- FlicenseAqualityBmaintenanceEnables AI clients to retrieve SEC company profiles, filing listings, and structured XBRL financial statements via MCP tools.13-
- FlicenseNot gradedqualityCmaintenanceEnables AI agents to search, retrieve, and analyze SEC 10-K filings with hybrid BM25+kNN retrieval, per-claim citations, and strict numeric grounding verification.-