{"record":{"id":"61ea15f85c10b68b","repo":"microsoft/aspire","slug":"foundry-toolbox-mcp-initialization-did-not-negotiate-a","errorCode":null,"errorMessage":"Foundry Toolbox MCP initialization did not negotiate a protocol version.","messagePattern":"Foundry Toolbox MCP initialization did not negotiate a protocol version\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.Foundry/Toolbox/FoundryToolboxReadinessProbe.cs","lineNumber":48,"sourceCode":"        using var discoveryCancellation = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);\n        discoveryCancellation.CancelAfter(_timeout);\n        try\n        {\n            var initialize = await SendRequestAsync(\n                endpoint,\n                accessToken,\n                sessionId: null,\n                protocolVersion: null,\n                \"\"\"\n                {\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"initialize\",\"params\":{\"protocolVersion\":\"2025-03-26\",\"capabilities\":{},\"clientInfo\":{\"name\":\"Aspire.Hosting.Foundry\",\"version\":\"1.0\"}}}\n                \"\"\",\n                discoveryCancellation.Token).ConfigureAwait(false);\n            var negotiatedProtocol = initialize.Result\n                .GetProperty(\"protocolVersion\")\n                .GetString();\n            if (string.IsNullOrEmpty(negotiatedProtocol))\n            {\n                throw new InvalidOperationException(\"Foundry Toolbox MCP initialization did not negotiate a protocol version.\");\n            }\n\n            await SendRequestAsync(\n                endpoint,\n                accessToken,\n                initialize.SessionId,\n                negotiatedProtocol,\n                \"\"\"{\"jsonrpc\":\"2.0\",\"method\":\"notifications/initialized\",\"params\":{}}\"\"\",\n                discoveryCancellation.Token).ConfigureAwait(false);\n\n            var requestId = 2;\n            while (true)\n            {\n                var discoveredToolNames = new HashSet<string>(StringComparer.Ordinal);\n                string? cursor = null;\n                var retryDiscovery = false;\n                do\n                {","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.Foundry/Toolbox/FoundryToolboxReadinessProbe.cs#L30-L66","documentation":"Thrown by FoundryToolboxReadinessProbe.WaitForToolsAsync when the MCP initialize handshake response contains no non-empty 'protocolVersion' property. The probe performs a full JSON-RPC MCP handshake to confirm the Toolbox is live before declaring readiness; a successful initialize must always negotiate a protocol version.","triggerScenarios":"The Toolbox MCP endpoint responds to 'initialize' with a JSON body lacking protocolVersion or with an empty string — e.g. the endpoint is not actually an MCP server, an auth gateway returns a 200 with an HTML/JSON error body, or a protocol-incompatible server version.","commonSituations":"Pointing the probe at a wrong or deprecated Toolbox URL; an API management layer intercepting the request and returning an unexpected payload; the Foundry Toolbox service deployed an incompatible MCP protocol revision.","solutions":["Verify the MCP endpoint URL is the correct Toolbox endpoint that speaks the MCP JSON-RPC protocol.","Check authentication — an auth redirect or error page returned with 200 would lack protocolVersion; ensure the access token is valid and scoped.","Confirm the Toolbox service version supports the MCP initialize handshake expected by the probe.","Retry after the service deploys/updates, since a mid-deploy endpoint can return malformed responses."],"exampleFix":"// before\nprobe endpoint: https://my-app.example.com/ (not the MCP route)\n// after\nprobe endpoint: https://my-app.example.com/mcp (the actual JSON-RPC MCP endpoint)","handlingStrategy":"retry","validationCode":"// Pre-check: verify the endpoint speaks MCP by expecting a JSON object with protocolVersion in the initialize reply before relying on the probe.","typeGuard":null,"tryCatchPattern":"try\n{\n    await probe.WaitForToolsAsync(accessToken, ct);\n}\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"did not negotiate a protocol version\"))\n{\n    logger.LogError(ex, \"Toolbox endpoint did not complete MCP handshake; verify URL and auth.\");\n    throw;\n}","preventionTips":["Point the probe at the actual JSON-RPC MCP route, not the app root.","Use a fresh, correctly-scoped access token so auth gateways don't intercept the handshake.","Keep the Foundry Toolbox service and Aspire.Hosting.Foundry package versions compatible."],"tags":["mcp","json-rpc","handshake","foundry-toolbox","readiness"],"backgroundTag":"unexpected-response-shape","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}