Public Beta

Retirement Lab MCP documentation

Run hypothetical retirement simulations across countries, taxes, spending, and market assumptions.

Endpoint: https://retirementlab.app/api/mcp

Retirement Lab is a financial calculator. Every result is a hypothetical projection based on the inputs and assumptions supplied, not financial, tax, investment, or legal advice and not a forecast or guarantee.

Connect a client

OAuth (primary)

Add https://retirementlab.app/api/mcp as a remote MCP server. A compatible client discovers Retirement Lab’s OAuth metadata, opens a browser, and asks you to approve the mcp scope. Access and refresh tokens are opaque and hashed at rest. Disconnect a client from Connected apps in the Retirement Lab account menu; its next MCP call will fail with 401.

API key (advanced fallback)

  1. Sign in at Retirement Lab.
  2. Open the account menu, choose MCP API keys, add a label, and issue the key.
  3. Copy the cleartext once. The server stores only its SHA-256 hash.
  4. Configure a Streamable HTTP client with URL https://retirementlab.app/api/mcp and header Authorization: Bearer <key>.
  5. Rotate or revoke the key from the same account screen. Rotation immediately invalidates the previous value.

Never send an API key to another host or place it in a prompt, source file, or shared transcript.

Supported clients and transport

Retirement Lab uses stateless Streamable HTTP and supports MCP protocol revisions 2025-03-26 and 2025-06-18. It is designed for remote-connector clients with OAuth, including Claude on the web and Claude Desktop. Remote connectors already added on the web can be used from Claude mobile. Claude Code and other MCP clients can connect when they support Streamable HTTP plus OAuth, or a client-specific static bearer header for the API-key fallback.

Generic setup values:

{
  "name": "Retirement Lab",
  "transport": "streamable_http",
  "url": "https://retirementlab.app/api/mcp",
  "authentication": "oauth"
}

Currency contract

  • A simulation’s country is its country of tax residence.
  • Country never determines the units of monetary input values.
  • Root-level input_currency declares those units as an ISO 4217 code.
  • All monetary values in one payload must use the same currency.
  • The server converts once into the tax-residence country’s calculator currency and returns the rate and provenance it used.

For explicit monetary sweep values, use sweep_currency. For a JSON Merge Patch containing money, use patch_currency. Do not infer currency from a symbol, country, citizenship, or income-source country.

Supported countries and tax regimes

This list is rendered from the calculator’s tax-policy registry:

Australia, Austria, Belgium, Brazil, Canada, Chile, Costa Rica, Cyprus, Czech Republic, France, Germany, Greece, Hungary, Italy, Japan, Malaysia, Malta, Mexico, Netherlands, Panama, Portugal, Singapore, South Africa, Spain, Switzerland, Thailand, UAE, UK, US, Uruguay, Vietnam

The default regime is the ordinary resident tax model for the selected country. These additional time-bounded regimes are rendered from the implementation registry:

RegimeCountryInput keyModeled duration
Cyprus_NonDomCyprusnon-dom17 years
Greece_PensionerGreeceforeign-pensioner-flat-7pct15 years
Italy_PensionerItalypensioner-flat-7pct10 years
Malta_NonDomMaltanon-dom17 years
NHRPortugalnhr10 years

Call get_supported_inputs at the start of a session for the current machine-readable countries, regimes, currencies, portfolio presets, assumptions version, wrapper IDs, and a minimal valid payload.

Account wrapper discovery

wrapper_ids_by_country lists the account wrappers available in each country. A Roth conversion must name a stable wrapper id, never a bucket name such as tax_deferred, and get_supported_inputs is the source of valid IDs.

