spring-projects / spring-projects/spring-ai
MCP server transports serialize `McpError` instead of JSON-RPC error responses
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 9.5k
- Forks
- 2.9k
- Avg merge
- 1d 7h
- Merged PRs (30d)
- 6
Description
Bug description
When an MCP server transport returns an error, the HTTP response body contains the serialized McpError exception rather than a JSON-RPC error response.
Since McpError extends RuntimeException, the response includes exception fields such as cause, localizedMessage, stackTrace, and suppressed. This occurs in the Stateless, SSE, and Streamable transports for both WebMVC and WebFlux.
A similar issue was reported for the Java SDK servlet transports in modelcontextprotocol/java-sdk#955.
Environment
- Spring AI 2.0.1
- Java 17
Steps to reproduce
Trigger an error response from one of the affected transports. For example:
- send malformed JSON to a Stateless endpoint
- omit the session ID when calling an SSE message endpoint
- send another initialization request to an already initialized Streamable session
The response body contains the exception object:
{
"jsonRpcError": {
"code": -32600,
"message": "Invalid message format"
},
"cause": null,
"localizedMessage": "Invalid message format",
"message": "Invalid message format",
"stackTrace": [
{
"className": "...",
"methodName": "..."
}
],
"suppressed": []
}
Expected behavior
The response body should contain only the JSON-RPC error response:
{
"jsonrpc": "2.0",
"error": {
"code": -32600,
"message": "Invalid message format"
}
}
The existing HTTP status should be retained. The response should include the request ID when it is available and omit the id member when it is not.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by tracing error handling in the Stateless, SSE, and Streamable transports for both WebMVC and WebFlux, using the malformed JSON, missing session ID, and repeated initialization cases as entry points. Done means each transport returns only the JSON-RPC error response, preserves the existing HTTP status, includes the request ID when available, and omits id otherwise.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100