microsoft/aspire · error · InvalidOperationException

The Toolbox MCP response did not contain JSON-RPC response…

Error message

The Toolbox MCP response did not contain JSON-RPC response ID {expectedId}.

What it means

Thrown by SendRequestAsync when, after reading all pending JSON-RPC responses for a request, none carries the expected response ID. The probe correlates JSON-RPC request IDs to responses; a missing ID means the reply stream ended or returned responses for other requests without answering this one.

Solutions

  1. Retry the readiness check — transient stream drops are the most common cause.
  2. Verify network path (proxies, gateways) between the probe and the Toolbox doesn't terminate SSE/WebSocket streams early.
  3. Ensure the access token is valid for the whole probe duration; refresh if the session outlives token expiry.
  4. Check Toolbox service logs for dropped or unhandled JSON-RPC requests.

Example fix

// before
// long-lived probe session with token expiring mid-handshake
cancellationToken = CancellationToken.None;
// after
// bound probe lifetime to a fresh, valid token and explicit timeout
cancellationToken = new CancellationTokenSource(TimeSpan.FromSeconds(30)).Token;
Defensive patterns

Strategy: retry

Try / catch

try
{
    await probe.WaitForToolsAsync(accessToken, ct);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("did not contain JSON-RPC response ID"))
{
    logger.LogWarning(ex, "MCP response stream dropped the reply; retrying readiness check.");
    await probe.WaitForToolsAsync(accessToken, ct);
}

Prevention

When it happens

Trigger: The Toolbox MCP stream closed before the response for expectedId arrived; the server dropped or never processed the request; responses arrive on a different connection than the probe is reading; the request was rejected before an ID-correlated response was emitted.

Common situations: SSE/streaming connection interrupted by a proxy or idle timeout; server crash mid-request; auth token expired mid-session causing the server to silently drop requests; mismatch between the probe's JSON-RPC framing and the server version.

Related errors


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

Appendix: source

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

            : responsePayload.Split('\n', StringSplitOptions.TrimEntries)
                .Where(line => line.StartsWith("data:", StringComparison.Ordinal))
                .Select(line => line["data:".Length..].Trim());
        JsonElement? matchingResponse = null;
        foreach (var responseMessage in responseMessages)
        {
            using var candidate = JsonDocument.Parse(responseMessage);
            if (candidate.RootElement.TryGetProperty("id", out var responseId) &&
                responseId.ValueKind == JsonValueKind.Number &&
                responseId.GetInt32() == expectedId)
            {
                matchingResponse = candidate.RootElement.Clone();
                break;
            }
        }

        if (matchingResponse is null)
        {
            throw new InvalidOperationException(
                $"The Toolbox MCP response did not contain JSON-RPC response ID {expectedId}.");
        }

        if (matchingResponse.Value.TryGetProperty("error", out var error))
        {
            throw new InvalidOperationException($"Toolbox MCP request failed: {error.GetRawText()}");
        }

        var result = matchingResponse.Value.TryGetProperty("result", out var resultElement)
            ? resultElement.Clone()
            : default;
        return new(result, responseSessionId);
    }

    private sealed record McpResponse(
        JsonElement Result,
        string? SessionId,
        bool IsRetryableFailure = false);

View on GitHub (pinned to 25830f84bd)