# Most MCP connection failures come from stdout noise, bad launch config, version mismatch or HTTP header rules

> A symptom-to-fix table for the MCP connection errors seen most often: stdout pollution, wrong command or path, protocol version mismatch, 406 from a missing Accept header, 405 on GET, 404 for an expired session and CORS in browser clients.

## Answer

Over **stdio**, most failures come from stray output on stdout or a server the client cannot launch (wrong `command`, relative paths, missing environment variables). Over **Streamable HTTP**, they come from HTTP rules: a missing `Accept` header (406), a GET the server does not serve (405), an expired session ID (404), an unsupported protocol version (400), or CORS in browser clients. Start by running the server alone in the MCP Inspector. Status codes and messages below follow MCP specification **2026-07-28** and 2025-11-25, and the TypeScript SDK where noted.

## Details

### stdio: stdout pollution

- **Symptom:** The host logs `SyntaxError: Unexpected token ... is not valid JSON` and the server never shows up.
- **Cause:** A non-protocol line reached stdout, which the spec forbids. A stray `console.log`, `print` or library banner is enough.
- **Fix:** Log to stderr. The quoted token is usually the first character of the stray line.

### stdio: wrong command, path or environment

- **Symptom:** The server works in your terminal but not in the client.
- **Cause:** The client may start the server with an undefined working directory (for example `/` on macOS). It also passes on only a limited, platform-dependent set of environment variables.
- **Fix:** Use absolute paths in `command` and `args`, and pass variables through the config's `env` key:

```json
{
  "mcpServers": {
    "notes": {
      "command": "/usr/local/bin/node",
      "args": ["/Users/me/notes-server/build/index.js"],
      "env": { "NOTES_DIR": "/Users/me/notes" }
    }
  }
}
```

Check the client's MCP logs (Claude Desktop on macOS: `~/Library/Logs/Claude/mcp*.log`).

### Protocol version mismatch

- **Symptom:** A 2026-07-28 server returns error `-32022` (`UnsupportedProtocolVersionError`) with a `supported` list. Over HTTP this comes with `400`.
- **Cause:** Client and server share no protocol revision.
- **Fix:** Retry with a version from `supported`, or call `server/discover` to see what the server offers. In SDK v2 clients, an `ERA_NEGOTIATION_FAILED` error in pin mode means the pinned version is not offered. Switch to `versionNegotiation: { mode: 'auto' }` to fall back to `initialize`.

### HTTP 406 Not Acceptable

- **Symptom:** A POST with `curl` returns `406` and `Not Acceptable: Client must accept both application/json and text/event-stream`. That message comes from the TypeScript SDK v1 transport.
- **Cause:** The spec requires the client's `Accept` header to list both types.
- **Fix:** Send `-H 'Accept: application/json, text/event-stream'`.

### HTTP 405 on GET

- **Symptom:** A GET to `/mcp` returns `405 Method Not Allowed`.
- **Cause:** In 2025-11-25 a server MUST answer 405 if it offers no GET SSE stream. In 2026-07-28 GET is removed and servers SHOULD answer GET and DELETE with 405.
- **Fix:** Nothing is broken. Use POST (in 2026-07-28, `subscriptions/listen` for long-lived notifications).

### HTTP 404 with a session ID (2025-era servers)

- **Symptom:** Requests that worked before now return `404`. The SDK v1 body is `Session not found` (`-32001`).
- **Cause:** The server ended or lost the session, for example after a restart.
- **Fix:** The spec says the client MUST send a new `initialize` without a session ID. On the server side, stateless mode (`sessionIdGenerator: undefined` in SDK v1) avoids this failure entirely.

### CORS in browser clients

- **Symptom:** It works with `curl` but fails in a browser. Or the client cannot read `Mcp-Session-Id`, so every later call gets `400 Bad Request: Mcp-Session-Id header is required`.
- **Cause:** JavaScript in a browser can only read response headers that `Access-Control-Expose-Headers` allows. Any request header outside the CORS safelist triggers a preflight, and the server must allow it in `Access-Control-Allow-Headers`.
- **Fix:** For 2025-era servers, the SDK README shows `exposedHeaders: ['Mcp-Session-Id']` and `allowedHeaders: ['Content-Type', 'mcp-session-id']`. For 2026-07-28, also allow `MCP-Protocol-Version`, `Mcp-Method` and `Mcp-Name`, which clients MUST send. Keep `Origin` validation on. The README's `origin: '*'` is a placeholder: set explicit origins in production.

## See also

- [[mcp-transports-stdio-vs-http]]
- [[mcp-streamable-http-sessions]]
- [[mcp-initialize-handshake]]
- [[mcp-server-typescript-minimal]]

## Sources

- [MCP Docs — Debugging](https://modelcontextprotocol.io/docs/2026-07-28/tools/debugging)
- [MCP Specification 2026-07-28 — Streamable HTTP](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http)
- [MCP Specification 2025-11-25 — Transports](https://modelcontextprotocol.io/specification/2025-11-25/basic/transports)
- [MCP TypeScript SDK — Troubleshooting](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/docs/troubleshooting.md)
- [MCP TypeScript SDK v1.x — Streamable HTTP server transport](https://github.com/modelcontextprotocol/typescript-sdk/blob/v1.x/src/server/webStandardStreamableHttp.ts)
- [MCP TypeScript SDK 1.20.0 README — CORS for browser-based clients](https://github.com/modelcontextprotocol/typescript-sdk/blob/1.20.0/README.md)
- [MDN — Cross-Origin Resource Sharing (CORS)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS)

## Sources

- [MCP Docs — Debugging](https://modelcontextprotocol.io/docs/2026-07-28/tools/debugging)
- [MCP Specification 2026-07-28 — Streamable HTTP](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http)
- [MCP Specification 2025-11-25 — Transports](https://modelcontextprotocol.io/specification/2025-11-25/basic/transports)
- [MCP TypeScript SDK — Troubleshooting](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/docs/troubleshooting.md)
- [MCP TypeScript SDK v1.x — Streamable HTTP server transport](https://github.com/modelcontextprotocol/typescript-sdk/blob/v1.x/src/server/webStandardStreamableHttp.ts)
- [MCP TypeScript SDK 1.20.0 README — CORS for browser-based clients](https://github.com/modelcontextprotocol/typescript-sdk/blob/1.20.0/README.md)
- [MDN — Cross-Origin Resource Sharing (CORS)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS)