spring-projects / spring-projects/spring-ai
ToolContext from MCP Client is lost in Spring AI MCP Server
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 9.5k
- Forks
- 2.9k
- Avg merge
- 1d 7h
- Merged PRs (30d)
- 6
Description
When using spring-ai-mcp (tested with 1.1.0-M3), the ToolContext values provided by the MCP client are not correctly propagated to the MCP server’s @Tool method.
This causes the ToolContext parameter injected into the tool method to lose the original client context, such as tokens or metadata.
Reproduction Steps
✅
MCP Client Code
chatClient.prompt()
.toolContext(Map.of("token", request.getToken()))
.user(request.getMessage())
.stream()
.content()
.subscribe();
The client sets a token inside toolContext, expecting the MCP server to receive it.
❌
MCP Server Tool
@Tool(description = "Calculate financial statistics for a user")
public String calculateUserStatistics(Long createdByUserId, ToolContext toolContext) {
// toolContext should contain "token" from client, but it’s missing
System.out.println("Received ToolContext: " + toolContext);
...
}
On the server side, the toolContext received by the @Tool method does not contain the client-provided values (e.g. "token").
Root Cause Analysis
In the class
org.springframework.ai.mcp.McpToolUtils#toSharedSyncToolSpecification
the current code creates a new ToolContext as follows:
new ToolContext(Map.of(TOOL_CONTEXT_MCP_EXCHANGE_KEY, exchangeOrContext))
However, it does not include the meta field from the CallToolRequest (which contains the client’s tool context).
So the original client-provided ToolContext is completely ignored.
Expected Behavior
The ToolContext passed into the tool callback should merge both:
- the existing MCP exchange context (TOOL_CONTEXT_MCP_EXCHANGE_KEY), and
- the meta values from CallToolRequest (coming from the MCP client).
Proposed Fix
Modify McpToolUtils#toSharedSyncToolSpecification() to merge the client context:
Map<String, Object> mergedContext = new HashMap<>();
mergedContext.put(TOOL_CONTEXT_MCP_EXCHANGE_KEY, exchangeOrContext);
if (request.meta() != null) {
mergedContext.putAll(request.meta());
}
ToolContext toolContext = new ToolContext(mergedContext);
String callResult = toolCallback.call(
ModelOptionsUtils.toJsonString(request.arguments()), toolContext);
This will ensure that any context values set on the MCP client (via .toolContext(...)) are correctly available on the server.
Environment
- Spring AI version: 1.1.0-M3
- Java version: 25
- MCP client: Spring AI MCP Client
- MCP server: Spring AI MCP Server
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
Start in org.springframework.ai.mcp.McpToolUtils#toSharedSyncToolSpecification and inspect how CallToolRequest, request.meta(), and the exchange context are converted into ToolContext. Reproduce the MCP client/server flow with the token example, then verify that the @Tool method receives both the exchange context and client-provided metadata.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, spring
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 74/100