EDGAR 13F point-in-time

io.github.Serios16由 GitHub 帳號 Serios16 發布v1.2.2更新於 Oct 29, 2026

SEC Form 13F holdings as they could have been known on a given date (stdio).

發布方自己的服務:edgar.tools SEC Intelligence

已驗證STDIO僅桌面金融資料與分析

概覽

AI 產生的概覽

本機 stdio MCP 伺服器,依指定日期當時可知的資訊回答 SEC 13F 持股問題,並遵循時點與修訂規則。

可以做什麼
  • 把經理人名稱解析為 EDGAR CIK 候選,優先列出有 13F 申報的機構
  • 列出某經理人在指定日期前已提交的 13F 申報(13F-HR、13F-HR/A、13F-NT、13F-NT/A)
  • 回傳某一報告期在指定日期可知的有效持股,並註明基礎申報與各項修訂
  • 在同一日期基準下比較兩季持股,標示新增、出清、增持、減持與不變
  • 依發行人、CUSIP 或最大持股數篩選與排序結果
適用情境
適合研究、回測與代理回答,要求不能看到所選日期之後才公開的申報;也適合比較某機構跨季的持股變化。定位是時點式 13F 查詢,而非一般 SEC 研究。
執行需求
透過 uvx 以 Python 3.11 在本機以 stdio 執行(PyPI 套件 edgar13f-mcp)。必須設定 SEC_USER_AGENT,否則伺服器不會連線 sec.gov。可選 EDGAR13F_CACHE_DIR、EDGAR13F_AGENT_MODE、EDGAR13F_REDACT、EDGAR13F_FIXTURE_DIR。需要連線 sec.gov 的網路;首次 find_manager 呼叫會讀取 EDGAR 索引,可能約需一分鐘。
安裝前請注意
SEC_USER_AGENT 需填寫真實姓名與電子郵件以符合 SEC 公平存取政策,並會傳送給 sec.gov。預設會移除部分 ETF、指數基金等標的的持股列且不再回傳,可用 EDGAR13F_REDACT=off 關閉。EDGAR13F_AGENT_MODE=on 會把未加篩選的持股與差異結果默默限制為 50 個持股。答案只反映 as_of 日期前已提交的申報,僅含多頭持股,且不含 2013 年前的文字格式申報。

安裝

在 SourceWeft 中

  1. 開啟 儀表板中的 EDGAR 13F point-in-time,將其新增到工作區。
  2. 為需要使用其工具的對話啟用該服務。

Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。

其他 MCP 客戶端

參照 儲存庫 中的啟動說明。

README

edgar13f-mcp

An MCP server that answers questions about SEC Form 13F holdings as they could have been known on a given date. It comes with an evaluation that was frozen before the server was written.

What it does, and why point-in-time matters

Institutional managers with US$100m or more in 13F securities file Form 13F every quarter, up to 45 days after the quarter ends. Many of them later amend the report. A restatement replaces the whole report. A new-holdings amendment adds rows to it. So "what did manager X hold at 2024-12-31?" has different correct answers on different days: nothing before the filing date, then the original report, and later the amended one.

A tool that always returns the latest version leaks the future into backtests, research notes and agent answers. This server takes an as_of date with every call and follows two rules (full text in contracts/CONTRACTS.md):

  • Visibility (§3): a filing is visible on as_of only if its EDGAR filing date is on or before as_of. Nothing filed later affects the answer: not the rows, the citations, the filing list, or which filing counts as "latest".
  • Amendments (§4): the visible filings for the period are put in order. The base is the last original or restatement. Every later new-holdings amendment is added to it. Each row cites the filing it came from.

Install and run

Python 3.11, with the official MCP Python SDK 2.x. The server speaks MCP over stdio only.

One command (needs uv). The package is edgar13f-mcp on PyPI, uploaded by this repository's release workflow with trusted publishing, and listed in the official MCP Registry as io.github.Serios16/edgar13f-mcp:

sh
export SEC_USER_AGENT="Your Name [email protected]"   # required by SEC fair accessuvx --python 3.11 edgar13f-mcp                              # pin a release: [email protected]

For an MCP client such as Claude Desktop:

json
{"mcpServers": {"edgar13f": {  "command": "uvx",  "args": ["--python", "3.11", "edgar13f-mcp"],  "env": {"SEC_USER_AGENT": "Your Name [email protected]"}}}}

