refactor: deprecate tool spec's arguments-only handler in favor of CallToolRequest (#375)
Tool handlers now receive CallToolRequest instead of raw arguments to enable access to additional metadata parameters like progressToken - Deprecate handlers that take only Map<String, Object> arguments - Introduce new handlers that receive the full CallToolRequest object - Maintain backward compatibility with deprecated call handlers - Enhance API to provide access to complete tool request context beyond just arguments - Add builder pattern for AsyncToolSpecification and SyncToolSpecification - Add duplicate tool name validation during server building and runtime registration - Update all test files to use new callTool handlers and builder pattern - Add test coverage for new builder functionality and CallToolRequest handling Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
This commit is contained in:
parent
95df67ec05
commit
901175e14f
4 changed files with 1687 additions and 692 deletions
|
|
@ -268,7 +268,7 @@ public class McpAsyncServer {
|
|||
// ---------------------------------------
|
||||
|
||||
/**
|
||||
* Add a new tool specification at runtime.
|
||||
* Add a new tool call specification at runtime.
|
||||
* @param toolSpecification The tool specification to add
|
||||
* @return Mono that completes when clients have been notified of the change
|
||||
*/
|
||||
|
|
@ -279,7 +279,7 @@ public class McpAsyncServer {
|
|||
if (toolSpecification.tool() == null) {
|
||||
return Mono.error(new McpError("Tool must not be null"));
|
||||
}
|
||||
if (toolSpecification.call() == null) {
|
||||
if (toolSpecification.call() == null && toolSpecification.callHandler() == null) {
|
||||
return Mono.error(new McpError("Tool call handler must not be null"));
|
||||
}
|
||||
if (this.serverCapabilities.tools() == null) {
|
||||
|
|
@ -360,7 +360,7 @@ public class McpAsyncServer {
|
|||
return Mono.error(new McpError("Tool not found: " + callToolRequest.name()));
|
||||
}
|
||||
|
||||
return toolSpecification.map(tool -> tool.call().apply(exchange, callToolRequest.arguments()))
|
||||
return toolSpecification.map(tool -> tool.callHandler().apply(exchange, callToolRequest))
|
||||
.orElse(Mono.error(new McpError("Tool not found: " + callToolRequest.name())));
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,12 +82,16 @@ import reactor.core.publisher.Mono;
|
|||
* .capabilities(new ServerCapabilities(...))
|
||||
* // Register tools
|
||||
* .tools(
|
||||
* new McpServerFeatures.AsyncToolSpecification(calculatorTool,
|
||||
* (exchange, args) -> Mono.fromSupplier(() -> calculate(args))
|
||||
* .map(result -> new CallToolResult("Result: " + result))),
|
||||
* new McpServerFeatures.AsyncToolSpecification(weatherTool,
|
||||
* (exchange, args) -> Mono.fromSupplier(() -> getWeather(args))
|
||||
* .map(result -> new CallToolResult("Weather: " + result)))
|
||||
* McpServerFeatures.AsyncToolSpecification.builder()
|
||||
* .tool(calculatorTool)
|
||||
* .callTool((exchange, args) -> Mono.fromSupplier(() -> calculate(args.arguments()))
|
||||
* .map(result -> new CallToolResult("Result: " + result))))
|
||||
*. .build(),
|
||||
* McpServerFeatures.AsyncToolSpecification.builder()
|
||||
* .tool((weatherTool)
|
||||
* .callTool((exchange, args) -> Mono.fromSupplier(() -> getWeather(args.arguments()))
|
||||
* .map(result -> new CallToolResult("Weather: " + result))))
|
||||
* .build()
|
||||
* )
|
||||
* // Register resources
|
||||
* .resources(
|
||||
|
|
@ -321,17 +325,47 @@ public interface McpServer {
|
|||
* map of arguments passed to the tool.
|
||||
* @return This builder instance for method chaining
|
||||
* @throws IllegalArgumentException if tool or handler is null
|
||||
* @deprecated Use {@link #toolCall(McpSchema.Tool, BiFunction)} instead for tool
|
||||
* calls that require a request object.
|
||||
*/
|
||||
@Deprecated
|
||||
public AsyncSpecification tool(McpSchema.Tool tool,
|
||||
BiFunction<McpAsyncServerExchange, Map<String, Object>, Mono<CallToolResult>> handler) {
|
||||
Assert.notNull(tool, "Tool must not be null");
|
||||
Assert.notNull(handler, "Handler must not be null");
|
||||
assertNoDuplicateTool(tool.name());
|
||||
|
||||
this.tools.add(new McpServerFeatures.AsyncToolSpecification(tool, handler));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a single tool with its implementation handler to the server. This is a
|
||||
* convenience method for registering individual tools without creating a
|
||||
* {@link McpServerFeatures.AsyncToolSpecification} explicitly.
|
||||
* @param tool The tool definition including name, description, and schema. Must
|
||||
* not be null.
|
||||
* @param callHandler The function that implements the tool's logic. Must not be
|
||||
* null. The function's first argument is an {@link McpAsyncServerExchange} upon
|
||||
* which the server can interact with the connected client. The second argument is
|
||||
* the {@link McpSchema.CallToolRequest} object containing the tool call
|
||||
* @return This builder instance for method chaining
|
||||
* @throws IllegalArgumentException if tool or handler is null
|
||||
*/
|
||||
public AsyncSpecification toolCall(McpSchema.Tool tool,
|
||||
BiFunction<McpAsyncServerExchange, McpSchema.CallToolRequest, Mono<CallToolResult>> callHandler) {
|
||||
|
||||
Assert.notNull(tool, "Tool must not be null");
|
||||
Assert.notNull(callHandler, "Handler must not be null");
|
||||
assertNoDuplicateTool(tool.name());
|
||||
|
||||
this.tools
|
||||
.add(McpServerFeatures.AsyncToolSpecification.builder().tool(tool).callHandler(callHandler).build());
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds multiple tools with their handlers to the server using a List. This method
|
||||
* is useful when tools are dynamically generated or loaded from a configuration
|
||||
|
|
@ -344,7 +378,12 @@ public interface McpServer {
|
|||
*/
|
||||
public AsyncSpecification tools(List<McpServerFeatures.AsyncToolSpecification> toolSpecifications) {
|
||||
Assert.notNull(toolSpecifications, "Tool handlers list must not be null");
|
||||
this.tools.addAll(toolSpecifications);
|
||||
|
||||
for (var tool : toolSpecifications) {
|
||||
assertNoDuplicateTool(tool.tool().name());
|
||||
this.tools.add(tool);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -355,24 +394,31 @@ public interface McpServer {
|
|||
* <p>
|
||||
* Example usage: <pre>{@code
|
||||
* .tools(
|
||||
* new McpServerFeatures.AsyncToolSpecification(calculatorTool, calculatorHandler),
|
||||
* new McpServerFeatures.AsyncToolSpecification(weatherTool, weatherHandler),
|
||||
* new McpServerFeatures.AsyncToolSpecification(fileManagerTool, fileManagerHandler)
|
||||
* McpServerFeatures.AsyncToolSpecification.builder().tool(calculatorTool).callTool(calculatorHandler).build(),
|
||||
* McpServerFeatures.AsyncToolSpecification.builder().tool(weatherTool).callTool(weatherHandler).build(),
|
||||
* McpServerFeatures.AsyncToolSpecification.builder().tool(fileManagerTool).callTool(fileManagerHandler).build()
|
||||
* )
|
||||
* }</pre>
|
||||
* @param toolSpecifications The tool specifications to add. Must not be null.
|
||||
* @return This builder instance for method chaining
|
||||
* @throws IllegalArgumentException if toolSpecifications is null
|
||||
* @see #tools(List)
|
||||
*/
|
||||
public AsyncSpecification tools(McpServerFeatures.AsyncToolSpecification... toolSpecifications) {
|
||||
Assert.notNull(toolSpecifications, "Tool handlers list must not be null");
|
||||
|
||||
for (McpServerFeatures.AsyncToolSpecification tool : toolSpecifications) {
|
||||
assertNoDuplicateTool(tool.tool().name());
|
||||
this.tools.add(tool);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private void assertNoDuplicateTool(String toolName) {
|
||||
if (this.tools.stream().anyMatch(toolSpec -> toolSpec.tool().name().equals(toolName))) {
|
||||
throw new IllegalArgumentException("Tool with name '" + toolName + "' is already registered.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers multiple resources with their handlers using a Map. This method is
|
||||
* useful when resources are dynamically generated or loaded from a configuration
|
||||
|
|
@ -814,17 +860,45 @@ public interface McpServer {
|
|||
* list of arguments passed to the tool.
|
||||
* @return This builder instance for method chaining
|
||||
* @throws IllegalArgumentException if tool or handler is null
|
||||
* @deprecated Use {@link #toolCall(McpSchema.Tool, BiFunction)} instead for tool
|
||||
* calls that require a request object.
|
||||
*/
|
||||
@Deprecated
|
||||
public SyncSpecification tool(McpSchema.Tool tool,
|
||||
BiFunction<McpSyncServerExchange, Map<String, Object>, McpSchema.CallToolResult> handler) {
|
||||
Assert.notNull(tool, "Tool must not be null");
|
||||
Assert.notNull(handler, "Handler must not be null");
|
||||
assertNoDuplicateTool(tool.name());
|
||||
|
||||
this.tools.add(new McpServerFeatures.SyncToolSpecification(tool, handler));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a single tool with its implementation handler to the server. This is a
|
||||
* convenience method for registering individual tools without creating a
|
||||
* {@link McpServerFeatures.SyncToolSpecification} explicitly.
|
||||
* @param tool The tool definition including name, description, and schema. Must
|
||||
* not be null.
|
||||
* @param handler The function that implements the tool's logic. Must not be null.
|
||||
* The function's first argument is an {@link McpSyncServerExchange} upon which
|
||||
* the server can interact with the connected client. The second argument is the
|
||||
* list of arguments passed to the tool.
|
||||
* @return This builder instance for method chaining
|
||||
* @throws IllegalArgumentException if tool or handler is null
|
||||
*/
|
||||
public SyncSpecification toolCall(McpSchema.Tool tool,
|
||||
BiFunction<McpSyncServerExchange, McpSchema.CallToolRequest, McpSchema.CallToolResult> handler) {
|
||||
Assert.notNull(tool, "Tool must not be null");
|
||||
Assert.notNull(handler, "Handler must not be null");
|
||||
assertNoDuplicateTool(tool.name());
|
||||
|
||||
this.tools.add(new McpServerFeatures.SyncToolSpecification(tool, null, handler));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds multiple tools with their handlers to the server using a List. This method
|
||||
* is useful when tools are dynamically generated or loaded from a configuration
|
||||
|
|
@ -837,7 +911,13 @@ public interface McpServer {
|
|||
*/
|
||||
public SyncSpecification tools(List<McpServerFeatures.SyncToolSpecification> toolSpecifications) {
|
||||
Assert.notNull(toolSpecifications, "Tool handlers list must not be null");
|
||||
this.tools.addAll(toolSpecifications);
|
||||
|
||||
for (var tool : toolSpecifications) {
|
||||
String toolName = tool.tool().name();
|
||||
assertNoDuplicateTool(toolName); // Check against existing tools
|
||||
this.tools.add(tool);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -860,12 +940,20 @@ public interface McpServer {
|
|||
*/
|
||||
public SyncSpecification tools(McpServerFeatures.SyncToolSpecification... toolSpecifications) {
|
||||
Assert.notNull(toolSpecifications, "Tool handlers list must not be null");
|
||||
|
||||
for (McpServerFeatures.SyncToolSpecification tool : toolSpecifications) {
|
||||
assertNoDuplicateTool(tool.tool().name());
|
||||
this.tools.add(tool);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private void assertNoDuplicateTool(String toolName) {
|
||||
if (this.tools.stream().anyMatch(toolSpec -> toolSpec.tool().name().equals(toolName))) {
|
||||
throw new IllegalArgumentException("Tool with name '" + toolName + "' is already registered.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers multiple resources with their handlers using a Map. This method is
|
||||
* useful when resources are dynamically generated or loaded from a configuration
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import java.util.function.BiConsumer;
|
|||
import java.util.function.BiFunction;
|
||||
|
||||
import io.modelcontextprotocol.spec.McpSchema;
|
||||
import io.modelcontextprotocol.spec.McpSchema.CallToolRequest;
|
||||
import io.modelcontextprotocol.util.Assert;
|
||||
import io.modelcontextprotocol.util.Utils;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
|
@ -205,51 +206,110 @@ public class McpServerFeatures {
|
|||
/**
|
||||
* Specification of a tool with its asynchronous handler function. Tools are the
|
||||
* primary way for MCP servers to expose functionality to AI models. Each tool
|
||||
* represents a specific capability, such as:
|
||||
* <ul>
|
||||
* <li>Performing calculations
|
||||
* <li>Accessing external APIs
|
||||
* <li>Querying databases
|
||||
* <li>Manipulating files
|
||||
* <li>Executing system commands
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* Example tool specification: <pre>{@code
|
||||
* new McpServerFeatures.AsyncToolSpecification(
|
||||
* new Tool(
|
||||
* "calculator",
|
||||
* "Performs mathematical calculations",
|
||||
* new JsonSchemaObject()
|
||||
* .required("expression")
|
||||
* .property("expression", JsonSchemaType.STRING)
|
||||
* ),
|
||||
* (exchange, args) -> {
|
||||
* String expr = (String) args.get("expression");
|
||||
* return Mono.fromSupplier(() -> evaluate(expr))
|
||||
* .map(result -> new CallToolResult("Result: " + result));
|
||||
* }
|
||||
* )
|
||||
* }</pre>
|
||||
* represents a specific capability.
|
||||
*
|
||||
* @param tool The tool definition including name, description, and parameter schema
|
||||
* @param call The function that implements the tool's logic, receiving arguments and
|
||||
* returning results. The function's first argument is an
|
||||
* {@link McpAsyncServerExchange} upon which the server can interact with the
|
||||
* connected client. The second arguments is a map of tool arguments.
|
||||
* @param call Deprecated. Uset he {@link AsyncToolSpecification#callHandler} instead.
|
||||
* @param callHandler The function that implements the tool's logic, receiving a
|
||||
* {@link McpAsyncServerExchange} and a
|
||||
* {@link io.modelcontextprotocol.spec.McpSchema.CallToolRequest} and returning
|
||||
* results. The function's first argument is an {@link McpAsyncServerExchange} upon
|
||||
* which the server can interact with the connected client. The second arguments is a
|
||||
* map of tool arguments.
|
||||
*/
|
||||
public record AsyncToolSpecification(McpSchema.Tool tool,
|
||||
BiFunction<McpAsyncServerExchange, Map<String, Object>, Mono<McpSchema.CallToolResult>> call) {
|
||||
@Deprecated BiFunction<McpAsyncServerExchange, Map<String, Object>, Mono<McpSchema.CallToolResult>> call,
|
||||
BiFunction<McpAsyncServerExchange, McpSchema.CallToolRequest, Mono<McpSchema.CallToolResult>> callHandler) {
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link AsyncToolSpecification(McpSchema.Tool, null,
|
||||
* BiFunction)} instead.
|
||||
**/
|
||||
@Deprecated
|
||||
public AsyncToolSpecification(McpSchema.Tool tool,
|
||||
BiFunction<McpAsyncServerExchange, Map<String, Object>, Mono<McpSchema.CallToolResult>> call) {
|
||||
this(tool, call, (exchange, toolReq) -> call.apply(exchange, toolReq.arguments()));
|
||||
}
|
||||
|
||||
static AsyncToolSpecification fromSync(SyncToolSpecification syncToolSpec) {
|
||||
return fromSync(syncToolSpec, false);
|
||||
}
|
||||
|
||||
static AsyncToolSpecification fromSync(SyncToolSpecification syncToolSpec, boolean immediate) {
|
||||
|
||||
static AsyncToolSpecification fromSync(SyncToolSpecification tool, boolean immediate) {
|
||||
// FIXME: This is temporary, proper validation should be implemented
|
||||
if (tool == null) {
|
||||
if (syncToolSpec == null) {
|
||||
return null;
|
||||
}
|
||||
return new AsyncToolSpecification(tool.tool(), (exchange, map) -> {
|
||||
var toolResult = Mono.fromCallable(() -> tool.call().apply(new McpSyncServerExchange(exchange), map));
|
||||
|
||||
BiFunction<McpAsyncServerExchange, Map<String, Object>, Mono<McpSchema.CallToolResult>> deprecatedCall = (syncToolSpec
|
||||
.call() != null) ? (exchange, map) -> {
|
||||
var toolResult = Mono
|
||||
.fromCallable(() -> syncToolSpec.call().apply(new McpSyncServerExchange(exchange), map));
|
||||
return immediate ? toolResult : toolResult.subscribeOn(Schedulers.boundedElastic());
|
||||
} : null;
|
||||
|
||||
BiFunction<McpAsyncServerExchange, McpSchema.CallToolRequest, Mono<McpSchema.CallToolResult>> callHandler = (
|
||||
exchange, req) -> {
|
||||
var toolResult = Mono
|
||||
.fromCallable(() -> syncToolSpec.callHandler().apply(new McpSyncServerExchange(exchange), req));
|
||||
return immediate ? toolResult : toolResult.subscribeOn(Schedulers.boundedElastic());
|
||||
});
|
||||
};
|
||||
|
||||
return new AsyncToolSpecification(syncToolSpec.tool(), deprecatedCall, callHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder for creating AsyncToolSpecification instances.
|
||||
*/
|
||||
public static class Builder {
|
||||
|
||||
private McpSchema.Tool tool;
|
||||
|
||||
private BiFunction<McpAsyncServerExchange, McpSchema.CallToolRequest, Mono<McpSchema.CallToolResult>> callHandler;
|
||||
|
||||
/**
|
||||
* Sets the tool definition.
|
||||
* @param tool The tool definition including name, description, and parameter
|
||||
* schema
|
||||
* @return this builder instance
|
||||
*/
|
||||
public Builder tool(McpSchema.Tool tool) {
|
||||
this.tool = tool;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the call tool handler function.
|
||||
* @param callHandler The function that implements the tool's logic
|
||||
* @return this builder instance
|
||||
*/
|
||||
public Builder callHandler(
|
||||
BiFunction<McpAsyncServerExchange, McpSchema.CallToolRequest, Mono<McpSchema.CallToolResult>> callHandler) {
|
||||
this.callHandler = callHandler;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the AsyncToolSpecification instance.
|
||||
* @return a new AsyncToolSpecification instance
|
||||
* @throws IllegalArgumentException if required fields are not set
|
||||
*/
|
||||
public AsyncToolSpecification build() {
|
||||
Assert.notNull(tool, "Tool must not be null");
|
||||
Assert.notNull(callHandler, "Call handler function must not be null");
|
||||
|
||||
return new AsyncToolSpecification(tool, null, callHandler);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new builder instance.
|
||||
* @return a new Builder instance
|
||||
*/
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -265,13 +325,13 @@ public class McpServerFeatures {
|
|||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* Example resource specification: <pre>{@code
|
||||
* Example resource specification:
|
||||
*
|
||||
* <pre>{@code
|
||||
* new McpServerFeatures.AsyncResourceSpecification(
|
||||
* new Resource("docs", "Documentation files", "text/markdown"),
|
||||
* (exchange, request) ->
|
||||
* Mono.fromSupplier(() -> readFile(request.getPath()))
|
||||
* .map(ReadResourceResult::new)
|
||||
* )
|
||||
* new Resource("docs", "Documentation files", "text/markdown"),
|
||||
* (exchange, request) -> Mono.fromSupplier(() -> readFile(request.getPath()))
|
||||
* .map(ReadResourceResult::new))
|
||||
* }</pre>
|
||||
*
|
||||
* @param resource The resource definition including name, description, and MIME type
|
||||
|
|
@ -308,16 +368,16 @@ public class McpServerFeatures {
|
|||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* Example prompt specification: <pre>{@code
|
||||
* Example prompt specification:
|
||||
*
|
||||
* <pre>{@code
|
||||
* new McpServerFeatures.AsyncPromptSpecification(
|
||||
* new Prompt("analyze", "Code analysis template"),
|
||||
* (exchange, request) -> {
|
||||
* String code = request.getArguments().get("code");
|
||||
* return Mono.just(new GetPromptResult(
|
||||
* "Analyze this code:\n\n" + code + "\n\nProvide feedback on:"
|
||||
* ));
|
||||
* }
|
||||
* )
|
||||
* new Prompt("analyze", "Code analysis template"),
|
||||
* (exchange, request) -> {
|
||||
* String code = request.getArguments().get("code");
|
||||
* return Mono.just(new GetPromptResult(
|
||||
* "Analyze this code:\n\n" + code + "\n\nProvide feedback on:"));
|
||||
* })
|
||||
* }</pre>
|
||||
*
|
||||
* @param prompt The prompt definition including name and description
|
||||
|
|
@ -386,41 +446,99 @@ public class McpServerFeatures {
|
|||
|
||||
/**
|
||||
* Specification of a tool with its synchronous handler function. Tools are the
|
||||
* primary way for MCP servers to expose functionality to AI models. Each tool
|
||||
* represents a specific capability, such as:
|
||||
* <ul>
|
||||
* <li>Performing calculations
|
||||
* <li>Accessing external APIs
|
||||
* <li>Querying databases
|
||||
* <li>Manipulating files
|
||||
* <li>Executing system commands
|
||||
* </ul>
|
||||
* primary way for MCP servers to expose functionality to AI models.
|
||||
*
|
||||
* <p>
|
||||
* Example tool specification: <pre>{@code
|
||||
* new McpServerFeatures.SyncToolSpecification(
|
||||
* new Tool(
|
||||
* "calculator",
|
||||
* "Performs mathematical calculations",
|
||||
* new JsonSchemaObject()
|
||||
* .required("expression")
|
||||
* .property("expression", JsonSchemaType.STRING)
|
||||
* ),
|
||||
* (exchange, args) -> {
|
||||
* String expr = (String) args.get("expression");
|
||||
* return new CallToolResult("Result: " + evaluate(expr));
|
||||
* }
|
||||
* )
|
||||
* Example tool specification:
|
||||
*
|
||||
* <pre>{@code
|
||||
* McpServerFeatures.SyncToolSpecification.builder()
|
||||
* .tool(new Tool(
|
||||
* "calculator",
|
||||
* "Performs mathematical calculations",
|
||||
* new JsonSchemaObject()
|
||||
* .required("expression")
|
||||
* .property("expression", JsonSchemaType.STRING)))
|
||||
* .toolHandler((exchange, req) -> {
|
||||
* String expr = (String) req.arguments().get("expression");
|
||||
* return new CallToolResult("Result: " + evaluate(expr));
|
||||
* }))
|
||||
* .build();
|
||||
* }</pre>
|
||||
*
|
||||
* @param tool The tool definition including name, description, and parameter schema
|
||||
* @param call The function that implements the tool's logic, receiving arguments and
|
||||
* returning results. The function's first argument is an
|
||||
* @param call (Deprected) The function that implements the tool's logic, receiving
|
||||
* arguments and returning results. The function's first argument is an
|
||||
* {@link McpSyncServerExchange} upon which the server can interact with the connected
|
||||
* client. The second arguments is a map of arguments passed to the tool.
|
||||
* @param callHandler The function that implements the tool's logic, receiving a
|
||||
* {@link McpSyncServerExchange} and a
|
||||
* {@link io.modelcontextprotocol.spec.McpSchema.CallToolRequest} and returning
|
||||
* results. The function's first argument is an {@link McpSyncServerExchange} upon
|
||||
* which the server can interact with the client. The second arguments is a map of
|
||||
* arguments passed to the tool.
|
||||
*/
|
||||
public record SyncToolSpecification(McpSchema.Tool tool,
|
||||
BiFunction<McpSyncServerExchange, Map<String, Object>, McpSchema.CallToolResult> call) {
|
||||
@Deprecated BiFunction<McpSyncServerExchange, Map<String, Object>, McpSchema.CallToolResult> call,
|
||||
BiFunction<McpSyncServerExchange, CallToolRequest, McpSchema.CallToolResult> callHandler) {
|
||||
|
||||
@Deprecated
|
||||
public SyncToolSpecification(McpSchema.Tool tool,
|
||||
BiFunction<McpSyncServerExchange, Map<String, Object>, McpSchema.CallToolResult> call) {
|
||||
this(tool, call, (exchange, toolReq) -> call.apply(exchange, toolReq.arguments()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder for creating SyncToolSpecification instances.
|
||||
*/
|
||||
public static class Builder {
|
||||
|
||||
private McpSchema.Tool tool;
|
||||
|
||||
private BiFunction<McpSyncServerExchange, CallToolRequest, McpSchema.CallToolResult> callHandler;
|
||||
|
||||
/**
|
||||
* Sets the tool definition.
|
||||
* @param tool The tool definition including name, description, and parameter
|
||||
* schema
|
||||
* @return this builder instance
|
||||
*/
|
||||
public Builder tool(McpSchema.Tool tool) {
|
||||
this.tool = tool;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the call tool handler function.
|
||||
* @param callHandler The function that implements the tool's logic
|
||||
* @return this builder instance
|
||||
*/
|
||||
public Builder callHandler(
|
||||
BiFunction<McpSyncServerExchange, CallToolRequest, McpSchema.CallToolResult> callHandler) {
|
||||
this.callHandler = callHandler;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the SyncToolSpecification instance.
|
||||
* @return a new SyncToolSpecification instance
|
||||
* @throws IllegalArgumentException if required fields are not set
|
||||
*/
|
||||
public SyncToolSpecification build() {
|
||||
Assert.notNull(tool, "Tool must not be null");
|
||||
Assert.notNull(callHandler, "CallTool function must not be null");
|
||||
|
||||
return new SyncToolSpecification(tool, null, callHandler);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new builder instance.
|
||||
* @return a new Builder instance
|
||||
*/
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -435,14 +553,15 @@ public class McpServerFeatures {
|
|||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* Example resource specification: <pre>{@code
|
||||
* Example resource specification:
|
||||
*
|
||||
* <pre>{@code
|
||||
* new McpServerFeatures.SyncResourceSpecification(
|
||||
* new Resource("docs", "Documentation files", "text/markdown"),
|
||||
* (exchange, request) -> {
|
||||
* String content = readFile(request.getPath());
|
||||
* return new ReadResourceResult(content);
|
||||
* }
|
||||
* )
|
||||
* new Resource("docs", "Documentation files", "text/markdown"),
|
||||
* (exchange, request) -> {
|
||||
* String content = readFile(request.getPath());
|
||||
* return new ReadResourceResult(content);
|
||||
* })
|
||||
* }</pre>
|
||||
*
|
||||
* @param resource The resource definition including name, description, and MIME type
|
||||
|
|
@ -467,16 +586,16 @@ public class McpServerFeatures {
|
|||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* Example prompt specification: <pre>{@code
|
||||
* Example prompt specification:
|
||||
*
|
||||
* <pre>{@code
|
||||
* new McpServerFeatures.SyncPromptSpecification(
|
||||
* new Prompt("analyze", "Code analysis template"),
|
||||
* (exchange, request) -> {
|
||||
* String code = request.getArguments().get("code");
|
||||
* return new GetPromptResult(
|
||||
* "Analyze this code:\n\n" + code + "\n\nProvide feedback on:"
|
||||
* );
|
||||
* }
|
||||
* )
|
||||
* new Prompt("analyze", "Code analysis template"),
|
||||
* (exchange, request) -> {
|
||||
* String code = request.getArguments().get("code");
|
||||
* return new GetPromptResult(
|
||||
* "Analyze this code:\n\n" + code + "\n\nProvide feedback on:");
|
||||
* })
|
||||
* }</pre>
|
||||
*
|
||||
* @param prompt The prompt definition including name and description
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
package io.modelcontextprotocol.server;
|
||||
|
||||
import io.modelcontextprotocol.server.McpServerFeatures.AsyncToolSpecification;
|
||||
import io.modelcontextprotocol.spec.McpSchema;
|
||||
import io.modelcontextprotocol.spec.McpSchema.LoggingMessageNotification;
|
||||
import io.modelcontextprotocol.util.Assert;
|
||||
|
|
|
|||
Loading…
Reference in a new issue