docs Improve MCP readme

This commit is contained in:
Christian Tzolov 2024-12-28 23:56:16 +01:00
commit 347f86ff19
6 changed files with 270 additions and 203 deletions

View file

@ -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.

View file

@ -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

View file

@ -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.
*/

View file

@ -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");

View file

@ -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();

View file

@ -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();