A deterministic, §6694-disciplined tax-compute API. JSON in, computed (or honestly declined) tax out.
Tax MCP is coverage-bounded: it computes inside a documented supported envelope and returns a deterministic unsupported or needs_review decline (with a reason and next_action) when a case is outside it — never a wrong-but-plausible number.
Machine-readable: GET /api/mcp/tax-capabilities returns the full supported envelope (years, statuses, modeled fields, out-of-scope, decline codes, billing semantics) — no auth, no payloads.
| Supported today | Out of scope (declines deterministically) |
|---|---|
W-2 wage workflows with standard or itemized deductions (Schedule A: SALT with the OBBBA-2025 cap + home mortgage interest with the §163(h)(3) $750k limit — supply mortgageAvgBalance; greater-of standard is chosen automatically); documented taxable interest / ordinary dividend facts; clean covered capital-gain facts; §199A QBI deduction for REIT dividends (1099-DIV box 5) only. Selected federal (ordinary tax, NIIT, Additional Medicare, preferential LTCG/QDIV) and CA / NY / NYC computation paths. Non-mutating reconcile (match / mismatch / unsupported / needs_review). | Full-return preparation or filing; credits; dependents; itemized deductions beyond SALT + mortgage interest (medical, charitable, etc.); broad payments/refund workflows; Schedule D loss / netting / carryforward; business / rental / pass-through income & business/PTP QBI (REIT §199A dividends ARE supported); broad multi-status state coverage; ambiguous or corrected source documents outside the documented envelope. |
Sign inand create a key from your dashboard. Keys are shown once — copy it immediately. Your plan's monthly call limit is shared across all your keys.
Send your key as a Bearer token on every request:
Authorization: Bearer taxmcp_YOUR_KEYcurl https://tax-mcp.com/api/mcp/tax-compute/federal \
-H "Authorization: Bearer taxmcp_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"year": 2025,
"filingStatus": "single",
"wages": 120000,
"taxableInterest": 800
}'Supply at least one income field. Amounts are whole-dollar — the engine applies the form's rounding. An HTTP 200 is billable whether the engine computed a result or honestly declined.
| Method | Path | Purpose |
|---|---|---|
| POST | /api/mcp/tax-compute/federal | Selected federal paths — ordinary tax, NIIT, Additional Medicare, LTCG/QDIV (declines outside coverage) |
| POST | /api/mcp/tax-compute/state | Selected CA / NY compute paths (set state); deterministic decline outside coverage |
| POST | /api/mcp/tax-compute/reconcile | Non-mutating, coverage-bounded reconcile vs a filed return (match / mismatch / unsupported / needs_review) |
| GET | /api/mcp/tax-compute/{federal,state,reconcile} | Capability / discovery (free — no quota charge) |
Send an Idempotency-Key header (a unique value per logical request) so a retry never double-bills. Retrying with the same key + same body replays the byte-identical first response (with header Idempotent-Replayed: true) and bills exactly once. The same key with a different body returns 409 idempotency_key_reused; a concurrent in-flight duplicate returns 409 idempotency_key_in_progress (retry). Keys are scoped to your account and replay for 24h. Errors are never cached — a retry after a 4xx/5xx is a fresh request.
curl https://tax-mcp.com/api/mcp/tax-compute/federal \
-H "Authorization: Bearer taxmcp_YOUR_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"year":2025,"filingStatus":"single","wages":120000}'A successful compute (200) returns either a computed return or an honest decline— both are billable answers. Every dollar amount is whole-dollar per the form's rounding, and each line carries its own primary-source derivation.
// computed
{
"computed": true,
"year": 2025,
"filingStatus": "single",
"taxableIncome": 44250,
"incomeTax": 5072,
"totalTax": 5072,
"owedOrRefund": 0, // present only when withholding is supplied
"lines": [ { "lineId": "1040:16", "label": "Income tax", "amount": 5072, "derivation": [ … ] } ],
"flags": [ … ], // advisory engine flags
"legal_notice": { // not-tax-advice notice, on computed + reconcile 200s
"ref": "https://tax-mcp.com/terms#compute-notice",
"version": "v1",
"text": "Computation support only. Not tax, legal, accounting, or financial advice. …"
}
}
// honest decline (still HTTP 200, still billable)
{
"computed": false,
"code": "schedule_c_needs_review",
"reason": "Schedule C self-employment compute (slice 1) requires scheduleCIsSingleSolePropFinalNetAffirmed:true — attesting the amount is the FINAL Schedule C line-31 net of ONE sole proprietor with no §199A QBI / depreciation / §179 / SE health-insurance / home-office, not farm/clergy/statutory, and not two spouses' combined SE …; a preparer must complete Schedule C + Schedule SE",
"billed": true, // a 200 decline is a billable answer on a metered key
"retry_safe": false, // resubmitting the same body will decline again — fix inputs, don't retry
"next_action": "review_inputs"
}The decline code names the specific surface a preparer must handle — e.g. year_not_modeled, out_of_scope_income, surtax_additional_medicare, capital_gain_lots_need_review, schedule_c_needs_review, schedule_e_needs_review, digital_asset_needs_review, and others. The authoritative, always-current set is published at GET /api/mcp/tax-capabilities (jurisdictions.federal.decline_codes) and in the OpenAPI DeclineCode enum. A decline is never a wrong-but-plausible number — it tells you the case is outside the modeled surface.
The point of this API is that it refuses to guess. This request looks computable — a W-2 wage-earner with $20,000 of Schedule C income — but it omits the required §6694 affirmation (scheduleCIsSingleSolePropFinalNetAffirmed) that the amount is a single sole-proprietor final net with no QBI / depreciation / spouse-split, so the engine returns a deterministic 200 decline instead of a plausible-but-wrong number. (Add the affirmation — and socialSecurityWages when W-2 wages are present — and it computes the self-employment tax.) Paste it with your key and you get the exact schedule_c_needs_review body above, every time:
curl https://tax-mcp.com/api/mcp/tax-compute/federal \
-H "Authorization: Bearer taxmcp_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"year":2025,"filingStatus":"single","wages":80000,"scheduleCIncome":20000}'
# -> HTTP 200 { "computed": false, "code": "schedule_c_needs_review", "next_action": "review_inputs", ... }Same idea for other boundaries: an unmodeled year (e.g. 2019) → year_not_modeled; a §1250 / collectibles special-rate gain → special_rate_gain_unmodeled. Discover the whole envelope up front (no taxpayer payload needed) at GET /api/mcp/tax-capabilities.
The product roadmap is published so users can see what is next and influence the order.
Successful responses carry your current usage so you can back off before hitting a limit. Both quota (monthly, account-wide) and rate (per-minute) fail closed with 429 — never a silent overage charge.
| Header | Meaning |
|---|---|
| X-Quota-Limit / X-Quota-Remaining | Monthly call allowance and calls left (shared across your keys) |
| X-RateLimit-Limit / X-RateLimit-Remaining | Per-minute request allowance and requests left this minute |
| Idempotent-Replayed | true when this response was replayed from a prior Idempotency-Key |
400 — invalid body or failed validation401 — missing / unknown / revoked key403 — account suspended (the key is valid — contact billing)409 — idempotency conflict (idempotency_key_reused = same key, different body; idempotency_key_in_progress = concurrent duplicate, retry)429 — monthly quota exhausted (account-wide) or per-minute rate exceeded500 — server error computing the return503 — metering outage (the call is never silently served free)Full machine-readable spec: /api/openapi.json (OpenAPI 3.1).