-
Notifications
You must be signed in to change notification settings - Fork 700
Description
Expected Behavior
As a developer extending the MCP Java SDK, I should be able to access and customize the request handlers after the
McpServerSession is initialized. This would enable dynamic replacement of default handlers with custom
implementations.
// Example use case: Replacing default handlers with custom implementations
McpServerSession session = // ... initialized session
Map<String, McpRequestHandler<?>> handlers = session.getRequestHandlers();
handlers.put(McpSchema.METHOD_TOOLS_LIST, new MyCustomListToolsRequestHandler());
handlers.put(McpSchema.METHOD_TOOLS_CALL, new MyCustomToolsCallRequestHandler());
Current Behavior
Currently, the McpServerSession class does not provide any way to access or modify the requestHandlers map after
initialization. The request handlers are set in the constructor and remain private with no getter method.
Without a proper getter method, developers are forced to use reflection-based workarounds. For example, using
Spring's ReflectionUtils:
// Workaround: Using reflection to access private requestHandlers field
Field field = ReflectionUtils.findField(McpServerSession.class, "requestHandlers");
ReflectionUtils.makeAccessible(field);
@SuppressWarnings("unchecked")
Map<String, McpRequestHandler> handlers = (Map>) ReflectionUtils.getField(field,
session);
// Replace with custom handlers
handlers.put(McpSchema.METHOD_TOOLS_LIST, new MyCustomListToolsRequestHandler());
handlers.put(McpSchema.METHOD_TOOLS_CALL, new MyCustomToolsCallRequestHandler());
Or to replace the entire map:
// Workaround: Using reflection to replace the requestHandlers field
Field field = ReflectionUtils.findField(McpServerSession.class, "requestHandlers");
ReflectionUtils.makeAccessible(field);
Map<String, McpRequestHandler<?>> customHandlers = new ConcurrentHashMap<>();
customHandlers.put(McpSchema.METHOD_TOOLS_LIST, new MyCustomListToolsRequestHandler());
customHandlers.put(McpSchema.METHOD_TOOLS_CALL, new MyCustomToolsCallRequestHandler());
// ... add other default handlers
ReflectionUtils.setField(field, session, customHandlers);
This approach is fragile, breaks encapsulation, and makes the code harder to maintain.
Context
How has this issue affected you?
When building custom MCP server implementations, I need to replace default tool handlers with custom logic.
Currently, I'm forced to use reflection hacks to access and modify the private requestHandlers field, which is not
a recommended practice.
What are you trying to accomplish?
I want to implement custom McpRequestHandler instances for standard MCP methods (like tools/list and tools/call)
and register them with an existing McpServerSession without using reflection.
My proposed solution:
- Make the requestHandlers field a ConcurrentHashMap (for thread-safety during modifications)
- Add a public getter getRequestHandlers() to expose the handlers map
This allows for safe runtime modification while maintaining backward compatibility and eliminating the need for
reflection-based workarounds.
What other alternatives have you considered?
- Creating a wrapper class around McpServerSession - not feasible due to private field access
- Rebuilding the session with new handlers - inefficient and loses session state
- Using reflection (current workaround) - fragile and breaks encapsulation
Are you aware of any workarounds?
Yes, using Spring's ReflectionUtils to access and modify the private field (as shown above), but this is not a
proper solution.