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-whiteboard.git
The following commit(s) were added to refs/heads/master by this push:
new e214433b chore(mcp): project moved to separate repository
e214433b is described below
commit e214433b5931318f4983843ba3d1ff5459a36648
Author: Robert Munteanu <[email protected]>
AuthorDate: Thu Jan 15 15:52:14 2026 +0100
chore(mcp): project moved to separate repository
---
mcp-server/README.md | 20 +-
mcp-server/bnd.bnd | 5 -
mcp-server/pom.xml | 266 ---------------------
mcp-server/src/main/features/main.json | 52 ----
.../sling/mcp/server/impl/DiscoveredPrompt.java | 35 ---
.../mcp/server/impl/McpJsonMapperProvider.java | 52 ----
.../apache/sling/mcp/server/impl/McpServlet.java | 207 ----------------
.../impl/contribs/DiscoveredPromptBuilder.java | 171 -------------
.../impl/contribs/RepositoryPromptsRegistrar.java | 149 ------------
.../mcp/server/spi/McpServerContribution.java | 65 -----
.../apache/sling/mcp/server/spi/package-info.java | 20 --
.../libs/sling/mcp/prompts/new-sling-servlet.md | 17 --
.../libs/sling/mcp/prompts/troubleshoot.md | 45 ----
.../impl/contribs/DiscoveredPromptBuilderTest.java | 129 ----------
14 files changed, 1 insertion(+), 1232 deletions(-)
diff --git a/mcp-server/README.md b/mcp-server/README.md
index d2988d45..8394956d 100644
--- a/mcp-server/README.md
+++ b/mcp-server/README.md
@@ -1,19 +1 @@
-# Apache Sling MCP Server
-
-Experimental MCP Server implementation for Apache Sling.
-
-## Usage
-
-Build the project with Maven and start up the MCP server, based on the Apache
Sling Starter:
-
-```
-$ mvn install feature-launcher:start feature-launcher:stop
-Dfeature-launcher.waitForInput
-```
-
-Then build and deploy the sibling contributions package:
-
-```
-$ mvn -f ../mcp-server-contributions/ install sling:install
-```
-
-Then open up your coding assistant tool and add an remote MCP server with
location http://localhost:8080/mcp .
+Moved to
[https://github.com/apache/sling-org-apache-sling-mcp-server](https://github.com/apache/sling-org-apache-sling-mcp-server)
diff --git a/mcp-server/bnd.bnd b/mcp-server/bnd.bnd
deleted file mode 100644
index f1ef54d5..00000000
--- a/mcp-server/bnd.bnd
+++ /dev/null
@@ -1,5 +0,0 @@
-# workaround for https://github.com/modelcontextprotocol/java-sdk/issues/562
-Private-Package: io.modelcontextprotocol.json.jackson, \
- io.modelcontextprotocol.json.schema.jackson
-
-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/mcp-server/pom.xml b/mcp-server/pom.xml
deleted file mode 100644
index 68b2502e..00000000
--- a/mcp-server/pom.xml
+++ /dev/null
@@ -1,266 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements. See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership. The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing,
- software distributed under the License is distributed on an
- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND, either express or implied. See the License for the
- specific language governing permissions and limitations
- under the License.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
-
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>org.apache.sling</groupId>
- <artifactId>sling-bundle-parent</artifactId>
- <version>65</version>
- <relativePath />
- </parent>
-
- <artifactId>org.apache.sling.mcp-server</artifactId>
- <version>0.1.0-SNAPSHOT</version>
-
- <name>Apache Sling MCP Server</name>
-
- <properties>
- <sling.java.version>17</sling.java.version>
- <!-- Run with
-Dslingfeature.app.vmOption=-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=30303
for debug mode-->
- <slingfeature.app.vmOption />
- </properties>
-
- <dependencies>
- <dependency>
- <groupId>org.osgi</groupId>
- <artifactId>org.osgi.framework</artifactId>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>org.osgi</groupId>
- <artifactId>org.osgi.resource</artifactId>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>org.osgi</groupId>
- <artifactId>org.osgi.annotation.bundle</artifactId>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>org.osgi</groupId>
- <artifactId>org.osgi.annotation.versioning</artifactId>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>org.osgi</groupId>
- <artifactId>org.osgi.service.component.annotations</artifactId>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>org.osgi</groupId>
- <artifactId>org.osgi.service.component</artifactId>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>org.osgi</groupId>
- <artifactId>org.osgi.service.metatype.annotations</artifactId>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>org.apache.sling</groupId>
- <artifactId>org.apache.sling.servlets.annotations</artifactId>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>org.jetbrains</groupId>
- <artifactId>annotations</artifactId>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>org.apache.sling</groupId>
- <artifactId>org.apache.sling.api</artifactId>
- <version>3.0.2</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>org.apache.sling</groupId>
- <artifactId>org.apache.sling.engine</artifactId>
- <version>2.10.2</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>jakarta.servlet</groupId>
- <artifactId>jakarta.servlet-api</artifactId>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>io.modelcontextprotocol.sdk</groupId>
- <artifactId>mcp</artifactId>
- <version>0.17.0</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>org.osgi</groupId>
- <artifactId>org.osgi.service.log</artifactId>
- <version>1.3.0</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>org.commonmark</groupId>
- <artifactId>commonmark</artifactId>
- <version>0.27.0</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>org.commonmark</groupId>
- <artifactId>commonmark-ext-yaml-front-matter</artifactId>
- <version>0.27.0</version>
- <scope>provided</scope>
- </dependency>
-
- <!-- test dependencies -->
- <dependency>
- <groupId>org.junit.jupiter</groupId>
- <artifactId>junit-jupiter-engine</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.mockito</groupId>
- <artifactId>mockito-core</artifactId>
- <version>5.20.0</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.assertj</groupId>
- <artifactId>assertj-core</artifactId>
- <version>3.27.6</version>
- <scope>test</scope>
- </dependency>
- </dependencies>
-
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.sling</groupId>
- <artifactId>slingfeature-maven-plugin</artifactId>
- <version>1.9.2</version>
- <extensions>true</extensions>
- <configuration>
-
<skipAddFeatureDependencies>true</skipAddFeatureDependencies>
- <framework>
- <groupId>org.apache.felix</groupId>
- <artifactId>org.apache.felix.framework</artifactId>
- <version>7.0.5</version>
- </framework>
-
- <!--
- Prepares a feature model aggregate that takes the
following features from
- the Sling Starter:
- - nosample_base - the base Sling Starter
- - oak_persistence_sns - SegmentNodeStore persistence
for Oak
- - composum - The Composum Nodes administration tool
- Notably missing are the slingshot and starter samples
- -->
- <aggregates>
- <aggregate>
- <classifier>app</classifier>
- <filesInclude>main.json</filesInclude>
- <attach>false</attach>
- <includeArtifact>
- <groupId>org.apache.sling</groupId>
-
<artifactId>org.apache.sling.starter</artifactId>
- <classifier>nosample_base</classifier>
- <version>14-SNAPSHOT</version>
- <type>slingosgifeature</type>
- </includeArtifact>
- <includeArtifact>
- <groupId>org.apache.sling</groupId>
-
<artifactId>org.apache.sling.starter</artifactId>
- <classifier>oak_persistence_sns</classifier>
- <version>14-SNAPSHOT</version>
- <type>slingosgifeature</type>
- </includeArtifact>
- <includeArtifact>
- <groupId>org.apache.sling</groupId>
-
<artifactId>org.apache.sling.starter</artifactId>
- <classifier>starter</classifier>
- <version>14-SNAPSHOT</version>
- <type>slingosgifeature</type>
- </includeArtifact>
- <includeArtifact>
- <groupId>org.apache.sling</groupId>
-
<artifactId>org.apache.sling.starter</artifactId>
- <classifier>composum</classifier>
- <version>14-SNAPSHOT</version>
- <type>slingosgifeature</type>
- </includeArtifact>
- </aggregate>
- </aggregates>
- <repositories>
- <repository>
- <includeClassifier>app</includeClassifier>
- </repository>
- </repositories>
- <scans>
- <scan>
- <includeClassifier>app</includeClassifier>
- </scan>
- </scans>
- </configuration>
- <executions>
- <execution>
- <id>prepare-features</id>
- <goals>
- <goal>aggregate-features</goal>
- <goal>analyse-features</goal>
- <goal>attach-features</goal>
- </goals>
- <phase>prepare-package</phase>
- </execution>
- <execution>
- <id>create-app-repository</id>
- <goals>
- <goal>repository</goal>
- </goals>
- <phase>package</phase>
- </execution>
- </executions>
- </plugin>
- <!-- Configure bnd-baseline to skip when no previous version
exists. Remove after first release -->
- <plugin>
- <groupId>biz.aQute.bnd</groupId>
- <artifactId>bnd-baseline-maven-plugin</artifactId>
- <configuration>
- <failOnMissing>false</failOnMissing>
- </configuration>
- </plugin>
- <!-- Added: Feature Launcher plugin for manually starting the
aggregated 'app' feature -->
- <plugin>
- <groupId>org.apache.sling</groupId>
- <artifactId>feature-launcher-maven-plugin</artifactId>
- <configuration>
- <launches>
- <launch>
- <id>app</id>
-
<featureFile>${project.slingfeature.outputDirectory}/feature-app.json</featureFile>
- <launcherArguments>
- <vmOptions>
-
<vmOption>${slingfeature.app.vmOption}</vmOption>
- </vmOptions>
- </launcherArguments>
- </launch>
- </launches>
- </configuration>
- </plugin>
- </plugins>
- </build>
-
-</project>
diff --git a/mcp-server/src/main/features/main.json
b/mcp-server/src/main/features/main.json
deleted file mode 100644
index ffae06af..00000000
--- a/mcp-server/src/main/features/main.json
+++ /dev/null
@@ -1,52 +0,0 @@
-{
- "bundles": [
- {
- "id": "${project.groupId}:${project.artifactId}:${project.version}",
- "start-order": 25
- },
- {
- "id": "io.modelcontextprotocol.sdk:mcp-core:0.17.0",
- "start-order": 25
- },
- {
- "id": "io.projectreactor:reactor-core:3.7.0",
- "start-order": 25
- },
- {
- "id": "org.reactivestreams:reactive-streams:1.0.4",
- "start-order": 25
- },
- {
- "id": "com.networknt:json-schema-validator:2.0.0",
- "start-order": 25
- },
- {
- "id": "com.ethlo.time:itu:1.14.0",
- "start-order": 25
- },
- {
- "id":
"com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.18.3",
- "start-order": 25
- },
- {
- "id": "org.yaml:snakeyaml:2.3",
- "start-order": 25
- },
- {
- "id": "org.commonmark:commonmark:0.27.0",
- "start-order": 25
- },
- {
- "id": "org.commonmark:commonmark-ext-yaml-front-matter:0.27.0",
- "start-order": 25
- }
- ],
- "configurations": {
-
"org.apache.sling.jcr.base.internal.LoginAdminWhitelist.fragment~mcp-server":{
- "whitelist.bundles":[
- "org.apache.sling.mcp-server"
- ],
- "whitelist.name":"mcp-server"
- }
- }
-}
diff --git
a/mcp-server/src/main/java/org/apache/sling/mcp/server/impl/DiscoveredPrompt.java
b/mcp-server/src/main/java/org/apache/sling/mcp/server/impl/DiscoveredPrompt.java
deleted file mode 100644
index 4e6e54f4..00000000
---
a/mcp-server/src/main/java/org/apache/sling/mcp/server/impl/DiscoveredPrompt.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sling.mcp.server.impl;
-
-import java.util.List;
-
-import io.modelcontextprotocol.common.McpTransportContext;
-import io.modelcontextprotocol.spec.McpSchema.GetPromptRequest;
-import io.modelcontextprotocol.spec.McpSchema.Prompt;
-import io.modelcontextprotocol.spec.McpSchema.PromptMessage;
-
-public interface DiscoveredPrompt {
-
- public static final String SERVICE_PROP_NAME = "mcp.prompt.name";
-
- List<PromptMessage> getPromptMessages(McpTransportContext c,
GetPromptRequest r);
-
- Prompt asPrompt();
-}
diff --git
a/mcp-server/src/main/java/org/apache/sling/mcp/server/impl/McpJsonMapperProvider.java
b/mcp-server/src/main/java/org/apache/sling/mcp/server/impl/McpJsonMapperProvider.java
deleted file mode 100644
index 5df93df3..00000000
---
a/mcp-server/src/main/java/org/apache/sling/mcp/server/impl/McpJsonMapperProvider.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sling.mcp.server.impl;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import io.modelcontextprotocol.json.McpJsonMapper;
-import io.modelcontextprotocol.json.jackson.JacksonMcpJsonMapper;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceRegistration;
-import org.osgi.service.component.annotations.Activate;
-import org.osgi.service.component.annotations.Component;
-import org.osgi.service.component.annotations.Deactivate;
-
-import static
com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;
-
-@Component
-public class McpJsonMapperProvider {
-
- private ServiceRegistration<McpJsonMapper> serviceRegistration;
-
- @Activate
- public void activate(BundleContext bundleContext) {
- ObjectMapper objectMapper = new ObjectMapper();
- // work around
https://github.com/modelcontextprotocol/java-sdk/issues/724
- objectMapper.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);
- McpJsonMapper jsonMapper = new JacksonMcpJsonMapper(objectMapper);
- serviceRegistration =
bundleContext.registerService(McpJsonMapper.class, jsonMapper, null);
- }
-
- @Deactivate
- public void deactivate() {
- if (serviceRegistration != null) {
- serviceRegistration.unregister();
- }
- }
-}
diff --git
a/mcp-server/src/main/java/org/apache/sling/mcp/server/impl/McpServlet.java
b/mcp-server/src/main/java/org/apache/sling/mcp/server/impl/McpServlet.java
deleted file mode 100644
index a7ae71bc..00000000
--- a/mcp-server/src/main/java/org/apache/sling/mcp/server/impl/McpServlet.java
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sling.mcp.server.impl;
-
-import java.io.IOException;
-import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodHandles;
-import java.util.List;
-import java.util.Map;
-
-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.McpStatelessServerFeatures.SyncPromptSpecification;
-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.sling.mcp.server.spi.McpServerContribution;
-import org.apache.sling.servlets.annotations.SlingServletPaths;
-import org.jetbrains.annotations.NotNull;
-import org.osgi.framework.BundleContext;
-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.component.annotations.Reference;
-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 static
org.osgi.service.component.annotations.ReferenceCardinality.MULTIPLE;
-import static
org.osgi.service.component.annotations.ReferencePolicyOption.GREEDY;
-
-@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();
-
- private McpStatelessSyncServer syncServer;
- private HttpServletStatelessServerTransport transportProvider;
- private MethodHandle doGetMethod;
- private MethodHandle doPostMethod;
-
- @Activate
- public McpServlet(
- BundleContext ctx,
- Config config,
- @Reference McpJsonMapper jsonMapper,
- @Reference(cardinality = MULTIPLE, policyOption = GREEDY)
List<McpServerContribution> contributions)
- throws IllegalAccessException, NoSuchMethodException {
-
- transportProvider = HttpServletStatelessServerTransport.builder()
- .messageEndpoint(ENDPOINT)
- .jsonMapper(jsonMapper)
- .contextExtractor(request -> McpTransportContext.create(
- Map.of("resourceResolver",
((SlingJakartaHttpServletRequest) request).getResourceResolver())))
- .build();
-
- MethodHandles.Lookup privateLookup =
-
MethodHandles.privateLookupIn(HttpServletStatelessServerTransport.class,
LOOKUP);
-
- doGetMethod = privateLookup.findVirtual(
- HttpServletStatelessServerTransport.class,
- "doGet",
- java.lang.invoke.MethodType.methodType(
- void.class, HttpServletRequest.class,
HttpServletResponse.class));
- doPostMethod = privateLookup.findVirtual(
- HttpServletStatelessServerTransport.class,
- "doPost",
- java.lang.invoke.MethodType.methodType(
- void.class, HttpServletRequest.class,
HttpServletResponse.class));
-
- String serverVersion = config.serverVersion();
- if (serverVersion == null || serverVersion.isEmpty()) {
- serverVersion = ctx.getBundle().getVersion().toString();
- }
-
- var completions = contributions.stream()
- .map(McpServerContribution::getSyncCompletionSpecification)
- .flatMap(List::stream)
- .toList();
-
- syncServer = McpServer.sync(transportProvider)
- .serverInfo(config.serverTitle(), serverVersion)
- .jsonMapper(jsonMapper)
- .jsonSchemaValidator(new DefaultJsonSchemaValidator())
- .instructions(config.instructions())
- .completions(completions)
- .capabilities(ServerCapabilities.builder()
- .tools(false)
- .prompts(false)
- .resources(false, false)
- .completions()
- .build())
- .build();
-
- contributions.stream()
- .map(McpServerContribution::getSyncToolSpecification)
- .flatMap(List::stream)
- .forEach(syncTool -> syncServer.addTool(syncTool));
-
- contributions.stream()
- .map(McpServerContribution::getSyncResourceSpecification)
- .flatMap(List::stream)
- .forEach(syncResource -> syncServer.addResource(syncResource));
-
- contributions.stream()
-
.map(McpServerContribution::getSyncResourceTemplateSpecification)
- .flatMap(List::stream)
- .forEach(syncResource ->
syncServer.addResourceTemplate(syncResource));
-
- contributions.stream()
- .map(McpServerContribution::getSyncPromptSpecification)
- .flatMap(List::stream)
- .forEach(syncPrompt -> syncServer.addPrompt(syncPrompt));
- }
-
- @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) -> {
- var messages = prompt.getPromptMessages(c, r);
- return new McpSchema.GetPromptResult(null, messages);
- }));
- }
-
- protected void unbindPrompt(Map<String, Object> properties) {
- String promptName = (String)
properties.get(DiscoveredPrompt.SERVICE_PROP_NAME);
- syncServer.removePrompt(promptName);
- }
-
- @Override
- protected void doGet(
- @NotNull SlingJakartaHttpServletRequest request, @NotNull
SlingJakartaHttpServletResponse response)
- throws ServletException, IOException {
- try {
- doGetMethod.invoke(transportProvider, request, response);
- } catch (ServletException | IOException | RuntimeException | Error e) {
- throw e;
- } catch (Throwable t) {
- throw new ServletException(t);
- }
- }
-
- @Override
- protected void doPost(
- @NotNull SlingJakartaHttpServletRequest request, @NotNull
SlingJakartaHttpServletResponse response)
- throws ServletException, IOException {
- try {
- doPostMethod.invoke(transportProvider, request, response);
- } catch (ServletException | IOException | RuntimeException | Error e) {
- throw e;
- } catch (Throwable t) {
- throw new ServletException(t);
- }
- }
-
- @Deactivate
- public void close() {
- if (syncServer != null) {
- syncServer.close();
- }
- }
-}
diff --git
a/mcp-server/src/main/java/org/apache/sling/mcp/server/impl/contribs/DiscoveredPromptBuilder.java
b/mcp-server/src/main/java/org/apache/sling/mcp/server/impl/contribs/DiscoveredPromptBuilder.java
deleted file mode 100644
index 99f2335e..00000000
---
a/mcp-server/src/main/java/org/apache/sling/mcp/server/impl/contribs/DiscoveredPromptBuilder.java
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sling.mcp.server.impl.contribs;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.List;
-
-import io.modelcontextprotocol.common.McpTransportContext;
-import io.modelcontextprotocol.spec.McpSchema.GetPromptRequest;
-import io.modelcontextprotocol.spec.McpSchema.Prompt;
-import io.modelcontextprotocol.spec.McpSchema.PromptArgument;
-import io.modelcontextprotocol.spec.McpSchema.PromptMessage;
-import io.modelcontextprotocol.spec.McpSchema.Role;
-import io.modelcontextprotocol.spec.McpSchema.TextContent;
-import org.apache.sling.api.resource.Resource;
-import org.apache.sling.api.resource.ResourceResolver;
-import org.apache.sling.mcp.server.impl.DiscoveredPrompt;
-import org.commonmark.ext.front.matter.YamlFrontMatterExtension;
-import org.commonmark.ext.front.matter.YamlFrontMatterVisitor;
-import org.commonmark.node.Node;
-import org.commonmark.parser.Parser;
-import org.commonmark.renderer.markdown.MarkdownRenderer;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-class DiscoveredPromptBuilder {
-
- private final Logger logger = LoggerFactory.getLogger(getClass());
-
- public DiscoveredPrompt buildPrompt(Resource prompt, String promptName)
throws IOException {
-
- Parser parser = Parser.builder()
- .extensions(List.of(YamlFrontMatterExtension.create()))
- .build();
- String charset = prompt.getResourceMetadata().getCharacterEncoding();
- if (charset == null) {
- charset = StandardCharsets.UTF_8.name();
- }
- try (InputStream is = prompt.adaptTo(InputStream.class)) {
- Node node = parser.parseReader(new InputStreamReader(is, charset));
- YamlFrontMatterVisitor visitor = new YamlFrontMatterVisitor();
- node.accept(visitor);
-
- String title = visitor.getData().getOrDefault("title",
List.of()).stream()
- .findFirst()
- .orElse(null);
- String description = visitor.getData().getOrDefault("description",
List.of()).stream()
- .findFirst()
- .orElse(null);
-
- List<PromptArgument> arguments = new ArrayList<>();
-
- visitor.getData().entrySet().stream()
- .filter(e -> e.getKey().startsWith("argument."))
- .forEach(e -> {
- String argName =
e.getKey().substring("argument.".length());
- List<String> values = e.getValue();
- String argTitle = null;
- String argDesc = null;
- boolean argRequired = false;
- for (String value : values) {
-
- if (value.startsWith("title:")) {
- argTitle =
value.substring("title:".length()).trim();
- } else if (value.startsWith("description:")) {
- argDesc =
-
value.substring("description:".length()).trim();
- } else if (value.startsWith("required:")) {
- String argRequiredRaw =
-
value.substring("required:".length()).trim();
- argRequired = Boolean.valueOf(argRequiredRaw);
- } else {
- logger.warn("Unknown argument property in
prompt {}: {}", promptName, value);
- }
- }
-
- arguments.add(new PromptArgument(argName, argTitle,
argDesc, argRequired));
- });
-
- return new RepositoryPrompt(prompt.getPath(), promptName, title,
description, arguments);
- }
- }
-
- static class RepositoryPrompt implements DiscoveredPrompt {
-
- private final String promptPath;
- private final String promptName;
- private final String promptTitle;
- private final String promptDescription;
- private final List<PromptArgument> arguments;
-
- RepositoryPrompt(
- String promptPath,
- String promptName,
- String promptTitle,
- String promptDescription,
- List<PromptArgument> arguments) {
- this.promptPath = promptPath;
- this.promptName = promptName;
- this.promptTitle = promptTitle;
- this.promptDescription = promptDescription;
- this.arguments = arguments;
- }
-
- @Override
- public List<PromptMessage> getPromptMessages(McpTransportContext c,
GetPromptRequest req) {
-
- ResourceResolver rr = (ResourceResolver) c.get("resourceResolver");
-
- try {
- Resource promptResource = rr.getResource(promptPath);
- String encoding =
promptResource.getResourceMetadata().getCharacterEncoding();
- if (encoding == null) {
- encoding = StandardCharsets.UTF_8.name();
- }
-
- Parser parser = Parser.builder()
- .extensions(List.of(YamlFrontMatterExtension.create()))
- .build();
-
- try (InputStream stream =
promptResource.adaptTo(InputStream.class)) {
-
- Node node = parser.parseReader(new
InputStreamReader(stream, encoding));
-
- // Render markdown without the front matter extension for
clarity and for keeping
- // the context usage low
- MarkdownRenderer renderer =
MarkdownRenderer.builder().build();
- String contents = renderer.render(node);
-
- for (PromptArgument arg : arguments) {
- String placeholder = "{" + arg.name() + "}";
- Object requestedArg = req.arguments().get(arg.name());
- String value = requestedArg != null ?
requestedArg.toString() : "";
- if (!value.isEmpty()) {
- contents = contents.replace(placeholder, value);
- }
- }
-
- return List.of(new PromptMessage(Role.ASSISTANT, new
TextContent(contents)));
- }
- } catch (IOException e) {
- return List.of();
- }
- }
-
- @Override
- public Prompt asPrompt() {
- return new Prompt(promptName, promptTitle, promptDescription,
arguments);
- }
- }
-}
diff --git
a/mcp-server/src/main/java/org/apache/sling/mcp/server/impl/contribs/RepositoryPromptsRegistrar.java
b/mcp-server/src/main/java/org/apache/sling/mcp/server/impl/contribs/RepositoryPromptsRegistrar.java
deleted file mode 100644
index 81b07a42..00000000
---
a/mcp-server/src/main/java/org/apache/sling/mcp/server/impl/contribs/RepositoryPromptsRegistrar.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sling.mcp.server.impl.contribs;
-
-import java.io.IOException;
-import java.util.Hashtable;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-
-import org.apache.sling.api.resource.LoginException;
-import org.apache.sling.api.resource.Resource;
-import org.apache.sling.api.resource.ResourceResolver;
-import org.apache.sling.api.resource.ResourceResolverFactory;
-import org.apache.sling.api.resource.observation.ResourceChange;
-import org.apache.sling.api.resource.observation.ResourceChange.ChangeType;
-import org.apache.sling.api.resource.observation.ResourceChangeListener;
-import org.apache.sling.mcp.server.impl.DiscoveredPrompt;
-import org.jetbrains.annotations.NotNull;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceRegistration;
-import org.osgi.service.component.annotations.Activate;
-import org.osgi.service.component.annotations.Component;
-import org.osgi.service.component.annotations.Reference;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-@Component
-public class RepositoryPromptsRegistrar {
-
- private static final String PROMPT_LIBS_DIR = "/libs/sling/mcp/prompts";
- private final Logger logger = LoggerFactory.getLogger(getClass());
- private ConcurrentMap<String, ServiceRegistration<DiscoveredPrompt>>
registrations = new ConcurrentHashMap<>();
- private final DiscoveredPromptBuilder promptBuilder = new
DiscoveredPromptBuilder();
-
- @Activate
- public RepositoryPromptsRegistrar(@Reference ResourceResolverFactory rrf,
BundleContext ctx) throws LoginException {
-
- ctx.registerService(
- ResourceChangeListener.class,
- new ResourceChangeListener() {
-
- @Override
- public void onChange(@NotNull List<ResourceChange>
changes) {
-
- try (ResourceResolver resolver =
rrf.getAdministrativeResourceResolver(null)) {
- for (ResourceChange change : changes) {
- if (change.getType() == ChangeType.REMOVED) {
- String promptName =
getPromptName(change.getPath());
- ServiceRegistration<DiscoveredPrompt> sr =
registrations.remove(promptName);
- if (sr != null) {
- sr.unregister();
- } else {
- logger.warn(
- "No registered prompt found
for removed prompt {} at path {}, unable to unregister prompt.",
- promptName,
- change.getPath());
- }
- } else {
- String promptName =
getPromptName(change.getPath());
- ServiceRegistration<DiscoveredPrompt> sr =
registrations.remove(promptName);
- if (sr != null) {
- sr.unregister();
- }
- Resource prompt =
resolver.getResource(change.getPath());
- if (prompt != null) {
- registerPrompt(ctx, promptName,
prompt);
- } else {
- logger.warn(
- "Prompt resource at {} not
found for change type {}, unable to register prompt.",
- change.getPath(),
- change.getType());
- }
- }
- }
- } catch (LoginException e) {
- logger.error("Error processing resource change",
e);
- }
- }
- },
- new Hashtable<>(Map.of(
- ResourceChangeListener.PATHS, PROMPT_LIBS_DIR,
ResourceChangeListener.CHANGES, new String[] {
- ResourceChangeListener.CHANGE_ADDED,
- ResourceChangeListener.CHANGE_CHANGED,
- ResourceChangeListener.CHANGE_REMOVED
- })));
-
- // TODO - use service user
- try (ResourceResolver resolver =
rrf.getAdministrativeResourceResolver(null)) {
-
- Iterator<Resource> prompts = resolver.findResources(
- "/jcr:root" + PROMPT_LIBS_DIR +
"//element(*,nt:file)[jcr:like(fn:name(), '%.md')]", "xpath");
- while (prompts.hasNext()) {
- Resource prompt = prompts.next();
- String promptName = getPromptName(prompt.getPath());
-
- registerPrompt(ctx, promptName, prompt);
- }
- }
- }
-
- private void registerPrompt(BundleContext ctx, String promptName, Resource
promptResource) {
-
- try {
- DiscoveredPrompt prompt =
promptBuilder.buildPrompt(promptResource, promptName);
-
- var sr = ctx.registerService(
- DiscoveredPrompt.class,
- prompt,
- new Hashtable<>(Map.of(DiscoveredPrompt.SERVICE_PROP_NAME,
promptName)));
-
- registrations.put(promptName, sr);
- } catch (IOException e) {
- logger.warn("Error registering prompt {} at path {}", promptName,
promptResource.getPath(), e);
- }
- }
-
- private String getPromptName(String path) {
-
- // remove prefix
- String promptName = path.substring(PROMPT_LIBS_DIR.length() + 1); //
account for trailing slash
-
- // remove optional /jcr:content node name
- if (promptName.endsWith("/jcr:content")) {
- promptName = promptName.substring(0, promptName.length() -
"/jcr:content".length());
- }
-
- // remove .md extension
- return promptName.substring(0, promptName.length() - ".md".length());
- }
-}
diff --git
a/mcp-server/src/main/java/org/apache/sling/mcp/server/spi/McpServerContribution.java
b/mcp-server/src/main/java/org/apache/sling/mcp/server/spi/McpServerContribution.java
deleted file mode 100644
index 70ada37f..00000000
---
a/mcp-server/src/main/java/org/apache/sling/mcp/server/spi/McpServerContribution.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sling.mcp.server.spi;
-
-import java.util.List;
-
-import
io.modelcontextprotocol.server.McpStatelessServerFeatures.SyncCompletionSpecification;
-import
io.modelcontextprotocol.server.McpStatelessServerFeatures.SyncPromptSpecification;
-import
io.modelcontextprotocol.server.McpStatelessServerFeatures.SyncResourceSpecification;
-import
io.modelcontextprotocol.server.McpStatelessServerFeatures.SyncResourceTemplateSpecification;
-import
io.modelcontextprotocol.server.McpStatelessServerFeatures.SyncToolSpecification;
-
-// Temporary abstraction to make it easier to contribute various MCP server
features
-//
-// The major problem with this approach is that all contributions are loaded
once the MCPServlet
-// is activated and therefore it does not take into account
added/changed/removed contributions
-//
-// Expect this abstraction to change
-/**
- * Provisional API for registering MCP server contributions
- *
- * <p>This abstraction is needed because the contributions themselves are Java
records and cannot
- * be registered as OSGi services directly.</p>
- *
- * <p><strong>Note:</strong> This API can change in incompatible ways while
the bundle version is < 1.0 . The exported package
- * version will remain 1.0.0 and will be changed to 1.1.0 once the bundle
version becomes 1.0 .</p>
- */
-public interface McpServerContribution {
-
- default List<SyncToolSpecification> getSyncToolSpecification() {
- return List.of();
- }
-
- default List<SyncResourceSpecification> getSyncResourceSpecification() {
- return List.of();
- }
-
- default List<SyncResourceTemplateSpecification>
getSyncResourceTemplateSpecification() {
- return List.of();
- }
-
- default List<SyncPromptSpecification> getSyncPromptSpecification() {
- return List.of();
- }
-
- default List<SyncCompletionSpecification> getSyncCompletionSpecification()
{
- return List.of();
- }
-}
diff --git
a/mcp-server/src/main/java/org/apache/sling/mcp/server/spi/package-info.java
b/mcp-server/src/main/java/org/apache/sling/mcp/server/spi/package-info.java
deleted file mode 100644
index aec19a47..00000000
--- a/mcp-server/src/main/java/org/apache/sling/mcp/server/spi/package-info.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
[email protected]("1.0.0")
-package org.apache.sling.mcp.server.spi;
diff --git
a/mcp-server/src/main/resources/SLING-INF/libs/sling/mcp/prompts/new-sling-servlet.md
b/mcp-server/src/main/resources/SLING-INF/libs/sling/mcp/prompts/new-sling-servlet.md
deleted file mode 100644
index c92cb837..00000000
---
a/mcp-server/src/main/resources/SLING-INF/libs/sling/mcp/prompts/new-sling-servlet.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-title: "Create new Sling Servlet"
-description: "Creates a new Sling Servlet in the current project using
annotations"
-argument.resource-type:
- - title: Resource Type
- - required: true
- - description: The Sling resource type to bind this servlet to
----
-
-# Create a new Sling Servlet
-
- Create a new Sling Servlet for resource type: `{resource-type}`
-
- Use the Sling-specific OSGi declarative services annotations -
`@SlingServletResourceTypes` and `@Component` .
- Configure by default with the GET method and the json extension.
- Provide a basic implementation of the doGet method that returns a JSON
response with a message 'Hello from Sling Servlet at resource type
{resource-type}'.
-
\ No newline at end of file
diff --git
a/mcp-server/src/main/resources/SLING-INF/libs/sling/mcp/prompts/troubleshoot.md
b/mcp-server/src/main/resources/SLING-INF/libs/sling/mcp/prompts/troubleshoot.md
deleted file mode 100644
index d5e95874..00000000
---
a/mcp-server/src/main/resources/SLING-INF/libs/sling/mcp/prompts/troubleshoot.md
+++ /dev/null
@@ -1,45 +0,0 @@
----
-title: "Troubleshooting guide"
-description: "Guide to troubleshoot common issues with Apache Sling
applications"
----
-# Troubleshooting Guide
-
-## Overview
-This guide helps you diagnose and resolve common issues with Apache Sling MCP
Server.
-
-## Common Issues
-
-### MCP Server Not Responding
-- Verify the MCP servlet is registered and active
-- Check OSGi component status
-- Review log files for errors
-
-### Bundle Issues
-- Check bundle state (ACTIVE, RESOLVED, INSTALLED)
-- Verify all dependencies are satisfied
-- Use the OSGi diagnostic tools
-
-### Performance Problems
-- Review recent requests and response times
-- Check system resources
-- Analyze thread dumps if available
-
-### Component Registration Issues
-- Verify component configurations
-- Check service dependencies
-- Review component lifecycle logs
-
-## Diagnostic Tools
-The MCP Server provides several diagnostic tools:
-- Bundle state inspection
-- Component resource analysis
-- Recent request tracking
-- Log file access
-- OSGi diagnostic reports
-
-## Getting Help
-If you continue to experience issues:
-1. Gather diagnostic information using the MCP tools
-2. Review the Apache Sling documentation
-3. Check the Apache Sling mailing lists
-4. File an issue in the Apache Sling JIRA
diff --git
a/mcp-server/src/test/java/org/apache/sling/mcp/server/impl/contribs/DiscoveredPromptBuilderTest.java
b/mcp-server/src/test/java/org/apache/sling/mcp/server/impl/contribs/DiscoveredPromptBuilderTest.java
deleted file mode 100644
index cd8d58eb..00000000
---
a/mcp-server/src/test/java/org/apache/sling/mcp/server/impl/contribs/DiscoveredPromptBuilderTest.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sling.mcp.server.impl.contribs;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
-import java.util.List;
-
-import io.modelcontextprotocol.spec.McpSchema.Prompt;
-import io.modelcontextprotocol.spec.McpSchema.PromptArgument;
-import org.apache.sling.api.resource.Resource;
-import org.apache.sling.api.resource.ResourceMetadata;
-import org.apache.sling.mcp.server.impl.DiscoveredPrompt;
-import org.junit.jupiter.api.Test;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-class DiscoveredPromptBuilderTest {
-
- @Test
- void basicMarkdownFile() throws IOException {
-
- String markdownFile = """
- # Basic Prompt
- """;
-
- Resource promptResource = mock(Resource.class);
- when(promptResource.getResourceMetadata()).thenReturn(new
ResourceMetadata());
- when(promptResource.adaptTo(InputStream.class))
- .thenReturn(new
ByteArrayInputStream(markdownFile.getBytes(StandardCharsets.UTF_8)));
-
- DiscoveredPromptBuilder builder = new DiscoveredPromptBuilder();
- DiscoveredPrompt prompt = builder.buildPrompt(promptResource,
"basic-prompt");
-
- assertThat(prompt)
- .as("prompt")
- .extracting(DiscoveredPrompt::asPrompt)
- .extracting(Prompt::name, Prompt::title, Prompt::description,
Prompt::arguments)
- .containsExactly("basic-prompt", null, null, List.of());
- }
-
- @Test
- void basicFrontMatter() throws IOException {
-
- String markdownFile = """
- ---
- title: Basic Prompt
- description: |
- A basic prompt for testing.
- Spans multiple lines.
- ---
- # Basic Prompt
- """;
-
- Resource promptResource = mock(Resource.class);
- when(promptResource.getResourceMetadata()).thenReturn(new
ResourceMetadata());
- when(promptResource.adaptTo(InputStream.class))
- .thenReturn(new
ByteArrayInputStream(markdownFile.getBytes(StandardCharsets.UTF_8)));
-
- DiscoveredPromptBuilder builder = new DiscoveredPromptBuilder();
- DiscoveredPrompt prompt = builder.buildPrompt(promptResource,
"prompt-with-front-matter");
-
- assertThat(prompt)
- .as("prompt")
- .extracting(DiscoveredPrompt::asPrompt)
- .extracting(Prompt::name, Prompt::title, Prompt::description,
Prompt::arguments)
- .containsExactly(
- "prompt-with-front-matter",
- "Basic Prompt",
- "A basic prompt for testing.\nSpans multiple lines.",
- List.of());
- }
-
- @Test
- void arguments() throws IOException {
-
- String markdownFile = """
- ---
- title: Basic Prompt
- argument.first:
- - title: First Argument
- - description: This is the first argument
- - required: true
- argument.second:
- - title: Second Argument
- ---
- # Basic Prompt
- """;
-
- Resource promptResource = mock(Resource.class);
- when(promptResource.getResourceMetadata()).thenReturn(new
ResourceMetadata());
- when(promptResource.adaptTo(InputStream.class))
- .thenReturn(new
ByteArrayInputStream(markdownFile.getBytes(StandardCharsets.UTF_8)));
-
- DiscoveredPromptBuilder builder = new DiscoveredPromptBuilder();
- DiscoveredPrompt prompt = builder.buildPrompt(promptResource,
"prompt-with-arguments");
- assertThat(prompt)
- .as("prompt")
- .extracting(DiscoveredPrompt::asPrompt)
- .extracting(Prompt::name, Prompt::title, Prompt::description,
Prompt::arguments)
- .containsExactly(
- "prompt-with-arguments",
- "Basic Prompt",
- null,
- List.of(
- new PromptArgument("first", "First Argument",
"This is the first argument", true),
- new PromptArgument("second", "Second
Argument", null, false)));
- }
-}