Any commit or tag also runs straight from GitHub: uvx --python 3.11 --from git+https://github.com/Serios16/[email protected] edgar13f-mcp. The older command name edgar13f-server still works. Both names are tested on the built wheel by tests/tools/install_smoke.sh (empty uv cache, MCP handshake; output in reports/artifacts/install_smoke_stage6.txt). From a clone instead:

sh
python3.11 -m venv .venv && . .venv/bin/activatepip install -e .export SEC_USER_AGENT="Your Name [email protected]"   # required by SEC fair accesspython -m edgar13f.server                                   # or: edgar13f-server

Environment variables:

  • SEC_USER_AGENT: the User-Agent sent to sec.gov. It is required; without it the server does not contact sec.gov.
  • EDGAR13F_CACHE_DIR: the on-disk cache. The default is $XDG_CACHE_HOME/edgar13f (or ~/.cache/edgar13f), then a private per-user temp dir. The server writes nowhere else.
  • EDGAR13F_REDACT: set to exactly off to return the rows that are redacted by default (see Limits). Any other value, or none, keeps redaction on.
  • EDGAR13F_AGENT_MODE: set to exactly on to cap unnarrowed holdings and diff answers at the 50 largest positions (see Agent use). Unset, every v1 call answers byte for byte as in v1.1.0.
  • EDGAR13F_FIXTURE_DIR: serve recorded fixtures instead of EDGAR (used by the tests; refused together with EDGAR13F_REDACT=off).

SEC access follows the fair-access policy. Across processes that share a cache dir, request starts are spaced at least 0.25 s apart (under 5 per second). 403/429/5xx responses and HTML error pages trigger exponential backoff. Responses are cached on disk.

The tools

ToolReturns
find_manager(name[, as_of][, limit])CIK candidates whose current or former EDGAR name contains name, managers with 13F filings first. entity_name is EDGAR's current name (not point-in-time); with as_of, has_13f_filings counts only 13F filings dated on or before it.
list_13f_filings(cik, as_of[, period])Every 13F-HR, 13F-HR/A, 13F-NT and 13F-NT/A filed by the manager on or before as_of (only those for period if given), with period, amendment number and type, report type, manager name and an EDGAR link.
get_holdings_as_of(cik, period, as_of[, cusip][, issuer][, max_positions][, position_type])The effective holdings for one quarter as known on as_of, row by row as filed (no merging or rescaling). It cites the base filing and every applied amendment.
diff_holdings(cik, period_a, period_b, as_of[, cusip][, issuer][, max_positions])Position changes between two quarters, both resolved on the same as_of, keyed by (CUSIP, put/call, SH/PRN): added, removed, increased, decreased or unchanged.

find_manager, period, issuer and max_positions come from Addendum A (additive: a call that uses none of them gets exactly the v1.1.0 answer).

Every response is a JSON object with the disclaimer "13F reports long positions only; data may lag the period end by up to 45 days." When the server cannot answer, it returns a normal result with status: "declined" and one of six reasons: unknown_cik, not_yet_filed, notice_only, invalid_period, invalid_argument, unsupported_request.

Agent use (Addendum A)

The extensions are meant for LLM agents, which usually start from a name and cannot read a 40 MB answer. A typical sequence:

jsonc
// 1. name -> CIK (managers that have filed Form 13F come first){"tool": "find_manager", "arguments": {"name": "berkshire hathaway", "as_of": "2025-08-27"}}// 2. which filings make up one quarter, as of a date{"tool": "list_13f_filings", "arguments": {"cik": "1067983", "as_of": "2025-08-27", "period": "2025-03-31"}}// 3. one issuer only; the answer adds matched_cusips{"tool": "get_holdings_as_of", "arguments": {"cik": "1067983", "period": "2025-03-31", "as_of": "2025-08-27",                                              "issuer": "apple"}}// 4. the 10 largest positions; the answer adds total_positions, truncated and order{"tool": "get_holdings_as_of", "arguments": {"cik": "1067983", "period": "2025-03-31", "as_of": "2025-08-27",                                              "max_positions": 10}}// 5. the 20 largest changes by |value_delta|{"tool": "diff_holdings", "arguments": {"cik": "1067983", "period_a": "2024-12-31", "period_b": "2025-03-31",                                         "as_of": "2025-08-27", "max_positions": 20}}
  • issuer (2-100 characters) keeps rows whose issuer name contains it, ignoring case and runs of whitespace; it combines with cusip as AND.
  • max_positions (1-200) ranks positions, i.e. (CUSIP, put/call, SH/PRN) groups, by summed value (holdings) or by |value_delta| (diff), and returns the top ones with all their rows. A position is never split, so a manager that files many rows per position can still return many rows; use issuer or cusip for one security.
  • The new parameters only filter or order rows. Citations (accession_number, source_accessions, filing_date) and point-in-time behaviour are unchanged, and redaction happens before any filter.
  • find_manager matches every current and former EDGAR name, returns EDGAR's current name, and is therefore not point-in-time for names. Its first call on an empty cache reads EDGAR's quarterly form indexes since 1993 (about a minute, once per cache directory); later calls take milliseconds.