CountryIDLabelBucket
AustraliasuperannuationSuperannuationtax_deferred
AustraliataxableTaxable accounttaxable
Austriataxable_genericTaxable brokeragetaxable
Austriatax_deferred_genericTax-deferred accounttax_deferred
Austriatax_free_genericTax-free accounttax_free
Belgiumtaxable_genericTaxable brokeragetaxable
Belgiumtax_deferred_genericTax-deferred accounttax_deferred
Belgiumtax_free_genericTax-free accounttax_free
Braziltaxable_genericTaxable brokeragetaxable
Braziltax_deferred_genericTax-deferred accounttax_deferred
Braziltax_free_genericTax-free accounttax_free
CanadarrspRRSPtax_deferred
CanadatfsaTFSAtax_free
Canadanon_registeredNon-registered accounttaxable
Chiletaxable_genericTaxable brokeragetaxable
Chiletax_deferred_genericTax-deferred accounttax_deferred
Chiletax_free_genericTax-free accounttax_free
Costa Ricataxable_genericTaxable brokeragetaxable
Costa Ricatax_deferred_genericTax-deferred accounttax_deferred
Costa Ricatax_free_genericTax-free accounttax_free
Cyprustaxable_genericTaxable brokeragetaxable
Cyprustax_deferred_genericTax-deferred accounttax_deferred
Cyprustax_free_genericTax-free accounttax_free
Czech Republictaxable_genericTaxable brokeragetaxable
Czech Republictax_deferred_genericTax-deferred accounttax_deferred
Czech Republictax_free_genericTax-free accounttax_free
FranceperPERtax_deferred
FrancepeaPEAtax_free
Franceassurance_vieAssurance-vietax_deferred
Francelivret_aLivret Atax_free
Francefr_taxable_brokerageTaxable brokeragetaxable
GermanyriesterRiestertax_deferred
GermanyruerupRueruptax_deferred
GermanybavbAVtax_deferred
Germanyde_taxable_brokerageTaxable brokeragetaxable
Greecetaxable_genericTaxable brokeragetaxable
Greecetax_deferred_genericTax-deferred accounttax_deferred
Greecetax_free_genericTax-free accounttax_free
Hungarytaxable_genericTaxable brokeragetaxable
Hungarytax_deferred_genericTax-deferred accounttax_deferred
Hungarytax_free_genericTax-free accounttax_free
Italyfondo_pensioneFondo pensionetax_deferred
ItalypipPIPtax_deferred
ItalypirPIRtax_free
Italyit_taxable_brokerageTaxable brokeragetaxable
JapanideciDeCotax_deferred
JapannisaNISAtax_free
Japancorporate_dcCorporate DCtax_deferred
Japanjp_taxable_brokerageTaxable brokeragetaxable
Malaysiataxable_genericTaxable brokeragetaxable
Malaysiatax_deferred_genericTax-deferred accounttax_deferred
Malaysiatax_free_genericTax-free accounttax_free
Maltataxable_genericTaxable brokeragetaxable
Maltatax_deferred_genericTax-deferred accounttax_deferred
Maltatax_free_genericTax-free accounttax_free
Mexicotaxable_genericTaxable brokeragetaxable
Mexicotax_deferred_genericTax-deferred accounttax_deferred
Mexicotax_free_genericTax-free accounttax_free
Netherlandstaxable_genericTaxable brokeragetaxable
Netherlandstax_deferred_genericTax-deferred accounttax_deferred
Netherlandstax_free_genericTax-free accounttax_free
Panamataxable_genericTaxable brokeragetaxable
Panamatax_deferred_genericTax-deferred accounttax_deferred
Panamatax_free_genericTax-free accounttax_free
PortugalpprPPRtax_deferred
Portugalpt_taxable_brokerageTaxable brokeragetaxable
Singaporetaxable_genericTaxable brokeragetaxable
Singaporetax_deferred_genericTax-deferred accounttax_deferred
Singaporetax_free_genericTax-free accounttax_free
South Africataxable_genericTaxable brokeragetaxable
South Africatax_deferred_genericTax-deferred accounttax_deferred
South Africatax_free_genericTax-free accounttax_free
Spainplan_de_pensionesPlan de Pensionestax_deferred
SpainppaPPAtax_deferred
SpainpiasPIAStax_free
Spaines_taxable_brokerageTaxable brokeragetaxable
Switzerlandtaxable_genericTaxable brokeragetaxable
Switzerlandtax_deferred_genericTax-deferred accounttax_deferred
Switzerlandtax_free_genericTax-free accounttax_free
Thailandtaxable_genericTaxable brokeragetaxable
Thailandtax_deferred_genericTax-deferred accounttax_deferred
Thailandtax_free_genericTax-free accounttax_free
UAEtaxable_genericTaxable brokeragetaxable
UAEtax_deferred_genericTax-deferred accounttax_deferred
UAEtax_free_genericTax-free accounttax_free
UKsippSIPPtax_deferred
UKisaISAtax_free
UKgiaGeneral Investment Accounttaxable
US401k401(k)tax_deferred
UStraditional_iraTraditional IRAtax_deferred
USroth_iraRoth IRAtax_free
USroth_401kRoth 401(k)tax_free
UShsaHSAtax_free
UStaxable_brokerageTaxable brokeragetaxable
Uruguaytaxable_genericTaxable brokeragetaxable
Uruguaytax_deferred_genericTax-deferred accounttax_deferred
Uruguaytax_free_genericTax-free accounttax_free
Vietnamtaxable_genericTaxable brokeragetaxable
Vietnamtax_deferred_genericTax-deferred accounttax_deferred
Vietnamtax_free_genericTax-free accounttax_free

