can1357/oh-my-pi · error · Error

Failed to parse MCP response

Error message

Failed to parse MCP response

What it means

callMCP() received an HTTP 2xx response but parseSSE() could not extract a JSON-RPC response object from the body, so it throws "Failed to parse MCP response". The first 500 chars of the raw response text are logged (with the redacted URL) to aid debugging. This indicates the endpoint returned something other than a well-formed JSON-RPC reply — often an HTML error page or an SSE stream without a data payload.

Source

Thrown at packages/coding-agent/src/mcp/json-rpc.ts:118

		signal: options?.signal ?? AbortSignal.timeout(MCP_DEFAULT_TIMEOUT_MS),
	});

	if (!response.ok) {
		const errorMsg = `MCP request failed: ${response.status} ${response.statusText}`;
		logger.error(errorMsg, { url: redactUrlForLog(url), method, params });
		throw new Error(errorMsg);
	}

	const text = await response.text();
	const result = parseSSE(text) as JsonRpcResponse<T> | null;

	if (!result) {
		logger.error("Failed to parse MCP response", {
			url: redactUrlForLog(url),
			method,
			responseText: text.slice(0, 500),
		});
		throw new Error("Failed to parse MCP response");
	}

	return result;
}

View on GitHub (pinned to 9690622007)

Solutions

  1. Inspect the log entry — responseText (first 500 chars) shows what actually came back (HTML? empty? truncated JSON?).
  2. Verify the url is the actual MCP/JSON-RPC endpoint, not the site root or a docs page.
  3. Open the responseText URL in a browser/curl to see if a login or error page is served.
  4. Check proxy/gateway config for response rewriting or content injection.
  5. Confirm the server implements the MCP JSON-RPC protocol with SSE or JSON responses.

Example fix

// before
{ "type": "http", "url": "https://mcp.example.com" }        // serves HTML landing page
// after
{ "type": "http", "url": "https://mcp.example.com/mcp" }   // actual JSON-RPC endpoint
Defensive patterns

Strategy: validation

Validate before calling

// Verify the endpoint speaks JSON-RPC/SSE before use
const probe = await fetch(endpointUrl, { headers: { Accept: "text/event-stream, application/json" } });
const ct = probe.headers.get("content-type") ?? "";
if (ct.includes("text/html")) throw new Error(`Endpoint returns HTML, not MCP: ${endpointUrl}`);

Type guard

function isHtmlErrorPage(text: string): boolean {
  return /^\s*(<!doctype html|<html)/i.test(text) || /<title>.*(login|sign in|error)<\/title>/i.test(text);
}

Try / catch

try {
  return await callMCP(url, method, params);
} catch (e) {
  if (e instanceof Error && e.message === "Failed to parse MCP response") {
    log.error("Non-JSON-RPC body from MCP endpoint — check url and proxy", { url });
    throw new Error(`Endpoint at ${url} did not return a JSON-RPC response; verify the MCP endpoint path`);
  }
  throw e;
}

Prevention

When it happens

Trigger: The server returned 200 but the body is HTML (login page, error page), plain text, truncated JSON, an SSE stream with no parsable data event, or a proxy/WAF rewriting the response.

Common situations: Pointing the url at a website root instead of the MCP endpoint (200 HTML page); auth-protected endpoint serving a redirect/login page with 200; misconfigured reverse proxy; server bug emitting malformed JSON-RPC or wrong Content-Type; TLS-terminating proxy injecting content.

Understand the failure class

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/03d603152be3984c. Report an issue: GitHub.