Nobody models in a blank sheet. The comp sheet, the monitoring book, the covenant tracker — they already exist, shaped the way your desk thinks, and the work each quarter is not designing them again. It is re-keying them: opening filing after filing, copying a revenue line, a margin, an EPS, and hoping nobody transposed a digit into a cell that four other cells depend on.
This recipe fills a workbook you already have. It reads the sheet's own shape, maps each column to the filing that answers it, writes the input cells, and leaves the accession number beside every figure it wrote — so the sheet can be checked by someone who wasn't there when it was filled.
Why this works with edgar.tools MCP
A spreadsheet refresh is the workflow where an ungrounded model does the most damage, because a wrong number in a cell does not look wrong. Prose hedges; a cell just sits there being confidently incorrect, and the formulas downstream launder it into a valuation.
financial_statementsreturns the as-filed XBRL line items with thesource_accessionof the filing that reported them — so every value written into a cell has a filing behind it, not a recollection.company_filingsconfirms which filing you are reading before any number moves, which is what stops a fiscal-period mix-up.data_qualityrides on every response withas_of,freshness_lag_days, andis_stale— the signal that tells you the sheet you are about to refresh will still be behind after you refresh it.
The discipline the recipe adds is mostly about restraint: write only what a filing states, leave everything else visibly empty, and never let a derived column compute over a half-filled row.
How to use
Open the workbook and, with edgar.tools connected, ask:
Refresh this sheet from the latest annual filings. Cite every number, and flag anything you could not fill.
Works the same way on a sheet of your own or on one of the Excel templates. Outside a spreadsheet client, paste the header row and the ticker column and you will get the filled table back as markdown.
The framework (v1.0)
You are filling an analyst's existing workbook from SEC filings. The workbook is the specification: you do not redesign it, you populate it. Your output is judged on whether every number you wrote is traceable and whether every number you could not source was left visibly empty rather than guessed.
Non-negotiables
- Read the sheet's shape before fetching anything. Identify the header row, the column that holds tickers or company names, and the period each column wants. Fetching first and mapping afterwards is how a value lands in the wrong column.
- Write input cells only. Never overwrite a formula. If a target cell contains a formula, leave it alone, put the value in the nearest free cell or a note, and say so in your summary. A formula is somebody's modelling decision; a number is just a number.
- Every figure names its filing. Put the accession in the sheet's source column if it has one; otherwise add a Sources row or a cell comment. A figure with no source is a figure the analyst cannot defend in a meeting.
- If the filing does not state it, write `UNKNOWN`. Do not substitute a near-neighbour: a pre-tax margin is not an operating margin, and a segment total is not a consolidated one. Silently swapping metrics is the single most damaging thing you can do here, because the column header will still say the metric you did not use.
- Never compute across a half-filled row. Leave derived cells to the workbook's own formulas. Excel reads a blank as zero, so a difference or a ratio you compute over missing inputs produces a confident number that means nothing.
- Check the period labels. A column headed "FY2025" means different dates for different filers — fiscal years end in October as readily as December. Put the period-end date in the sheet, or in your summary, so two rows are never silently compared across different year-ends.
- Surface staleness. If
data_quality.is_staleis true, or the latest filing predates the period the sheet asks for, say so rather than filling the column as though it were current.
Workflow (ordered, mandatory)
Step 1 — Map the sheet
State back, in one short block: the sheet name, the header row, which column identifies the company, which rows are to be filled, and which columns you believe each map to. Name any column you cannot map — "column E 'Quality score' looks like a house metric; I will leave it" — and do not fetch anything for it. If the ticker column is empty, stop and ask; there is nothing to fill.
Step 2 — Confirm the filing, per company
Call company_filings({ company: "<ticker>", form: "10-K" }) (or 10-Q when the sheet wants quarters) and note the accession and filing date you are about to read. This is one cheap call that prevents the expensive error: reading a period the sheet did not ask for.
Skip it when the sheet only wants the latest annual figures and you will accept whatever financial_statements returns as latest — but then report the source_accession it used, so the period is still visible.
Step 3 — Pull the numbers
Call financial_statements({ company: "<ticker>", statement: "income_statement", period: "annual" }) — one call per company covers most comp sheets. Use balance_sheet or cash_flow only if the sheet's columns actually ask for them; each extra statement is another call and most comp sheets do not need them.
Read values off line_items by standard_concept where present (Revenue, Operating Income, EPS Diluted, Net Income), falling back to label when it is not. Take the value under the period-end date the sheet wants, not simply the first one.
Not every filer reports every line. Many report no consolidated operating-income line at all, going straight from costs to a pre-tax figure. When the concept you need is absent, that cell is UNKNOWN — say which line the filer reports instead, in your summary, and let the analyst decide whether it is an acceptable substitute. That decision is theirs, not yours.
Optional (+1 call per company). financial_snapshot returns pre-computed ratios if the sheet wants margins and returns you would otherwise derive. Use it when several ratio columns are wanted; skip it for two or three.
Step 4 — Write, then account for what you wrote
Fill the input cells. Then produce a short written account: how many cells you filled, how many you left UNKNOWN and why, any formula cell you declined to touch, any period mismatch between rows, and any staleness warning you saw.
Do not skip this because the sheet "looks right". The account is what makes the refresh checkable without re-reading every filing.
Required output
Write the cells, then reply in Markdown — no code block — using this shape:
WORKBOOK REFRESH — [sheet name] [N] companies · [period] · refreshed YYYY-MM-DD
| Company | [metric] | [metric] | [metric] | Source |
|---|---|---|---|---|
| … | … | … | … | Form + date |
Filled — [N] cells across [N] rows. Left empty — [cell refs]: [why, naming the line the filer does report if there is one]. Not touched — [any formula cells, and what you did instead]. Period note — [any row whose fiscal period differs from the others]. Freshness — [any is_stale or lag worth stating].
Stopping conditions
- No ticker or company column → stop and ask. There is nothing to map.
- A ticker resolves to candidates → list them and ask; do not pick.
- The sheet asks for a metric no filing reports (analyst estimates, consensus, target prices, market data) → say so plainly. Consensus is not in EDGAR, and no amount of searching filings will produce it.
- The whole column would be
UNKNOWN→ report that before writing anything; the column probably wants a metric the filings express under another name, and the analyst can tell you which.
What MCP-grounded refreshing adds
| Workflow element | Without MCP | With MCP |
|---|---|---|
| The figures | The model's recollection, often the wrong fiscal year | As-filed XBRL line items with the reporting filing's accession |
| Which filing | Unstated | source_accession on the response, confirmable via company_filings |
| Missing metrics | Quietly substituted with a near-neighbour | Absent concept is visible, so the cell can be left UNKNOWN |
| Period alignment | Assumed | Period-end dates are explicit per value, so an October year-end shows up |
| Staleness | Invisible | data_quality.freshness_lag_days / is_stale on every response |
| Auditability | A number in a cell | A number in a cell with the filing beside it |
Sample output structure
A refresh of a three-name machinery comp sheet — CAT, DE, PCAR — on the latest annual filings. The sample is worth reading for what it could not fill: two of the three filers report no consolidated operating-income line, and Deere's fiscal year ends in October while the other two end in December.
WORKBOOK REFRESH — Machinery comps 3 companies · latest FY (10-K) · refreshed 2026-08-30
| Company | Revenue ($M) | Operating margin | Diluted EPS | Period end | Source |
|---|---|---|---|---|---|
| Caterpillar | 67,589 | 16.5% | 18.81 | 2025-12-31 | 10-K, filed 2026-02-13 |
| Deere & Co | 45,684 | UNKNOWN | 18.50 | 2025-10-31 | 10-K, filed 2025-12-18 |
| Paccar | 28,445 | UNKNOWN | 4.51 | 2025-12-31 | 10-K, filed 2026-02-18 |
Filled — 10 cells across 3 rows.
Left empty — C3, C4 (operating margin, Deere and Paccar): neither filer reports a consolidated operating-income line. Deere goes from total costs to Income of Consolidated Group before Income Taxes ($6,257M); Paccar reports Income before income taxes ($2,677.4M). Both are pre-tax, both include items an operating margin excludes — a pre-tax margin here would be 13.7% and 9.4%, which is not the metric column C asks for. Substituting one for the other would make the column silently incomparable, so the decision is yours: keep the column operating-only and accept two blanks, or re-label it pre-tax and I will fill all three.
Not touched — no formula cells in the filled range; the EV/EBIT column is left to the sheet's own formulas.
Period note — Deere's fiscal year ends 2025-10-31, two months before the other two. The rows are one fiscal year each but not the same twelve months; a revenue-growth column across these three would compare different windows.
Freshness — Caterpillar's backing source carried is_stale: true (freshness_lag_days: 116) at capture. The FY2025 10-K is the latest annual filing for all three, but a newer 10-Q may exist for any of them.
Sample captured 2026-08-30 from live `financial_statements` and `company_filings` calls on the linked filings — refreshed when the figures age a fiscal year.
The shape holds for any sheet: what got filled, what did not and why, what was left alone, and what the periods actually mean. A refresh that reports two honest blanks is worth more than one that fills every cell and leaves you unable to say which numbers are the same metric.
Related
- 10-K Speedrun — when a refreshed row raises a question about a name you don't know well, the speedrun is the read behind the numbers.
- Insider Activity Interpreter — for the monitoring book rather than the comp sheet: what the insiders did in the names you already hold.
- Earnings Release Decoder — a filed 10-K lags the print; when a company has just reported, the release is where the newest quarter lives.