With EDGAR13F_AGENT_MODE=on, a get_holdings_as_of or diff_holdings call that has none of cusip, issuer or max_positions is answered as if max_positions were 50, and the answer adds auto_limited: true. Every other call is unaffected. MCP client config:

json
{"mcpServers": {"edgar13f": {  "command": "uvx",  "args": ["--python", "3.11", "edgar13f-mcp"],  "env": {"SEC_USER_AGENT": "Your Name [email protected]", "EDGAR13F_AGENT_MODE": "on"}}}}

Limits

  • Long positions only. Form 13F has no short positions, so position_type other than "long" is declined.
  • Lag. Reports are due up to 45 days after quarter end, and amendments can arrive months later. An answer is only as current as what was filed by as_of.
  • Redaction. By default, rows for gold ETFs/trusts, US energy-sector ETFs, S&P 500 index funds/ETFs, and UCITS copies of these are removed when the information table is parsed, because the author keeps a separate study blind to these instruments. They are then never returned, cached or logged. Matching uses issuer-name and title patterns plus a CUSIP list, and deliberately errs toward removing too much. Some ordinary securities are dropped too. Two concrete cases cost graded points: every "SPDR S&P ..." fund (any SPDR fund that names S&P, not only S&P 500 ones), and bonds of issuers named like a trust or fund whose class title carries a ".500" coupon (e.g. "5.500% NOTES"). An energy company whose class title says "UNIT" is another. Ruling D2 forbids narrowing the list to recover such points. A query for a removed CUSIP returns ok with no rows. Redaction applies to holdings rows; find_manager returns entity names unfiltered (ruling N1). To switch redaction off, set EDGAR13F_REDACT=off (exactly off); rows read that way are cached in a separate directory and never served once redaction is back on. See CLAUDE.md rule 2 and ruling D2 in REGISTER.md.
  • The server does not cover pre-2013 text-format 13F filings, and it has no prices, charts or performance figures.

How it is evaluated

  • Hidden, frozen grader. The gold sets, leakage set and grader were frozen in a separate private repository before any server code existed. The builder cannot read or write that repository. contracts/PREREG_COMMITMENT.md holds the SHA-256 of that repository's manifest and of the contract files copied here. Everything will be published after the final stage so the hash can be checked.
  • Gold sets: 40 curated items and 700 generated items, stratified by case type (for example the day before and the day of a restatement), plus 3,114 leakage cases.
  • Beyond the gates, the private repository also holds, each pre-registered before it ran: an out-of-sample set, an evaluation with an LLM agent in the loop, a diagnostic re-run of that evaluation, and a live capture around the Q3 2026 filing deadline (results below).
  • Controls in this repository. They run in CI on every push, offline; the tests refuse sockets:
    • a leakage suite with a mutant control (visibility check disabled; it must find violations, also for every Addendum A parameter and find_manager(as_of)) and a no-op control;
    • blocklist proofs on synthetic rows, with a planted failure;
    • an exhaustive check of the §4 amendment rules against an independent oracle, killed by each planted rule mutation (tests/unit/test_restatement.py);
    • size, map and claims checks, each with a planted failure.
  • OS-level isolation. CI runs the server as a separate unprivileged OS user from a read-only copy of the checkout. The job fails if that user creates any file or directory outside the expected cache dir, and a planted stray write must be caught (tests/tools/unprivileged_probe.sh).
  • External cross-check (test time only). tests/tools/datasets_crosscheck.py compares answers for randomly sampled (cik, period, as_of) triples against the SEC Form 13F Data Sets. The server never reads the data sets.

Gate results (REPORTED by the evaluator; aggregates only)

Item-level results are withheld by design. Gate 2, the pre-registered decision gate, passed on commit b208c47, which is tagged v1.0.0. Gates 3, 4 and 5 passed on commits ca60c5c, f7ee806 and cc61944, tagged v1.1.0, v1.2.0 and v1.2.1. All five gates have the same aggregates. v1.2.2, the first release on PyPI, changes only the packaging: it adds the edgar13f-mcp command, and under src/ only the version string differs from v1.2.1.

