Bug description
Remote MCP servers that implement the MCP streamable-HTTP transport in stateless mode (POST-only, no SSE) are unusable with ToolHive. The transparent proxy forwards all HTTP methods to the remote server, including GET. Stateless servers don't serve an SSE stream on GET, so the response is not a valid SSE stream and the client never discovers tools.
Steps to reproduce
- Run a remote MCP server that implements stateless streamable-HTTP. One concrete example: a Spring AI server configured with
WebMvcStatelessServerTransport. You can verify a server is stateless by confirming that a POST to the MCP endpoint returns a JSON-RPC response, but a GET does not return a valid SSE stream.
- Register it with ToolHive:
thv run --name myserver https://my-stateless-server.example.com/mcp
- Connect a client (e.g., Claude Code) and attempt to list tools
Expected behavior
Tools are discoverable. The client can send JSON-RPC requests via POST and receive inline responses.
Actual behavior
Zero tools appear. The client sends GET to initiate an SSE stream; the proxy forwards it to the stateless server. Because stateless servers don't serve an SSE stream on GET, the response is not a valid SSE stream and the client never discovers tools.
Environment (if relevant)
- Reproducible on current main
Additional context
The MCP streamable-HTTP spec defines two server modes: stateful (supports GET for SSE stream initiation) and stateless (POST-only, inline responses, no sessions). The transparent proxy currently assumes stateful behavior for all remote servers. A server operating in stateless mode needs the proxy to restrict incoming requests to POST and to use a POST-based health check instead of the default GET probe.
Bug description
Remote MCP servers that implement the MCP streamable-HTTP transport in stateless mode (POST-only, no SSE) are unusable with ToolHive. The transparent proxy forwards all HTTP methods to the remote server, including GET. Stateless servers don't serve an SSE stream on GET, so the response is not a valid SSE stream and the client never discovers tools.
Steps to reproduce
WebMvcStatelessServerTransport. You can verify a server is stateless by confirming that a POST to the MCP endpoint returns a JSON-RPC response, but a GET does not return a valid SSE stream.thv run --name myserver https://my-stateless-server.example.com/mcpExpected behavior
Tools are discoverable. The client can send JSON-RPC requests via POST and receive inline responses.
Actual behavior
Zero tools appear. The client sends GET to initiate an SSE stream; the proxy forwards it to the stateless server. Because stateless servers don't serve an SSE stream on GET, the response is not a valid SSE stream and the client never discovers tools.
Environment (if relevant)
Additional context
The MCP streamable-HTTP spec defines two server modes: stateful (supports GET for SSE stream initiation) and stateless (POST-only, inline responses, no sessions). The transparent proxy currently assumes stateful behavior for all remote servers. A server operating in stateless mode needs the proxy to restrict incoming requests to POST and to use a POST-based health check instead of the default GET probe.