Skip to content

Tools calls are getting mixed up (Streamable Http). Wrong tool method is invoked. (v0.8.1) #5

@krishnanmms

Description

@krishnanmms

I am using streamable Http transport (v 0.8.1) and have multiple tool methods registered from same class (e.g toolA(), toolB() etc). When the call is made to the server wrong tool method is getting invoked. for example, when toolA is called, toolB gets invoked.

The problem can be traced to #McpServerComponentRegister where tool registration happens. The componentClass is McpServerTool, for which only one instance is created (outside the loop).

 private <T> void register(
      Class<? extends Annotation> annotationClass,
      Class<? extends McpServerComponent<T>> componentClass,
      BiConsumer<McpSyncServer, T> serverAddComponent) {

    Set<Method> methods = reflections.getMethodsAnnotatedWith(annotationClass);
    McpServerComponent<T> component = injector.getInstance(componentClass);
    for (Method method : methods) {
      serverAddComponent.accept(server.get(), component.create(method));
    }
  }

In McpServerTool's create method, methodCache is looked up and stored as instance field. At the end of this method, this is included as part of callHandler(). So multiple calls to the create method corrupts this instance and the last method's methodCache is stored, which is later used for invocation. The same problem may be applicable for Prompt and Resource since the approach is the same.

  @Override
  public McpServerFeatures.SyncToolSpecification create(Method method) {
    // Use reflection cache for performance optimization
    methodCache = ReflectionCache.INSTANCE.getMethodMetadata(method);
    instance = injector.getInstance(methodCache.getDeclaringClass());

    McpTool toolMethod = methodCache.getMcpToolAnnotation();

    ......
    return McpServerFeatures.SyncToolSpecification.builder().tool(tool).callHandler(this).build();

A simple (naive?) fix would be to create an instance of the componentClass for each method. It doesn't look like instance of the class (like McpServerTool) are meant to be shared, since they include state related to the method. I tried this fix and it seem to work.

 private <T> void register(...) {

    Set<Method> methods = reflections.getMethodsAnnotatedWith(annotationClass);
    // McpServerComponent<T> component = injector.getInstance(c);
    for (Method method : methods) {
      McpServerComponent<T> component  = componentClass.newInstance();  // handle exception
      serverAddComponent.accept(server.get(), component.create(method));
    }
  }

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingfixed and releasedThis issue has been fixed and included in the latest releasewaiting for userWaiting for user feedback or more details

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions