diff --git a/README.md b/README.md index 9ebb37c..aa6519c 100644 --- a/README.md +++ b/README.md @@ -895,6 +895,63 @@ public List smartComplete( This feature enables context-aware MCP operations where the behavior can be customized based on client-provided metadata such as user identity, preferences, session information, or any other contextual data. +#### metaProvider (_meta) Support + +The `@McpTool`, `@McpPrompt`, and `@McpResource` annotations support a `metaProvider` attribute that allows attaching arbitrary `_meta` data to MCP tool, prompt, and resource declarations. This metadata is propagated to both the declarations and to resource content in `ReadResourceResult`. + +To use this feature, implement the `MetaProvider` interface and reference the class in the annotation: + +```java +class MyMetaProvider implements MetaProvider { + @Override + public Map getMeta() { + return Map.of( + "openai/widgetPrefersBorder", true, + "openai/widgetDomain", "https://chatgpt.com" + ); + } +} +``` + +**Tool with _meta:** +```java +@McpTool(name = "my-tool", + description = "A tool with metadata", + metaProvider = MyMetaProvider.class) +public String myTool(@McpToolParam(description = "Input", required = true) String input) { + return "Processed: " + input; +} +``` + +**Prompt with _meta:** +```java +@McpPrompt(name = "my-prompt", + description = "A prompt with metadata", + metaProvider = MyMetaProvider.class) +public GetPromptResult myPrompt( + @McpArg(name = "topic", required = true) String topic) { + return new GetPromptResult("My Prompt", + List.of(new PromptMessage(Role.ASSISTANT, new TextContent("About: " + topic)))); +} +``` + +**Resource with _meta:** +```java +@McpResource(uri = "data://{id}", + name = "My Resource", + description = "A resource with metadata", + metaProvider = MyMetaProvider.class) +public String getData(String id) { + return "Data for: " + id; +} +``` + +**MetaProvider behavior:** +- **Default**: `DefaultMetaProvider.class` — returns `null`, meaning no `_meta` is appended to declarations +- **Custom**: Implement `MetaProvider` and return a `Map` with the desired key-value pairs +- The provider must have a public no-arg constructor (it is instantiated via reflection) +- Metadata is propagated to both the MCP declaration and to resource content in `ReadResourceResult` + #### McpRequestContext Support The library provides unified request context interfaces (`McpSyncRequestContext` and `McpAsyncRequestContext`) that offer a higher-level abstraction over the underlying MCP infrastructure. These context objects provide convenient access to: @@ -2275,6 +2332,7 @@ Override `AbstractMcpToolProvider#doGetToolCallException()` to customize the exc - **Sampling support** - Handle sampling requests from MCP servers - **Progress notification support** - Handle progress notifications for long-running operations - **Tool list changed support** - Handle tool list change notifications from MCP servers when tools are dynamically added, removed, or modified +- **_meta support via metaProvider** - Attach arbitrary `_meta` data to tool, prompt, and resource declarations using a pluggable `MetaProvider` interface on `@McpTool`, `@McpPrompt`, and `@McpResource` ## Requirements diff --git a/mcp-annotations/src/main/java/org/springaicommunity/mcp/MetaUtils.java b/mcp-annotations/src/main/java/org/springaicommunity/mcp/MetaUtils.java index 93f6640..1fa86e9 100644 --- a/mcp-annotations/src/main/java/org/springaicommunity/mcp/MetaUtils.java +++ b/mcp-annotations/src/main/java/org/springaicommunity/mcp/MetaUtils.java @@ -21,6 +21,9 @@ * {@link IllegalArgumentException IllegalArgumentExceptions}. This class is stateless and * not intended to be instantiated. *

+ * + * @author Vadzim Shurmialiou + * @author Craig Walls */ public final class MetaUtils { diff --git a/mcp-annotations/src/main/java/org/springaicommunity/mcp/adapter/PromptAdapter.java b/mcp-annotations/src/main/java/org/springaicommunity/mcp/adapter/PromptAdapter.java index 8c870d8..8aaa641 100644 --- a/mcp-annotations/src/main/java/org/springaicommunity/mcp/adapter/PromptAdapter.java +++ b/mcp-annotations/src/main/java/org/springaicommunity/mcp/adapter/PromptAdapter.java @@ -19,6 +19,8 @@ * Utility class for adapting between McpPrompt annotations and McpSchema.Prompt objects. * * @author Christian Tzolov + * @author Vadzim Shurmialiou + * @author Craig Walls */ public class PromptAdapter { diff --git a/mcp-annotations/src/main/java/org/springaicommunity/mcp/adapter/ResourceAdapter.java b/mcp-annotations/src/main/java/org/springaicommunity/mcp/adapter/ResourceAdapter.java index 6de5cc3..b228f3e 100644 --- a/mcp-annotations/src/main/java/org/springaicommunity/mcp/adapter/ResourceAdapter.java +++ b/mcp-annotations/src/main/java/org/springaicommunity/mcp/adapter/ResourceAdapter.java @@ -4,17 +4,21 @@ package org.springaicommunity.mcp.adapter; import java.util.List; -import java.util.Map; import io.modelcontextprotocol.spec.McpSchema; -import io.modelcontextprotocol.util.Utils; import org.springaicommunity.mcp.MetaUtils; import org.springaicommunity.mcp.annotation.McpResource; -import org.springaicommunity.mcp.method.tool.utils.JsonParser; /** + * Utility class that converts {@link McpResource} annotations into MCP schema objects. + * Provides factory methods to build {@link McpSchema.Resource} and + * {@link McpSchema.ResourceTemplate} instances from annotation metadata, including URI, + * name, description, MIME type, annotations, and optional {@code _meta} fields. + * * @author Christian Tzolov * @author Alexandros Pappas + * @author Vadzim Shurmialiou + * @author Craig Walls */ public class ResourceAdapter { @@ -66,12 +70,4 @@ public static McpSchema.ResourceTemplate asResourceTemplate(McpResource mcpResou .build(); } - @SuppressWarnings("unchecked") - private static Map parseMeta(String metaJson) { - if (!Utils.hasText(metaJson)) { - return null; - } - return JsonParser.fromJson(metaJson, Map.class); - } - } diff --git a/mcp-annotations/src/main/java/org/springaicommunity/mcp/annotation/McpPrompt.java b/mcp-annotations/src/main/java/org/springaicommunity/mcp/annotation/McpPrompt.java index 65531c5..7a5c04e 100644 --- a/mcp-annotations/src/main/java/org/springaicommunity/mcp/annotation/McpPrompt.java +++ b/mcp-annotations/src/main/java/org/springaicommunity/mcp/annotation/McpPrompt.java @@ -17,6 +17,8 @@ * Marks a method as a MCP Prompt. * * @author Christian Tzolov + * @author Vadzim Shurmialiou + * @author Craig Walls */ @Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE }) @Retention(RetentionPolicy.RUNTIME) diff --git a/mcp-annotations/src/main/java/org/springaicommunity/mcp/annotation/McpResource.java b/mcp-annotations/src/main/java/org/springaicommunity/mcp/annotation/McpResource.java index 6770418..0ca56e2 100644 --- a/mcp-annotations/src/main/java/org/springaicommunity/mcp/annotation/McpResource.java +++ b/mcp-annotations/src/main/java/org/springaicommunity/mcp/annotation/McpResource.java @@ -19,6 +19,8 @@ * * @author Christian Tzolov * @author Alexandros Pappas + * @author Vadzim Shurmialiou + * @author Craig Walls */ @Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE }) @Retention(RetentionPolicy.RUNTIME) diff --git a/mcp-annotations/src/main/java/org/springaicommunity/mcp/annotation/McpTool.java b/mcp-annotations/src/main/java/org/springaicommunity/mcp/annotation/McpTool.java index 3b89b3e..7d1bdde 100644 --- a/mcp-annotations/src/main/java/org/springaicommunity/mcp/annotation/McpTool.java +++ b/mcp-annotations/src/main/java/org/springaicommunity/mcp/annotation/McpTool.java @@ -3,19 +3,20 @@ */ package org.springaicommunity.mcp.annotation; -import org.springaicommunity.mcp.context.DefaultMetaProvider; -import org.springaicommunity.mcp.context.MetaProvider; - import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import java.util.Map; + +import org.springaicommunity.mcp.context.DefaultMetaProvider; +import org.springaicommunity.mcp.context.MetaProvider; /** * @author Christian Tzolov * @author Alexandros Pappas + * @author Vadzim Shurmialiou + * @author Craig Walls */ @Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE }) @Retention(RetentionPolicy.RUNTIME) diff --git a/mcp-annotations/src/main/java/org/springaicommunity/mcp/context/DefaultMetaProvider.java b/mcp-annotations/src/main/java/org/springaicommunity/mcp/context/DefaultMetaProvider.java index 766a059..3876f97 100644 --- a/mcp-annotations/src/main/java/org/springaicommunity/mcp/context/DefaultMetaProvider.java +++ b/mcp-annotations/src/main/java/org/springaicommunity/mcp/context/DefaultMetaProvider.java @@ -15,6 +15,9 @@ * Use this when your tool, prompt, or resource does not need to expose any meta * information or you want to keep responses minimal by default. *