MeasureGate 1Gate 2 (v1.0.0)Gate 3 (v1.1.0)Gate 4 (v1.2.0)Gate 5 (v1.2.1)
Primary gatesall PASSall PASSall PASSall PASSall PASS
Generated items698 / 700698 / 700698 / 700698 / 700698 / 700
Generated misses1 restatement_before, 1 restatement_aftersamesame; both are D2 over-matchessamesame
Citation validity669 / 671669 / 671669 / 671669 / 671669 / 671
Leakage0 violations over 3,114 cases0 over 3,1140 over 3,1140 over 3,1140 over 3,114
Curated items34 / 3434 / 3434 / 3434 / 3434 / 34
Declines6 / 66 / 66 / 66 / 66 / 6

Both generated misses come from ruling D2: the blocklist removes rows the grader expected (see Limits for the two known over-match patterns). D2 forbids narrowing the list to win them back.

Out of sample. On filings dated 2025-09 to 2026-08, outside the window the frozen evaluation covers (as_of up to 2025-08-27), all primary gates PASS: generated 699 / 700, 0 leakage violations over 3,102 cases, citations 639 / 640, declines 6 / 6. The one miss is a D2 over-match, predicted before grading.

Does it help an AI agent? (REPORTED by the evaluator; aggregates only)

Pre-registered before the run (2026-10-14): the same model (Claude Sonnet 5.5, effort medium), the same 80 plain-English questions, the same instructions, a 12-turn budget and a 50,000-character cap per tool result, 2 runs per question. Every tool result passed through the same redaction before the model saw it. Each question names the manager and the issuer (not the CIK or CUSIP), the quarter, and "as filed with the SEC on or before" a date.

ToolboxCorrectLeaksTool calls per runCost per correct answer
No tools5 / 150 (declines only; stopped at its budget cap)00$0.17
edgar13f v1.2.0, agent mode160 / 16002.2$0.017
EdgarTools MCP 5.60.0105 / 16009.0$0.145

Paired difference against EdgarTools: +34 points (95% CI +24 to +44), so by the pre-registered rule edgar13f is better. EdgarTools was weakest on diffs (7 / 20), amendments (7 / 20) and point-in-time questions (23 / 40); edgar13f answered every type correctly.

Why EdgarTools missed. A pre-registered diagnostic re-run of its 31 missed questions (2026-10-15) reproduced the misses (49 of 62 runs), again with no wrong numbers and no leaks:

  • 33 ran out of the 12 turns, 31 of them after the model had already located the right filing;
  • 16 were declines: 13 on questions that had an answer, 3 with the wrong decline reason; 4 of them followed the wrong filing or period;
  • none came from the character cap, and none was a wrong number.

A larger turn budget would probably close part of the gap, at a higher cost; that has not been measured. The pre-stated reading also expected fewer leaks with edgar13f, but there were none on either side. Leak prevention is therefore shown at the tool level (the gates above), but neither supported nor refuted for agents.

Caveats:

  • One model and one prompt.
  • The questions are point-in-time 13F lookups, this server's purpose, not general SEC questions. Questions whose issuer name matched more than one security were excluded.
  • The grader requires citing the base filing. Under a rule that also accepts the new-holdings amendment where the asked row lives, edgar13f's citations are 126 / 126 valid (recorded 122 / 126).

Live test (pre-registered, pending)

Around the Q3 2026 filing deadline (16 November 2026), the evaluator captures v1.1.0's answers for 300 randomly drawn managers on 13, 17, 19 and 26 November, each time asking about the previous day. The answers are graded once the SEC publishes the data set that covers those filings. v1.1.0 is the release that was current when the test was pre-registered. These calls use none of v1.2.0's new parameters, and v1.2.0's defaults are byte-identical to v1.1.0 (3,689 fixture calls and 1,328 live calls compared), so the result applies to v1.2.0 as well. The capture and grading code were frozen before the first capture; their hashes are in reports/LIVE_TEST_COMMITMENT.md.

Latency

Cold start (empty cache), get_holdings_as_of(cik, 2025-03-31, as_of=2025-08-27) for the five 13F-HRs of that quarter with the most rows after redaction, measured in-process (MEASURED; tests/tools/cold_latency.py, artifacts reports/artifacts/cold_latency_stage3_*.json). Each cell is the worst of two runs (v1.0.0) or three runs (v1.1). For 1776033 a restatement filed the next day replaces the 34,332-row original, so the answer has 1,599 rows.

