This is an automated email from the ASF dual-hosted git repository. rombert pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-mcp-server.git
commit b199ac0ae1ea75edbd091e5a08c4a5191d3d045e Author: Robert Munteanu <[email protected]> AuthorDate: Tue Dec 9 11:43:36 2025 +0100 feat(mcp-server): various improvements - add empty completions for the new-sling-servlet prompt to remove errors in the MCP inspector about missing completions - make the name/version/instructions for the MCP configurable and provide sensible defaults --- .../apache/sling/mcp/server/impl/McpServlet.java | 44 +++++++++++++++++++--- 1 file changed, 38 insertions(+), 6 deletions(-) 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 3f62a10..b12faa6 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 @@ -33,18 +33,19 @@ import io.modelcontextprotocol.json.jackson.JacksonMcpJsonMapper; import io.modelcontextprotocol.json.schema.jackson.DefaultJsonSchemaValidator; import io.modelcontextprotocol.server.McpServer; import io.modelcontextprotocol.server.McpStatelessServerFeatures; +import io.modelcontextprotocol.server.McpStatelessServerFeatures.SyncCompletionSpecification; import io.modelcontextprotocol.server.McpStatelessServerFeatures.SyncPromptSpecification; import io.modelcontextprotocol.server.McpStatelessServerFeatures.SyncToolSpecification; import io.modelcontextprotocol.server.McpStatelessSyncServer; import io.modelcontextprotocol.server.transport.HttpServletStatelessServerTransport; import io.modelcontextprotocol.spec.McpSchema; import io.modelcontextprotocol.spec.McpSchema.CallToolResult; +import io.modelcontextprotocol.spec.McpSchema.CompleteResult.CompleteCompletion; import io.modelcontextprotocol.spec.McpSchema.Prompt; import io.modelcontextprotocol.spec.McpSchema.PromptArgument; import io.modelcontextprotocol.spec.McpSchema.PromptMessage; import io.modelcontextprotocol.spec.McpSchema.ReadResourceResult; import io.modelcontextprotocol.spec.McpSchema.Resource; -import io.modelcontextprotocol.spec.McpSchema.ResourceContents; import io.modelcontextprotocol.spec.McpSchema.ResourceTemplate; import io.modelcontextprotocol.spec.McpSchema.Role; import io.modelcontextprotocol.spec.McpSchema.ServerCapabilities; @@ -65,11 +66,30 @@ import org.osgi.framework.wiring.FrameworkWiring; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.metatype.annotations.AttributeDefinition; +import org.osgi.service.metatype.annotations.Designate; +import org.osgi.service.metatype.annotations.ObjectClassDefinition; @Component(service = Servlet.class) @SlingServletPaths(value = {McpServlet.ENDPOINT}) +@Designate(ocd = McpServlet.Config.class) public class McpServlet extends SlingJakartaAllMethodsServlet { + @ObjectClassDefinition(name = "Apache Sling MCP Server Configuration") + public @interface Config { + @AttributeDefinition(name = "Server Title", description = "The title of the MCP server") + String serverTitle() default "Apache Sling"; + + @AttributeDefinition( + name = "Server Version", + description = "The version of the MCP server. Defaults to the bundle version if not set") + String serverVersion(); + + @AttributeDefinition(name = "Instructions", description = "Initial instructions for the MCP server") + String instructions() default + "This MCP server provides access to an Apache Sling development instance. Exposed tools and information always reference the Sling deployment and not local projects or files"; + } + static final String ENDPOINT = "/bin/mcp"; private static final long serialVersionUID = 1L; private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); @@ -92,7 +112,7 @@ public class McpServlet extends SlingJakartaAllMethodsServlet { } @Activate - public McpServlet(BundleContext ctx) throws IllegalAccessException, NoSuchMethodException { + public McpServlet(BundleContext ctx, Config config) throws IllegalAccessException, NoSuchMethodException { McpJsonMapper jsonMapper = new JacksonMcpJsonMapper(new ObjectMapper()); @@ -115,14 +135,26 @@ public class McpServlet extends SlingJakartaAllMethodsServlet { java.lang.invoke.MethodType.methodType( void.class, HttpServletRequest.class, HttpServletResponse.class)); + SyncCompletionSpecification servletCompletionSpec = new McpStatelessServerFeatures.SyncCompletionSpecification( + new McpSchema.PromptReference("ref/prompt", "new-sling-servlet"), (context, request) -> { + return new McpSchema.CompleteResult(new CompleteCompletion(List.of(), 0, false)); + }); + + String serverVersion = config.serverVersion(); + if (serverVersion == null || serverVersion.isEmpty()) { + serverVersion = ctx.getBundle().getVersion().toString(); + } syncServer = McpServer.sync(transportProvider) - .serverInfo("apache-sling", "0.1.0") + .serverInfo(config.serverTitle(), serverVersion) .jsonMapper(jsonMapper) .jsonSchemaValidator(new DefaultJsonSchemaValidator()) + .instructions(config.instructions()) + .completions(List.of(servletCompletionSpec)) .capabilities(ServerCapabilities.builder() - .tools(true) - .prompts(true) - .resources(true, true) + .tools(false) + .prompts(false) + .resources(false, false) + .completions() .build()) .build();
