spring-projects / spring-projects/spring-ai
MCP Server stdio Communication Polluted by Maven Build Logs when using spring-boot:run
Nobody has claimed this yet.
- 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
-
Clone the MCP Server Repository:
git clone https://github.com/JamesSmith888/mcp-mysql-server.git cd mcp-mysql-server -
Ensure Server
application.ymlis configured forstdiowith console logging enabled (as in the problem state):
src/main/resources/application.ymlshould 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: -
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'sapplication.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 -
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)
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
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