Generic wrapper IDs: taxable_generic (taxable), tax_deferred_generic (tax_deferred), tax_free_generic (tax_free). A generic ID requires a corresponding explicit account when accounts are provided. taxable, tax_deferred, and tax_free are bucket classifications, not wrapper IDs.

Annual savings window

Validation rule: A positive annual_savings requires retirement_year to be greater than initial_year. The MCP error returned before enqueue states the same rule.

Relocation discovery

Only same-currency relocation events are currently supported, such as Spain to Portugal (EUR). For different-currency tax residences, use compare_countries to run separate hypothetical projections.

Asynchronous run lifecycle

  1. Enqueue: call run_simulation, compare_countries, sensitivity_sweep, or run_sweep. Save the returned run_id and poll_after_ms.
  2. Wait or poll: call wait_for_run with that id, or poll get_run_result, until status is succeeded or failed.
  3. Inspect: call get_run_result with selectors such as sweep_points, comparison, yearly_percentiles, or simulation_snapshot. The stored result reports what the hypothetical simulation shows; it does not rerun compute.

Succeeded sweeps return compact sweep_points by default, and sweep_points is also an explicit get_run_result selector.

Idempotent enqueue

Reusing an idempotency_key replays a stored enqueue for 15 minutes. After that window the key has expired, so the same key is a new enqueue rather than a replay guarantee.

Inspect an immutable share

get_share returns compact headline results by default and omits the full configuration and percentile time series.

{
  "token_or_url": "example-token"
}

Request canonical inputs or year-by-year bands explicitly:

{
  "token_or_url": "example-token",
  "selectors": [
    "simulation_snapshot"
  ]
}
{
  "token_or_url": "example-token",
  "selectors": [
    "yearly_percentiles"
  ]
}

Current quotas and tier limitations

The values below are read from the same settings used by the runtime. They can change as the Public Beta is tuned.

LimitFreePro / 30-day Pass
Daily MCP compute units101000
Simulation paths per payload10,000100,000
Explicit sweep values10100
Simulation horizon75 years120 years
Country comparisonUp to 2 countriesSubject to sweep caps

Compute requests also use a distributed limit of 60 requests per 60 minutes, a 1,000,000-byte compact-result cap, and a 30-second maximum per wait_for_run call. An account can keep up to 5 active API keys. OAuth and API keys for one user draw from the same user-level compute allowance. Product feature gates still apply; for example, a comparison with three or more countries requires Pro or a 30-day Pass.

Complete example workflows

These inline examples deliberately omit simulation_mode. For MCP simulation and sweep calls, omission defaults to monte_carlo_iid; set another supported mode explicitly to override it.

1. Run a retirement simulation

First call get_supported_inputs. Then call run_simulation with these arguments:

{
  "input_currency": "USD",
  "simulation": {
    "initial_year": 2026,
    "age": 45,
    "plan_to_age": 95,
    "initial_net_worth": 1000000,
    "baseline_annual_expenses": 60000,
    "additional_expenses": [],
    "additional_income": [],
    "country": "US",
    "avg_return": 0.07,
    "volatility": 0.12,
    "approximate_yield_rate": 0.02,
    "taxable_balance": 500000,
    "tax_deferred_balance": 350000,
    "tax_free_balance": 150000,
    "taxable_cost_basis": 350000
  },
  "idempotency_key": "example-retirement-run-1"
}

Use the returned id in wait_for_run:

{
  "run_id": 123,
  "max_wait_seconds": 10
}

If still queued or running, wait for poll_after_ms and repeat. When it succeeds, inspect compact results:

{
  "run_id": 123,
  "selectors": [
    "yearly_percentiles"
  ]
}

2. Compare countries or tax-residence assumptions

Call compare_countries with the same USD-denominated financial inputs for each tax residence. A three-country comparison requires Pro or a 30-day Pass.

{
  "input_currency": "USD",
  "base_payload": {
    "simulation": {
      "initial_year": 2026,
      "age": 45,
      "plan_to_age": 95,
      "initial_net_worth": 1000000,
      "baseline_annual_expenses": 60000,
      "additional_expenses": [],
      "additional_income": [],
      "country": "US",
      "avg_return": 0.07,
      "volatility": 0.12,
      "approximate_yield_rate": 0.02,
      "taxable_balance": 500000,
      "tax_deferred_balance": 350000,
      "tax_free_balance": 150000,
      "taxable_cost_basis": 350000
    }
  },
  "countries": [
    "US",
    "Spain",
    "Portugal"
  ],
  "idempotency_key": "example-country-comparison-1"
}

