server: handle DELETE on /cors-proxy for MCP streamable-http - #25296
Closed
tlemaire wants to merge 1 commit into
Closed
server: handle DELETE on /cors-proxy for MCP streamable-http#25296tlemaire wants to merge 1 commit into
tlemaire wants to merge 1 commit into
Conversation
MCP streamable-http clients send DELETE to terminate a session. Hosted MCP servers (e.g. Exa) reject DELETE with 405, which made the Web UI health check throw "Protocol error after initialize: Failed to terminate session" and disabled the server for conversations. Register a DELETE route on /cors-proxy that returns 200 directly instead of forwarding to the upstream, since session teardown is pure cleanup. Signed-off-by: Thierry Lemaire <thierry.lemaire@gmail.com>
ngxson
requested changes
Jul 4, 2026
ngxson
left a comment
Collaborator
There was a problem hiding this comment.
you didn't respect the PR description template
ngxson
reviewed
Jul 4, 2026
Comment on lines
+85
to
+97
| static server_http_context::handler_t proxy_handler_delete = [](const server_http_req &) -> server_http_res_ptr { | ||
| // MCP streamable-http clients send DELETE to terminate a session. Some hosted | ||
| // upstreams (e.g. Exa) reject DELETE, which makes the UI health check fail and | ||
| // disables the server for conversations. Session teardown is pure cleanup, so | ||
| // answer 200 directly instead of forwarding. | ||
| auto res = std::make_unique<server_http_res>(); | ||
| res->status = 200; | ||
| res->headers["Access-Control-Allow-Origin"] = "*"; | ||
| res->headers["Access-Control-Allow-Headers"] = "*"; | ||
| res->headers["Access-Control-Allow-Methods"] = "GET,POST,DELETE,OPTIONS"; | ||
| res->headers["Access-Control-Expose-Headers"] = "*"; | ||
| return res; | ||
| }; |
Collaborator
There was a problem hiding this comment.
this is not a proxy, it's a fake response
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The built-in CORS proxy (
--ui-mcp-proxy) only registersGETandPOSThandlers for/cors-proxy. The MCP streamable-http transport terminates a session by sending aDELETErequest, which has no matching route and falls through to the 403 handler. As a result the Web UI health-check fails for hosted MCP servers that follow the streamable-http spec (e.g. Exa), and the server is disabled for every conversation:This registers a
DELETEroute on/cors-proxythat responds200directly, since session teardown is pure cleanup and the upstream response is irrelevant to the client.Background
tools/server/server.cpppreviously registered onlyget/postfor/cors-proxy.tools/server/server-cors-proxy.hhad noDELETEhandler.https://mcp.exa.ai/mcpis the reported case).Changes
tools/server/server-cors-proxy.h: addproxy_handler_deletereturning a permissive200with the same CORS headers as the other handlers (GET,POST,DELETE,OPTIONS).tools/server/server.cpp: registerctx_http.del("/cors-proxy", proxy_handler_delete)and the matchingres_403fallback when the proxy is disabled.Testing
llama-serverwith--ui-mcp-proxy, configured the Exa MCP server in the Web UI.405from Exa, server marked unhealthy, tools invisible.web_search_exatool is available and callable.cc @ngxson @allozaur (server/ui maintainers per recent MCP proxy PRs #24500, #24970)