spring-projects / spring-projects/spring-ai

MCP Server stdio Communication Polluted by Maven Build Logs when using spring-boot:run

Open
#3,472 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

status: waiting-for-triage
Dominant language
Java
Stars
9.5k
Forks
2.9k
Avg merge
1d 7h
Merged PRs (30d)
6

Description

When running a Spring AI Model Context Protocol (MCP) server configured for stdio transport via mvnw spring-boot:run, the io.modelcontextprotocol.spec.McpSchema class in the Java SDK's client-side attempts to deserialize unexpected, non-JSON strings (specifically, Maven build logs) from the standard output (stdout) stream. This leads to JSON deserialization errors, preventing proper MCP communication.

The issue does not occur when the server JAR is executed directly using java -jar, indicating that the interference is specifically related to the spring-boot:run execution environment and Maven's build output.

Reproduction Steps
  1. Clone the MCP Server Repository:

    git clone https://github.com/JamesSmith888/mcp-mysql-server.git
    cd mcp-mysql-server
    
  2. Ensure Server application.yml is configured for stdio with console logging enabled (as in the problem state):
    src/main/resources/application.yml should contain:

    spring:
      config:
        import: classpath:extension.yml
      ai:
        mcp:
          server:
            name: mcp-mysql-server
            version: 1.0.0
            stdio: true
      application:
        name: mcp-mysql-server
      main:
        banner-mode: off
    server:
      port: 9433
    logging:
      pattern:
        console: 
    
  3. Configure an MCP client to launch this server using mvnw spring-boot:run:
    An example client configuration (e.g., in a separate Spring AI client application's application.yml):

    spring:
      ai:
        mcp:
          client:
            stdio:
              root-change-notification: true
              connections:
                server1:
                  command: /Users/yangxin/IdeaProjects/mcp-mysql-server/mvnw # Adjust path if needed
                  args:
                    - --f
                    - /Users/yangxin/IdeaProjects/mcp-mysql-server/pom.xml # Specify pom.xml to avoid ambiguity
                    - spring-boot:run
    
  4. Run the MCP client application.

Observed Behavior

Upon running the MCP client, the MCP server process (launched by mvnw spring-boot:run) will output Maven build logs to stdout before the Spring Boot application fully initializes and sends its first MCP response. These Maven logs are then read by the MCP client's io.modelcontextprotocol.spec.McpSchema.deserializeJsonRpcMessage method, leading to a java.io.IOException or java.lang.IllegalArgumentException due to an "Unexpected token" or "Cannot deserialize JSONRPCMessage" error when attempting to parse non-JSON strings (e.g., [INFO] Scanning for projects...) as JSON RPC messages.

Example of conflicting stdout output (from Maven before Spring Boot starts):

[INFO] Scanning for projects...
[INFO] ----------------------< org.jim:mcp-mysql-server >----------------------
[INFO] Building mcp-mysql-server 0.0.1-SNAPSHOT
[INFO]   from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- clean:3.4.1:clean (default-clean) @ mcp-mysql-server ---
[INFO] Deleting /Users/yangxin/IdeaProjects/mcp-mysql-server/target
... (more Maven build logs) ...
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------

Relevant server-side code snippet that attempts deserialization:

// Located in io.modelcontextprotocol.spec.McpSchema
public static JSONRPCMessage deserializeJsonRpcMessage(ObjectMapper objectMapper, String jsonText)
       throws IOException {

    logger.debug("Received JSON message: {}", jsonText); // This line logs the problematic non-JSON string

    var map = objectMapper.readValue(jsonText, MAP_TYPE_REF); // This is where the deserialization error occurs

    // Determine message type based on specific JSON structure
    if (map.containsKey("method") && map.containsKey("id")) {
       return objectMapper.convertValue(map, JSONRPCRequest.class);
    }
    else if (map.containsKey("method") && !map.containsKey("id")) {
       return objectMapper.convertValue(map, JSONRPCNotification.class);
    }
    else if (map.containsKey("result") || map.containsKey("error")) {
       return objectMapper.convertValue(map, JSONRPCResponse.class);
    }

    throw new IllegalArgumentException("Cannot deserialize JSONRPCMessage: " + jsonText);
}
Expected Behavior

The stdout stream of an MCP server (when configured for stdio transport) should exclusively carry JSON RPC messages. Maven build logs (or any other non-protocol-defined output) should not be written to stdout in a way that interferes with MCP communication. The McpSchema.deserializeJsonRpcMessage method should only receive valid JSON strings for deserialization.

Ideally, the Spring AI framework's stdio transport should be robust enough to handle the execution context of spring-boot:run (e.g., by implicitly redirecting initial non-JSON output or providing clearer guidance on process execution for stdio servers), or the spring-boot:run plugin should offer a way to suppress its own stdout for this specific use case.

Please help me on how to best handle this scenario to ensure clean stdio communication for MCP servers launched via mvnw spring-boot:run.


Environment
  • Spring AI Version: 1.0.0
  • Java Version: 23.0.2
  • Maven Version: (Implicitly managed by mvnw)
  • Operating System: macOS
Server Repository (for reproduction)

https://github.com/JamesSmith888/mcp-mysql-server

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce the issue with the referenced mcp-mysql-server application.yml and the configured mvnw spring-boot:run command, then inspect io.modelcontextprotocol.spec.McpSchema.deserializeJsonRpcMessage. Compare the process stdout with direct java -jar execution; done means stdio carries only valid JSON-RPC messages without Maven log interference.

Written by the indexing model from the issue text.

Assessment

Tech stack
java, spring-boot
Domain
api, backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.