From 69509ed9748a7b4068f33dcf1e900e7edf2ae935 Mon Sep 17 00:00:00 2001 From: John McBride Date: Mon, 29 Dec 2025 09:47:28 -0500 Subject: [PATCH] fix: Correctly propose protocol version vs. error Signed-off-by: John McBride --- src/server/index.ts | 56 ++++++++++++------------------- src/server/initialization.test.ts | 27 +++++---------- 2 files changed, 29 insertions(+), 54 deletions(-) diff --git a/src/server/index.ts b/src/server/index.ts index 59755fa..81cebdd 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -42,10 +42,6 @@ import type { } from "../mcp/20251125/types.js"; import { LATEST_PROTOCOL_VERSION, - PROTOCOL_VERSION_2024_10_07, - PROTOCOL_VERSION_2024_11_05, - PROTOCOL_VERSION_2025_03_26, - PROTOCOL_VERSION_2025_06_18, SUPPORTED_PROTOCOL_VERSIONS, } from "../mcp/versions.js"; import type { PromptConfig, RegisteredPrompt } from "../prompts/types.js"; @@ -432,37 +428,27 @@ export class MCPServer { }); } - const protocolVersion = parseResult.data.params.protocolVersion; - - switch (protocolVersion) { - case LATEST_PROTOCOL_VERSION: - case PROTOCOL_VERSION_2025_06_18: - case PROTOCOL_VERSION_2025_03_26: - case PROTOCOL_VERSION_2024_11_05: - case PROTOCOL_VERSION_2024_10_07: { - const initResponse: InitializeResult = { - protocolVersion: protocolVersion, - capabilities: this.getCapabilities(), - serverInfo: { - name: this.name, - version: this.version, - }, - ...(this.instructions ? { instructions: this.instructions } : {}), - }; - - return newJSONRPCReponse({ id: request.id, result: initResponse }); - } - default: { - return newJSONRPCError({ - id: request.id, - code: ErrorCode.InvalidParams, - message: `Unsupported protocol version: ${protocolVersion} - supported versions: ${SUPPORTED_PROTOCOL_VERSIONS}`, - data: { - supportedVersions: SUPPORTED_PROTOCOL_VERSIONS, - }, - }); - } - } + // The MCP spec defines that a server should attempt to negotiate + // the highest protocol version it supports: + // https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle#version-negotiation + const requestedVersion = parseResult.data.params.protocolVersion; + const negotiatedVersion = SUPPORTED_PROTOCOL_VERSIONS.includes( + requestedVersion + ) + ? requestedVersion + : LATEST_PROTOCOL_VERSION; + + const initResponse: InitializeResult = { + protocolVersion: negotiatedVersion, + capabilities: this.getCapabilities(), + serverInfo: { + name: this.name, + version: this.version, + }, + ...(this.instructions ? { instructions: this.instructions } : {}), + }; + + return newJSONRPCReponse({ id: request.id, result: initResponse }); } private async handleToolListRequest( diff --git a/src/server/initialization.test.ts b/src/server/initialization.test.ts index 2273a09..b8a9754 100644 --- a/src/server/initialization.test.ts +++ b/src/server/initialization.test.ts @@ -165,9 +165,7 @@ describe("MCPServer", () => { } }); - it("handles ill-supported MCP protocolVersion", async () => { - // should get an error JSON RPC 2 message if protocolVersion is something - // totally untenable like "2001-01-01" + it("negotiates unsupported protocolVersion to server's latest", async () => { const serverName = "example ping server"; const serverVersion = "0.0.0"; const server = new MCPServer({ @@ -179,7 +177,7 @@ describe("MCPServer", () => { id: 0, method: "initialize", params: { - protocolVersion: "2001-01-01", + protocolVersion: "2099-01-01", capabilities: { sampling: {}, roots: { @@ -199,22 +197,13 @@ describe("MCPServer", () => { expect(response.jsonrpc).toBe("2.0"); expect(response.id).toBe(0); - if ("error" in response) { - expect(response.error.code).toBe(-32602); - expect(response.error.message).toContain( - "Unsupported protocol version" - ); - expect(response.error.data).toEqual({ - supportedVersions: [ - "2025-11-25", - "2025-06-18", - "2025-03-26", - "2024-11-05", - "2024-10-07", - ], - }); + if ("result" in response) { + const result = response.result as InitializeResult; + expect(result.protocolVersion).toBe(LATEST_PROTOCOL_VERSION); + expect(result.serverInfo.name).toBe(serverName); + expect(result.serverInfo.version).toBe(serverVersion); } else { - fail("Expected an error response, got a result"); + fail("Expected a result response, got an error"); } }); });