docs Improve MCP readme
This commit is contained in:
parent
abd0facf4e
commit
347f86ff19
6 changed files with 270 additions and 203 deletions
336
mcp/README.md
336
mcp/README.md
|
|
@ -1,10 +1,6 @@
|
|||
# Model Context Protocol (MCP) Java SDK
|
||||
# Spring AI MCP SDK
|
||||
|
||||
A Java implementation of the [Model Context Protocol](https://modelcontextprotocol.org/docs/concepts/architecture) specification, providing both synchronous and asynchronous clients for MCP server interactions.
|
||||
|
||||
## Overview
|
||||
|
||||
This SDK implements the Model Context Protocol, enabling seamless integration with AI models and tools through a standardized interface. It supports both synchronous and asynchronous communication patterns, making it suitable for various use cases and integration scenarios.
|
||||
This SDK implements the Model Context Protocol, enabling seamless integration with language models and AI tools.
|
||||
|
||||
## Features
|
||||
|
||||
|
|
@ -46,11 +42,6 @@ The SDK follows a layered architecture with clear separation of concerns:
|
|||
- **Session Layer (McpSession)**: Manages communication patterns and state using DefaultMcpSession implementation.
|
||||
- **Client/Server Layer**: Both use McpSession for sync/async operations, with McpClient handling client-side protocol operations and McpServer managing server-side protocol operations.
|
||||
|
||||
Following class diagram illustrates the layered architecture of the MCP SDK, showing the relationships between core interfaces (McpTransport, McpSession), their implementations, and the client/server components. It highlights how the transport layer connects to sessions, which in turn support both synchronous and asynchronous client/server implementations.
|
||||
|
||||
<img src="../docs/spring-ai-mcp-uml-classdiagram.svg" width="600"/>
|
||||
|
||||
|
||||
### Key Interactions
|
||||
|
||||
- **Client/Server Initialization**: Transport setup, protocol compatibility check, capability negotiation, and implementation details exchange.
|
||||
|
|
@ -59,149 +50,183 @@ Following class diagram illustrates the layered architecture of the MCP SDK, sho
|
|||
- **Prompt System**: Discovery, parameter-based retrieval, change notifications, and content management.
|
||||
- **Tool Execution**: Discovery, parameter validation, timeout-aware execution, and result processing.
|
||||
|
||||
## Client Usage Examples
|
||||
|
||||
### [Reference Documentation](../docs/ref-index.md)
|
||||
Detailed reference documentation covering the Spring AI implementation of the Model Context Protocol (MCP) specification.
|
||||
|
||||
|
||||
## Quick Start
|
||||
|
||||
### McpClient
|
||||
|
||||
Factory for creating `sync` and `async` variants MCP clients. Uses McpSession for communication and handles client-side protocol operations.
|
||||
|
||||
#### Sync MCP Client
|
||||
### MCP Client (Sync API)
|
||||
|
||||
```java
|
||||
// Create and initialize sync client
|
||||
McpTransport mcpTransport = ...
|
||||
// Create a sync client with custom configuration
|
||||
McpSyncClient client = McpClient.using(transport)
|
||||
.requestTimeout(Duration.ofSeconds(10))
|
||||
.capabilities(ClientCapabilities.builder()
|
||||
.roots(true) // Enable roots capability
|
||||
.sampling() // Enable sampling capability
|
||||
.build())
|
||||
.sync();
|
||||
|
||||
try (McpSyncClient client = McpClient.using(mcpTransport).sync()) {
|
||||
// Initialize connection with protocol version and capabilities
|
||||
InitializeResult initResult = client.initialize();
|
||||
// Initialize connection
|
||||
client.initialize();
|
||||
|
||||
// List available tools
|
||||
ListToolsResult tools = client.listTools();
|
||||
// List available tools
|
||||
ListToolsResult tools = client.listTools();
|
||||
|
||||
// Execute a tool
|
||||
CallToolResult result = client.callTool(
|
||||
new CallToolRequest("echo", Map.of("message", "Hello!"))
|
||||
);
|
||||
// Call a tool
|
||||
CallToolResult result = client.callTool(
|
||||
new CallToolRequest("calculator",
|
||||
Map.of("operation", "add", "a", 2, "b", 3))
|
||||
);
|
||||
|
||||
// Resource management
|
||||
ListResourcesResult resources = client.listResources();
|
||||
ReadResourceResult resource = client.readResource(
|
||||
new ReadResourceRequest("resource-uri")
|
||||
);
|
||||
// List and read resources
|
||||
ListResourcesResult resources = client.listResources();
|
||||
ReadResourceResult resource = client.readResource(
|
||||
new ReadResourceRequest("resource://uri")
|
||||
);
|
||||
|
||||
// List and retrieve prompts
|
||||
ListPromptsResult prompts = client.listPrompts();
|
||||
GetPromptResult prompt = client.getPrompt(
|
||||
new GetPromptRequest("prompt-id", Map.of())
|
||||
);
|
||||
}
|
||||
// List and use prompts
|
||||
ListPromptsResult prompts = client.listPrompts();
|
||||
GetPromptResult prompt = client.getPrompt(
|
||||
new GetPromptRequest("greeting", Map.of("name", "Spring"))
|
||||
);
|
||||
|
||||
// Add/remove roots
|
||||
client.addRoot(new Root("file:///path", "description"));
|
||||
client.removeRoot("file:///path");
|
||||
client.rootsListChangedNotification();
|
||||
|
||||
// Close client
|
||||
client.closeGracefully();
|
||||
```
|
||||
|
||||
#### Async MCP Client
|
||||
### MCP Client (Async API)
|
||||
|
||||
```java
|
||||
McpTransport mcpTransport = ...
|
||||
|
||||
// Initialize async client with custom timeout
|
||||
McpAsyncClient client = McpClient.using(mcpTransport)
|
||||
.requestTimeout(Duration.ofSeconds(30))
|
||||
// Create an async client with custom configuration
|
||||
McpAsyncClient client = McpClient.using(transport)
|
||||
.requestTimeout(Duration.ofSeconds(10))
|
||||
.capabilities(ClientCapabilities.builder()
|
||||
.roots(true) // Enable roots capability
|
||||
.sampling() // Enable sampling capability
|
||||
.build())
|
||||
.toolsChangeConsumer(tools -> {
|
||||
logger.info("Tools updated: {}", tools);
|
||||
})
|
||||
.resourcesChangeConsumer(resources -> {
|
||||
logger.info("Resources updated: {}", resources);
|
||||
})
|
||||
.promptsChangeConsumer(prompts -> {
|
||||
logger.info("Prompts updated: {}", prompts);
|
||||
})
|
||||
.async();
|
||||
|
||||
// Initialize connection and chain operations
|
||||
var result = client.initialize()
|
||||
// Connection initialized with protocol version compatibility
|
||||
.flatMap(initResult -> client.listTools())
|
||||
// Process available tools
|
||||
.flatMap(tools -> client.callTool(
|
||||
new CallToolRequest("echo", Map.of("message", "Hello MCP!"))))
|
||||
// Handle tool execution result
|
||||
.flatMap(toolResult -> client.listPrompts())
|
||||
// Process available prompts
|
||||
.flatMap(prompts -> client.getPrompt(new GetPromptRequest("prompt-id", Map.of()));
|
||||
|
||||
// Subscribe to resource changes
|
||||
var subscription = client.listResources()
|
||||
.flatMap(resources -> client.subscribeResource(new SubscribeRequest("resource-uri")));
|
||||
|
||||
// Handle results reactively or block if needed
|
||||
GetPromptResult promptResult = result.block();
|
||||
subscription.block();
|
||||
|
||||
// Cleanup
|
||||
client.closeGracefully().block();
|
||||
// Initialize connection
|
||||
client.initialize()
|
||||
.flatMap(initResult -> {
|
||||
// List available tools
|
||||
return client.listTools();
|
||||
})
|
||||
.flatMap(tools -> {
|
||||
// Call a tool
|
||||
return client.callTool(new CallToolRequest(
|
||||
"calculator",
|
||||
Map.of("operation", "add", "a", 2, "b", 3)
|
||||
));
|
||||
})
|
||||
.flatMap(result -> {
|
||||
// List and read resources
|
||||
return client.listResources()
|
||||
.flatMap(resources ->
|
||||
client.readResource(new ReadResourceRequest("resource://uri"))
|
||||
);
|
||||
})
|
||||
.flatMap(resource -> {
|
||||
// List and use prompts
|
||||
return client.listPrompts()
|
||||
.flatMap(prompts ->
|
||||
client.getPrompt(new GetPromptRequest(
|
||||
"greeting",
|
||||
Map.of("name", "Spring")
|
||||
))
|
||||
);
|
||||
})
|
||||
.flatMap(prompt -> {
|
||||
// Add/remove roots
|
||||
return client.addRoot(new Root("file:///path", "description"))
|
||||
.then(client.removeRoot("file:///path"))
|
||||
.then(client.rootsListChangedNotification());
|
||||
})
|
||||
.doFinally(signalType -> {
|
||||
// Close client
|
||||
client.closeGracefully().subscribe();
|
||||
})
|
||||
.subscribe();
|
||||
```
|
||||
|
||||
#### Client Transports
|
||||
Clients can use the following transport options:
|
||||
|
||||
##### StdioClientTransport
|
||||
Standard I/O based transport for process-based communication with MCP servers:
|
||||
### Client Transport Options
|
||||
|
||||
#### StdioClientTransport
|
||||
```java
|
||||
// Create transport for process-based communication
|
||||
ServerParameters params = ServerParameters.builder("npx")
|
||||
.args("-y", "@modelcontextprotocol/server-everything", "dir")
|
||||
.build();
|
||||
McpTransport transport = new StdioClientTransport(params);
|
||||
```
|
||||
|
||||
##### SseClientTransport
|
||||
Server-Sent Events (SSE) based transport following the MCP HTTP with SSE transport specification:
|
||||
|
||||
#### SseClientTransport
|
||||
```java
|
||||
// Create transport for HTTP streaming
|
||||
WebClient.Builder webClientBuilder = WebClient.builder()
|
||||
.baseUrl("http://your-mcp-server");
|
||||
McpTransport transport = new SseClientTransport(webClientBuilder);
|
||||
```
|
||||
|
||||
|
||||
### MCP Server
|
||||
## Server Usage Examples
|
||||
|
||||
Factory for creating `sync` and `async` variants MCP servers. Uses McpSession for communication and handles server-side protocol operations.
|
||||
|
||||
#### MCP Sync Server
|
||||
### MCP Server (Sync API)
|
||||
|
||||
```java
|
||||
// Create a sync server with custom configuration
|
||||
// Create a server with custom configuration
|
||||
McpSyncServer syncServer = McpServer.using(transport)
|
||||
.serverInfo("my-server", "1.0.0")
|
||||
.serverCapabilities(new ServerCapabilities(...))
|
||||
.addTool(new CalculatorTool())
|
||||
.resourcesProvider(cursor -> resources)
|
||||
.promptsProvider(cursor -> prompts)
|
||||
.info("my-server", "1.0.0")
|
||||
.capabilities(ServerCapabilities.builder()...build())
|
||||
.tools(new CalculatorTool())
|
||||
.resources(resourceRegistration)
|
||||
.prompts(promptRegistration)
|
||||
.sync();
|
||||
|
||||
// Add a tool handler at runtime
|
||||
syncServer.addTool(new CalculatorTool());
|
||||
logger.info("Tool added");
|
||||
|
||||
// Remove a tool handler
|
||||
// Remove a tool handler at runtime
|
||||
syncServer.removeTool("calculator");
|
||||
logger.info("Tool removed");
|
||||
|
||||
// Notify clients of changes
|
||||
syncServer.notifyToolsListChanged();
|
||||
syncServer.notifyResourcesListChanged();
|
||||
syncServer.notifyPromptsListChanged();
|
||||
// Add a resource at runtime
|
||||
syncServer.addResource(resourceRegistration);
|
||||
|
||||
// Remove a resource at runtime
|
||||
syncServer.removeResource(resourceUri);
|
||||
|
||||
// Add a prompt at runtime
|
||||
syncServer.addPrompt(promptRegistration);
|
||||
|
||||
// Remove a prompt at runtime
|
||||
syncServer.removePrompt(promptName);
|
||||
|
||||
// Graceful shutdown
|
||||
syncServer.closeGracefully();
|
||||
```
|
||||
|
||||
#### MCP Async Server
|
||||
### MCP Server (Async API)
|
||||
|
||||
```java
|
||||
// Create an async server with custom configuration
|
||||
McpAsyncServer asyncServer = McpServer.using(transport)
|
||||
.serverInfo("my-server", "1.0.0")
|
||||
.serverCapabilities(new ServerCapabilities(...))
|
||||
.addTool(new CalculatorTool())
|
||||
.resourcesProvider(cursor -> resources)
|
||||
.promptsProvider(cursor -> prompts)
|
||||
.info("my-server", "1.0.0")
|
||||
.capabilities(ServerCapabilities.builder()...build())
|
||||
.tools(new CalculatorTool())
|
||||
.resources(resourceRegistration)
|
||||
.prompts(promptRegistration)
|
||||
.async();
|
||||
|
||||
// Add a tool handler at runtime
|
||||
|
|
@ -209,11 +234,31 @@ asyncServer.addTool(new CalculatorTool())
|
|||
.doOnSuccess(v -> logger.info("Tool added"))
|
||||
.subscribe();
|
||||
|
||||
// Remove a tool handler
|
||||
// Remove a tool handler at runtime
|
||||
asyncServer.removeTool("calculator")
|
||||
.doOnSuccess(v -> logger.info("Tool removed"))
|
||||
.subscribe();
|
||||
|
||||
// Add a resource at runtime
|
||||
asyncServer.addResource(resourceRegistration)
|
||||
.doOnSuccess(v -> logger.info("Resource added"))
|
||||
.subscribe();
|
||||
|
||||
// Remove a resource at runtime
|
||||
asyncServer.removeResource(resourceUri)
|
||||
.doOnSuccess(v -> logger.info("Resource removed"))
|
||||
.subscribe();
|
||||
|
||||
// Add a prompt at runtime
|
||||
asyncServer.addPrompt(promptRegistration)
|
||||
.doOnSuccess(v -> logger.info("Prompt added"))
|
||||
.subscribe();
|
||||
|
||||
// Remove a prompt at runtime
|
||||
asyncServer.removePrompt(promptName)
|
||||
.doOnSuccess(v -> logger.info("Prompt removed"))
|
||||
.subscribe();
|
||||
|
||||
// Notify clients of changes
|
||||
asyncServer.notifyToolsListChanged().subscribe();
|
||||
asyncServer.notifyResourcesListChanged().subscribe();
|
||||
|
|
@ -223,12 +268,9 @@ asyncServer.notifyPromptsListChanged().subscribe();
|
|||
asyncServer.closeGracefully().subscribe();
|
||||
```
|
||||
|
||||
#### Server Transports
|
||||
### Server Transport Options
|
||||
|
||||
Servers can use the following transport options:
|
||||
|
||||
##### StdioServerTransport
|
||||
Standard I/O based transport for process-based communication:
|
||||
#### StdioServerTransport
|
||||
```java
|
||||
// Create transport with custom ObjectMapper
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
|
|
@ -237,8 +279,7 @@ StdioServerTransport transport = new StdioServerTransport(mapper);
|
|||
|
||||
Provides bidirectional JSON-RPC message handling over standard input/output streams with non-blocking message processing, serialization/deserialization, and graceful shutdown support.
|
||||
|
||||
##### SseServerTransport
|
||||
Server-Sent Events based transport for HTTP streaming:
|
||||
#### SseServerTransport
|
||||
```java
|
||||
// Create SSE transport
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
|
|
@ -251,26 +292,65 @@ RouterFunction<?> router = transport.getRouterFunction();
|
|||
|
||||
Implements the MCP HTTP with SSE transport specification, providing concurrent client connections through SSE endpoints with message routing, session management, and graceful shutdown capabilities.
|
||||
|
||||
|
||||
### Server Capabilities
|
||||
|
||||
The server can be configured with various capabilities:
|
||||
|
||||
```java
|
||||
var capabilities = ServerCapabilities.builder()
|
||||
.resources(false, true) // Resource support with list changes notifications
|
||||
.tools(true) // Tool support with list changes notifications
|
||||
.prompts(true) // Prompt support with list changes notifications
|
||||
.build();
|
||||
```
|
||||
|
||||
### Tool Registration
|
||||
|
||||
```java
|
||||
var toolRegistration = new ToolRegistration(
|
||||
new Tool("calculator", "Basic calculator", Map.of(
|
||||
"operation", "string",
|
||||
"a", "number",
|
||||
"b", "number"
|
||||
)),
|
||||
arguments -> {
|
||||
// Tool implementation
|
||||
return new CallToolResult(result, false);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
### Resource Registration
|
||||
|
||||
```java
|
||||
var resourceRegistration = new ResourceRegistration(
|
||||
new Resource("custom://resource", "name", "description", "mime-type", null),
|
||||
request -> {
|
||||
// Resource read implementation
|
||||
return new ReadResourceResult(contents);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
### Prompt Registration
|
||||
|
||||
```java
|
||||
var promptRegistration = new PromptRegistration(
|
||||
new Prompt("greeting", "description", List.of(
|
||||
new PromptArgument("name", "description", true)
|
||||
)),
|
||||
request -> {
|
||||
// Prompt implementation
|
||||
return new GetPromptResult(description, messages);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
The SDK provides comprehensive error handling through the McpError class, covering protocol compatibility, transport communication, JSON-RPC messaging, tool execution, resource management, prompt handling, timeouts, and connection issues. This unified error handling approach ensures consistent and reliable error management across both synchronous and asynchronous operations.
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are welcome! Please feel free to submit a Pull Request.
|
||||
|
||||
## License
|
||||
|
||||
Copyright 2024 - 2024 the original author or authors.
|
||||
|
||||
Licensed 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
|
||||
|
||||
https://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.
|
||||
See [CONTRIBUTING.md](../CONTRIBUTING.md) for details on our code of conduct and the process for submitting pull requests.
|
||||
|
|
|
|||
|
|
@ -155,19 +155,6 @@ public interface McpServer {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the server implementation information using name and version.
|
||||
* @param name The server name
|
||||
* @param version The server version
|
||||
* @return This builder instance
|
||||
*/
|
||||
public Builder serverInfo(String name, String version) {
|
||||
Assert.notNull(name, "Server name must not be null");
|
||||
Assert.notNull(version, "Server version must not be null");
|
||||
this.serverInfo = new McpSchema.Implementation(name, version);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the server capabilities.
|
||||
* @param serverCapabilities The server capabilities configuration
|
||||
|
|
|
|||
|
|
@ -60,27 +60,6 @@ public class McpSyncServer {
|
|||
this.asyncServer.removeTool(toolName).block();
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify clients that the list of available tools has changed.
|
||||
*/
|
||||
public void notifyToolsListChanged() {
|
||||
this.asyncServer.notifyToolsListChanged().block();
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify clients that the list of available resources has changed.
|
||||
*/
|
||||
public void notifyResourcesListChanged() {
|
||||
this.asyncServer.notifyResourcesListChanged().block();
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify clients that the list of available prompts has changed.
|
||||
*/
|
||||
public void notifyPromptsListChanged() {
|
||||
this.asyncServer.notifyPromptsListChanged().block();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new resource handler.
|
||||
* @param resourceHandler The resource handler to add
|
||||
|
|
@ -113,6 +92,27 @@ public class McpSyncServer {
|
|||
this.asyncServer.removePrompt(promptName).block();
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify clients that the list of available tools has changed.
|
||||
*/
|
||||
public void notifyToolsListChanged() {
|
||||
this.asyncServer.notifyToolsListChanged().block();
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify clients that the list of available resources has changed.
|
||||
*/
|
||||
public void notifyResourcesListChanged() {
|
||||
this.asyncServer.notifyResourcesListChanged().block();
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify clients that the list of available prompts has changed.
|
||||
*/
|
||||
public void notifyPromptsListChanged() {
|
||||
this.asyncServer.notifyPromptsListChanged().block();
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the server gracefully.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ public class DemoServer {
|
|||
SseServerTransport transport = new SseServerTransport(new ObjectMapper(), "/mcp/message");
|
||||
|
||||
var mcpServer = McpServer.using(transport)
|
||||
.serverInfo("Weather Forecast", "1.0.0")
|
||||
.info("Weather Forecast", "1.0.0")
|
||||
.tool(new McpSchema.Tool("weather", "Weather forecast tool by location", Map.of("city", "String")),
|
||||
(arguments) -> {
|
||||
String city = (String) arguments.get("city");
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ public abstract class AbstractMcpAsyncServerTests {
|
|||
void testAddTool() {
|
||||
Tool newTool = new McpSchema.Tool("new-tool", "New test tool", Map.of("input", "string"));
|
||||
var mcpAsyncServer = McpServer.using(createMcpTransport())
|
||||
.serverInfo("test-server", "1.0.0")
|
||||
.info("test-server", "1.0.0")
|
||||
.capabilities(ServerCapabilities.builder().tools(true).build())
|
||||
.async();
|
||||
|
||||
|
|
@ -105,7 +105,7 @@ public abstract class AbstractMcpAsyncServerTests {
|
|||
Tool duplicateTool = new McpSchema.Tool(TEST_TOOL_NAME, "Duplicate tool", Map.of("input", "string"));
|
||||
|
||||
var mcpAsyncServer = McpServer.using(createMcpTransport())
|
||||
.serverInfo("test-server", "1.0.0")
|
||||
.info("test-server", "1.0.0")
|
||||
.capabilities(ServerCapabilities.builder().tools(true).build())
|
||||
.tool(duplicateTool, args -> new CallToolResult(List.of(), false))
|
||||
.async();
|
||||
|
|
@ -126,7 +126,7 @@ public abstract class AbstractMcpAsyncServerTests {
|
|||
Tool too = new McpSchema.Tool(TEST_TOOL_NAME, "Duplicate tool", Map.of("input", "string"));
|
||||
|
||||
var mcpAsyncServer = McpServer.using(createMcpTransport())
|
||||
.serverInfo("test-server", "1.0.0")
|
||||
.info("test-server", "1.0.0")
|
||||
.capabilities(ServerCapabilities.builder().tools(true).build())
|
||||
.tool(too, args -> new CallToolResult(List.of(), false))
|
||||
.async();
|
||||
|
|
@ -139,7 +139,7 @@ public abstract class AbstractMcpAsyncServerTests {
|
|||
@Test
|
||||
void testRemoveNonexistentTool() {
|
||||
var mcpAsyncServer = McpServer.using(createMcpTransport())
|
||||
.serverInfo("test-server", "1.0.0")
|
||||
.info("test-server", "1.0.0")
|
||||
.capabilities(ServerCapabilities.builder().tools(true).build())
|
||||
.async();
|
||||
|
||||
|
|
@ -155,7 +155,7 @@ public abstract class AbstractMcpAsyncServerTests {
|
|||
Tool too = new McpSchema.Tool(TEST_TOOL_NAME, "Duplicate tool", Map.of("input", "string"));
|
||||
|
||||
var mcpAsyncServer = McpServer.using(createMcpTransport())
|
||||
.serverInfo("test-server", "1.0.0")
|
||||
.info("test-server", "1.0.0")
|
||||
.capabilities(ServerCapabilities.builder().tools(true).build())
|
||||
.tool(too, args -> new CallToolResult(List.of(), false))
|
||||
.async();
|
||||
|
|
@ -167,7 +167,7 @@ public abstract class AbstractMcpAsyncServerTests {
|
|||
|
||||
@Test
|
||||
void testNotifyResourcesListChanged() {
|
||||
var mcpAsyncServer = McpServer.using(createMcpTransport()).serverInfo("test-server", "1.0.0").async();
|
||||
var mcpAsyncServer = McpServer.using(createMcpTransport()).info("test-server", "1.0.0").async();
|
||||
|
||||
StepVerifier.create(mcpAsyncServer.notifyResourcesListChanged()).verifyComplete();
|
||||
|
||||
|
|
@ -176,7 +176,7 @@ public abstract class AbstractMcpAsyncServerTests {
|
|||
|
||||
@Test
|
||||
void testNotifyPromptsListChanged() {
|
||||
var mcpAsyncServer = McpServer.using(createMcpTransport()).serverInfo("test-server", "1.0.0").async();
|
||||
var mcpAsyncServer = McpServer.using(createMcpTransport()).info("test-server", "1.0.0").async();
|
||||
|
||||
StepVerifier.create(mcpAsyncServer.notifyPromptsListChanged()).verifyComplete();
|
||||
|
||||
|
|
@ -185,14 +185,14 @@ public abstract class AbstractMcpAsyncServerTests {
|
|||
|
||||
@Test
|
||||
void testGracefulShutdown() {
|
||||
var mcpAsyncServer = McpServer.using(createMcpTransport()).serverInfo("test-server", "1.0.0").async();
|
||||
var mcpAsyncServer = McpServer.using(createMcpTransport()).info("test-server", "1.0.0").async();
|
||||
|
||||
StepVerifier.create(mcpAsyncServer.closeGracefully()).verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testImmediateClose() {
|
||||
var mcpAsyncServer = McpServer.using(createMcpTransport()).serverInfo("test-server", "1.0.0").async();
|
||||
var mcpAsyncServer = McpServer.using(createMcpTransport()).info("test-server", "1.0.0").async();
|
||||
|
||||
assertThatCode(() -> mcpAsyncServer.close()).doesNotThrowAnyException();
|
||||
}
|
||||
|
|
@ -200,7 +200,7 @@ public abstract class AbstractMcpAsyncServerTests {
|
|||
@Test
|
||||
void testAddResource() {
|
||||
var mcpAsyncServer = McpServer.using(createMcpTransport())
|
||||
.serverInfo("test-server", "1.0.0")
|
||||
.info("test-server", "1.0.0")
|
||||
.capabilities(ServerCapabilities.builder().resources(true, false).build())
|
||||
.async();
|
||||
|
||||
|
|
@ -218,7 +218,7 @@ public abstract class AbstractMcpAsyncServerTests {
|
|||
void testAddResourceWithNullRegistration() {
|
||||
|
||||
var mcpAsyncServer = McpServer.using(createMcpTransport())
|
||||
.serverInfo("test-server", "1.0.0")
|
||||
.info("test-server", "1.0.0")
|
||||
.capabilities(ServerCapabilities.builder().resources(true, false).build())
|
||||
.async();
|
||||
|
||||
|
|
@ -232,7 +232,7 @@ public abstract class AbstractMcpAsyncServerTests {
|
|||
@Test
|
||||
void testAddPromptWithNullRegistration() {
|
||||
var mcpAsyncServer = McpServer.using(createMcpTransport())
|
||||
.serverInfo("test-server", "1.0.0")
|
||||
.info("test-server", "1.0.0")
|
||||
.capabilities(ServerCapabilities.builder().prompts(false).build())
|
||||
.async();
|
||||
|
||||
|
|
@ -245,7 +245,7 @@ public abstract class AbstractMcpAsyncServerTests {
|
|||
void testAddResourceWithoutCapability() {
|
||||
// Create a server without resource capabilities
|
||||
McpAsyncServer serverWithoutResources = McpServer.using(createMcpTransport())
|
||||
.serverInfo("test-server", "1.0.0")
|
||||
.info("test-server", "1.0.0")
|
||||
.async();
|
||||
|
||||
Resource resource = new Resource(TEST_RESOURCE_URI, "Test Resource", "text/plain", "Test resource description",
|
||||
|
|
@ -263,7 +263,7 @@ public abstract class AbstractMcpAsyncServerTests {
|
|||
void testAddPromptWithoutCapability() {
|
||||
// Create a server without prompt capabilities
|
||||
McpAsyncServer serverWithoutPrompts = McpServer.using(createMcpTransport())
|
||||
.serverInfo("test-server", "1.0.0")
|
||||
.info("test-server", "1.0.0")
|
||||
.async();
|
||||
|
||||
Prompt prompt = new Prompt(TEST_PROMPT_NAME, "Test Prompt", List.of());
|
||||
|
|
@ -281,7 +281,7 @@ public abstract class AbstractMcpAsyncServerTests {
|
|||
void testRemoveResourceWithoutCapability() {
|
||||
// Create a server without resource capabilities
|
||||
McpAsyncServer serverWithoutResources = McpServer.using(createMcpTransport())
|
||||
.serverInfo("test-server", "1.0.0")
|
||||
.info("test-server", "1.0.0")
|
||||
.async();
|
||||
|
||||
StepVerifier.create(serverWithoutResources.removeResource(TEST_RESOURCE_URI)).verifyErrorSatisfies(error -> {
|
||||
|
|
@ -294,7 +294,7 @@ public abstract class AbstractMcpAsyncServerTests {
|
|||
void testRemovePromptWithoutCapability() {
|
||||
// Create a server without prompt capabilities
|
||||
McpAsyncServer serverWithoutPrompts = McpServer.using(createMcpTransport())
|
||||
.serverInfo("test-server", "1.0.0")
|
||||
.info("test-server", "1.0.0")
|
||||
.async();
|
||||
|
||||
StepVerifier.create(serverWithoutPrompts.removePrompt(TEST_PROMPT_NAME)).verifyErrorSatisfies(error -> {
|
||||
|
|
@ -313,7 +313,7 @@ public abstract class AbstractMcpAsyncServerTests {
|
|||
List.of(new PromptMessage(McpSchema.Role.ASSISTANT, new McpSchema.TextContent("Test content")))));
|
||||
|
||||
var mcpAsyncServer = McpServer.using(createMcpTransport())
|
||||
.serverInfo("test-server", "1.0.0")
|
||||
.info("test-server", "1.0.0")
|
||||
.capabilities(ServerCapabilities.builder().prompts(true).build())
|
||||
.prompts(registration)
|
||||
.async();
|
||||
|
|
@ -326,7 +326,7 @@ public abstract class AbstractMcpAsyncServerTests {
|
|||
@Test
|
||||
void testRemoveNonexistentPrompt() {
|
||||
var mcpAsyncServer2 = McpServer.using(createMcpTransport())
|
||||
.serverInfo("test-server", "1.0.0")
|
||||
.info("test-server", "1.0.0")
|
||||
.capabilities(ServerCapabilities.builder().prompts(true).build())
|
||||
.async();
|
||||
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ public abstract class AbstractMcpSyncServerTests {
|
|||
@Test
|
||||
void testAddTool() {
|
||||
var mcpSyncServer = McpServer.using(createMcpTransport())
|
||||
.serverInfo("test-server", "1.0.0")
|
||||
.info("test-server", "1.0.0")
|
||||
.capabilities(ServerCapabilities.builder().tools(true).build())
|
||||
.sync();
|
||||
|
||||
|
|
@ -103,7 +103,7 @@ public abstract class AbstractMcpSyncServerTests {
|
|||
Tool duplicateTool = new McpSchema.Tool(TEST_TOOL_NAME, "Duplicate tool", Map.of("input", "string"));
|
||||
|
||||
var mcpSyncServer = McpServer.using(createMcpTransport())
|
||||
.serverInfo("test-server", "1.0.0")
|
||||
.info("test-server", "1.0.0")
|
||||
.capabilities(ServerCapabilities.builder().tools(true).build())
|
||||
.tool(duplicateTool, args -> new CallToolResult(List.of(), false))
|
||||
.sync();
|
||||
|
|
@ -121,7 +121,7 @@ public abstract class AbstractMcpSyncServerTests {
|
|||
Tool tool = new McpSchema.Tool(TEST_TOOL_NAME, "Test tool", Map.of("input", "string"));
|
||||
|
||||
var mcpSyncServer = McpServer.using(createMcpTransport())
|
||||
.serverInfo("test-server", "1.0.0")
|
||||
.info("test-server", "1.0.0")
|
||||
.capabilities(ServerCapabilities.builder().tools(true).build())
|
||||
.tool(tool, args -> new CallToolResult(List.of(), false))
|
||||
.sync();
|
||||
|
|
@ -134,7 +134,7 @@ public abstract class AbstractMcpSyncServerTests {
|
|||
@Test
|
||||
void testRemoveNonexistentTool() {
|
||||
var mcpSyncServer = McpServer.using(createMcpTransport())
|
||||
.serverInfo("test-server", "1.0.0")
|
||||
.info("test-server", "1.0.0")
|
||||
.capabilities(ServerCapabilities.builder().tools(true).build())
|
||||
.sync();
|
||||
|
||||
|
|
@ -146,7 +146,7 @@ public abstract class AbstractMcpSyncServerTests {
|
|||
|
||||
@Test
|
||||
void testNotifyToolsListChanged() {
|
||||
var mcpSyncServer = McpServer.using(createMcpTransport()).serverInfo("test-server", "1.0.0").sync();
|
||||
var mcpSyncServer = McpServer.using(createMcpTransport()).info("test-server", "1.0.0").sync();
|
||||
|
||||
assertThatCode(() -> mcpSyncServer.notifyToolsListChanged()).doesNotThrowAnyException();
|
||||
|
||||
|
|
@ -155,7 +155,7 @@ public abstract class AbstractMcpSyncServerTests {
|
|||
|
||||
@Test
|
||||
void testNotifyResourcesListChanged() {
|
||||
var mcpSyncServer = McpServer.using(createMcpTransport()).serverInfo("test-server", "1.0.0").sync();
|
||||
var mcpSyncServer = McpServer.using(createMcpTransport()).info("test-server", "1.0.0").sync();
|
||||
|
||||
assertThatCode(() -> mcpSyncServer.notifyResourcesListChanged()).doesNotThrowAnyException();
|
||||
|
||||
|
|
@ -164,7 +164,7 @@ public abstract class AbstractMcpSyncServerTests {
|
|||
|
||||
@Test
|
||||
void testNotifyPromptsListChanged() {
|
||||
var mcpSyncServer = McpServer.using(createMcpTransport()).serverInfo("test-server", "1.0.0").sync();
|
||||
var mcpSyncServer = McpServer.using(createMcpTransport()).info("test-server", "1.0.0").sync();
|
||||
|
||||
assertThatCode(() -> mcpSyncServer.notifyPromptsListChanged()).doesNotThrowAnyException();
|
||||
|
||||
|
|
@ -173,14 +173,14 @@ public abstract class AbstractMcpSyncServerTests {
|
|||
|
||||
@Test
|
||||
void testGracefulShutdown() {
|
||||
var mcpSyncServer = McpServer.using(createMcpTransport()).serverInfo("test-server", "1.0.0").sync();
|
||||
var mcpSyncServer = McpServer.using(createMcpTransport()).info("test-server", "1.0.0").sync();
|
||||
|
||||
assertThatCode(() -> mcpSyncServer.closeGracefully()).doesNotThrowAnyException();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testImmediateClose() {
|
||||
var mcpSyncServer = McpServer.using(createMcpTransport()).serverInfo("test-server", "1.0.0").sync();
|
||||
var mcpSyncServer = McpServer.using(createMcpTransport()).info("test-server", "1.0.0").sync();
|
||||
|
||||
assertThatCode(() -> mcpSyncServer.close()).doesNotThrowAnyException();
|
||||
}
|
||||
|
|
@ -188,7 +188,7 @@ public abstract class AbstractMcpSyncServerTests {
|
|||
@Test
|
||||
void testAddResource() {
|
||||
var mcpSyncServer = McpServer.using(createMcpTransport())
|
||||
.serverInfo("test-server", "1.0.0")
|
||||
.info("test-server", "1.0.0")
|
||||
.capabilities(ServerCapabilities.builder().resources(true, false).build())
|
||||
.sync();
|
||||
|
||||
|
|
@ -205,7 +205,7 @@ public abstract class AbstractMcpSyncServerTests {
|
|||
@Test
|
||||
void testAddResourceWithNullRegistration() {
|
||||
var mcpSyncServer = McpServer.using(createMcpTransport())
|
||||
.serverInfo("test-server", "1.0.0")
|
||||
.info("test-server", "1.0.0")
|
||||
.capabilities(ServerCapabilities.builder().resources(true, false).build())
|
||||
.sync();
|
||||
|
||||
|
|
@ -218,7 +218,7 @@ public abstract class AbstractMcpSyncServerTests {
|
|||
@Test
|
||||
void testAddPromptWithNullRegistration() {
|
||||
var mcpSyncServer = McpServer.using(createMcpTransport())
|
||||
.serverInfo("test-server", "1.0.0")
|
||||
.info("test-server", "1.0.0")
|
||||
.capabilities(ServerCapabilities.builder().prompts(false).build())
|
||||
.sync();
|
||||
|
||||
|
|
@ -228,7 +228,7 @@ public abstract class AbstractMcpSyncServerTests {
|
|||
|
||||
@Test
|
||||
void testAddResourceWithoutCapability() {
|
||||
var serverWithoutResources = McpServer.using(createMcpTransport()).serverInfo("test-server", "1.0.0").sync();
|
||||
var serverWithoutResources = McpServer.using(createMcpTransport()).info("test-server", "1.0.0").sync();
|
||||
|
||||
Resource resource = new Resource(TEST_RESOURCE_URI, "Test Resource", "text/plain", "Test resource description",
|
||||
null);
|
||||
|
|
@ -241,7 +241,7 @@ public abstract class AbstractMcpSyncServerTests {
|
|||
|
||||
@Test
|
||||
void testAddPromptWithoutCapability() {
|
||||
var serverWithoutPrompts = McpServer.using(createMcpTransport()).serverInfo("test-server", "1.0.0").sync();
|
||||
var serverWithoutPrompts = McpServer.using(createMcpTransport()).info("test-server", "1.0.0").sync();
|
||||
|
||||
Prompt prompt = new Prompt(TEST_PROMPT_NAME, "Test Prompt", List.of());
|
||||
PromptRegistration registration = new PromptRegistration(prompt, req -> new GetPromptResult(
|
||||
|
|
@ -254,7 +254,7 @@ public abstract class AbstractMcpSyncServerTests {
|
|||
|
||||
@Test
|
||||
void testRemoveResourceWithoutCapability() {
|
||||
var serverWithoutResources = McpServer.using(createMcpTransport()).serverInfo("test-server", "1.0.0").sync();
|
||||
var serverWithoutResources = McpServer.using(createMcpTransport()).info("test-server", "1.0.0").sync();
|
||||
|
||||
assertThatThrownBy(() -> serverWithoutResources.removeResource(TEST_RESOURCE_URI)).isInstanceOf(McpError.class)
|
||||
.hasMessage("Server must be configured with resource capabilities");
|
||||
|
|
@ -262,7 +262,7 @@ public abstract class AbstractMcpSyncServerTests {
|
|||
|
||||
@Test
|
||||
void testRemovePromptWithoutCapability() {
|
||||
var serverWithoutPrompts = McpServer.using(createMcpTransport()).serverInfo("test-server", "1.0.0").sync();
|
||||
var serverWithoutPrompts = McpServer.using(createMcpTransport()).info("test-server", "1.0.0").sync();
|
||||
|
||||
assertThatThrownBy(() -> serverWithoutPrompts.removePrompt(TEST_PROMPT_NAME)).isInstanceOf(McpError.class)
|
||||
.hasMessage("Server must be configured with prompt capabilities");
|
||||
|
|
@ -277,7 +277,7 @@ public abstract class AbstractMcpSyncServerTests {
|
|||
List.of(new PromptMessage(McpSchema.Role.ASSISTANT, new McpSchema.TextContent("Test content")))));
|
||||
|
||||
var mcpSyncServer = McpServer.using(createMcpTransport())
|
||||
.serverInfo("test-server", "1.0.0")
|
||||
.info("test-server", "1.0.0")
|
||||
.capabilities(ServerCapabilities.builder().prompts(true).build())
|
||||
.prompts(registration)
|
||||
.sync();
|
||||
|
|
@ -292,7 +292,7 @@ public abstract class AbstractMcpSyncServerTests {
|
|||
@Test
|
||||
void testRemoveNonexistentPrompt() {
|
||||
var mcpSyncServer = McpServer.using(createMcpTransport())
|
||||
.serverInfo("test-server", "1.0.0")
|
||||
.info("test-server", "1.0.0")
|
||||
.capabilities(ServerCapabilities.builder().prompts(true).build())
|
||||
.sync();
|
||||
|
||||
|
|
@ -304,7 +304,7 @@ public abstract class AbstractMcpSyncServerTests {
|
|||
|
||||
@Test
|
||||
void testGetAsyncServer() {
|
||||
var mcpSyncServer = McpServer.using(createMcpTransport()).serverInfo("test-server", "1.0.0").sync();
|
||||
var mcpSyncServer = McpServer.using(createMcpTransport()).info("test-server", "1.0.0").sync();
|
||||
|
||||
assertThat(mcpSyncServer.getAsyncServer()).isNotNull();
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue