Problem description
I'm encountering unexpected issues while trying to call a tool on a MCP server provided with Spring AI. However, while the tool parameters are showing up correctly in the mcp inspector, the call fails with the following error:
"Cannot construct instance of `com.test.Person` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 3] (through reference chain: java.util.ArrayList[0])"
Environment
Kotlin version: 2.2.0
JDK: 21 JVM
Gradle 8.14
MCP transport: streamable-http
MCP type: sync
References:
I use webmvc: org.springframework.ai:spring-ai-starter-mcp-server-webmvc: https://docs.spring.io/spring-ai/reference/api/mcp/mcp-streamable-http-server-boot-starter-docs.html#_streamable_http_webmvc_server
I use the Spring MCP annotations (@MCPTool): https://docs.spring.io/spring-ai/reference/api/mcp/mcp-annotations-server.html
Reproduction with existing project:
I prepared a simple example project to demonstrate the issue: https://github.com/nautnatic/spring-mcp-server-tool-deserialization-issue. You can also find out most of my setup in there if any information is missing.
Reproduction with own project:
Create a gradle kotlin project
Add org.springframework.ai:spring-ai-starter-mcp-server-webmvc dependency (https://docs.spring.io/spring-ai/reference/api/mcp/mcp-streamable-http-server-boot-starter-docs.html#_streamable_http_webmvc_server).
Add kotlin data class DataClass
Register a MCP Tool with an input parameter that has the type of List
[My fix attempt]: Register a custom Jackson ObjectMapper, which has the kotlin module enabled through
@Bean(name = ["mcpServerObjectMapper"])Run the application
Use the MCP inspector to call the tool: npx -y @modelcontextprotocol/inspector@0.18.0
You should see the error from above now.
Problem description and solution approach
As I understand, I need a custom Jackson ObjectMapper, which uses the jackson-module-kotlin to deserialize into Kotlin data classes. This works when calling the deserializer directly (see exemplary test in my example project above), but not when it's used through the MCP Tool call.
Any ideas on what I'm doing wrong / is there another way? Or is this a bug?