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

rombert pushed a commit to branch issue/javax-servlet-compat
in repository 
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-mcp-server.git

commit d71df6e2892b8625449aea0db18b89cd4174f8ae
Author: Robert Munteanu <[email protected]>
AuthorDate: Fri Feb 13 12:10:08 2026 +0100

    feat: make bundle compatible with javax.servlet APIs
    
    Since the Servlets from the SDK use the jakarta.servlet APIs we embed those 
APIs and the felix
    wrappers in the bundle. This allows MCP SDK servlets to function unaltered 
and the Sling
    McpServlet to use the old javax.servlet API.
    
    We also restrict slf4j imports to work with the older Sling commons.log 
version on the premise that
    projects that compile against slf4j 2.0 don't actually use any of the new 
APIs and can function
    with 1.7.x as well.
---
 bnd.bnd                                            | 19 ++++++-
 pom.xml                                            | 14 ++++-
 .../apache/sling/mcp/server/impl/McpServlet.java   | 61 +++++++++++++++-------
 3 files changed, 72 insertions(+), 22 deletions(-)

diff --git a/bnd.bnd b/bnd.bnd
index f1ef54d..15a8895 100644
--- a/bnd.bnd
+++ b/bnd.bnd
@@ -1,5 +1,20 @@
-# workaround for https://github.com/modelcontextprotocol/java-sdk/issues/562
+# 1. workaround for https://github.com/modelcontextprotocol/java-sdk/issues/562
+# 2. compatibility with javax.servlet
 Private-Package: io.modelcontextprotocol.json.jackson, \
-    io.modelcontextprotocol.json.schema.jackson
+    io.modelcontextprotocol.json.schema.jackson, \
+    jakarta.servlet, \
+    jakarta.servlet.annotation, \
+    jakarta.servlet.descriptor, \
+    jakarta.servlet.http, \
+    org.apache.felix.http.jakartawrappers, \
+    org.apache.felix.http.javaxwrappers
+
+# compatibility with slf4j 1.7 and 2.0. A bit of the gamble since we assume 
that libraries
+# that compile against slf4j 2.x only use 1.7 APIs
+Import-Package:  org.slf4j;version="[1.7,2)", \
+    *
+
+# Strictly control exports to prevent bnd from exporting packages that from 
embedded dependencies
+-exportcontents: org.apache.sling.mcp.server.spi
 
 Sling-Initial-Content: 
SLING-INF/libs/sling/mcp/prompts;path:=/libs/sling/mcp/prompts;overwrite:=true
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index ab1074a..f623c04 100644
--- a/pom.xml
+++ b/pom.xml
@@ -93,7 +93,7 @@
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.api</artifactId>
-            <version>3.0.2</version>
+            <version>2.27.6</version>
             <scope>provided</scope>
         </dependency>
         <dependency>
@@ -102,10 +102,20 @@
             <version>2.10.2</version>
             <scope>provided</scope>
         </dependency>
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>javax.servlet-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
         <dependency>
             <groupId>jakarta.servlet</groupId>
             <artifactId>jakarta.servlet-api</artifactId>
-            <scope>provided</scope>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.http.wrappers</artifactId>
+            <scope>compile</scope>
         </dependency>
         <dependency>
             <groupId>io.modelcontextprotocol.sdk</groupId>
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 643265c..2ba0354 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
@@ -18,6 +18,9 @@
  */
 package org.apache.sling.mcp.server.impl;
 
+import javax.servlet.Servlet;
+import javax.servlet.ServletException;
+
 import java.io.IOException;
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
@@ -35,13 +38,11 @@ import 
io.modelcontextprotocol.server.McpStatelessSyncServer;
 import 
io.modelcontextprotocol.server.transport.HttpServletStatelessServerTransport;
 import io.modelcontextprotocol.spec.McpSchema;
 import io.modelcontextprotocol.spec.McpSchema.ServerCapabilities;
-import jakarta.servlet.Servlet;
-import jakarta.servlet.ServletException;
-import jakarta.servlet.http.HttpServletRequest;
-import jakarta.servlet.http.HttpServletResponse;
-import org.apache.sling.api.SlingJakartaHttpServletRequest;
-import org.apache.sling.api.SlingJakartaHttpServletResponse;
-import org.apache.sling.api.servlets.SlingJakartaAllMethodsServlet;
+import org.apache.felix.http.jakartawrappers.HttpServletRequestWrapper;
+import org.apache.felix.http.jakartawrappers.HttpServletResponseWrapper;
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.SlingHttpServletResponse;
+import org.apache.sling.api.servlets.SlingAllMethodsServlet;
 import org.apache.sling.mcp.server.spi.McpServerContribution;
 import org.apache.sling.servlets.annotations.SlingServletPaths;
 import org.jetbrains.annotations.NotNull;
