diff --git a/mcp-core/src/main/java/io/modelcontextprotocol/server/McpAsyncServer.java b/mcp-core/src/main/java/io/modelcontextprotocol/server/McpAsyncServer.java index 23285d514..0a6b9e3fd 100644 --- a/mcp-core/src/main/java/io/modelcontextprotocol/server/McpAsyncServer.java +++ b/mcp-core/src/main/java/io/modelcontextprotocol/server/McpAsyncServer.java @@ -5,6 +5,7 @@ package io.modelcontextprotocol.server; import java.time.Duration; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -117,6 +118,10 @@ public class McpAsyncServer { private final ConcurrentHashMap completions = new ConcurrentHashMap<>(); + private final boolean callGetToolCallbacksEverytime; + + private final List toolCallbackProviders; + private List protocolVersions; private McpUriTemplateManagerFactory uriTemplateManagerFactory = new DefaultMcpUriTemplateManagerFactory(); @@ -143,6 +148,18 @@ public class McpAsyncServer { this.completions.putAll(features.completions()); this.uriTemplateManagerFactory = uriTemplateManagerFactory; this.jsonSchemaValidator = jsonSchemaValidator; + this.callGetToolCallbacksEverytime = features.callGetToolCallbacksEverytime(); + this.toolCallbackProviders = features.toolCallbackProviders(); + + // If flag is false, call getToolCallbacks during startup + if (!this.callGetToolCallbacksEverytime && !this.toolCallbackProviders.isEmpty()) { + for (ToolCallbackProvider provider : this.toolCallbackProviders) { + List callbackTools = provider.getToolCallbacks(); + if (callbackTools != null) { + this.tools.addAll(withStructuredOutputHandling(jsonSchemaValidator, callbackTools)); + } + } + } Map> requestHandlers = prepareRequestHandlers(); Map notificationHandlers = prepareNotificationHandlers(features); @@ -168,6 +185,18 @@ public class McpAsyncServer { this.completions.putAll(features.completions()); this.uriTemplateManagerFactory = uriTemplateManagerFactory; this.jsonSchemaValidator = jsonSchemaValidator; + this.callGetToolCallbacksEverytime = features.callGetToolCallbacksEverytime(); + this.toolCallbackProviders = features.toolCallbackProviders(); + + // If flag is false, call getToolCallbacks during startup + if (!this.callGetToolCallbacksEverytime && !this.toolCallbackProviders.isEmpty()) { + for (ToolCallbackProvider provider : this.toolCallbackProviders) { + List callbackTools = provider.getToolCallbacks(); + if (callbackTools != null) { + this.tools.addAll(withStructuredOutputHandling(jsonSchemaValidator, callbackTools)); + } + } + } Map> requestHandlers = prepareRequestHandlers(); Map notificationHandlers = prepareNotificationHandlers(features); @@ -513,8 +542,23 @@ public Mono notifyToolsListChanged() { private McpRequestHandler toolsListRequestHandler() { return (exchange, params) -> { - List tools = this.tools.stream().map(McpServerFeatures.AsyncToolSpecification::tool).toList(); - + List tools = new ArrayList<>(); + + // Add static tools + tools.addAll(this.tools.stream().map(McpServerFeatures.AsyncToolSpecification::tool).toList()); + + // If flag is true, call getToolCallbacks on every request + if (this.callGetToolCallbacksEverytime && !this.toolCallbackProviders.isEmpty()) { + for (ToolCallbackProvider provider : this.toolCallbackProviders) { + List callbackTools = provider.getToolCallbacks(); + if (callbackTools != null) { + tools.addAll(callbackTools.stream() + .map(McpServerFeatures.AsyncToolSpecification::tool) + .toList()); + } + } + } + return Mono.just(new McpSchema.ListToolsResult(tools, null)); }; } diff --git a/mcp-core/src/main/java/io/modelcontextprotocol/server/McpServer.java b/mcp-core/src/main/java/io/modelcontextprotocol/server/McpServer.java index fe3125271..0d9217533 100644 --- a/mcp-core/src/main/java/io/modelcontextprotocol/server/McpServer.java +++ b/mcp-core/src/main/java/io/modelcontextprotocol/server/McpServer.java @@ -237,7 +237,7 @@ private SingleSessionAsyncSpecification(McpServerTransportProvider transportProv public McpAsyncServer build() { var features = new McpServerFeatures.Async(this.serverInfo, this.serverCapabilities, this.tools, this.resources, this.resourceTemplates, this.prompts, this.completions, this.rootsChangeHandlers, - this.instructions); + this.instructions, this.callGetToolCallbacksEverytime, this.toolCallbackProviders); var jsonSchemaValidator = (this.jsonSchemaValidator != null) ? this.jsonSchemaValidator : JsonSchemaValidator.getDefault(); @@ -265,7 +265,7 @@ public StreamableServerAsyncSpecification(McpStreamableServerTransportProvider t public McpAsyncServer build() { var features = new McpServerFeatures.Async(this.serverInfo, this.serverCapabilities, this.tools, this.resources, this.resourceTemplates, this.prompts, this.completions, this.rootsChangeHandlers, - this.instructions); + this.instructions, this.callGetToolCallbacksEverytime, this.toolCallbackProviders); var jsonSchemaValidator = this.jsonSchemaValidator != null ? this.jsonSchemaValidator : JsonSchemaValidator.getDefault(); return new McpAsyncServer(transportProvider, jsonMapper == null ? McpJsonMapper.getDefault() : jsonMapper, @@ -331,6 +331,10 @@ abstract class AsyncSpecification> { final List, Mono>> rootsChangeHandlers = new ArrayList<>(); + boolean callGetToolCallbacksEverytime = false; + + final List toolCallbackProviders = new ArrayList<>(); + Duration requestTimeout = Duration.ofHours(10); // Default timeout public abstract McpAsyncServer build(); @@ -407,6 +411,42 @@ public AsyncSpecification instructions(String instructions) { return this; } + /** + * Sets whether to call getToolCallbacks on every tools/list request. + * When true, registered ToolCallbackProviders will be called on every tools/list request, + * allowing for dynamic tool generation. When false, getToolCallbacks is only called during startup. + * @param callGetToolCallbacksEverytime true to call on every request, false for startup only + * @return This builder instance for method chaining + */ + public AsyncSpecification callGetToolCallbacksEverytime(boolean callGetToolCallbacksEverytime) { + this.callGetToolCallbacksEverytime = callGetToolCallbacksEverytime; + return this; + } + + /** + * Registers a ToolCallbackProvider that can dynamically generate tool definitions. + * @param provider The tool callback provider. Must not be null. + * @return This builder instance for method chaining + * @throws IllegalArgumentException if provider is null + */ + public AsyncSpecification toolCallbackProvider(ToolCallbackProvider provider) { + Assert.notNull(provider, "Tool callback provider must not be null"); + this.toolCallbackProviders.add(provider); + return this; + } + + /** + * Registers multiple ToolCallbackProviders. + * @param providers The tool callback providers. Must not be null. + * @return This builder instance for method chaining + * @throws IllegalArgumentException if providers is null + */ + public AsyncSpecification toolCallbackProviders(List providers) { + Assert.notNull(providers, "Tool callback providers must not be null"); + this.toolCallbackProviders.addAll(providers); + return this; + } + /** * Sets the server capabilities that will be advertised to clients during * connection initialization. Capabilities define what features the server @@ -829,7 +869,8 @@ private SingleSessionSyncSpecification(McpServerTransportProvider transportProvi public McpSyncServer build() { McpServerFeatures.Sync syncFeatures = new McpServerFeatures.Sync(this.serverInfo, this.serverCapabilities, this.tools, this.resources, this.resourceTemplates, this.prompts, this.completions, - this.rootsChangeHandlers, this.instructions); + this.rootsChangeHandlers, this.instructions, this.callGetToolCallbacksEverytime, + this.toolCallbackProviders); McpServerFeatures.Async asyncFeatures = McpServerFeatures.Async.fromSync(syncFeatures, this.immediateExecution); @@ -860,7 +901,8 @@ private StreamableSyncSpecification(McpStreamableServerTransportProvider transpo public McpSyncServer build() { McpServerFeatures.Sync syncFeatures = new McpServerFeatures.Sync(this.serverInfo, this.serverCapabilities, this.tools, this.resources, this.resourceTemplates, this.prompts, this.completions, - this.rootsChangeHandlers, this.instructions); + this.rootsChangeHandlers, this.instructions, this.callGetToolCallbacksEverytime, + this.toolCallbackProviders); McpServerFeatures.Async asyncFeatures = McpServerFeatures.Async.fromSync(syncFeatures, this.immediateExecution); var jsonSchemaValidator = this.jsonSchemaValidator != null ? this.jsonSchemaValidator @@ -930,6 +972,10 @@ abstract class SyncSpecification> { final List>> rootsChangeHandlers = new ArrayList<>(); + boolean callGetToolCallbacksEverytime = false; + + final List toolCallbackProviders = new ArrayList<>(); + Duration requestTimeout = Duration.ofSeconds(10); // Default timeout boolean immediateExecution = false; @@ -1008,6 +1054,42 @@ public SyncSpecification instructions(String instructions) { return this; } + /** + * Sets whether to call getToolCallbacks on every tools/list request. + * When true, registered ToolCallbackProviders will be called on every tools/list request, + * allowing for dynamic tool generation. When false, getToolCallbacks is only called during startup. + * @param callGetToolCallbacksEverytime true to call on every request, false for startup only + * @return This builder instance for method chaining + */ + public SyncSpecification callGetToolCallbacksEverytime(boolean callGetToolCallbacksEverytime) { + this.callGetToolCallbacksEverytime = callGetToolCallbacksEverytime; + return this; + } + + /** + * Registers a ToolCallbackProvider that can dynamically generate tool definitions. + * @param provider The tool callback provider. Must not be null. + * @return This builder instance for method chaining + * @throws IllegalArgumentException if provider is null + */ + public SyncSpecification toolCallbackProvider(ToolCallbackProvider provider) { + Assert.notNull(provider, "Tool callback provider must not be null"); + this.toolCallbackProviders.add(provider); + return this; + } + + /** + * Registers multiple ToolCallbackProviders. + * @param providers The tool callback providers. Must not be null. + * @return This builder instance for method chaining + * @throws IllegalArgumentException if providers is null + */ + public SyncSpecification toolCallbackProviders(List providers) { + Assert.notNull(providers, "Tool callback providers must not be null"); + this.toolCallbackProviders.addAll(providers); + return this; + } + /** * Sets the server capabilities that will be advertised to clients during * connection initialization. Capabilities define what features the server @@ -1472,6 +1554,10 @@ class StatelessAsyncSpecification { final Map completions = new HashMap<>(); + boolean callGetToolCallbacksEverytime = false; + + final List toolCallbackProviders = new ArrayList<>(); + Duration requestTimeout = Duration.ofSeconds(10); // Default timeout public StatelessAsyncSpecification(McpStatelessServerTransport transport) { @@ -1551,6 +1637,42 @@ public StatelessAsyncSpecification instructions(String instructions) { return this; } + /** + * Sets whether to call getToolCallbacks on every tools/list request. + * When true, registered ToolCallbackProviders will be called on every tools/list request, + * allowing for dynamic tool generation. When false, getToolCallbacks is only called during startup. + * @param callGetToolCallbacksEverytime true to call on every request, false for startup only + * @return This builder instance for method chaining + */ + public StatelessAsyncSpecification callGetToolCallbacksEverytime(boolean callGetToolCallbacksEverytime) { + this.callGetToolCallbacksEverytime = callGetToolCallbacksEverytime; + return this; + } + + /** + * Registers a ToolCallbackProvider that can dynamically generate tool definitions. + * @param provider The tool callback provider. Must not be null. + * @return This builder instance for method chaining + * @throws IllegalArgumentException if provider is null + */ + public StatelessAsyncSpecification toolCallbackProvider(ToolCallbackProvider provider) { + Assert.notNull(provider, "Tool callback provider must not be null"); + this.toolCallbackProviders.add(provider); + return this; + } + + /** + * Registers multiple ToolCallbackProviders. + * @param providers The tool callback providers. Must not be null. + * @return This builder instance for method chaining + * @throws IllegalArgumentException if providers is null + */ + public StatelessAsyncSpecification toolCallbackProviders(List providers) { + Assert.notNull(providers, "Tool callback providers must not be null"); + this.toolCallbackProviders.addAll(providers); + return this; + } + /** * Sets the server capabilities that will be advertised to clients during * connection initialization. Capabilities define what features the server @@ -1870,7 +1992,8 @@ public StatelessAsyncSpecification jsonSchemaValidator(JsonSchemaValidator jsonS public McpStatelessAsyncServer build() { var features = new McpStatelessServerFeatures.Async(this.serverInfo, this.serverCapabilities, this.tools, - this.resources, this.resourceTemplates, this.prompts, this.completions, this.instructions); + this.resources, this.resourceTemplates, this.prompts, this.completions, this.instructions, + this.callGetToolCallbacksEverytime, this.toolCallbackProviders); return new McpStatelessAsyncServer(transport, jsonMapper == null ? McpJsonMapper.getDefault() : jsonMapper, features, requestTimeout, uriTemplateManagerFactory, jsonSchemaValidator != null ? jsonSchemaValidator : JsonSchemaValidator.getDefault()); @@ -1934,6 +2057,10 @@ class StatelessSyncSpecification { final Map completions = new HashMap<>(); + boolean callGetToolCallbacksEverytime = false; + + final List toolCallbackProviders = new ArrayList<>(); + Duration requestTimeout = Duration.ofSeconds(10); // Default timeout public StatelessSyncSpecification(McpStatelessServerTransport transport) { @@ -2013,6 +2140,42 @@ public StatelessSyncSpecification instructions(String instructions) { return this; } + /** + * Sets whether to call getToolCallbacks on every tools/list request. + * When true, registered ToolCallbackProviders will be called on every tools/list request, + * allowing for dynamic tool generation. When false, getToolCallbacks is only called during startup. + * @param callGetToolCallbacksEverytime true to call on every request, false for startup only + * @return This builder instance for method chaining + */ + public StatelessSyncSpecification callGetToolCallbacksEverytime(boolean callGetToolCallbacksEverytime) { + this.callGetToolCallbacksEverytime = callGetToolCallbacksEverytime; + return this; + } + + /** + * Registers a ToolCallbackProvider that can dynamically generate tool definitions. + * @param provider The tool callback provider. Must not be null. + * @return This builder instance for method chaining + * @throws IllegalArgumentException if provider is null + */ + public StatelessSyncSpecification toolCallbackProvider(ToolCallbackProvider provider) { + Assert.notNull(provider, "Tool callback provider must not be null"); + this.toolCallbackProviders.add(provider); + return this; + } + + /** + * Registers multiple ToolCallbackProviders. + * @param providers The tool callback providers. Must not be null. + * @return This builder instance for method chaining + * @throws IllegalArgumentException if providers is null + */ + public StatelessSyncSpecification toolCallbackProviders(List providers) { + Assert.notNull(providers, "Tool callback providers must not be null"); + this.toolCallbackProviders.addAll(providers); + return this; + } + /** * Sets the server capabilities that will be advertised to clients during * connection initialization. Capabilities define what features the server @@ -2348,7 +2511,8 @@ public StatelessSyncSpecification immediateExecution(boolean immediateExecution) public McpStatelessSyncServer build() { var syncFeatures = new McpStatelessServerFeatures.Sync(this.serverInfo, this.serverCapabilities, this.tools, - this.resources, this.resourceTemplates, this.prompts, this.completions, this.instructions); + this.resources, this.resourceTemplates, this.prompts, this.completions, this.instructions, + this.callGetToolCallbacksEverytime, this.toolCallbackProviders); var asyncFeatures = McpStatelessServerFeatures.Async.fromSync(syncFeatures, this.immediateExecution); var asyncServer = new McpStatelessAsyncServer(transport, jsonMapper == null ? McpJsonMapper.getDefault() : jsonMapper, asyncFeatures, requestTimeout, diff --git a/mcp-core/src/main/java/io/modelcontextprotocol/server/McpServerFeatures.java b/mcp-core/src/main/java/io/modelcontextprotocol/server/McpServerFeatures.java index fe0608b1c..4e90cff14 100644 --- a/mcp-core/src/main/java/io/modelcontextprotocol/server/McpServerFeatures.java +++ b/mcp-core/src/main/java/io/modelcontextprotocol/server/McpServerFeatures.java @@ -45,7 +45,9 @@ record Async(McpSchema.Implementation serverInfo, McpSchema.ServerCapabilities s Map prompts, Map completions, List, Mono>> rootsChangeConsumers, - String instructions) { + String instructions, + boolean callGetToolCallbacksEverytime, + List toolCallbackProviders) { /** * Create an instance and validate the arguments. @@ -58,6 +60,8 @@ record Async(McpSchema.Implementation serverInfo, McpSchema.ServerCapabilities s * @param rootsChangeConsumers The list of consumers that will be notified when * the roots list changes * @param instructions The server instructions text + * @param callGetToolCallbacksEverytime If true, call getToolCallbacks on every tools/list request + * @param toolCallbackProviders The list of tool callback providers */ Async(McpSchema.Implementation serverInfo, McpSchema.ServerCapabilities serverCapabilities, List tools, Map resources, @@ -65,7 +69,9 @@ record Async(McpSchema.Implementation serverInfo, McpSchema.ServerCapabilities s Map prompts, Map completions, List, Mono>> rootsChangeConsumers, - String instructions) { + String instructions, + boolean callGetToolCallbacksEverytime, + List toolCallbackProviders) { Assert.notNull(serverInfo, "Server info must not be null"); @@ -89,6 +95,8 @@ record Async(McpSchema.Implementation serverInfo, McpSchema.ServerCapabilities s this.completions = (completions != null) ? completions : Map.of(); this.rootsChangeConsumers = (rootsChangeConsumers != null) ? rootsChangeConsumers : List.of(); this.instructions = instructions; + this.callGetToolCallbacksEverytime = callGetToolCallbacksEverytime; + this.toolCallbackProviders = (toolCallbackProviders != null) ? toolCallbackProviders : List.of(); } /** @@ -136,7 +144,8 @@ static Async fromSync(Sync syncSpec, boolean immediateExecution) { } return new Async(syncSpec.serverInfo(), syncSpec.serverCapabilities(), tools, resources, resourceTemplates, - prompts, completions, rootChangeConsumers, syncSpec.instructions()); + prompts, completions, rootChangeConsumers, syncSpec.instructions(), + syncSpec.callGetToolCallbacksEverytime(), syncSpec.toolCallbackProviders()); } } @@ -159,7 +168,9 @@ record Sync(McpSchema.Implementation serverInfo, McpSchema.ServerCapabilities se Map resourceTemplates, Map prompts, Map completions, - List>> rootsChangeConsumers, String instructions) { + List>> rootsChangeConsumers, String instructions, + boolean callGetToolCallbacksEverytime, + List toolCallbackProviders) { /** * Create an instance and validate the arguments. @@ -172,6 +183,8 @@ record Sync(McpSchema.Implementation serverInfo, McpSchema.ServerCapabilities se * @param rootsChangeConsumers The list of consumers that will be notified when * the roots list changes * @param instructions The server instructions text + * @param callGetToolCallbacksEverytime If true, call getToolCallbacks on every tools/list request + * @param toolCallbackProviders The list of tool callback providers */ Sync(McpSchema.Implementation serverInfo, McpSchema.ServerCapabilities serverCapabilities, List tools, @@ -180,7 +193,9 @@ record Sync(McpSchema.Implementation serverInfo, McpSchema.ServerCapabilities se Map prompts, Map completions, List>> rootsChangeConsumers, - String instructions) { + String instructions, + boolean callGetToolCallbacksEverytime, + List toolCallbackProviders) { Assert.notNull(serverInfo, "Server info must not be null"); @@ -204,6 +219,8 @@ record Sync(McpSchema.Implementation serverInfo, McpSchema.ServerCapabilities se this.completions = (completions != null) ? completions : new HashMap<>(); this.rootsChangeConsumers = (rootsChangeConsumers != null) ? rootsChangeConsumers : new ArrayList<>(); this.instructions = instructions; + this.callGetToolCallbacksEverytime = callGetToolCallbacksEverytime; + this.toolCallbackProviders = (toolCallbackProviders != null) ? toolCallbackProviders : new ArrayList<>(); } } diff --git a/mcp-core/src/main/java/io/modelcontextprotocol/server/McpStatelessAsyncServer.java b/mcp-core/src/main/java/io/modelcontextprotocol/server/McpStatelessAsyncServer.java index c7a1fd0d7..9ddb07f6c 100644 --- a/mcp-core/src/main/java/io/modelcontextprotocol/server/McpStatelessAsyncServer.java +++ b/mcp-core/src/main/java/io/modelcontextprotocol/server/McpStatelessAsyncServer.java @@ -71,6 +71,10 @@ public class McpStatelessAsyncServer { private final ConcurrentHashMap completions = new ConcurrentHashMap<>(); + private final boolean callGetToolCallbacksEverytime; + + private final List toolCallbackProviders; + private List protocolVersions; private McpUriTemplateManagerFactory uriTemplateManagerFactory = new DefaultMcpUriTemplateManagerFactory(); @@ -92,6 +96,19 @@ public class McpStatelessAsyncServer { this.completions.putAll(features.completions()); this.uriTemplateManagerFactory = uriTemplateManagerFactory; this.jsonSchemaValidator = jsonSchemaValidator; + this.callGetToolCallbacksEverytime = features.callGetToolCallbacksEverytime(); + this.toolCallbackProviders = features.toolCallbackProviders(); + + // If flag is false, call getToolCallbacks during startup + // Note: ToolCallbackProvider returns McpServerFeatures.AsyncToolSpecification which + // is not directly compatible with stateless server. For startup, we can't easily + // convert the handlers, so we skip adding them at startup for stateless servers. + // They will only be available when callGetToolCallbacksEverytime is true. + if (!this.callGetToolCallbacksEverytime && !this.toolCallbackProviders.isEmpty()) { + logger.warn("ToolCallbackProvider is registered but callGetToolCallbacksEverytime is false. " + + "For stateless servers, tools from ToolCallbackProvider are only available when " + + "callGetToolCallbacksEverytime is true."); + } Map> requestHandlers = new HashMap<>(); @@ -385,9 +402,28 @@ public Mono removeTool(String toolName) { private McpStatelessRequestHandler toolsListRequestHandler() { return (ctx, params) -> { - List tools = this.tools.stream() + List tools = new ArrayList<>(); + + // Add static tools + tools.addAll(this.tools.stream() .map(McpStatelessServerFeatures.AsyncToolSpecification::tool) - .toList(); + .toList()); + + // If flag is true, call getToolCallbacks on every request + if (this.callGetToolCallbacksEverytime && !this.toolCallbackProviders.isEmpty()) { + for (ToolCallbackProvider provider : this.toolCallbackProviders) { + List callbackTools = provider.getToolCallbacks(); + if (callbackTools != null) { + // Extract Tool definitions from callback tools for listing + // Note: The handlers from McpServerFeatures.AsyncToolSpecification are not + // directly compatible with stateless server handlers, so we only use the Tool definitions + for (McpServerFeatures.AsyncToolSpecification callbackTool : callbackTools) { + tools.add(callbackTool.tool()); + } + } + } + } + return Mono.just(new McpSchema.ListToolsResult(tools, null)); }; } diff --git a/mcp-core/src/main/java/io/modelcontextprotocol/server/McpStatelessServerFeatures.java b/mcp-core/src/main/java/io/modelcontextprotocol/server/McpStatelessServerFeatures.java index a15681ba5..2d4d521b2 100644 --- a/mcp-core/src/main/java/io/modelcontextprotocol/server/McpStatelessServerFeatures.java +++ b/mcp-core/src/main/java/io/modelcontextprotocol/server/McpStatelessServerFeatures.java @@ -44,7 +44,9 @@ record Async(McpSchema.Implementation serverInfo, McpSchema.ServerCapabilities s Map resourceTemplates, Map prompts, Map completions, - String instructions) { + String instructions, + boolean callGetToolCallbacksEverytime, + List toolCallbackProviders) { /** * Create an instance and validate the arguments. @@ -55,6 +57,8 @@ record Async(McpSchema.Implementation serverInfo, McpSchema.ServerCapabilities s * @param resourceTemplates The map of resource templates * @param prompts The map of prompt specifications * @param instructions The server instructions text + * @param callGetToolCallbacksEverytime If true, call getToolCallbacks on every tools/list request + * @param toolCallbackProviders The list of tool callback providers */ Async(McpSchema.Implementation serverInfo, McpSchema.ServerCapabilities serverCapabilities, List tools, @@ -62,7 +66,9 @@ record Async(McpSchema.Implementation serverInfo, McpSchema.ServerCapabilities s Map resourceTemplates, Map prompts, Map completions, - String instructions) { + String instructions, + boolean callGetToolCallbacksEverytime, + List toolCallbackProviders) { Assert.notNull(serverInfo, "Server info must not be null"); @@ -82,6 +88,8 @@ record Async(McpSchema.Implementation serverInfo, McpSchema.ServerCapabilities s this.prompts = (prompts != null) ? prompts : Map.of(); this.completions = (completions != null) ? completions : Map.of(); this.instructions = instructions; + this.callGetToolCallbacksEverytime = callGetToolCallbacksEverytime; + this.toolCallbackProviders = (toolCallbackProviders != null) ? toolCallbackProviders : List.of(); } /** @@ -121,7 +129,8 @@ static Async fromSync(Sync syncSpec, boolean immediateExecution) { }); return new Async(syncSpec.serverInfo(), syncSpec.serverCapabilities(), tools, resources, resourceTemplates, - prompts, completions, syncSpec.instructions()); + prompts, completions, syncSpec.instructions(), + syncSpec.callGetToolCallbacksEverytime(), syncSpec.toolCallbackProviders()); } } @@ -142,7 +151,9 @@ record Sync(McpSchema.Implementation serverInfo, McpSchema.ServerCapabilities se Map resourceTemplates, Map prompts, Map completions, - String instructions) { + String instructions, + boolean callGetToolCallbacksEverytime, + List toolCallbackProviders) { /** * Create an instance and validate the arguments. @@ -153,6 +164,8 @@ record Sync(McpSchema.Implementation serverInfo, McpSchema.ServerCapabilities se * @param resourceTemplates The map of resource templates * @param prompts The map of prompt specifications * @param instructions The server instructions text + * @param callGetToolCallbacksEverytime If true, call getToolCallbacks on every tools/list request + * @param toolCallbackProviders The list of tool callback providers */ Sync(McpSchema.Implementation serverInfo, McpSchema.ServerCapabilities serverCapabilities, List tools, @@ -160,7 +173,9 @@ record Sync(McpSchema.Implementation serverInfo, McpSchema.ServerCapabilities se Map resourceTemplates, Map prompts, Map completions, - String instructions) { + String instructions, + boolean callGetToolCallbacksEverytime, + List toolCallbackProviders) { Assert.notNull(serverInfo, "Server info must not be null"); @@ -183,6 +198,8 @@ record Sync(McpSchema.Implementation serverInfo, McpSchema.ServerCapabilities se this.prompts = (prompts != null) ? prompts : new HashMap<>(); this.completions = (completions != null) ? completions : new HashMap<>(); this.instructions = instructions; + this.callGetToolCallbacksEverytime = callGetToolCallbacksEverytime; + this.toolCallbackProviders = (toolCallbackProviders != null) ? toolCallbackProviders : new ArrayList<>(); } } diff --git a/mcp-core/src/main/java/io/modelcontextprotocol/server/ToolCallbackProvider.java b/mcp-core/src/main/java/io/modelcontextprotocol/server/ToolCallbackProvider.java new file mode 100644 index 000000000..62931f5dc --- /dev/null +++ b/mcp-core/src/main/java/io/modelcontextprotocol/server/ToolCallbackProvider.java @@ -0,0 +1,29 @@ +/* + * Copyright 2024-2025 the original author or authors. + */ + +package io.modelcontextprotocol.server; + +import java.util.List; + +/** + * Provider interface for dynamically generating tool definitions. + * When {@code callGetToolCallbacksEverytime} is enabled, this provider's + * {@link #getToolCallbacks()} method will be called on every tools/list request, + * allowing for dynamic tool generation based on the current request context. + * + * @author Generated + */ +public interface ToolCallbackProvider { + + /** + * Returns a list of tool specifications that should be included in the tools/list response. + * This method is called either during server startup (when {@code callGetToolCallbacksEverytime} + * is false) or on every tools/list request (when {@code callGetToolCallbacksEverytime} is true). + * + * @return A list of tool specifications. Must not be null, but can be empty. + */ + List getToolCallbacks(); + +} +