CIKRowsv1.0.0v1.1SEC requests
201238350,1588.3 s4.1 s9 -> 6
31993349,5948.1 s4.3 s9 -> 5
176175544,54816.2 s4.2 s31 -> 5
89542144,19244.5 s7.6 s118 -> 13
17760331,5998.1 s2.9 s23 -> 6

v1.1 reads only the cover pages and history pages that can affect the requested quarter. Warm calls take under 0.6 s. list_13f_filings still reads every filing's cover page, so its first call costs 2-36 s for these managers. Over MCP stdio the server adds about 1 s for a 50k-row answer (~40 MB), but the MCP Python SDK's stdio client (2.2.0) itself needs 6-15 s to read a message that large (quadratic in the message size; an upstream report is drafted in reports/upstream/).

Agent-use extensions, same five managers, two runs (MEASURED; tests/tools/agent_latency.py, artifacts reports/artifacts/agent_latency_run1.json and _run2.json):

CallFirst call, empty cacheLater
find_manager(name)63-79 s (EDGAR's name file and 136 quarterly form-index prefixes, once per cache directory)0.02-0.05 s; 1.7-3.2 s in a new process
list_13f_filings(cik, as_of, period)0.7-3.7 s (the full list: 2-36 s)under 0.05 s

max_positions=50 shrinks a 17-19 MB holdings answer (44-50k rows) to 0.4-1.0 MB for three of the four large managers, and the SDK client then reads it in 0.2-0.3 s instead of 6-14 s. The fourth reports each position in hundreds of rows, so its 50 positions are still 17,741 rows (6.7 MB). Diff answers drop from 0.4-2.1 MB to about 13 KB.

Stage reports with measured artifacts are in reports/.

Tests

sh
pip install -e ".[test]"python -m pytest -q tests          # offline; sockets are refusedpython tests/checks/size_budget.py . && python tests/checks/map_check.py . && python tests/checks/claims_check.py .

Protocol checks: the inspector CI job runs the pinned MCP Inspector CLI (tests/inspector/inspector_check.sh) against the server on recorded fixtures, in both protocol eras (2025-11-25 with the initialize handshake, 2026-07-28 without), checks the result against reports/artifacts/inspector_stage5.json, and must fail on a stub that lists three tools. Lifecycle checks (stdin close, malformed lines, SIGTERM/SIGKILL mid-call) are in tests/invariants/test_lifecycle.py. Registry metadata: server.json; steps in PUBLISHING.md.

MAP.md lists the modules and shows where each contract rule is enforced and tested. REGISTER.md records rulings, assumptions and proposals.

Licence

MIT; see LICENSE. Runtime dependencies use permissive OSI licences only (MIT/Apache/BSD/PSF/ISC). The server does not use edgartools (the evaluation uses it only as a comparison baseline) and contains no code from AGPL projects. It is not affiliated with the SEC, and nothing it returns is investment advice.

來源:README.md,提交 309236d

工具

4

find_manager

Find a manager's CIK from its name (a case-insensitive substring of current or former EDGAR entity names). Candidates that have filed Form 13F come first. Use it before the other tools when you only know the name. entity_name is EDGAR's current name (not point-in-time); with as_of, has_13f_filings counts only 13F filings dated on or before as_of.

輸入參數name必填as_oflimit

list_13f_filings

Every Form 13F submission (13F-HR, 13F-HR/A, 13F-NT, 13F-NT/A) by the manager whose EDGAR filing date is on or before as_of (what was publicly filed by then). Pass period to list only the filings for one report period.

輸入參數cik必填as_of必填period

get_holdings_as_of

Effective 13F holdings of the manager for one report period as knowable on as_of (point-in-time and amendment rules), with the accession number(s) they come from. Large managers file tens of thousands of rows: narrow with issuer, cusip or max_positions. as_of means what was publicly filed by that date.

輸入參數cik必填as_of必填cusipissuerperiod必填max_positionsposition_type

diff_holdings

Position-level changes between period_a and period_b, each computed with get_holdings_as_of rules on the same as_of and consolidated by (cusip, put_call, sh_prn). Large managers file tens of thousands of rows: narrow with issuer, cusip or max_positions. as_of means what was publicly filed by that date.

輸入參數cik必填as_of必填cusipissuerperiod_a必填period_b必填max_positions

版本歷史

1
  1. v1.2.2最新Oct 22, 2026

評分

已滿足適用檢查項的 90%

該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。

  • 近 30 天內可連通25 分
  • 已宣告認證方式10 分

    請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。

  • 已列出工具必需15 分
  • 描述必需15 分
  • 圖示10 分
  • 文件15 分
  • 授權條款10 分

其他 Edgar 整合