+ * + * @author Vadzim Shurmialiou + * @author Craig Walls */ public class DefaultMetaProvider implements MetaProvider { diff --git a/mcp-annotations/src/main/java/org/springaicommunity/mcp/context/MetaProvider.java b/mcp-annotations/src/main/java/org/springaicommunity/mcp/context/MetaProvider.java index 0d37863..4802ecd 100644 --- a/mcp-annotations/src/main/java/org/springaicommunity/mcp/context/MetaProvider.java +++ b/mcp-annotations/src/main/java/org/springaicommunity/mcp/context/MetaProvider.java @@ -5,6 +5,9 @@ /** * Common interface for classes that provide metadata for the "_meta" field. This metadata * is used in tool, prompt, and resource declarations. + * + * @author Vadzim Shurmialiou + * @author Craig Walls */ public interface MetaProvider { diff --git a/mcp-annotations/src/main/java/org/springaicommunity/mcp/method/resource/AbstractMcpResourceMethodCallback.java b/mcp-annotations/src/main/java/org/springaicommunity/mcp/method/resource/AbstractMcpResourceMethodCallback.java index 9d58c92..8855fcc 100644 --- a/mcp-annotations/src/main/java/org/springaicommunity/mcp/method/resource/AbstractMcpResourceMethodCallback.java +++ b/mcp-annotations/src/main/java/org/springaicommunity/mcp/method/resource/AbstractMcpResourceMethodCallback.java @@ -36,6 +36,8 @@ * * @author Christian Tzolov * @author Alexandros Pappas + * @author Vadzim Shurmialiou + * @author Craig Walls */ public abstract class AbstractMcpResourceMethodCallback { diff --git a/mcp-annotations/src/main/java/org/springaicommunity/mcp/method/resource/AsyncMcpResourceMethodCallback.java b/mcp-annotations/src/main/java/org/springaicommunity/mcp/method/resource/AsyncMcpResourceMethodCallback.java index 8741f4e..75a613b 100644 --- a/mcp-annotations/src/main/java/org/springaicommunity/mcp/method/resource/AsyncMcpResourceMethodCallback.java +++ b/mcp-annotations/src/main/java/org/springaicommunity/mcp/method/resource/AsyncMcpResourceMethodCallback.java @@ -31,6 +31,8 @@ * * @author Christian Tzolov * @author Alexandros Pappas + * @author Vadzim Shurmialiou + * @author Craig Walls */ public final class AsyncMcpResourceMethodCallback extends AbstractMcpResourceMethodCallback implements BiFunction> { diff --git a/mcp-annotations/src/main/java/org/springaicommunity/mcp/method/resource/AsyncStatelessMcpResourceMethodCallback.java b/mcp-annotations/src/main/java/org/springaicommunity/mcp/method/resource/AsyncStatelessMcpResourceMethodCallback.java index 9bc8984..223a93c 100644 --- a/mcp-annotations/src/main/java/org/springaicommunity/mcp/method/resource/AsyncStatelessMcpResourceMethodCallback.java +++ b/mcp-annotations/src/main/java/org/springaicommunity/mcp/method/resource/AsyncStatelessMcpResourceMethodCallback.java @@ -31,6 +31,8 @@ * * @author Christian Tzolov * @author Alexandros Pappas + * @author Vadzim Shurmialiou + * @author Craig Walls */ public final class AsyncStatelessMcpResourceMethodCallback extends AbstractMcpResourceMethodCallback implements BiFunction> { diff --git a/mcp-annotations/src/main/java/org/springaicommunity/mcp/method/resource/DefaultMcpReadResourceResultConverter.java b/mcp-annotations/src/main/java/org/springaicommunity/mcp/method/resource/DefaultMcpReadResourceResultConverter.java index 301b278..539c01b 100644 --- a/mcp-annotations/src/main/java/org/springaicommunity/mcp/method/resource/DefaultMcpReadResourceResultConverter.java +++ b/mcp-annotations/src/main/java/org/springaicommunity/mcp/method/resource/DefaultMcpReadResourceResultConverter.java @@ -23,6 +23,8 @@ * * @author Christian Tzolov * @author Alexandros Pappas + * @author Vadzim Shurmialiou + * @author Craig Walls */ public class DefaultMcpReadResourceResultConverter implements McpReadResourceResultConverter { diff --git a/mcp-annotations/src/main/java/org/springaicommunity/mcp/method/resource/McpReadResourceResultConverter.java b/mcp-annotations/src/main/java/org/springaicommunity/mcp/method/resource/McpReadResourceResultConverter.java index 4439737..689802e 100644 --- a/mcp-annotations/src/main/java/org/springaicommunity/mcp/method/resource/McpReadResourceResultConverter.java +++ b/mcp-annotations/src/main/java/org/springaicommunity/mcp/method/resource/McpReadResourceResultConverter.java @@ -18,6 +18,8 @@ * * @author Christian Tzolov * @author Alexandros Pappas + * @author Vadzim Shurmialiou + * @author Craig Walls */ public interface McpReadResourceResultConverter { diff --git a/mcp-annotations/src/main/java/org/springaicommunity/mcp/method/resource/SyncMcpResourceMethodCallback.java b/mcp-annotations/src/main/java/org/springaicommunity/mcp/method/resource/SyncMcpResourceMethodCallback.java index 98bfb30..c91d1fe 100644 --- a/mcp-annotations/src/main/java/org/springaicommunity/mcp/method/resource/SyncMcpResourceMethodCallback.java +++ b/mcp-annotations/src/main/java/org/springaicommunity/mcp/method/resource/SyncMcpResourceMethodCallback.java @@ -29,6 +29,8 @@ * * @author Christian Tzolov * @author Alexandros Pappas + * @author Vadzim Shurmialiou + * @author Craig Walls */ public final class SyncMcpResourceMethodCallback extends AbstractMcpResourceMethodCallback implements BiFunction { diff --git a/mcp-annotations/src/main/java/org/springaicommunity/mcp/method/resource/SyncStatelessMcpResourceMethodCallback.java b/mcp-annotations/src/main/java/org/springaicommunity/mcp/method/resource/SyncStatelessMcpResourceMethodCallback.java index 551dd38..2e7eb30 100644 --- a/mcp-annotations/src/main/java/org/springaicommunity/mcp/method/resource/SyncStatelessMcpResourceMethodCallback.java +++ b/mcp-annotations/src/main/java/org/springaicommunity/mcp/method/resource/SyncStatelessMcpResourceMethodCallback.java @@ -30,6 +30,8 @@ * * @author Christian Tzolov * @author Alexandros Pappas + * @author Vadzim Shurmialiou + * @author Craig Walls */ public final class SyncStatelessMcpResourceMethodCallback extends AbstractMcpResourceMethodCallback implements BiFunction { diff --git a/mcp-annotations/src/main/java/org/springaicommunity/mcp/provider/resource/AsyncMcpResourceProvider.java b/mcp-annotations/src/main/java/org/springaicommunity/mcp/provider/resource/AsyncMcpResourceProvider.java index a687d71..79e527d 100644 --- a/mcp-annotations/src/main/java/org/springaicommunity/mcp/provider/resource/AsyncMcpResourceProvider.java +++ b/mcp-annotations/src/main/java/org/springaicommunity/mcp/provider/resource/AsyncMcpResourceProvider.java @@ -49,6 +49,8 @@ * * @author Christian Tzolov * @author Alexandros Pappas + * @author Vadzim Shurmialiou + * @author Craig Walls */ public class AsyncMcpResourceProvider { diff --git a/mcp-annotations/src/main/java/org/springaicommunity/mcp/provider/resource/AsyncStatelessMcpResourceProvider.java b/mcp-annotations/src/main/java/org/springaicommunity/mcp/provider/resource/AsyncStatelessMcpResourceProvider.java index 8af5f93..c4f1a11 100644 --- a/mcp-annotations/src/main/java/org/springaicommunity/mcp/provider/resource/AsyncStatelessMcpResourceProvider.java +++ b/mcp-annotations/src/main/java/org/springaicommunity/mcp/provider/resource/AsyncStatelessMcpResourceProvider.java @@ -49,6 +49,8 @@ * * @author Christian Tzolov * @author Alexandros Pappas + * @author Vadzim Shurmialiou + * @author Craig Walls */ public class AsyncStatelessMcpResourceProvider { diff --git a/mcp-annotations/src/main/java/org/springaicommunity/mcp/provider/resource/SyncMcpResourceProvider.java b/mcp-annotations/src/main/java/org/springaicommunity/mcp/provider/resource/SyncMcpResourceProvider.java index f31388b..8fae24f 100644 --- a/mcp-annotations/src/main/java/org/springaicommunity/mcp/provider/resource/SyncMcpResourceProvider.java +++ b/mcp-annotations/src/main/java/org/springaicommunity/mcp/provider/resource/SyncMcpResourceProvider.java @@ -36,6 +36,8 @@ /** * @author Christian Tzolov * @author Alexandros Pappas + * @author Vadzim Shurmialiou + * @author Craig Walls */ public class SyncMcpResourceProvider { diff --git a/mcp-annotations/src/main/java/org/springaicommunity/mcp/provider/resource/SyncStatelessMcpResourceProvider.java b/mcp-annotations/src/main/java/org/springaicommunity/mcp/provider/resource/SyncStatelessMcpResourceProvider.java index dcbfea4..713d855 100644 --- a/mcp-annotations/src/main/java/org/springaicommunity/mcp/provider/resource/SyncStatelessMcpResourceProvider.java +++ b/mcp-annotations/src/main/java/org/springaicommunity/mcp/provider/resource/SyncStatelessMcpResourceProvider.java @@ -48,6 +48,8 @@ * * @author Christian Tzolov * @author Alexandros Pappas + * @author Vadzim Shurmialiou + * @author Craig Walls */ public class SyncStatelessMcpResourceProvider { diff --git a/mcp-annotations/src/main/java/org/springaicommunity/mcp/provider/tool/AbstractMcpToolProvider.java b/mcp-annotations/src/main/java/org/springaicommunity/mcp/provider/tool/AbstractMcpToolProvider.java index 966b97d..a997c5f 100644 --- a/mcp-annotations/src/main/java/org/springaicommunity/mcp/provider/tool/AbstractMcpToolProvider.java +++ b/mcp-annotations/src/main/java/org/springaicommunity/mcp/provider/tool/AbstractMcpToolProvider.java @@ -14,6 +14,8 @@ /** * @author Christian Tzolov * @author Alexandros Pappas + * @author Vadzim Shurmialiou + * @author Craig Walls */ public abstract class AbstractMcpToolProvider { diff --git a/mcp-annotations/src/main/java/org/springaicommunity/mcp/provider/tool/AsyncMcpToolProvider.java b/mcp-annotations/src/main/java/org/springaicommunity/mcp/provider/tool/AsyncMcpToolProvider.java index 0029dab..aed93e5 100644 --- a/mcp-annotations/src/main/java/org/springaicommunity/mcp/provider/tool/AsyncMcpToolProvider.java +++ b/mcp-annotations/src/main/java/org/springaicommunity/mcp/provider/tool/AsyncMcpToolProvider.java @@ -43,6 +43,8 @@ /** * @author Christian Tzolov * @author Alexandros Pappas + * @author Vadzim Shurmialiou + * @author Craig Walls */ public class AsyncMcpToolProvider extends AbstractMcpToolProvider { diff --git a/mcp-annotations/src/main/java/org/springaicommunity/mcp/provider/tool/AsyncStatelessMcpToolProvider.java b/mcp-annotations/src/main/java/org/springaicommunity/mcp/provider/tool/AsyncStatelessMcpToolProvider.java index 676e1c9..96413dc 100644 --- a/mcp-annotations/src/main/java/org/springaicommunity/mcp/provider/tool/AsyncStatelessMcpToolProvider.java +++ b/mcp-annotations/src/main/java/org/springaicommunity/mcp/provider/tool/AsyncStatelessMcpToolProvider.java @@ -49,6 +49,8 @@ * * @author Christian Tzolov * @author Alexandros Pappas + * @author Vadzim Shurmialiou + * @author Craig Walls */ public class AsyncStatelessMcpToolProvider extends AbstractMcpToolProvider { diff --git a/mcp-annotations/src/main/java/org/springaicommunity/mcp/provider/tool/SyncMcpToolProvider.java b/mcp-annotations/src/main/java/org/springaicommunity/mcp/provider/tool/SyncMcpToolProvider.java index c9d49db..bb5688f 100644 --- a/mcp-annotations/src/main/java/org/springaicommunity/mcp/provider/tool/SyncMcpToolProvider.java +++ b/mcp-annotations/src/main/java/org/springaicommunity/mcp/provider/tool/SyncMcpToolProvider.java @@ -41,6 +41,8 @@ /** * @author Christian Tzolov * @author Alexandros Pappas + * @author Vadzim Shurmialiou + * @author Craig Walls */ public class SyncMcpToolProvider extends AbstractMcpToolProvider { diff --git a/mcp-annotations/src/main/java/org/springaicommunity/mcp/provider/tool/SyncStatelessMcpToolProvider.java b/mcp-annotations/src/main/java/org/springaicommunity/mcp/provider/tool/SyncStatelessMcpToolProvider.java index a130d1a..016804e 100644 --- a/mcp-annotations/src/main/java/org/springaicommunity/mcp/provider/tool/SyncStatelessMcpToolProvider.java +++ b/mcp-annotations/src/main/java/org/springaicommunity/mcp/provider/tool/SyncStatelessMcpToolProvider.java @@ -46,6 +46,8 @@ * * @author Christian Tzolov * @author Alexandros Pappas + * @author Vadzim Shurmialiou + * @author Craig Walls */ public class SyncStatelessMcpToolProvider extends AbstractMcpToolProvider {