microsoft/aspire · error · InvalidOperationException

Foundry Toolbox MCP initialization did not negotiate a…

Error message

Foundry Toolbox MCP initialization did not negotiate a protocol version.

What it means

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.

Solutions

  1. Verify the MCP endpoint URL is the correct Toolbox endpoint that speaks the MCP JSON-RPC protocol.
  2. Check authentication — an auth redirect or error page returned with 200 would lack protocolVersion; ensure the access token is valid and scoped.
  3. Confirm the Toolbox service version supports the MCP initialize handshake expected by the probe.
  4. Retry after the service deploys/updates, since a mid-deploy endpoint can return malformed responses.

Example fix

// before
probe endpoint: https://my-app.example.com/ (not the MCP route)
// after
probe endpoint: https://my-app.example.com/mcp (the actual JSON-RPC MCP endpoint)
Defensive patterns

Strategy: retry

Validate before calling

// Pre-check: verify the endpoint speaks MCP by expecting a JSON object with protocolVersion in the initialize reply before relying on the probe.

Try / catch

try
{
    await probe.WaitForToolsAsync(accessToken, ct);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("did not negotiate a protocol version"))
{
    logger.LogError(ex, "Toolbox endpoint did not complete MCP handshake; verify URL and auth.");
    throw;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16). Data as JSON: /api/errors/61ea15f85c10b68b. Report an issue: GitHub.

Appendix: source

Thrown at src/Aspire.Hosting.Foundry/Toolbox/FoundryToolboxReadinessProbe.cs:48

        using var discoveryCancellation = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
        discoveryCancellation.CancelAfter(_timeout);
        try
        {
            var initialize = await SendRequestAsync(
                endpoint,
                accessToken,
                sessionId: null,
                protocolVersion: null,
                """
                {"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"Aspire.Hosting.Foundry","version":"1.0"}}}
                """,
                discoveryCancellation.Token).ConfigureAwait(false);
            var negotiatedProtocol = initialize.Result
                .GetProperty("protocolVersion")
                .GetString();
            if (string.IsNullOrEmpty(negotiatedProtocol))
            {
                throw new InvalidOperationException("Foundry Toolbox MCP initialization did not negotiate a protocol version.");
            }

            await SendRequestAsync(
                endpoint,
                accessToken,
                initialize.SessionId,
                negotiatedProtocol,
                """{"jsonrpc":"2.0","method":"notifications/initialized","params":{}}""",
                discoveryCancellation.Token).ConfigureAwait(false);

            var requestId = 2;
            while (true)
            {
                var discoveredToolNames = new HashSet<string>(StringComparer.Ordinal);
                string? cursor = null;
                var retryDiscovery = false;
                do
                {

View on GitHub (pinned to 25830f84bd)