conductor-oss/conductor · error · RuntimeException

MCP response exceeds the 10 MiB payload limit

Error message

MCP response exceeds the 10 MiB payload limit

What it means

Thrown by readBoundedBody when the response body's declared Content-Length exceeds ExternalDataLimits.MAX_PAYLOAD_BYTES (10 MiB). This is the pre-read size guard: it checks the server-advertised length before streaming, so an oversized response is rejected without being downloaded. Protects against memory/exhaustion attacks from a malicious or buggy MCP server.

Source

Thrown at ai/src/main/java/org/conductoross/conductor/ai/mcp/MCPService.java:443

                || request.header("Proxy-Authorization") != null;
    }

    private boolean isSameOrigin(String firstUrl, String secondUrl) {
        okhttp3.HttpUrl first = okhttp3.HttpUrl.parse(firstUrl);
        okhttp3.HttpUrl second = okhttp3.HttpUrl.parse(secondUrl);
        return first != null
                && second != null
                && first.scheme().equalsIgnoreCase(second.scheme())
                && first.host().equalsIgnoreCase(second.host())
                && first.port() == second.port();
    }

    private String readBoundedBody(ResponseBody body) throws Exception {
        if (body == null) {
            return "";
        }
        if (body.contentLength() > ExternalDataLimits.MAX_PAYLOAD_BYTES) {
            throw new RuntimeException("MCP response exceeds the 10 MiB payload limit");
        }
        try (body) {
            okio.Buffer buffer = new okio.Buffer();
            long total = 0;
            long read;
            while ((read = body.source().read(buffer, 8192)) != -1) {
                total += read;
                if (total > ExternalDataLimits.MAX_PAYLOAD_BYTES) {
                    buffer.clear();
                    throw new RuntimeException("MCP response exceeds the 10 MiB payload limit");
                }
            }
            return buffer.readUtf8();
        }
    }

    private record ResponsePayload(int statusCode, String contentType, String body) {}

View on GitHub (pinned to cf7c3e4a8a)

Solutions

  1. Reduce the size of what the server returns (paginate tools, trim descriptions, avoid embedding large blobs in tool results).
  2. If a larger limit is genuinely required and trusted, raise ExternalDataLimits.MAX_PAYLOAD_BYTES (weigh memory/exhaustion risk first).
  3. Confirm the server isn't accidentally returning a binary payload as text.
  4. For large tool outputs, have the tool return a reference/URL instead of inline content.
Defensive patterns

Strategy: validation

Validate before calling

// There is no pre-call API to know response size; the guard runs server-side.
// Mitigate by ensuring the server does not return >10MiB (paginate tools, trim descriptions).

Try / catch

try {
    mcpService.listTools(serverUrl, headers);
} catch (RuntimeException e) {
    if (e.getMessage().contains("payload limit")) {
        // server response too large; reduce tool count/description size server-side
    }
    throw e;
}

Prevention

When it happens

Trigger: Server sets Content-Length to a value > 10 MiB on the JSON-RPC response (e.g. a tools/list returning an enormous tool catalog, or a tool result with a huge embedded blob). The check fires before any bytes are buffered.

Common situations: MCP server returning very large tool descriptions or tool results; a server streaming a file/blob through a text content item; an adversarial server attempting resource exhaustion.

Related errors


AI-assisted analysis of conductor-oss/conductor@cf7c3e4a8a (2026-08-14). Data as JSON: /api/errors/4637d7227c010cb8. Report an issue: GitHub.