MCP Server Versioning and Backwards Compatibility: Managing Breaking Changes Across MCP Server Upgrades
MCP Server Versioning and Backwards Compatibility: Managing Breaking Changes Across MCP Server Upgrades
Introduction
If you run more than a handful of MCP servers with Codex CLI, you have already felt the pain: a server upgrades its tool schema, your agent workflow silently breaks, and the first symptom is a cryptic -32602 Invalid Params error three pipeline stages downstream. The Model Context Protocol now has a formal versioning specification, a feature lifecycle policy, and — landing on 28 July 2026 — a release candidate that introduces genuinely breaking changes to the protocol itself1. This article maps the full versioning landscape from protocol revisions through server-level SemVer to the practical Codex CLI configuration you need to survive an upgrade without downtime.
Protocol-Level Versioning
MCP uses date-stamped version strings in YYYY-MM-DD format2. The current protocol version is 2025-11-25; the next revision, 2026-07-28, is in its ten-week validation window with a release candidate locked on 21 May 20261.
The version is not incremented for backwards-compatible changes — only for breaking ones2. During the initialize handshake, the client sends its desired version and the server responds with the version it will use. If negotiation fails, the client must terminate gracefully2.
sequenceDiagram
participant Client as Codex CLI
participant Server as MCP Server
Client->>Server: initialize { protocolVersion: "2025-11-25" }
Server-->>Client: { protocolVersion: "2025-11-25", capabilities: {...} }
Client->>Server: initialized {}
Note over Client,Server: Session established on agreed version
What Changes in 2026-07-28
The upcoming revision introduces several breaking changes that every MCP consumer must prepare for1:
| Change | Impact | Migration |
|---|---|---|
| Stateless architecture (SEP-2575) | initialize/initialized handshake removed |
Adopt explicit handle patterns |
| Tasks API → extension | tools/call responses replaced with task handles |
Use tasks/get, tasks/update, tasks/cancel |
Error code -32002 → -32602 |
Missing resource error code changes | Update error matching logic |
JSON Schema 2020-12 for inputSchema/outputSchema |
oneOf, anyOf, allOf, $ref now permitted |
Validate against full JSON Schema |
Mandatory Mcp-Method and Mcp-Name headers |
Streamable HTTP transport routing | Add headers to HTTP server implementations |
ttlMs and cacheScope metadata |
List and resource responses include caching hints | Implement cache-aware client logic |
Three features are deprecated with a twelve-month removal window: Roots, Sampling, and Logging1. Roots should be replaced with tool parameters or resource URIs; Logging should migrate to OpenTelemetry1.
The Feature Lifecycle Policy
Adopted via SEP-2596, the feature lifecycle defines three states3:
stateDiagram-v2
[*] --> Active
Active --> Deprecated: SEP accepted
Deprecated --> Removed: After min. 12 months
Deprecated --> Active: SEP supersedes deprecation
Removed --> [*]
Key constraints:
- Minimum deprecation window: twelve months from the revision release, not from the SEP date3.
- Expedited removal: only for active security risks with a published advisory — still requires ninety days minimum3.
- SDK obligation: Tier 1 SDKs must mark deprecated APIs using native language mechanisms in their next release after the deprecation revision ships3.
- Migration path: every deprecation SEP must document one, or explicitly state none is required3.
This means any feature deprecated in the 2026-07-28 revision cannot be removed before approximately August 2027 at the earliest.
Server-Level Versioning
The protocol version governs the wire format; individual MCP servers need their own versioning strategy. The MCP Registry (currently in preview) mandates a version string in server.json and recommends Semantic Versioning4:
{
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
"name": "io.github.acme/database-mcp",
"title": "Database Tools",
"version": "2.1.0",
"packages": [
{
"registryType": "npm",
"identifier": "@acme/database-mcp",
"version": "2.1.0",
"transport": { "type": "stdio" }
}
]
}
Critical rules from the registry specification4:
- The version string must be unique per publication; once published, it is immutable.
- Server version should align with the underlying package version to avoid the confusion documented in GitHub Discussion #1176, where
server-everythingreported1.0.0whilepackage.jsonlisted0.6.25. - Version ranges (
^1.2.3,~1.2.3,1.x) are prohibited. - Servers must not change the behaviour of an existing
(name, version)pair without bumping the version6.
Tool Schema Evolution
The forthcoming tool versioning guidance (GitHub Issue #1915) proposes that tool names should remain stable across minor versions, with breaking schema changes requiring a major version bump6. In practice, this means:
# Pin to a known-good version via container tag
[mcp_servers.database]
command = "docker"
args = ["run", "--rm", "-i", "acme/database-mcp:2.1.0"]
Rather than:
# Risky: :latest may introduce breaking tool schema changes
[mcp_servers.database]
command = "docker"
args = ["run", "--rm", "-i", "acme/database-mcp:latest"]
Managing Upgrades in Codex CLI
Version Pinning in config.toml
Codex CLI stores MCP server configuration in ~/.codex/config.toml (global) or .codex/config.toml (project-scoped, trusted projects only)7. The configuration supports several controls relevant to version management:
[mcp_servers.database]
command = "npx"
args = ["-y", "@acme/database-mcp@2.1.0"]
startup_timeout_sec = 15
tool_timeout_sec = 120
enabled = true
required = true
enabled_tools = ["query", "schema_inspect", "migrate"]
Key parameters for upgrade safety7:
required = true: Codex CLI will fail to start if this server cannot initialise, catching version incompatibilities early rather than mid-workflow.enabled_tools: allowlist specific tools you depend on — if a server upgrade renames or removes a tool, the missing tool is immediately visible.startup_timeout_sec: increase if a new server version has a heavier initialisation path.
The Canary Upgrade Pattern
When upgrading an MCP server, run the old and new versions in parallel using Codex CLI profiles:
# ~/.codex/config.toml
[profiles.stable]
[profiles.stable.mcp_servers.database]
command = "npx"
args = ["-y", "@acme/database-mcp@2.1.0"]
enabled = true
[profiles.canary]
[profiles.canary.mcp_servers.database]
command = "npx"
args = ["-y", "@acme/database-mcp@3.0.0-rc.1"]
enabled = true
Test with the canary profile before cutting over:
# Run a targeted workflow against the new version
codex --profile canary "Run the database migration dry-run and report any tool errors"
# If stable, switch default
# In config.toml, set: profile = "canary"
The --profile flag is the primary profile selector in Codex CLI v0.50+, covering CLI, TUI permissions, and sandbox flows8.
Handling the 2026-07-28 Protocol Migration
When Codex CLI ships support for the 2026-07-28 protocol revision, servers that still speak 2025-11-25 will continue to work during a transition period — but the following changes require attention:
- Error code matching: if your agent scripts match on
-32002for missing resources, update to-326021. - Tasks API consumers: any workflow using
tools/calltask responses must migrate to the Tasks extension withtasks/getandtasks/update1. - HTTP server headers: remote MCP servers behind Streamable HTTP must add
Mcp-MethodandMcp-Nameheaders1.
flowchart TD
A[MCP Server Upgrade Available] --> B{Breaking change?}
B -->|No| C[Bump version pin in config.toml]
C --> D[Run agent smoke test]
D --> E{Tests pass?}
E -->|Yes| F[Deploy]
E -->|No| G[Investigate tool schema diff]
B -->|Yes| H[Create canary profile]
H --> I[Run parallel testing]
I --> J{Canary stable?}
J -->|Yes| K[Migrate primary profile]
J -->|No| L[Pin to current version, file upstream issue]
Defensive Patterns for Multi-Server Configurations
When running multiple MCP servers, a single server’s breaking change can cascade through your agent workflow. Apply these patterns:
1. Explicit Version Constraints
Pin every server to a specific version. For npm-based servers, use exact versions in args; for Docker-based servers, use immutable image digests rather than tags:
[mcp_servers.database]
command = "docker"
args = ["run", "--rm", "-i", "acme/database-mcp@sha256:a1b2c3d4..."]
2. Tool Allowlisting
Use enabled_tools to create an explicit contract between your agent workflow and the server’s tool surface:
[mcp_servers.database]
enabled_tools = ["query", "schema_inspect"]
disabled_tools = ["drop_table"]
If version 3.0 renames query to execute_query, the missing tool surfaces immediately rather than producing silent failures7.
3. Last-Known-Good Branching
Maintain a Git branch with your last stable .codex/config.toml. If an upgrade breaks a downstream consumer, revert to the known-good configuration, fix forward, and retry8:
git checkout last-known-good -- .codex/config.toml
codex "Verify all MCP tools are accessible and responding"
4. Read-Only Concurrency
Codex CLI now runs read-only MCP tools concurrently when they advertise readOnlyHint8. When upgrading a server, verify that tools which previously ran sequentially still behave correctly under concurrent execution — a common source of subtle regressions.
The MCP Registry and Aggregator Ecosystem
The MCP Registry (preview) provides a centralised publication point for server metadata4. Aggregators should follow these version comparison rules:
- If one version is marked “latest”, treat it as later.
- If both are valid SemVer, use SemVer comparison.
- If neither is valid SemVer, compare by published timestamp.
- If only one is valid SemVer, treat the SemVer version as later4.
This standardisation makes it feasible to build automated upgrade tooling that respects version ordering — though such tooling remains nascent in mid-2026.
Conclusion
MCP’s versioning story has matured significantly: protocol revisions use date stamps with formal lifecycle policies; the registry enforces SemVer for published servers; and the twelve-month deprecation window gives implementers a predictable migration timeline. The 2026-07-28 release candidate is the first real test of this machinery — with the stateless architecture shift, Tasks API redesign, and three feature deprecations landing simultaneously. Pin your versions, test with canary profiles, allowlist your tools, and keep a last-known-good branch. The protocol’s governance structures are designed to prevent surprise breakage going forward; your job is to ensure your configuration is equally disciplined.
Citations
-
The 2026-07-28 MCP Specification Release Candidate — Model Context Protocol Blog ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8
-
Versioning — Model Context Protocol — Official specification ↩ ↩2 ↩3
-
Feature Lifecycle and Deprecation Policy — Model Context Protocol ↩ ↩2 ↩3 ↩4 ↩5
-
Versioning Published MCP Servers — MCP Registry documentation ↩ ↩2 ↩3 ↩4
-
MCP Server Versioning Guidelines Proposal — Discussion #1176 — GitHub ↩
-
Document recommended tool versioning and naming patterns — Issue #1915 — GitHub ↩ ↩2
-
Model Context Protocol — Codex CLI — OpenAI Developers ↩ ↩2 ↩3
-
Codex CLI Changelog — OpenAI Developers ↩ ↩2 ↩3