Skip to content

Resource/Prompt method callbacks should use INTERNAL_ERROR (-32603) instead of INVALID_PARAMS (-32602) for runtime exceptions #926

@feelform

Description

@feelform

Problem

When a @McpResource or @McpPrompt annotated method throws a runtime exception (e.g., IOException, NullPointerException),
the framework wraps it with ErrorCodes.INVALID_PARAMS (-32602).

However, the MCP specification defines distinct error codes for different failure scenarios:

  • -32602 (INVALID_PARAMS): Invalid method parameter(s)
  • -32603 (INTERNAL_ERROR): Internal JSON-RPC error

A runtime exception during method execution is an internal error, not an invalid parameter error.

Affected files

All four resource callbacks and all four prompt callbacks use INVALID_PARAMS in the catch block:

Resource:

  • SyncMcpResourceMethodCallback.java:129
  • AsyncMcpResourceMethodCallback.java:143
  • SyncStatelessMcpResourceMethodCallback.java:124
  • AsyncStatelessMcpResourceMethodCallback.java:137

Prompt:

  • SyncMcpPromptMethodCallback.java:114
  • AsyncMcpPromptMethodCallback.java:122
  • SyncStatelessMcpPromptMethodCallback.java:108
  • AsyncStatelessMcpPromptMethodCallback.java:119

Example (SyncMcpResourceMethodCallback.java:124-135)

catch (Exception e) {
if (e instanceof McpError mcpError && mcpError.getJsonRpcError() != null) {
throw mcpError;
}

  throw McpError.builder(ErrorCodes.INVALID_PARAMS)  // ← should be ErrorCodes.INTERNAL_ERROR                         
      .message("Error invoking resource method: " + this.method.getName() + " in "                                      
              + this.bean.getClass().getName() + ". /nCause: "
              + ErrorUtils.findCauseUsingPlainJava(e).getMessage())                                                     
      .data(ErrorUtils.findCauseUsingPlainJava(e).getMessage())                                                         
      .build();               

}

Expected behavior

Runtime exceptions during method execution should be wrapped with ErrorCodes.INTERNAL_ERROR (-32603), matching the MCP
specification:

Additional note

The MCP SDK itself already follows this convention — McpStreamableServerSession uses INTERNAL_ERROR as the fallback when a
handler throws a non-McpError exception (line 184).

Environment

  • mcp-annotations: 0.8.0
  • mcp-core (SDK): 0.17.0
  • Spring AI: 1.1.4

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions