Streamable HTTP error: Failed to open SSE stream: Not Found
Your client tried to open the server-sent-events stream of a remote MCP server
over HTTP, and got a 404 back. That single fact settles more than it appears
to: something at that address accepted the connection and produced an HTTP
response, so this is not DNS, not TLS, not a firewall, and not a server that is
down. It is also not an error from the model provider — an Anthropic API 404
arrives as a JSON body with error.type set to not_found_error and a
request_id attached, and this string has neither. Nothing here was sent to a
model, billed, or counted against a rate limit.
A 404 is an answer, and that is the whole diagnosis
Almost every other failure in this family is an absence: a connection refused, a handshake that never completes, a stream that goes quiet. This one is a reply. Something is listening on that host and port, it is speaking HTTP, it understood your request well enough to route it, and it concluded there is nothing at that path.
So stop testing reachability. Pinging the host, checking the port, and restarting your network do not address a response you already received. The question this error asks is narrower and more useful: which server answered, and is it the one you meant to configure?
The second half of the string matters as much as the status. The failure is at opening the SSE stream, a specific step, not at sending a request. That is where the most common cause hides, and it is the reason a configuration that “looks right” produces a 404.
Which endpoint you are actually asking for
Two HTTP transports for MCP exist in the wild, and they do not use the same URL shape.
The Streamable HTTP transport uses one endpoint: the client POSTs JSON-RPC messages to it, and opens an SSE stream against the same path when it needs server-initiated messages. The older HTTP+SSE arrangement uses two: a dedicated stream endpoint, plus a separate POST endpoint that the server advertises once the stream is open.
That produces a failure that is deeply confusing if you are not expecting it: a URL can be correct for one transport and a 404 for the other, and a configuration that half-works is a real state. Concretely, if your entry points at the older stream path while the client speaks Streamable HTTP, or at a single Streamable HTTP endpoint while the client is trying the legacy two-URL dance, the request goes to a route the server never registered. Check what the server’s documentation says its endpoint is, and check which transport type your entry declares — a mismatch between those two is the first thing to rule out, and it is a one-line fix.
The same logic covers a plainer version of the mistake: a trailing path segment that was correct for a previous release of the server, a base URL with the path omitted entirely, or a server mounted under a prefix by whatever is hosting it.
Is retrying useful?
Yes — exactly once, and the retry is a test rather than a hope.
A 404 can come from two very different places, and the message cannot tell them apart for you:
- The server’s own router, which means the path genuinely does not exist. Deterministic. It will 404 forever.
- Something in front of the server — a tunnel whose backend has not attached yet, a platform that is mid-deploy, a load balancer with no healthy target registered, a local dev server that is restarting. These return 404 for a window of seconds and then start routing correctly.
One retry separates them, which no amount of reading the config will do. If the second attempt connects, you were behind an intermediary in a transient state and nothing needs fixing — though it is worth knowing that is your topology, because it will happen again on every deploy.
If the second attempt returns Not Found identically, stop retrying. You are on the deterministic branch, and everything below is about which route is wrong. Repeating a request whose answer is “that path does not exist” is the cheapest way to waste ten minutes, and a retry loop around it turns a misconfiguration into a small denial-of-service against your own server.
Telling the server’s 404 from an intermediary’s
Beyond the retry, three observations discriminate:
- Ask the base URL for anything at all. If the host answers on other paths — a health endpoint, the root — and only the MCP path 404s, the server is up and the route is wrong. If every path 404s, you are almost certainly talking to the wrong server entirely: a default vhost, a tunnel pointing somewhere else, a proxy that no longer forwards to this backend.
- Compare the response’s fingerprint. A 404 rendered by a hosting platform, a CDN, or a tunnel provider looks nothing like an MCP server’s — it carries the platform’s branding, its own headers, or an HTML body. If the body you get back is a branded page, the request never reached your server.
- Check whether the 404 is authentication in disguise. Some gateways answer unauthenticated requests with 404 rather than 401, deliberately, so they do not reveal which routes exist. If the same URL behaves differently with and without your credentials attached, you have a permission problem wearing a routing problem’s clothes.
That last case comes with a caution worth stating plainly: some servers accept a
token as part of the URL. Avoid it where you have the choice — a secret in a URL
ends up in proxy logs, browser history and error reports — and when you paste a
failing URL into an issue or a chat, mask the credential (Bearer ****) rather
than the hostname.
Fix by which 404 you have
- Transport mismatch — set the entry’s type to the transport the server actually speaks, and use the endpoint that transport expects. Do not change both at once; you will not know which one mattered.
- Wrong path, right server — take the URL from the server’s own docs rather than from a blog post or an older config. Server endpoints move between releases more often than hostnames do.
- Intermediary not attached — nothing to fix in the client. Start the backend first, wait for the tunnel or deployment to report ready, then start the session. If this is a daily annoyance, the fix is in your dev workflow, not your MCP config.
- Authentication returning 404 — attach credentials the way the server documents, through headers rather than the URL, and confirm the route appears once you are authenticated.
- Everything 404s — you are pointed at the wrong host. Verify the address resolves to what you think it does before touching anything else.
Confirming it is fixed
Open the stream twice in two separate sessions, and then call a tool. A single success immediately after a deploy can be the deploy finishing rather than your edit working, which is precisely the ambiguity that makes this error waste time.
The stronger confirmation is that the server appears healthy in your client’s MCP status view and returns a real tool result. A stream that opens and a server that works are not the same claim: the 404 is gone as soon as the route exists, while the tools only work once the server behind that route is the one you wanted.
Related failures
If the stream opens and then dies partway through a response, you have left routing behind entirely and are in connection-closed-mid-response territory, where the useful question is whether the failure lands at a consistent point. If it opens and simply goes quiet, the diagnosis is different again — a stream idle timeout with a partial response points at an intermediary killing idle connections rather than a missing route. If your client instead sits waiting and tells you there is no response from the API and it is retrying, nothing answered at all, which is the opposite of the situation on this page. And for a local MCP server, a 404 is impossible by construction; what you get there is a closed connection with no status at all. The AI coding error triage tool starts from the distinction this page turns on: did something answer you, or not?