Skip to content

Stateless server handler throws exception instead of returning JSON-RPC -32601 (Method not found) for not registered capabilities #784

Description

@maff

Bug description
In the stateless server path (DefaultMcpStatelessServerHandler), when a request is received for a method that does not have a registered handler, the server currently throws an McpError exception instead of returning a JSON-RPC response with an error code. This is inconsistent with the stateful/session server implementations (McpServerSession, etc.), which respond with the standard JSON-RPC error -32601 (Method not found).

Environment
ModelContextProtocol Java SDK, stateless/server mode.

Steps to reproduce

  1. Start a stateless MCP server instance (e.g., without advertising or registering a resources or prompts capability).
  2. Send a request with method: "resources/list" (or another method for which the handler is not registered).
  3. Exception is thrown instead of returning a JSON-RPC response with a "Method not found" error

Expected behavior
Stateless server should respond to any unknown/unregistered method with the standard JSON-RPC -32601 "Method not found" error, to be consistent with other server implementations in the SDK and with JSON-RPC specification.

Minimal Complete Reproducible example

Minimal Spring AI reproducer:

package com.example.demo;

import org.springaicommunity.mcp.annotation.McpTool;
import org.springaicommunity.mcp.annotation.McpToolParam;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Component;

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @Component
    public static class DemoTools {

        @McpTool
        public String hello(@McpToolParam String name) {
            return "Hello, " + name;
        }

    }
}
spring:
  ai:
    mcp:
      server:
        enabled: true
        type: sync
        protocol: stateless
        annotation-scanner:
          enabled: true
        streamable-http:
          mcp-endpoint: /mcp
        capabilities:
          completion: false
          prompt: false
          resource: false
          tool: true
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>4.0.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>21</java.version>
        <spring-ai.version>2.0.0-M2</spring-ai.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.ai</groupId>
                <artifactId>spring-ai-bom</artifactId>
                <version>${spring-ai.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>io.modelcontextprotocol.sdk</groupId>
                <artifactId>mcp-bom</artifactId>
                <version>0.17.2</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-mcp-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

Running a resources/list command against this server returns a JSON stack trace instead of a JSON-RPC response:

$ curl -H "Accept: application/json, text/event-stream" -H "Content-Type: application/json" -X POST http://localhost:8080/mcp -d '{"jsonrpc": "2.0", "method": "resources/list", "id": 1}' | jq
{
  "cause": null,
  "jsonRpcError": null,
  "localizedMessage": "Failed to handle request: Missing handler for request type: resources/list",
  "message": "Failed to handle request: Missing handler for request type: resources/list",
  "stackTrace": [
    {
      "classLoaderName": "app",
      "className": "io.modelcontextprotocol.server.transport.WebMvcStatelessServerTransport",
      "fileName": "WebMvcStatelessServerTransport.java",
      "lineNumber": 126,
      "methodName": "handlePost",
      "moduleName": null,
      "moduleVersion": null,
      "nativeMethod": false
    },
    {
      "classLoaderName": "app",
      "className": "org.springframework.web.servlet.function.support.HandlerFunctionAdapter",
      "fileName": "HandlerFunctionAdapter.java",
      // ...
    },
    // ...
  ],
  "suppressed": []
}

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No fields configured for Bug.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions