diff --git a/src/services/mcp-compatibility.ts b/src/services/mcp-compatibility.ts index 12e38a9bfb..91f77d1b3e 100644 --- a/src/services/mcp-compatibility.ts +++ b/src/services/mcp-compatibility.ts @@ -59,6 +59,9 @@ export function classifyMcpClientVersion(version: string | null | undefined): Mc const minimumComparison = compareMcpSemver(version, MINIMUM_SUPPORTED_MCP_VERSION); if (minimumComparison === null) return "unknown"; if (minimumComparison < 0) return "incompatible"; + // The client semver already parsed for the minimum check, so this comparison cannot return null. + const recommendedComparison = compareMcpSemver(version, LATEST_RECOMMENDED_MCP_VERSION)!; + if (recommendedComparison < 0) return "stale"; return "current"; } diff --git a/test/unit/mcp-compatibility.test.ts b/test/unit/mcp-compatibility.test.ts index 346d0239da..8a90a9e7f7 100644 --- a/test/unit/mcp-compatibility.test.ts +++ b/test/unit/mcp-compatibility.test.ts @@ -8,9 +8,27 @@ describe("MCP compatibility telemetry", () => { expect(classifyMcpClientVersion("0.2.1")).toBe("incompatible"); expect(classifyMcpClientVersion("0.3.0")).toBe("incompatible"); expect(classifyMcpClientVersion("0.4.0")).toBe("incompatible"); - expect(classifyMcpClientVersion("0.5.0")).toBe("current"); + expect(classifyMcpClientVersion("0.5.0")).toBe("stale"); + expect(classifyMcpClientVersion("0.5.9")).toBe("stale"); + expect(classifyMcpClientVersion("0.6.0")).toBe("current"); + expect(classifyMcpClientVersion("0.7.0")).toBe("current"); expect(classifyMcpClientVersion("not-a-version")).toBe("unknown"); expect(classifyMcpClientVersion(undefined)).toBe("unknown"); + expect(classifyMcpClientVersion(null)).toBe("unknown"); + }); + + it("treats prerelease builds below the minimum or recommended cutoffs as incompatible or stale", () => { + expect(classifyMcpClientVersion("0.4.9-rc.1")).toBe("incompatible"); + expect(classifyMcpClientVersion("0.5.0-rc.1")).toBe("incompatible"); + expect(classifyMcpClientVersion("0.6.0-rc.1")).toBe("stale"); + }); + + it("classifies the exact recommended version and newer releases as current", () => { + expect(classifyMcpClientVersion("0.6.0")).toBe("current"); + expect(classifyMcpClientVersion("0.6.1")).toBe("current"); + expect(classifyMcpClientVersion("1.0.0")).toBe("current"); + expect(compareMcpSemver("0.6.0", "0.6.0")).toBe(0); + expect(compareMcpSemver("0.7.0", "0.6.0")).toBe(1); }); it("builds bounded telemetry from allowlisted MCP headers", () => { @@ -50,7 +68,7 @@ describe("MCP compatibility telemetry", () => { clientVersion: "0.5.0", metadata: { packageName: "@example/custom-mcp", - compatibilityStatus: "current", + compatibilityStatus: "stale", }, }); }); diff --git a/test/unit/mcp-server-telemetry.test.ts b/test/unit/mcp-server-telemetry.test.ts index f8e6dc5960..be49e01d74 100644 --- a/test/unit/mcp-server-telemetry.test.ts +++ b/test/unit/mcp-server-telemetry.test.ts @@ -57,7 +57,7 @@ describe("MCP server telemetry", () => { clientVersion: "0.5.0", metadata: expect.objectContaining({ toolName: "gittensory_local_status", - compatibilityStatus: "current", + compatibilityStatus: "stale", }), }), ]);