soi-mcp
The shape of a ZIP's income.
An MCP server that lets an LLM pull the real income distribution, tax, credits, and deductions of any U.S. ZIP — straight from the IRS Statistics of Income. Not a survey estimate — the aggregates of actual filed returns. Read-only, all public-domain data, no API key, bulk-downloaded once then served offline.
See it in action
One prompt in Claude Code, start to finish:
Using soi, show me the income distribution of ZIP 10021 — what share of filers are high earners, and how concentrated is the income?
What happened
- Claude called
lookup_zip("10021")to confirm the ZIP — Upper East Side, NY, 22,450 returns, tax year 2022 (the latest SOI ZIP release). - Then
get_agi_distribution("10021")returned all six IRS AGI brackets. The top bracket ($200k+) is 35.2% of returns but holds 90.6% of the ZIP's $12.8B in AGI; the bottom three brackets (under $75k) are 30.5% of filers yet under 2% of the income. - That's the point of the signature tool: a ZIP's income shape, not just an average. Atherton's $1.6M average AGI and the Upper East Side's $571k both hide wildly different distributions underneath.
Every figure comes from the local SOI store the server built on first run — not the model's memory.
What you can ask
Real exchanges (tax year 2022), driven entirely by the tools below.
Which is wealthier per filer — Atherton (94027), Fisher Island (33109), or Beverly Hills (90210)?
compare_zips by average AGI: Fisher Island, FL leads at
$4.40M per return (just 400 returns, $1.76B total AGI), then Atherton, CA
at $1.59M, then Beverly Hills at $665k — sorted highest-first.
How much income tax does ZIP 94027 actually pay?
get_tax on Atherton, CA: $1.24B in income tax and
$1.35B in total tax liability across 3,050 returns — an average total tax of
$443,303 per return.
What's the EITC take-up in Brownsville, TX (78521)?
get_credits: of 38,820 returns, 15,550 (40%)
claimed the Earned Income Tax Credit for $51.0M total — broken out by qualifying
children (none / one / two / three+), the refundable side of the code most ZIP datasets
never surface.
How big is California's individual income base, and how does it compare to New York's?
get_state_totals from the IRS state rollup: CA — 18.1M
returns, $2.0T in AGI, $110,196 average; NY — 9.6M returns, $1.03T
in AGI. Each comes with the state's own six-bracket AGI distribution.
Tools
| Tool | What it does |
|---|---|
lookup_zip | Confirm a ZIP has SOI data; returns state, number of returns, individuals, and the tax year. |
get_income | Total AGI, average AGI per return, and the main income components (wages, interest, dividends, business income, capital gains). |
get_agi_distribution | The signature. All six IRS AGI brackets for a ZIP — returns and AGI per bracket, plus each bracket's share. The income shape. |
get_tax | Income tax, total tax liability, total payments, and average total tax per return. |
get_credits | Refundable-credit take-up: the EITC (split by qualifying children) and the additional child tax credit. |
get_deductions | Standard vs. itemized deductions, the taxes-paid (SALT) deduction, and the % of returns that itemized. |
get_filing_status | Single / married-joint / head-of-household mix, elderly (65+) returns, and e-file share. |
compare_zips | Rank several ZIPs by one metric (avg AGI, % earning $200k+, income tax, EITC, …), highest first. |
get_state_totals | State-level totals and AGI distribution from the IRS 00000 state-rollup row. |
get_soi_field | Escape hatch: the raw value of any SOI field for a ZIP, by code or friendly name. |
SOI is aggregated from actual filed returns (not a survey), so it
reports income, tax, and credits the Census ACS can't. The ZIP release lags ~2–3 years —
tax year 2022 loads by default, and older years are one refresh <year>
away. ZIPs with fewer than 100 returns are suppressed by the IRS for privacy.
Install
Requires Python 3.12+ and uv. No API key — the data is public domain.
uvx mcpwright-soi setup # one-time: bulk-download the latest SOI year into a local store
Claude Code
claude mcp add soi -- uvx mcpwright-soi
Claude Desktop
Add to claude_desktop_config.json:
{
"mcpServers": {
"soi": {
"command": "uvx",
"args": ["mcpwright-soi"]
}
}
}
OpenAI & other MCP clients
It's a standard stdio MCP server — so it works beyond Claude: the OpenAI Agents SDK, Cursor, VS Code, Cline, Goose, Zed, and more all launch it the same way.
{
"mcpServers": {
"soi": {
"command": "uvx",
"args": ["mcpwright-soi"]
}
}
}
The first run downloads the full SOI ZIP file (~28k ZIPs, all six AGI brackets each) into
a local SQLite store, so every later lookup is instant and offline — no per-query network
calls, no rate limits, no key. mcpwright-soi refresh re-pulls when a new year
drops; refresh <year> loads a specific older tax year for comparison.
Source, full tool reference, and roadmap → github.com/mcpwright/soi-mcp
Questions or ideas? → Discussions · found a bug? → Issues