Wait for the returned run id, then call get_run_result with:

{
  "run_id": 124,
  "selectors": [
    "comparison"
  ]
}

Each row is a hypothetical projection for the same supplied inputs under that tax-residence assumption. It is not a relocation instruction.

Cost-of-living scaling can change the spending basis for each country point, and applied_assumptions.cost_of_living is the receipt for what was applied. failure_rate_without_tax removes taxes from an already transformed point; it does not undo FX conversion, COL-adjusted spending, or other explicit point transforms.

3. Run a sensitivity sweep and inspect the result

Call sensitivity_sweep to vary one supported assumption:

{
  "input_currency": "USD",
  "payload": {
    "simulation": {
      "initial_year": 2026,
      "age": 45,
      "plan_to_age": 95,
      "initial_net_worth": 1000000,
      "baseline_annual_expenses": 60000,
      "additional_expenses": [],
      "additional_income": [],
      "country": "US",
      "avg_return": 0.07,
      "volatility": 0.12,
      "approximate_yield_rate": 0.02,
      "taxable_balance": 500000,
      "tax_deferred_balance": 350000,
      "tax_free_balance": 150000,
      "taxable_cost_basis": 350000
    }
  },
  "variable": "retirement_year",
  "values": [
    "2040",
    "2045",
    "2050"
  ],
  "idempotency_key": "example-retirement-age-sweep-1"
}

Wait for the returned run id, then inspect the stored sweep:

{
  "run_id": 125,
  "selectors": [
    "sweep_points"
  ]
}

Summarize only the failure probabilities and other values the simulation returns, given these assumptions.

Completed-run web records

When presenting a completed run, include its history_url as the account's saved web record. Succeeded result tools describe only manifested, same-account web capabilities. Public-share availability names create_share_link only when available and always requires the user's request; it does not create a share automatically.

Link campaigns distinguish surfaces: history uses run_result, result attribution uses funnel_attribution, shares use share_link, and downloads use run_export. They are not impression, click, or CTR events.

Tool catalog and safety behavior

This catalog is generated from the registered MCP tools. Public-share creation is explicitly marked as a state-changing action that crosses a public boundary.