@@ -64,7 +65,7 @@ import static 
org.osgi.service.component.annotations.ReferencePolicyOption.GREED
 @Component(service = Servlet.class)
 @SlingServletPaths(value = {McpServlet.ENDPOINT})
 @Designate(ocd = McpServlet.Config.class)
-public class McpServlet extends SlingJakartaAllMethodsServlet {
+public class McpServlet extends SlingAllMethodsServlet {
 
     @ObjectClassDefinition(name = "Apache Sling MCP Server Configuration")
     public @interface Config {
@@ -102,8 +103,11 @@ public class McpServlet extends 
SlingJakartaAllMethodsServlet {
         transportProvider = HttpServletStatelessServerTransport.builder()
                 .messageEndpoint(ENDPOINT)
                 .jsonMapper(jsonMapper)
-                .contextExtractor(request -> McpTransportContext.create(
-                        Map.of("resourceResolver", 
((SlingJakartaHttpServletRequest) request).getResourceResolver())))
+                .contextExtractor(request -> McpTransportContext.create(Map.of(
+                        "resourceResolver",
+                        ((BridgedJakartaHttpServletRequest) request)
+                                .getSlingRequest()
+                                .getResourceResolver())))
                 .build();
 
         MethodHandles.Lookup privateLookup =
@@ -113,12 +117,16 @@ public class McpServlet extends 
SlingJakartaAllMethodsServlet {
                 HttpServletStatelessServerTransport.class,
                 "doGet",
                 java.lang.invoke.MethodType.methodType(
-                        void.class, HttpServletRequest.class, 
HttpServletResponse.class));
+                        void.class,
+                        jakarta.servlet.http.HttpServletRequest.class,
+                        jakarta.servlet.http.HttpServletResponse.class));
         doPostMethod = privateLookup.findVirtual(
                 HttpServletStatelessServerTransport.class,
                 "doPost",
                 java.lang.invoke.MethodType.methodType(
-                        void.class, HttpServletRequest.class, 
HttpServletResponse.class));
+                        void.class,
+                        jakarta.servlet.http.HttpServletRequest.class,
+                        jakarta.servlet.http.HttpServletResponse.class));
 
         String serverVersion = config.serverVersion();
         if (serverVersion == null || serverVersion.isEmpty()) {
@@ -205,11 +213,13 @@ public class McpServlet extends 
SlingJakartaAllMethodsServlet {
     }
 
     @Override
-    protected void doGet(
-            @NotNull SlingJakartaHttpServletRequest request, @NotNull 
SlingJakartaHttpServletResponse response)
+    protected void doGet(@NotNull SlingHttpServletRequest request, @NotNull 
SlingHttpServletResponse response)
             throws ServletException, IOException {
         try {
-            doGetMethod.invoke(transportProvider, request, response);
+            doGetMethod.invoke(
+                    transportProvider,
+                    new BridgedJakartaHttpServletRequest(request),
+                    new HttpServletResponseWrapper(response));
         } catch (ServletException | IOException | RuntimeException | Error e) {
             throw e;
         } catch (Throwable t) {
@@ -218,11 +228,13 @@ public class McpServlet extends 
SlingJakartaAllMethodsServlet {
     }
 
     @Override
-    protected void doPost(
-            @NotNull SlingJakartaHttpServletRequest request, @NotNull 
SlingJakartaHttpServletResponse response)
+    protected void doPost(@NotNull SlingHttpServletRequest request, @NotNull 
SlingHttpServletResponse response)
             throws ServletException, IOException {
         try {
-            doPostMethod.invoke(transportProvider, request, response);
+            doPostMethod.invoke(
+                    transportProvider,
+                    new BridgedJakartaHttpServletRequest(request),
+                    new HttpServletResponseWrapper(response));
         } catch (ServletException | IOException | RuntimeException | Error e) {
             throw e;
         } catch (Throwable t) {
@@ -236,4 +248,17 @@ public class McpServlet extends 
SlingJakartaAllMethodsServlet {
             syncServer.close();
         }
     }
+
+    static class BridgedJakartaHttpServletRequest extends 
HttpServletRequestWrapper {
+        private SlingHttpServletRequest slingRequest;
+
+        public BridgedJakartaHttpServletRequest(SlingHttpServletRequest 
request) {
+            super(request);
+            this.slingRequest = request;
+        }
+
+        public SlingHttpServletRequest getSlingRequest() {
+            return slingRequest;
+        }
+    }
 }

Reply via email to