This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to branch issue/fix-cursor-mcp-registration
in repository 
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-mcp-server.git

commit 208170af19c873a6a9ec1e9a9688fc73d6c807bd
Author: Robert Munteanu <[email protected]>
AuthorDate: Fri Feb 6 22:39:25 2026 +0100

    fix: work around issue in recent Cursor versions that prevents MCP server 
registration
    
    Cursor tries to register for resource updates even if we don't advertise 
that capability. This
    causes an internal error to be returned and blocks the MCP server 
activation.
    
    We work around it by using reflection to register a no-op handler, which 
seems to make
    Cursor happy.
---
 .../apache/sling/mcp/server/impl/McpServlet.java   | 32 ++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/src/main/java/org/apache/sling/mcp/server/impl/McpServlet.java 
b/src/main/java/org/apache/sling/mcp/server/impl/McpServlet.java
index a7ae71b..643265c 100644
--- a/src/main/java/org/apache/sling/mcp/server/impl/McpServlet.java
+++ b/src/main/java/org/apache/sling/mcp/server/impl/McpServlet.java
@@ -28,7 +28,9 @@ import io.modelcontextprotocol.common.McpTransportContext;
 import io.modelcontextprotocol.json.McpJsonMapper;
 import io.modelcontextprotocol.json.schema.jackson.DefaultJsonSchemaValidator;
 import io.modelcontextprotocol.server.McpServer;
+import io.modelcontextprotocol.server.McpStatelessRequestHandler;
 import 
io.modelcontextprotocol.server.McpStatelessServerFeatures.SyncPromptSpecification;
+import io.modelcontextprotocol.server.McpStatelessServerHandler;
 import io.modelcontextprotocol.server.McpStatelessSyncServer;
 import 
io.modelcontextprotocol.server.transport.HttpServletStatelessServerTransport;
 import io.modelcontextprotocol.spec.McpSchema;
@@ -52,6 +54,9 @@ import org.osgi.service.component.annotations.ReferencePolicy;
 import org.osgi.service.metatype.annotations.AttributeDefinition;
 import org.osgi.service.metatype.annotations.Designate;
 import org.osgi.service.metatype.annotations.ObjectClassDefinition;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import reactor.core.publisher.Mono;
 
 import static 
org.osgi.service.component.annotations.ReferenceCardinality.MULTIPLE;
 import static 
org.osgi.service.component.annotations.ReferencePolicyOption.GREEDY;
@@ -80,6 +85,7 @@ public class McpServlet extends SlingJakartaAllMethodsServlet 
{
     private static final long serialVersionUID = 1L;
     private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
 
+    private final Logger logger = LoggerFactory.getLogger(getClass());
     private McpStatelessSyncServer syncServer;
     private HttpServletStatelessServerTransport transportProvider;
     private MethodHandle doGetMethod;
@@ -138,6 +144,10 @@ public class McpServlet extends 
SlingJakartaAllMethodsServlet {
                         .build())
                 .build();
 
+        // workaround for 
https://github.com/modelcontextprotocol/java-sdk/issues/776
+        // cursor tries to register for resource updates even if we don't 
advertise that capability
+        tryRegisterNoopResourcesSubscribeHandler();
+
         contributions.stream()
                 .map(McpServerContribution::getSyncToolSpecification)
                 .flatMap(List::stream)
@@ -159,6 +169,28 @@ public class McpServlet extends 
SlingJakartaAllMethodsServlet {
                 .forEach(syncPrompt -> syncServer.addPrompt(syncPrompt));
     }
 
+    private void tryRegisterNoopResourcesSubscribeHandler() {
+        try {
+            MethodHandles.Lookup transportLookup =
+                    
MethodHandles.privateLookupIn(HttpServletStatelessServerTransport.class, 
LOOKUP);
+            MethodHandle mcpHandlerGetter = transportLookup.findGetter(
+                    HttpServletStatelessServerTransport.class, "mcpHandler", 
McpStatelessServerHandler.class);
+            Object mcpHandler = mcpHandlerGetter.invoke(transportProvider);
+
+            Class<?> handlerClass = mcpHandler.getClass();
+            MethodHandles.Lookup handlerLookup = 
MethodHandles.privateLookupIn(handlerClass, LOOKUP);
+            MethodHandle requestHandlersGetter = 
handlerLookup.findGetter(handlerClass, "requestHandlers", Map.class);
+            Map<String, McpStatelessRequestHandler<?>> handlers =
+                    (Map<String, McpStatelessRequestHandler<?>>) 
requestHandlersGetter.invoke(mcpHandler);
+
+            handlers.put(McpSchema.METHOD_RESOURCES_SUBSCRIBE, (context, 
params) -> Mono.just(Map.of()));
+        } catch (Throwable t) {
+            logger.warn(
+                    "Failed to register MCP resources subscribe handler, 
non-compliant clients requesting resource updates might fail",
+                    t);
+        }
+    }
+
     @Reference(policy = ReferencePolicy.DYNAMIC, policyOption = GREEDY, 
cardinality = MULTIPLE)
     protected void bindPrompt(DiscoveredPrompt prompt, Map<String, Object> 
properties) {
         syncServer.addPrompt(new SyncPromptSpecification(prompt.asPrompt(), 
(c, r) -> {

Reply via email to