Live registry: 22 tools · catalog revision sha256-40b7b9835a984757

  • Render Projection render_projectionRead-only

    After reading or waiting for a completed run or immutable share, call this once to render its stored hypothetical projection. It never starts or polls compute.

  • Run Retirement Simulation run_simulationChanges account state; may cross a public/external boundary

    Enqueue a hypothetical projection; based on your inputs, the simulation shows status and polling details after REST authorization checks run. For an inline simulation, omitting simulation_mode defaults to monte_carlo_iid.

  • Run Parameter Sweep run_sweepChanges account state; may cross a public/external boundary

    General sweep interface for the broader sweep-variable set and engine-generated points. Enqueue a hypothetical projection after REST tier and run-limit checks; use compare_countries for country comparisons. For an inline simulation, omitting simulation_mode defaults to monte_carlo_iid.

  • Compare Tax Residences compare_countriesChanges account state; may cross a public/external boundary

    Compare supported countries by enqueueing a country sweep for a hypothetical projection; based on your inputs, the simulation shows status and polling details. For an inline simulation, omitting simulation_mode defaults to monte_carlo_iid.

  • Run Sensitivity Sweep sensitivity_sweepChanges account state; may cross a public/external boundary

    Preferred convenience wrapper for explicit values of its supported single non-country variables. Enqueue a hypothetical projection and return status and polling details. For an inline simulation, omitting simulation_mode defaults to monte_carlo_iid.

  • Inspect Simulation Result get_run_resultRead-only

    Return compact stored results for a run; the simulation shows probabilities, terminal-wealth percentiles, and selected details based on your inputs. Succeeded sweeps include compact sweep_points by default; sweep_points is also an explicit sweep selector. Use the yearly_percentiles selector for year-by-year percentile bands of the hypothetical projection, suitable for charting.

  • Read Saved Scenario get_scenarioRead-only

    Read a private mutable saved scenario and its normalized calculator inputs.

  • Read Shared Result get_shareRead-only; may cross a public/external boundary

    Read a compact immutable public hypothetical-result share summary. The default omits the full configuration and year-by-year arrays. Select simulation_snapshot for canonical inputs or yearly_percentiles for aligned years and p10/p50/p90 arrays. To change its inputs, create a private variant from the share directly.

  • List Saved Scenarios list_scenariosRead-only

    List private saved calculator scenarios, which may later be updated or cloned.

  • List Simulation Runs list_runsRead-only

    List private immutable hypothetical-run summaries without loading result or simulation payloads.

  • List Shared Results list_sharesRead-only

    List immutable public hypothetical-result share snapshots owned by this account.

  • Create Saved Scenario create_scenarioChanges account state; may cross a public/external boundary

    Create a new mutable saved calculator scenario from a validated simulation payload.

  • Update Saved Scenario update_scenarioChanges account state

    Apply JSON Merge Patch to saved calculator inputs using optimistic concurrency. Runs and public shares cannot be updated.

  • Clone Scenario clone_scenarioChanges account state

    Create a new mutable saved calculator scenario from a scenario, immutable run, or immutable public share snapshot.

  • Create Scenario Variant create_variantChanges account state; may cross a public/external boundary

    Apply JSON Merge Patch to a scenario, run, or public share; optionally save and enqueue the resulting hypothetical projection. Lineage is persisted.

  • Preview Exit Tax preview_exit_taxRead-only; may cross a public/external boundary

    Preview a proposed relocation exit-tax calculation; based on your inputs, the hypothetical projection shows estimated tax impact without enqueueing compute.

  • Preview Roth Conversion Tax preview_conversion_taxRead-only; may cross a public/external boundary

    Preview a Roth conversion tax calculation; based on your inputs, the hypothetical projection shows estimated tax impact without enqueueing compute.

  • Wait for Simulation Run wait_for_runRead-only

    Poll a stored run for a bounded period and return what the simulation shows once available, or a still-running envelope. Use the yearly_percentiles selector for year-by-year percentile bands of the hypothetical projection, suitable for charting.

  • Save Run as Scenario save_scenarioChanges account state

    Save an unnamed run as a named scenario when the user asks to keep, name, or share it; otherwise runs stay unnamed and appear in the web app's run history. The history_url opens the stored hypothetical projection in the web app.

  • Create Public Share Link create_share_linkChanges account state; may cross a public/external boundary

    Create an externally visible, unlisted, immutable hypothetical-result share URL from exactly one completed run_id or the latest clean completed run for config_name. Anyone with the URL can view it; this never reruns a scenario.

  • Cancel Simulation Run cancel_runChanges account state

    Cancel a queued or running MCP-originated hypothetical projection owned by this account.

  • List Supported Inputs get_supported_inputsRead-only

    List supported calculator inputs, including countries, tax regimes, simulation modes, and the current assumptions version. The response also includes a ready-to-adapt minimal example payload and a short list of common input traps, including that omitted simulation_mode defaults to monte_carlo_iid for MCP runs.

Data handling

  • OAuth and API-key calls run as your Retirement Lab account and can read or change only resources the account can access.
  • Scenario inputs and simulation results are stored so you can inspect and rerun them. Authenticated account data remains until account deletion.
  • OAuth tokens and API keys are opaque and stored only as hashes. Cleartext API keys are displayed once.
  • Tool-call analytics record an internal user id, tool name, result status, tier, and coarse authentication method. They do not store raw credentials, email addresses, prompts, or financial payloads for adoption measurement.
  • A link created by create_share_link is unlisted but public: anyone with it can view the immutable shared result.

See the Retirement Lab Privacy Policy for collected data, processors, retention, export, deletion, and contact details.

Active-user metric: A distinct non-test Retirement Lab user with at least one MCP tool-call analytics event in the rolling window. OAuth and API-key breakdowns may overlap when one user uses both methods; no credential secrets or email addresses are stored in this metric.

Troubleshooting

OAuth does not start or fails
Confirm the endpoint is exactly https://retirementlab.app/api/mcp, allow the browser sign-in window, and retry from the client. If a prior connection is stale, disconnect it under Connected apps and connect again.
Invalid inputs
Call get_supported_inputs, use an exact country label, include input_currency, and keep all money in that payload in the declared currency. Read structured validation details before retrying.
A run is still queued or running
This is expected: simulations are asynchronous. Honor poll_after_ms and call wait_for_run or get_run_result again. Do not enqueue a duplicate; reuse an idempotency_key when retrying an enqueue.
Quota or tier error
Read the returned cap, remaining daily compute units, and reset timing. Reduce paths, sweep values, or countries, or wait for the quota window. A tier error describes the product capability required.
Expired or revoked credentials
For OAuth, restart the connection flow. For an API key, issue or rotate a key in the account menu and replace the old bearer value. Revoked values cannot be restored.

Support

Visit support or contact support@cedarwelllabs.com and include the client name, approximate time, tool name, and non-secret error text. Never send an API key, OAuth token, or complete financial payload. The availability of inbound routing does not establish how outbound replies are configured.