Protocol Eras
nexus-mcp supports two MCP protocol eras at the same time, on the same connection: a current, handshake-free 2026-07-28 style, and the classic 2025-06-18initialize handshake. supportedVersions is ["2026-07-28", "2025-06-18"] — nothing outside that pair is accepted. This page is about picking one and using it correctly; the full negotiation contract, including every field name, lives in MCP Protocol.
The one thing to get right: era is per request
Nothing about this server remembers "which era this connection is speaking." Every single request is classified on its own, by looking at that request's own _meta block:
- A request whose
_metacarries a valid stringio.modelcontextprotocol/protocolVersionis evaluated as2026-07-28. - A request with no such key at all is evaluated as legacy
2025-06-18.
A client is expected to pick one era and stay there for the life of a connection, but nothing enforces that from the server's side — if your client code sends a mix, each request is still judged individually rather than inheriting a mode from whatever came before it on the same connection. Build your client as if this were a hard rule, even though the server does not itself detect drift.
If you're writing a new client: use 2026-07-28
There is no initialize handshake in this era. The first thing a client sends is server/discover, which every 2026-07-28 request must be able to reach — it is how a client learns what this server offers before calling anything else.
{
"jsonrpc": "2.0",
"id": 1,
"method": "server/discover",
"params": {},
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": { "name": "example-cli", "version": "1.4.0" },
"io.modelcontextprotocol/clientCapabilities": {}
}
}{
"jsonrpc": "2.0",
"id": 1,
"result": {
"resultType": "server/discover",
"supportedVersions": ["2026-07-28", "2025-06-18"],
"capabilities": { "tools": {} },
"ttlMs": 60000,
"cacheScope": "session",
"_meta": { "io.modelcontextprotocol/serverInfo": { "name": "nexus-mcp" } }
}
}Every subsequent request in this era carries the same _meta block (client identity and capabilities are typically present but not re-validated the way the version is), and every successful result carries resultType; a result returning a list (like server/discover and tools/list) additionally carries ttlMs and cacheScope describing how long that specific result may be treated as current — treat the exact numbers as illustrative and read them from your own response rather than hardcoding them.
If you're integrating an older MCP client: 2025-06-18 still works, unchanged
Nothing about supporting a second, newer era changed how the classic handshake behaves. A legacy client calls initialize, gets back a plain MCP result with no resultType envelope, sends initialized, and proceeds exactly as it would against any other 2025-06-18 server:
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-06-18",
"capabilities": {},
"clientInfo": { "name": "example-cli", "version": "1.0.0" }
}
}{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2025-06-18",
"capabilities": { "tools": {} },
"serverInfo": { "name": "nexus-mcp" }
}
}When a version doesn't match
Whichever era you declare — _meta in the modern style, or initialize.params in the legacy style — an unsupported value is rejected before anything else about the request is looked at:
{
"jsonrpc": "2.0",
"id": 7,
"error": {
"code": -32022,
"message": "Unsupported protocol version",
"data": { "supported": ["2026-07-28", "2025-06-18"], "requested": "2024-11-05" }
}
}data.supported always lists the current supportedVersions, so a client that speaks more than one era itself can decide whether to retry on one it also supports rather than giving up. See Troubleshooting for this alongside the other failures worth handling explicitly, and MCP Protocol for the malformed-_meta case that sits next to this one (-32602, when _meta engages the reserved namespace without a valid version string).
Once connected, both eras reach the same tools
Nothing about which era you speak changes what canvas_* and agent_* tools do or what they accept — see Tool Namespaces. The era only changes the shape of the envelope around a call, never the tool contract inside it.
Where to go next
- MCP Protocol — the complete, field-by-field contract.
- Tool Namespaces — what's available once connected.
- Troubleshooting — failed discovery, version mismatch, and credential problems on the wire.