MCP Tool Versioning & Deprecation Contract
A written commitment about what we won’t break on mcp.digitalcalculator.info/mcp, when we’ll tell you before we do, and how our CI enforces it. If you’re integrating our MCP server into a production system, this page tells you exactly what stability you can count on. For the full technical specification, see the API Reference for per-tool schemas.
Our Promise
Our MCP server is designed for AI agents that make financial decisions. That only works if the shape of our answers stays predictable. So we make three promises:
- We will not silently change the shape of any tool. Every input parameter and every output field on
mcp.digitalcalculator.info/mcpis versioned. Changes that could break your code trigger a version bump and a deprecation notice. - We will not remove or rename anything without notice. Anonymous callers get at least 90 days notice; Bearer-tier customers get at least 180 days notice. During the notice window and for at least 60 days after, both the old shape and the new shape work.
- We enforce this with CI, not just documentation. Every build runs a schema-snapshot check plus a golden baseline of real tool calls against the live server. If either changes without an intentional version bump, the deploy fails.
- We will not break the REST aliases — ever. Every REST alias that has ever existed at
api.digitalcalculator.info/v1/tools/{alias}/calculatekeeps working indefinitely with its original request/response shapes, including the aliases of tools consolidated away from the MCP surface at the contract 1.0.0 release. The REST twin is where backward compatibility lives permanently, untouched by the MCP-side argument-spelling changes that shipped in 1.1.0/1.2.0; see the alias table.
Contract history: 1.0.0 through 2.7.0
Contract 1.0.0 (released 2026-08-07) was the pre-listing surface consolidation that reshaped the anonymous surface into 10 tools — four scenario tools plus the kept calculators and money_flow_map — and added the provenance envelope fields (rule_year, sources[]), reference-data resources, and prompts. It was executed deliberately under the 0.x rules, which permitted breaking changes precisely so that the surface frozen by directory listings would be the intended one; the promises on this page bind every release from 1.0.0 forward. What 1.0.0 did and kept is itemized in the changelog; the retired-tool migration map is in the API Reference.
The contract line has since moved through eleven additive (MINOR) releases to 1.11.0, and then to 2.0.0, the first MAJOR release — 1.1.0 added the argument deprecation notice below plus resultType, snake_case aliases, and MCP Apps/ChatGPT view extensions; 1.2.0 added JSON-RPC Bearer error envelopes, the discovery-exemption to the anonymous rate window, enforced additionalProperties: false, and plan_retirement_income provenance; 1.3.0 gave every validation-failure class its own message, added JSON Schema default to the 23 input properties whose prose already stated one, restructured instructions, and completed the retirement-readiness-review prompt’s own argument list; 1.4.0 added a tenth tool, evaluate_affordability, with its REST twin and manifest entry, changing nothing about the nine that existed; 1.5.0 added two opt-in capabilities to the existing surface — an optional target input on plan_retirement_income that solves for an input from a stated outcome, and Multi Round-Trip elicitation, which lets a call missing a required input come back as resultType: "input_required" naming what it needs; 1.6.0 made the statutory reference data versioned and diffable — a version and content_hash on every statutory resource, a real supersedes link, and rule-year diff resources — and added two resources; 1.7.0 added an https page beside every dc:// source (source_links[], provenance[].url), gave clients that declare a protocol revision with structuredContent a short text summary in content while structuredContent keeps the full result, and pointed evaluate_affordability at its own methodology page; 1.8.0 added the v2 envelope — a snake_case twin beside every camelCase output key, *_percent fields for every rate or ratio, and an inputs echo — and scheduled the removal of the camelCase names under the rule in Upcoming changes; 1.9.0 added the foundation for interactive result views — one app-only tool, recompute_scenario, that returns exactly what the tool it names returns, and content-hashed view URIs whose earlier fixed forms keep resolving; 1.10.0 added an interactive view for evaluate_affordability, shared with mortgage_monthly_payment, and rebuilt the loan view, both served by the stage endpoint only for now; 1.11.0 added an interactive view for emergency_fund_recommendation and rebuilt the project_growth view, again on the stage endpoint only for now, and began counting calls per tool per day (the tool name and the date only); 2.0.0 stopped paycheck_net_pay computing state income tax for any state, added the optional state_local_tax_annual argument and the state_tax_status field, and made five state output fields nullable. None of the twelve releases removed or renamed anything, but making a field nullable changes its type, which the rules below class as breaking, so 2.0.0 is MAJOR; its notice window was waived and disclosed (see below). A client that reads state_tax as a number should check state_tax_status first. 2.1.0 is MINOR again: project_growth gained the optional rate_type argument (nominal, the default and the earlier reading, or apy for a bank’s advertised yield), and two corrections toward the specified behavior rode it, which the rules below class as PATCH — plan_retirement_income’s accumulation module applies the IRC 415(c) limit on total annual additions, as the 401(k) calculator does, and emergency_fund_recommendation’s description no longer claims a methodology difference that no longer exists. 2.2.0 is MINOR too: plan_retirement_income gained the optional birth_month argument, and a correction toward the statute rode it — the rmd module’s start age is 72, not 70½, for people born from July 1, 1949 through 1950, as the SECURE Act of 2019 provides. 2.3.0 is MINOR too: paycheck_net_pay gained optional children_under_17 and other_dependents arguments and a dependent_credit_status output field, replacing the flat $2,000-per-dependent reading with Form W-4 (2026) Step 3’s two amounts ($2,200 per qualifying child under 17, $500 per other dependent) and its $200,000 / $400,000 income limit; the legacy dependents argument still works, read as qualifying children under 17; 2.4.0 added a warnings[] entry with field: "rule_year" to check_contribution_eligibility and plan_retirement_income when the IRS figures behind an answer may be out of date (a newer year published but not yet applied, or the rule year past its review date), moving no figure; 2.5.0 added a warnings[] entry with code: "input_out_of_range" when an argument is answered although it is outside its documented range (today only paycheck_net_pay’s legacy dependents), and announced that such values will be refused; 2.6.0 added first_rmd_estimate to plan_retirement_income’s rmd module, an estimate of the first required minimum distribution when accumulation is selected too and RMDs have not started, moving no figure; 2.7.0 gave evaluate_roth_conversion the optional horizon_years argument and redefined its break_even_years as the first year converting is at least even with not converting, compared like with like (or null), replacing a log-ratio estimate that could show a break-even where converting never caught up — the field keeps its name and type, so the new meaning is a correction toward the specified behavior and the release is MINOR. The serverInfo.version field of the live initialize handshake is always the authoritative answer for what production is currently running (1.4.0 through 2.0.0 reached production on 2026-09-27 and 2.1.0 through 2.6.0 on 2026-10-04; 2.7.0 reaches it on the owner’s dispatch, and until then production serves 2.6.0); see the changelog for the full release-by-release detail.
Versioning Rules
The MCP contract version is carried in the serverInfo.version field returned by the initialize handshake. It follows Semantic Versioning 2.0.0. This is the version of the contract, and it is deliberately distinct from the shim npm package version (@markcolabs/mcp) and from the internal deploy stack version.
| Bump | When it happens | Worked example |
|---|---|---|
| MAJOR | A change that could break an existing client. Removing a tool, renaming a tool, removing an input parameter, renaming an output field, changing an output field’s type, or tightening an input validation so previously-accepted inputs are now rejected. | Renaming mortgage_monthly_payment.monthlyPayment → monthlyPi. Existing code reading result.monthlyPayment would break, so this is MAJOR — and it would trigger the full notice + coexistence process below. |
| MINOR | An additive change that a compliant existing client keeps working through unchanged. New tools, new optional input parameters with documented defaults, new output fields, or expanding an input validation so previously-rejected inputs are now accepted. | Adding an optional catchUpEnabled: boolean parameter to retirement_401k_projection with default false. Clients that omit the field get the pre-existing behavior; clients that supply it get the new option. |
| PATCH | Internal changes that do not alter any observable contract surface. Engine formula refinements that keep the same output shape, bug fixes that bring outputs closer to specified behavior, performance improvements, documentation edits. | Refining an engine’s math to match a corrected IRS interpretation while keeping the same output field names and types (e.g., MPC-ENGINE-002, shipped in Sprint 148). |
Anonymous-parity note
A change that looks additive (MINOR) but causes the response to an anonymous caller to differ byte-for-byte from what it was before is treated as MAJOR — unless the change is scoped exclusively to authenticated responses. Bearer-tier feature additions cannot leak into the free anonymous tier. See Anonymous-Parity Guarantee.
Deprecation Policy
When we bump MAJOR, we commit to the following notice + coexistence process before the old shape is removed:
| Caller | Minimum notice before removal | Coexistence after notice window |
|---|---|---|
Anonymous tier (no Authorization header) |
90 days | ≥ 60 days with both shapes working |
| Bearer tier (authenticated) | 180 days | ≥ 60 days with both shapes working |
The Bearer window is longer because Bearer customers integrate the endpoint into production systems with change-management cycles measured in months. Anonymous callers are typically experimenting; they can pivot faster. The 90-day floor is still non-trivial — a developer who evaluates the endpoint anonymously and then upgrades to Bearer should not be surprised by a shape change 30 days in.
Every MAJOR bump publishes:
- A dated deprecation notice on this page under Upcoming changes.
- A notice in the deprecated tool’s MCP
descriptionfield — visible to any client that callstools/list. - An
X-DeprecationHTTP response header on the deprecated tool’s responses. Not every MCP client surfaces response headers, but this is machine-readable for those that do. - For Bearer-tier customers: a direct email to the address on file.
Emergency exception
A security fix or regulatory-compliance obligation that requires a breaking change without the full notice window MAY ship immediately. In that case the change is published here on the day of the deploy and affected customers are emailed directly. This exception is not routine — it exists so we can act on genuine security issues without waiting six months.
Notice waived and disclosed: contract 2.0.0
2.0.0 is a MAJOR change: in paycheck_net_pay, five output fields that were always numbers or booleans (state_tax, state_tax_annual, state_effective_rate_percent, state_tax_source, no_state_income_tax, with their camelCase twins) may now be null. The 90-day notice and the coexistence window were waived, and are disclosed here, because the release withdraws a state-tax figure that could be materially wrong on a tax question; keeping it published for the notice period was the greater risk. The owner decided this on 2026-09-26. Nothing was removed or renamed, and every call that worked before still works. See the changelog.
Argument Deprecation Notice: camelCase spellings (contract 1.1.0)
As of contract 1.1.0, the 17 camelCase input arguments on the four single-quantity calculator tools are deprecated in favor of a snake_case spelling: mortgage_monthly_payment (2 arguments), loan_monthly_payment (3), paycheck_net_pay (6), and emergency_fund_recommendation (6). Full per-field mapping: API Reference § Argument naming. This is the announcement surface DEPRECATION_NOTICE_URL in the server points to.
- Both spellings are accepted. This is additive under the rules above (a MINOR change, not MAJOR) — the old spelling still computes the same answer.
- The deprecated spelling is marked in the schema.
tools/listlists the camelCase property with the JSON Schemadeprecated: truekeyword, so a client reading the live schema can see the notice without reading this page. - Using the old spelling still works, with a marker. A request using a deprecated spelling computes its answer normally and adds a namespaced
_metafield to the result:result._meta["info.digitalcalculator/deprecatedArguments"], naming which field(s) were re-spelled. - Both spellings, different values, is rejected. If a request somehow supplies both the snake_case and camelCase spelling of the same field with different values, the server does not silently prefer one — it fails closed with the existing
INPUT_VALIDATIONshape. - Removal is scheduled by rule (contract 1.8.0). The camelCase spellings are removed together with the camelCase output keys, under the rule in Upcoming changes. Until then both spellings keep working, and the deprecated properties’ descriptions and the
_metamarker (itsremovalfield) carry the rule.
Upcoming changes: removing the camelCase names (announced 2026-09-25, contract 1.8.0)
Contract 1.8.0 gives every result one naming convention — the v2 envelope: a snake_case twin beside every camelCase output key, a whole-number *_percent field for every rate or ratio, and an inputs echo. The names it replaces will be removed in a later MAJOR release:
- What is removed: the 17 camelCase argument spellings listed above; every camelCase key in
structuredContent(for examplemonthlyPayment,yearByYear,calculatedAt), which includes every decimal-ratio key (monthlyRate,marginalRateOnConversion,effectiveRateOnConversion,stateEffectiveRate); andwarnings[].field, replaced bywarnings[].argument. The output schemas mark each removed propertydeprecated: true, and the API Reference lists every name and its replacement. - When: 2 minor versions or 60 days after production serves contract 1.8.0, whichever is later. Production serves 1.3.0 today and gets 1.8.0 on the owner’s deploy, so the rule counts from that deploy rather than from a fixed date; this page will carry the date once it is known.
- How: the removal is a MAJOR release, so the notice and coexistence windows above apply to it as well — whichever of these dates is latest governs. The removal ships no earlier than the rule allows and no earlier than those windows allow.
- What to do now: send the snake_case argument names and read the snake_case and
*_percentkeys. Both are live from 1.8.0, so a client that moves now is unaffected by the removal. - Not affected: the legacy REST aliases, which keep their wire shapes indefinitely, and enum values such as
"fullyDeductible", which keep their spelling.
Upcoming changes: refusing out-of-range arguments (announced 2026-09-29, contract 2.5.0)
Every numeric argument documents its accepted range in the tool’s inputSchema, and almost every range is enforced: a value outside it is refused with INPUT_VALIDATION. A value that is answered anyway will be refused too, in a later MAJOR release:
- What changes: a numeric argument outside its documented range (its minimum, its maximum, or a whole-number requirement) is refused with
INPUT_VALIDATIONinstead of answered. Today this affects one argument:paycheck_net_pay’s legacydependents, documented as a whole number from 0 to 20. - When: no earlier than 2027-05-27, which is the 180-day notice (the Bearer-tier window, the longer of the two above) plus the 60-day coexistence window, counted from this announcement; and no earlier than 180 days after production first serves contract 2.5.0. Whichever date is later governs.
- Until then: the value is answered as before, and from contract 2.5.0 the answer carries a
warnings[]entry withcode: "input_out_of_range"naming the argument, the value and the accepted range. The argument’s description intools/listcarries the date. - What to do now: send values inside the documented range. For
dependents, send a whole number from 0 to 20, or usechildren_under_17andother_dependents.
Amendment B: the generate_report.input exception
generate_report’s input argument is a documented, permanent exception to the snake_case argument policy above: it is not re-spelled, and carries no deprecated-argument aliases. input is the POST /v1/reports/{tool} REST report body, carried verbatim to the report renderer — ADR-0064 § 2.6 Amendment B pin #3 states that legacy REST wire vocabulary is preserved “verbatim through a thin translation map at the dispatch layer … so ‘REST unchanged’ stays literally true.” Three of the five report-capable tool aliases (retirement-401k, education, credit-card) have no snake_case MCP twin at all, so introducing an alias layer here would cover 2 of 5 tools and invent a new vocabulary for the rest. additionalProperties: false is still enforced on generate_report’s own top level (tool, input); it is input’s own contents that stay an open, un-aliased object matching the REST wire.
Anonymous-Parity Guarantee
Every request without an Authorization header must return byte-for-byte the same response body as it would have returned before Bearer tier existed. That is what we mean by anonymous parity: the free tier does not silently regress when we ship paid features. It matters because the anonymous tier is how developers evaluate our server before they buy — if the evaluation drifts, the buy decision does too. We enforce it with a golden baseline of real tool calls that runs in CI on every build; the baseline was captured with no Authorization header, so any Bearer-tier addition that leaks into anonymous responses fails the build. The technical specification is ADR-0053 § 2.4.
What This Doesn’t Cover
- The REST companion endpoint at
api.digitalcalculator.info/v1/…uses URL-path versioning (/v1/,/v2/) rather thanserverInfo.version. Its alias-compatibility guarantee (every alias that predates the contract-1.0.0 consolidation works indefinitely, original wire shapes preserved) is stated above and in the API Reference; a fuller standalone REST contract publishes when REST reaches GA. - Pricing tiers, quotas, and SLA commitments live on the pricing page (when published) and in the Bearer-tier terms. Changes to those are not contract changes governed here unless they change a tool’s
inputSchemaor output. - Uptime SLAs. This is a stability contract about the shape of our answers, not a guarantee about how often the endpoint is reachable. Availability commitments for Bearer tier are in the Bearer terms.
- The
@markcolabs/mcpnpm shim is versioned separately. A shim PATCH does not imply a contract change; a contract MINOR does not imply a shim change.
FAQ
What is the current contract version?
The version is returned in the serverInfo.version field of the initialize handshake response. Point any MCP client at https://mcp.digitalcalculator.info/mcp and read the field. That is the canonical answer — it can never disagree with what the server is actually running.
Does adding a new tool require a MAJOR bump?
No. Adding a tool is additive — it is a MINOR bump. Existing clients that were not calling the new tool continue to work with no change. Removing or renaming an existing tool is what triggers MAJOR.
What counts as a “shape change” that requires notice?
Any change a compliant client would notice on the wire: a field disappearing, a field changing type, a field being renamed, an input value that used to be accepted now being rejected, or a tool being removed / renamed. Engine math refinements that keep the same output field names and types are PATCH — not shape changes — and do not require notice. The per-tool engineVersion field in every response tells you when the math has been refined.
Where do I subscribe to deprecation notices?
Today: check this page and, if you’re a Bearer-tier customer, watch the email on your account. A formal changelog surface with RSS + email subscription is planned but not yet live. Until it ships, this page is the single source of truth.
How do I know you’re actually enforcing this?
Every build on our stage and production pipelines runs two checks: a JSON schema snapshot of every tool’s input and output, and a golden baseline of live tool responses. Either check failing blocks the deploy. If we want to change a shape, we have to update the snapshot in the same pull request — which is where a reviewer confirms the version bump matches the change class. The baseline was published in June 2026 at qa-reports/mcp/MCP-TOOL-BASELINE-2026-06-12.md.
What if you discover a serious contract-design flaw after Bearer customers are onboarded?
The 180-day Bearer notice window is by design — fixing a design flaw takes six-plus months from notice to full cutover. That’s the cost of the promise’s value. Security or regulatory fixes ship faster under the emergency exception; other design flaws wait for the coexistence window.
See Also
- API Reference — per-tool schemas, output shapes, and error codes (the technical surface this contract governs)
- MCP Server hub — overview + connection options
- Quickstart — connect and make your first call
- FAQ — accuracy, support, and general questions