Repository navigation
feat(mcp): opt-in limit for edgar_read 13F holdings - #1548
Conversation
edgar_read stopped a 13F-HR holdings section at 30 rows, and every section was then cut to 6,000 characters, so a full portfolio could not be read or reconciled to the filing's total value. Add an optional limit argument (default 30, so existing callers are unchanged; 0 returns every row). It is threaded through edgar_read, _extract_sections, _extract_section and _extract_13f_section. 13F holdings skip the 6,000-character cap because limit already bounds them; every other section keeps it. A negative or non-integer limit returns an INVALID_ARGUMENTS error before any filing is fetched. Fixes dgunning#1416 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
Read the diff and checked the synthetic fixture: 211 rows give 188,845,000 in total and the first 30 give 29,565,000, as the test docstring says. The Three things I'd look at:
The input validation (bool, negative, |
…ession lookup (#1554) Opening a filing from an accession asks EDGAR full-text search first and the quarterly filing index second (edgartools-vx29). #1498 made an EFTS error body (HTTP 200, {"errorType": ...}) raise TransportError instead of reading as no hits, and resolve_accession re-raises transport errors (07lk.10). So when SEC's search backend failed on its own -- `getaddrinfo EBUSY` on 10-14 and 10-15 -- find(accession) raised for filings the index would have found. Five regression tests failed that way across #1545, #1548 and #1550. _filing_from_efts, the caller with a correct fallback, now logs a warning and returns None on a transport error, so the index is asked. resolve_accession still raises, and search_filings still raises, since there the error is the answer. If SEC itself is unreachable, the index fetch raises the same error. #1498 is unreleased, so no released version had this; no changelog fragment. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…t=0 size (dgunning#1416) Review follow-up on the edgar_read limit. The "Top holdings (N of M)" header used the number of rows requested, but _holding_rows skips a row with no usable cell, so N could be larger than the number of lines listed. N is now the number of rows actually listed. Document that limit=0 returns every row, which for a large manager can be thousands of rows and a large payload, in the tool schema, the MCP tools reference and the quickstart. No sort is added: ThirteenF.holdings is already sorted by Value descending, which tests/thirteenf/test_holdings_aggregation.py pins, so the first rows are the top holdings. A comment in the extractor says so. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
@arhancanli Thanks for the careful review, all three points were useful. (1) |
What this changes
edgar_readstopped a 13F-HRholdingssection at 30 rows and cut every section to 6,000 characters, so a full portfolio could not be read or reconciled to its filed total. It now takes an optionallimit(default 30;0returns every row). 13F holdings skip the 6,000-character cap, sincelimitalready bounds them; other sections keep it. The default output is unchanged for realistic issuer names.limitis validated for all forms and applied only to 13F holdings. A negative or non-integer value (includingTrue) returns anINVALID_ARGUMENTSerror before any filing is fetched; integral floats like30.0are accepted, since the JSON schema counts them as integers. The error is a deliberate divergence fromedgar_ownership(no validation) andedgar_fund(clamps), solimit=-1doesn't quietly return nothing or everything.Fixes #1416
Verification
0001999371-26-017606(period 2026-06-30), run live on 2026-10-15. Default returnsTop holdings (30 of 34);limit=0returns all 34 rows (34 of 34), matching the filing's 34 holdings ($2,170,182,768 total). The tests use a synthetic 211-row fixture.tests/issues/regression/test_issue_1416_edgar_read_limit.py, docstring links edgar_read: opt-inlimitso a full 13F portfolio can be read #1416; all 13 cases fail onmain'sreader.pylimitreturn a clear error, not a silent resultdocs/ai/mcp-tools.md,MCP_QUICKSTART.mdand theserver.pyexamples listlimitchangelog.d/1416.added.mdWorking context
Written with AI assistance (Claude Code) and reviewed by me; I'm responsible for it.
Evidence: reproduced the cap offline (a 211-row fixture returned 30 rows).
limit=0is turned into the row count becauseDataFrame.head(0)is empty. The new tests pass;tests/aiand the related MCP regression tests pass (534 passed).ruff checkadds no findings, and the provenance and changelog checks pass. Failures in the full fast suite on Windows are pre-existing on clean main (verified).