MCP Server Transport: SSE vs Streamable HTTP for Spring AI MCP Apps
I spent hours trying to connect my Spring AI MCP server to Claude Desktop, and nothing worked. The server was running, the endpoints were correct, but Claude Desktop just wouldn’t talk to it. The culprit? A transport protocol mismatch that I didn’t even know existed.
The Problem I Ran Into
I had built a simple MCP server using Spring AI. It had a few tools for rolling dice and returning results. Everything worked perfectly when I tested it with an HTTP client. But when I configured Claude Desktop to use my server, I got nothing - no connection, no error messages, just silence.
Here was my setup:
spring.ai.mcp.server.protocol=streamableserver.port=3001And my Claude Desktop configuration:
{ "mcpServers": { "dice-tools": { "url": "http://localhost:3001/mcp" } }}Seemed simple enough. But the connection never established.
Understanding Transport Protocols in MCP
After digging through documentation and GitHub issues, I learned that MCP servers can use two different transport protocols:
-
SSE (Server-Sent Events): The older, deprecated protocol. Clients open a persistent connection and the server pushes events.
-
Streamable HTTP: The newer, recommended protocol. It uses standard HTTP with streaming capabilities and better handles the bidirectional communication MCP needs.
Spring AI defaults to SSE for backward compatibility, but recommends Streamable HTTP for new projects. The catch? Not all MCP clients support both protocols.
+------------------+-------------------+------------------------+| Transport | Direction | Status |+------------------+-------------------+------------------------+| SSE | Server to Client | Deprecated || Streamable HTTP | Bidirectional | Recommended |+------------------+-------------------+------------------------+Client Compatibility: The Missing Piece
The root of my problem was client compatibility. Here’s what I found:
| Client | SSE | Streamable HTTP ||----------------|-----|-----------------|| MCP Jam | Yes | Yes || Claude Desktop | Yes | No || Goose | Yes | Yes (limited) |Claude Desktop only supports SSE transport. It cannot directly connect to a Streamable HTTP MCP server. That’s why my configuration silently failed - Claude Desktop didn’t understand how to talk to my server.
The Solution: Using mcp-remote Proxy
To make Claude Desktop work with a Streamable HTTP MCP server, you need a proxy. The mcp-remote npm package bridges the gap by converting between transport protocols.
Here’s the corrected Claude Desktop configuration:
{ "mcpServers": { "dice-tools": { "command": "npx", "args": [ "-y", "mcp-remote", "http://localhost:3001/mcp" ] } }}The mcp-remote package:
- Accepts SSE connections from Claude Desktop
- Translates them to Streamable HTTP requests
- Sends them to your MCP server
- Translates responses back to SSE for Claude Desktop
Choosing Your Transport Protocol
I had two options to fix my problem:
Option 1: Switch to SSE (Not Recommended)
spring.ai.mcp.server.protocol=sseserver.port=3001This would let Claude Desktop connect directly, but SSE is deprecated. It may not receive future updates or bug fixes.
Option 2: Keep Streamable HTTP with Proxy (Recommended)
spring.ai.mcp.server.protocol=streamableserver.port=3001Keep the modern protocol and use mcp-remote for clients that don’t support it yet. This is the recommended approach.
I chose Option 2. Here’s why:
- Streamable HTTP is actively maintained and improved
- Most new MCP clients will support it
- The proxy adds minimal overhead for local development
- I can remove the proxy once Claude Desktop adds native support
What is SSE vs Streamable HTTP?
If you’re wondering what makes these transports different, here’s the technical breakdown.
Server-Sent Events (SSE)
SSE creates a long-lived HTTP connection where the server can push messages to the client. It’s unidirectional - the server talks, the client listens. For MCP, this meant:
Client ----[GET /sse]----> ServerClient <---[Event Stream]-- Server (keeps connection open)The client sends a GET request, the server keeps the connection open, and sends events as they happen. To send messages back to the server, MCP had to open separate HTTP requests.
Streamable HTTP
Streamable HTTP uses standard HTTP methods but with streaming request and response bodies. It’s bidirectional - both sides can send messages over the same logical connection:
Client <--[POST /mcp with stream]--> Server (bidirectional communication)This is more efficient because:
- Single HTTP connection handles both directions
- Better support for concurrent requests
- Cleaner error handling
- Standard HTTP semantics (methods, headers, status codes)
Port Convention
You may have noticed I used port 3001 instead of the default 8080. While not required, there’s a growing convention in the MCP community:
Default Spring Boot: 8080Common MCP Port: 3001Using port 3001 helps avoid conflicts with other Spring Boot apps and makes it clear this is an MCP server. It’s just a convention though - use whatever port works for your setup.
Common Mistakes I Made
Assuming All Clients Support Both Transports
I assumed MCP was MCP - that any client could talk to any server. But the transport layer matters, and client support varies. Always check what transports your target clients support.
Not Reading the Spring AI Defaults
Spring AI defaults to SSE for backward compatibility. I didn’t realize I needed to explicitly set spring.ai.mcp.server.protocol=streamable to get the recommended protocol.
Missing the -y Flag in npx
When using mcp-remote, the -y flag tells npx to run the package without prompting for confirmation. Without it, Claude Desktop hangs waiting for confirmation that never comes.
Wrong Endpoint Path
I initially tried http://localhost:3001 without the /mcp path. The MCP endpoint isn’t at the root - it’s at /mcp. Always include the full path.
How I Debugged This
When things weren’t working, I used a few techniques:
- Tested with curl: Verified the server was actually running and responding
curl -X POST http://localhost:3001/mcp -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","method":"tools/list","id":1}'- Checked Claude Desktop logs: Looked for connection errors
tail -f ~/Library/Logs/Claude/mcp*.log-
Tried different clients: Tested with MCP Jam to see if the server worked at all
-
Read the MCP spec: Found the transport protocol documentation
Related Knowledge
Why MCP Needs Bidirectional Transport
MCP is designed for interactive AI applications. The AI might need to:
- List available tools
- Call a tool and get results
- Read resources
- Subscribe to resource updates
All of this happens during a conversation, so the transport needs to handle requests in both directions efficiently. Streamable HTTP handles this better than SSE’s unidirectional model.
The Future of MCP Transports
The MCP specification is still evolving. Streamable HTTP is the current recommended transport, but the community is actively working on improvements. Keeping up with the spec means watching the official MCP GitHub repository and documentation.
Alternative: Using a Different Client
If you don’t want to deal with the proxy, you could use a client that supports Streamable HTTP directly:
- MCP Jam: A web-based MCP client with full transport support
- Custom clients: Build your own using the MCP SDK with Streamable HTTP
But most people want to use Claude Desktop, so the proxy is the practical solution.
Final Words + More Resources
My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!
Comments