mcpwright.

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

  1. Claude called lookup_zip("10021") to confirm the ZIP — Upper East Side, NY, 22,450 returns, tax year 2022 (the latest SOI ZIP release).
  2. 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.
  3. 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

ToolWhat it does
lookup_zipConfirm a ZIP has SOI data; returns state, number of returns, individuals, and the tax year.
get_incomeTotal AGI, average AGI per return, and the main income components (wages, interest, dividends, business income, capital gains).
get_agi_distributionThe signature. All six IRS AGI brackets for a ZIP — returns and AGI per bracket, plus each bracket's share. The income shape.
get_taxIncome tax, total tax liability, total payments, and average total tax per return.
get_creditsRefundable-credit take-up: the EITC (split by qualifying children) and the additional child tax credit.
get_deductionsStandard vs. itemized deductions, the taxes-paid (SALT) deduction, and the % of returns that itemized.
get_filing_statusSingle / married-joint / head-of-household mix, elderly (65+) returns, and e-file share.
compare_zipsRank several ZIPs by one metric (avg AGI, % earning $200k+, income tax, EITC, …), highest first.
get_state_totalsState-level totals and AGI distribution from the IRS 00000 state-rollup row.
get_soi_fieldEscape 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