refactor: use builder pattern for CallToolResult and Resource (#652)

* use builder pattern for CallToolResult
* use builder pattern for Resource
* simplify lambda expressions in tests
This commit is contained in:
codeboyzhou 2025-11-21 20:44:29 +08:00 • committed by GitHub
commit 7e950ebb6c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 405 additions and 202 deletions

View file

@ -24,7 +24,6 @@ import io.modelcontextprotocol.spec.McpSchema;
import io.modelcontextprotocol.spec.McpSchema.CallToolResult; import io.modelcontextprotocol.spec.McpSchema.CallToolResult;
import io.modelcontextprotocol.spec.McpSchema.CompleteResult.CompleteCompletion; import io.modelcontextprotocol.spec.McpSchema.CompleteResult.CompleteCompletion;
import io.modelcontextprotocol.spec.McpSchema.ErrorCodes; import io.modelcontextprotocol.spec.McpSchema.ErrorCodes;
import io.modelcontextprotocol.spec.McpSchema.JSONRPCResponse;
import io.modelcontextprotocol.spec.McpSchema.LoggingLevel; import io.modelcontextprotocol.spec.McpSchema.LoggingLevel;
import io.modelcontextprotocol.spec.McpSchema.LoggingMessageNotification; import io.modelcontextprotocol.spec.McpSchema.LoggingMessageNotification;
import io.modelcontextprotocol.spec.McpSchema.PromptReference; import io.modelcontextprotocol.spec.McpSchema.PromptReference;
@ -398,11 +397,12 @@ public class McpAsyncServer {
// results that conform to this schema. // results that conform to this schema.
// https://modelcontextprotocol.io/specification/2025-06-18/server/tools#output-schema // https://modelcontextprotocol.io/specification/2025-06-18/server/tools#output-schema
if (result.structuredContent() == null) { if (result.structuredContent() == null) {
logger.warn( String content = "Response missing structured content which is expected when calling tool with non-empty outputSchema";
"Response missing structured content which is expected when calling tool with non-empty outputSchema"); logger.warn(content);
return new CallToolResult( return CallToolResult.builder()
"Response missing structured content which is expected when calling tool with non-empty outputSchema", .content(List.of(new McpSchema.TextContent(content)))
true); .isError(true)
.build();
} }
// Validate the result against the output schema // Validate the result against the output schema
@ -410,7 +410,10 @@ public class McpAsyncServer {
if (!validation.valid()) { if (!validation.valid()) {
logger.warn("Tool call result validation failed: {}", validation.errorMessage()); logger.warn("Tool call result validation failed: {}", validation.errorMessage());
return new CallToolResult(validation.errorMessage(), true); return CallToolResult.builder()
.content(List.of(new McpSchema.TextContent(validation.errorMessage())))
.isError(true)
.build();
} }
if (Utils.isEmpty(result.content())) { if (Utils.isEmpty(result.content())) {

View file

@ -67,7 +67,10 @@ import reactor.core.publisher.Mono;
* McpServer.sync(transportProvider) * McpServer.sync(transportProvider)
* .serverInfo("my-server", "1.0.0") * .serverInfo("my-server", "1.0.0")
* .tool(Tool.builder().name("calculator").title("Performs calculations").inputSchema(schema).build(), * .tool(Tool.builder().name("calculator").title("Performs calculations").inputSchema(schema).build(),
* (exchange, args) -> new CallToolResult("Result: " + calculate(args))) * (exchange, args) -> CallToolResult.builder()
* .content(List.of(new McpSchema.TextContent("Result: " + calculate(args))))
* .isError(false)
* .build())
* .build(); * .build();
* }</pre> * }</pre>
* *
@ -76,7 +79,10 @@ import reactor.core.publisher.Mono;
* .serverInfo("my-server", "1.0.0") * .serverInfo("my-server", "1.0.0")
* .tool(Tool.builder().name("calculator").title("Performs calculations").inputSchema(schema).build(), * .tool(Tool.builder().name("calculator").title("Performs calculations").inputSchema(schema).build(),
* (exchange, args) -> Mono.fromSupplier(() -> calculate(args)) * (exchange, args) -> Mono.fromSupplier(() -> calculate(args))
* .map(result -> new CallToolResult("Result: " + result))) * .map(result -> CallToolResult.builder()
* .content(List.of(new McpSchema.TextContent("Result: " + result)))
* .isError(false)
* .build()))
* .build(); * .build();
* }</pre> * }</pre>
* *
@ -90,12 +96,18 @@ import reactor.core.publisher.Mono;
* McpServerFeatures.AsyncToolSpecification.builder() * McpServerFeatures.AsyncToolSpecification.builder()
* .tool(calculatorTool) * .tool(calculatorTool)
* .callTool((exchange, args) -> Mono.fromSupplier(() -> calculate(args.arguments())) * .callTool((exchange, args) -> Mono.fromSupplier(() -> calculate(args.arguments()))
* .map(result -> new CallToolResult("Result: " + result)))) * .map(result -> CallToolResult.builder()
* .content(List.of(new McpSchema.TextContent("Result: " + result)))
* .isError(false)
* .build()))
*. .build(), *. .build(),
* McpServerFeatures.AsyncToolSpecification.builder() * McpServerFeatures.AsyncToolSpecification.builder()
* .tool((weatherTool) * .tool((weatherTool)
* .callTool((exchange, args) -> Mono.fromSupplier(() -> getWeather(args.arguments())) * .callTool((exchange, args) -> Mono.fromSupplier(() -> getWeather(args.arguments()))
* .map(result -> new CallToolResult("Weather: " + result)))) * .map(result -> CallToolResult.builder()
* .content(List.of(new McpSchema.TextContent("Weather: " + result)))
* .isError(false)
* .build()))
* .build() * .build()
* ) * )
* // Register resources * // Register resources
@ -425,7 +437,10 @@ public interface McpServer {
* .tool( * .tool(
* Tool.builder().name("calculator").title("Performs calculations").inputSchema(schema).build(), * Tool.builder().name("calculator").title("Performs calculations").inputSchema(schema).build(),
* (exchange, args) -> Mono.fromSupplier(() -> calculate(args)) * (exchange, args) -> Mono.fromSupplier(() -> calculate(args))
* .map(result -> new CallToolResult("Result: " + result)) * .map(result -> CallToolResult.builder()
* .content(List.of(new McpSchema.TextContent("Result: " + result)))
* .isError(false)
* .build()))
* ) * )
* }</pre> * }</pre>
* @param tool The tool definition including name, description, and schema. Must * @param tool The tool definition including name, description, and schema. Must
@ -1022,7 +1037,10 @@ public interface McpServer {
* Example usage: <pre>{@code * Example usage: <pre>{@code
* .tool( * .tool(
* Tool.builder().name("calculator").title("Performs calculations".inputSchema(schema).build(), * Tool.builder().name("calculator").title("Performs calculations".inputSchema(schema).build(),
* (exchange, args) -> new CallToolResult("Result: " + calculate(args)) * (exchange, args) -> CallToolResult.builder()
* .content(List.of(new McpSchema.TextContent("Result: " + calculate(args))))
* .isError(false)
* .build())
* ) * )
* }</pre> * }</pre>
* @param tool The tool definition including name, description, and schema. Must * @param tool The tool definition including name, description, and schema. Must

View file

@ -334,7 +334,13 @@ public class McpServerFeatures {
* *
* <pre>{@code * <pre>{@code
* new McpServerFeatures.AsyncResourceSpecification( * new McpServerFeatures.AsyncResourceSpecification(
* new Resource("docs", "Documentation files", "text/markdown"), * Resource.builder()
* .uri("docs")
* .name("Documentation files")
* .title("Documentation files")
* .mimeType("text/markdown")
* .description("Markdown documentation files")
* .build(),
* (exchange, request) -> Mono.fromSupplier(() -> readFile(request.getPath())) * (exchange, request) -> Mono.fromSupplier(() -> readFile(request.getPath()))
* .map(ReadResourceResult::new)) * .map(ReadResourceResult::new))
* }</pre> * }</pre>
@ -508,7 +514,10 @@ public class McpServerFeatures {
* .build() * .build()
* .toolHandler((exchange, req) -> { * .toolHandler((exchange, req) -> {
* String expr = (String) req.arguments().get("expression"); * String expr = (String) req.arguments().get("expression");
* return new CallToolResult("Result: " + evaluate(expr)); * return CallToolResult.builder()
* .content(List.of(new McpSchema.TextContent("Result: " + evaluate(expr))))
* .isError(false)
* .build();
* })) * }))
* .build(); * .build();
* }</pre> * }</pre>
@ -604,7 +613,13 @@ public class McpServerFeatures {
* *
* <pre>{@code * <pre>{@code
* new McpServerFeatures.SyncResourceSpecification( * new McpServerFeatures.SyncResourceSpecification(
* new Resource("docs", "Documentation files", "text/markdown"), * Resource.builder()
* .uri("docs")
* .name("Documentation files")
* .title("Documentation files")
* .mimeType("text/markdown")
* .description("Markdown documentation files")
* .build(),
* (exchange, request) -> { * (exchange, request) -> {
* String content = readFile(request.getPath()); * String content = readFile(request.getPath());
* return new ReadResourceResult(content); * return new ReadResourceResult(content);

View file

@ -14,7 +14,6 @@ import io.modelcontextprotocol.spec.McpSchema;
import io.modelcontextprotocol.spec.McpSchema.CallToolResult; import io.modelcontextprotocol.spec.McpSchema.CallToolResult;
import io.modelcontextprotocol.spec.McpSchema.CompleteResult.CompleteCompletion; import io.modelcontextprotocol.spec.McpSchema.CompleteResult.CompleteCompletion;
import io.modelcontextprotocol.spec.McpSchema.ErrorCodes; import io.modelcontextprotocol.spec.McpSchema.ErrorCodes;
import io.modelcontextprotocol.spec.McpSchema.JSONRPCResponse;
import io.modelcontextprotocol.spec.McpSchema.PromptReference; import io.modelcontextprotocol.spec.McpSchema.PromptReference;
import io.modelcontextprotocol.spec.McpSchema.ResourceReference; import io.modelcontextprotocol.spec.McpSchema.ResourceReference;
import io.modelcontextprotocol.spec.McpSchema.Tool; import io.modelcontextprotocol.spec.McpSchema.Tool;
@ -277,11 +276,12 @@ public class McpStatelessAsyncServer {
// results that conform to this schema. // results that conform to this schema.
// https://modelcontextprotocol.io/specification/2025-06-18/server/tools#output-schema // https://modelcontextprotocol.io/specification/2025-06-18/server/tools#output-schema
if (result.structuredContent() == null) { if (result.structuredContent() == null) {
logger.warn( String content = "Response missing structured content which is expected when calling tool with non-empty outputSchema";
"Response missing structured content which is expected when calling tool with non-empty outputSchema"); logger.warn(content);
return new CallToolResult( return CallToolResult.builder()
"Response missing structured content which is expected when calling tool with non-empty outputSchema", .content(List.of(new McpSchema.TextContent(content)))
true); .isError(true)
.build();
} }
// Validate the result against the output schema // Validate the result against the output schema
@ -289,7 +289,10 @@ public class McpStatelessAsyncServer {
if (!validation.valid()) { if (!validation.valid()) {
logger.warn("Tool call result validation failed: {}", validation.errorMessage()); logger.warn("Tool call result validation failed: {}", validation.errorMessage());
return new CallToolResult(validation.errorMessage(), true); return CallToolResult.builder()
.content(List.of(new McpSchema.TextContent(validation.errorMessage())))
.isError(true)
.build();
} }
if (Utils.isEmpty(result.content())) { if (Utils.isEmpty(result.content())) {

View file

@ -1562,6 +1562,7 @@ public final class McpSchema {
* content contains error information. If false or absent, indicates successful * content contains error information. If false or absent, indicates successful
* execution. * execution.
*/ */
@Deprecated
public CallToolResult(String content, Boolean isError) { public CallToolResult(String content, Boolean isError) {
this(List.of(new TextContent(content)), isError, null); this(List.of(new TextContent(content)), isError, null);
} }
@ -1676,7 +1677,7 @@ public final class McpSchema {
* @return a new CallToolResult instance * @return a new CallToolResult instance
*/ */
public CallToolResult build() { public CallToolResult build() {
return new CallToolResult(content, isError, (Object) structuredContent, meta); return new CallToolResult(content, isError, structuredContent, meta);
} }
} }

View file

@ -7,7 +7,6 @@ package io.modelcontextprotocol.server;
import java.time.Duration; import java.time.Duration;
import java.util.List; import java.util.List;
import io.modelcontextprotocol.spec.McpError;
import io.modelcontextprotocol.spec.McpSchema; import io.modelcontextprotocol.spec.McpSchema;
import io.modelcontextprotocol.spec.McpSchema.CallToolResult; import io.modelcontextprotocol.spec.McpSchema.CallToolResult;
import io.modelcontextprotocol.spec.McpSchema.GetPromptResult; import io.modelcontextprotocol.spec.McpSchema.GetPromptResult;
@ -86,7 +85,7 @@ public abstract class AbstractMcpAsyncServerTests {
void testImmediateClose() { void testImmediateClose() {
var mcpAsyncServer = prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0").build(); var mcpAsyncServer = prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0").build();
assertThatCode(() -> mcpAsyncServer.close()).doesNotThrowAnyException(); assertThatCode(mcpAsyncServer::close).doesNotThrowAnyException();
} }
// --------------------------------------- // ---------------------------------------
@ -104,8 +103,9 @@ public abstract class AbstractMcpAsyncServerTests {
.capabilities(ServerCapabilities.builder().tools(true).build()) .capabilities(ServerCapabilities.builder().tools(true).build())
.build(); .build();
StepVerifier.create(mcpAsyncServer.addTool(new McpServerFeatures.AsyncToolSpecification(newTool, StepVerifier
(exchange, args) -> Mono.just(new CallToolResult(List.of(), false))))) .create(mcpAsyncServer.addTool(new McpServerFeatures.AsyncToolSpecification(newTool,
(exchange, args) -> Mono.just(CallToolResult.builder().content(List.of()).isError(false).build()))))
.verifyComplete(); .verifyComplete();
assertThatCode(() -> mcpAsyncServer.closeGracefully().block(Duration.ofSeconds(10))).doesNotThrowAnyException(); assertThatCode(() -> mcpAsyncServer.closeGracefully().block(Duration.ofSeconds(10))).doesNotThrowAnyException();
@ -125,7 +125,8 @@ public abstract class AbstractMcpAsyncServerTests {
StepVerifier.create(mcpAsyncServer.addTool(McpServerFeatures.AsyncToolSpecification.builder() StepVerifier.create(mcpAsyncServer.addTool(McpServerFeatures.AsyncToolSpecification.builder()
.tool(newTool) .tool(newTool)
.callHandler((exchange, request) -> Mono.just(new CallToolResult(List.of(), false))) .callHandler((exchange, request) -> Mono
.just(CallToolResult.builder().content(List.of()).isError(false).build()))
.build())).verifyComplete(); .build())).verifyComplete();
assertThatCode(() -> mcpAsyncServer.closeGracefully().block(Duration.ofSeconds(10))).doesNotThrowAnyException(); assertThatCode(() -> mcpAsyncServer.closeGracefully().block(Duration.ofSeconds(10))).doesNotThrowAnyException();
@ -142,11 +143,13 @@ public abstract class AbstractMcpAsyncServerTests {
var mcpAsyncServer = prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0") var mcpAsyncServer = prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0")
.capabilities(ServerCapabilities.builder().tools(true).build()) .capabilities(ServerCapabilities.builder().tools(true).build())
.tool(duplicateTool, (exchange, args) -> Mono.just(new CallToolResult(List.of(), false))) .tool(duplicateTool,
(exchange, args) -> Mono.just(CallToolResult.builder().content(List.of()).isError(false).build()))
.build(); .build();
StepVerifier.create(mcpAsyncServer.addTool(new McpServerFeatures.AsyncToolSpecification(duplicateTool, StepVerifier
(exchange, args) -> Mono.just(new CallToolResult(List.of(), false))))) .create(mcpAsyncServer.addTool(new McpServerFeatures.AsyncToolSpecification(duplicateTool,
(exchange, args) -> Mono.just(CallToolResult.builder().content(List.of()).isError(false).build()))))
.verifyComplete(); .verifyComplete();
assertThatCode(() -> mcpAsyncServer.closeGracefully().block(Duration.ofSeconds(10))).doesNotThrowAnyException(); assertThatCode(() -> mcpAsyncServer.closeGracefully().block(Duration.ofSeconds(10))).doesNotThrowAnyException();
@ -162,12 +165,15 @@ public abstract class AbstractMcpAsyncServerTests {
var mcpAsyncServer = prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0") var mcpAsyncServer = prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0")
.capabilities(ServerCapabilities.builder().tools(true).build()) .capabilities(ServerCapabilities.builder().tools(true).build())
.toolCall(duplicateTool, (exchange, request) -> Mono.just(new CallToolResult(List.of(), false))) .toolCall(duplicateTool,
(exchange, request) -> Mono
.just(CallToolResult.builder().content(List.of()).isError(false).build()))
.build(); .build();
StepVerifier.create(mcpAsyncServer.addTool(McpServerFeatures.AsyncToolSpecification.builder() StepVerifier.create(mcpAsyncServer.addTool(McpServerFeatures.AsyncToolSpecification.builder()
.tool(duplicateTool) .tool(duplicateTool)
.callHandler((exchange, request) -> Mono.just(new CallToolResult(List.of(), false))) .callHandler((exchange, request) -> Mono
.just(CallToolResult.builder().content(List.of()).isError(false).build()))
.build())).verifyComplete(); .build())).verifyComplete();
assertThatCode(() -> mcpAsyncServer.closeGracefully().block(Duration.ofSeconds(10))).doesNotThrowAnyException(); assertThatCode(() -> mcpAsyncServer.closeGracefully().block(Duration.ofSeconds(10))).doesNotThrowAnyException();
@ -183,8 +189,12 @@ public abstract class AbstractMcpAsyncServerTests {
assertThatThrownBy(() -> prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0") assertThatThrownBy(() -> prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0")
.capabilities(ServerCapabilities.builder().tools(true).build()) .capabilities(ServerCapabilities.builder().tools(true).build())
.toolCall(duplicateTool, (exchange, request) -> Mono.just(new CallToolResult(List.of(), false))) .toolCall(duplicateTool,
.toolCall(duplicateTool, (exchange, request) -> Mono.just(new CallToolResult(List.of(), false))) // Duplicate! (exchange, request) -> Mono
.just(CallToolResult.builder().content(List.of()).isError(false).build()))
.toolCall(duplicateTool,
(exchange, request) -> Mono
.just(CallToolResult.builder().content(List.of()).isError(false).build())) // Duplicate!
.build()).isInstanceOf(IllegalArgumentException.class) .build()).isInstanceOf(IllegalArgumentException.class)
.hasMessage("Tool with name 'duplicate-build-toolcall' is already registered."); .hasMessage("Tool with name 'duplicate-build-toolcall' is already registered.");
} }
@ -200,11 +210,13 @@ public abstract class AbstractMcpAsyncServerTests {
List<McpServerFeatures.AsyncToolSpecification> specs = List.of( List<McpServerFeatures.AsyncToolSpecification> specs = List.of(
McpServerFeatures.AsyncToolSpecification.builder() McpServerFeatures.AsyncToolSpecification.builder()
.tool(duplicateTool) .tool(duplicateTool)
.callHandler((exchange, request) -> Mono.just(new CallToolResult(List.of(), false))) .callHandler((exchange, request) -> Mono
.just(CallToolResult.builder().content(List.of()).isError(false).build()))
.build(), .build(),
McpServerFeatures.AsyncToolSpecification.builder() McpServerFeatures.AsyncToolSpecification.builder()
.tool(duplicateTool) .tool(duplicateTool)
.callHandler((exchange, request) -> Mono.just(new CallToolResult(List.of(), false))) .callHandler((exchange, request) -> Mono
.just(CallToolResult.builder().content(List.of()).isError(false).build()))
.build() // Duplicate! .build() // Duplicate!
); );
@ -227,11 +239,13 @@ public abstract class AbstractMcpAsyncServerTests {
.capabilities(ServerCapabilities.builder().tools(true).build()) .capabilities(ServerCapabilities.builder().tools(true).build())
.tools(McpServerFeatures.AsyncToolSpecification.builder() .tools(McpServerFeatures.AsyncToolSpecification.builder()
.tool(duplicateTool) .tool(duplicateTool)
.callHandler((exchange, request) -> Mono.just(new CallToolResult(List.of(), false))) .callHandler((exchange, request) -> Mono
.just(CallToolResult.builder().content(List.of()).isError(false).build()))
.build(), .build(),
McpServerFeatures.AsyncToolSpecification.builder() McpServerFeatures.AsyncToolSpecification.builder()
.tool(duplicateTool) .tool(duplicateTool)
.callHandler((exchange, request) -> Mono.just(new CallToolResult(List.of(), false))) .callHandler((exchange, request) -> Mono
.just(CallToolResult.builder().content(List.of()).isError(false).build()))
.build() // Duplicate! .build() // Duplicate!
) )
.build()).isInstanceOf(IllegalArgumentException.class) .build()).isInstanceOf(IllegalArgumentException.class)
@ -248,7 +262,9 @@ public abstract class AbstractMcpAsyncServerTests {
var mcpAsyncServer = prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0") var mcpAsyncServer = prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0")
.capabilities(ServerCapabilities.builder().tools(true).build()) .capabilities(ServerCapabilities.builder().tools(true).build())
.toolCall(too, (exchange, request) -> Mono.just(new CallToolResult(List.of(), false))) .toolCall(too,
(exchange, request) -> Mono
.just(CallToolResult.builder().content(List.of()).isError(false).build()))
.build(); .build();
StepVerifier.create(mcpAsyncServer.removeTool(TEST_TOOL_NAME)).verifyComplete(); StepVerifier.create(mcpAsyncServer.removeTool(TEST_TOOL_NAME)).verifyComplete();
@ -277,7 +293,8 @@ public abstract class AbstractMcpAsyncServerTests {
var mcpAsyncServer = prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0") var mcpAsyncServer = prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0")
.capabilities(ServerCapabilities.builder().tools(true).build()) .capabilities(ServerCapabilities.builder().tools(true).build())
.toolCall(too, (exchange, args) -> Mono.just(new CallToolResult(List.of(), false))) .toolCall(too,
(exchange, args) -> Mono.just(CallToolResult.builder().content(List.of()).isError(false).build()))
.build(); .build();
StepVerifier.create(mcpAsyncServer.notifyToolsListChanged()).verifyComplete(); StepVerifier.create(mcpAsyncServer.notifyToolsListChanged()).verifyComplete();
@ -316,8 +333,13 @@ public abstract class AbstractMcpAsyncServerTests {
.capabilities(ServerCapabilities.builder().resources(true, false).build()) .capabilities(ServerCapabilities.builder().resources(true, false).build())
.build(); .build();
Resource resource = new Resource(TEST_RESOURCE_URI, "Test Resource", "text/plain", "Test resource description", Resource resource = Resource.builder()
null); .uri(TEST_RESOURCE_URI)
.name("Test Resource")
.title("Test Resource")
.mimeType("text/plain")
.description("Test resource description")
.build();
McpServerFeatures.AsyncResourceSpecification specification = new McpServerFeatures.AsyncResourceSpecification( McpServerFeatures.AsyncResourceSpecification specification = new McpServerFeatures.AsyncResourceSpecification(
resource, (exchange, req) -> Mono.just(new ReadResourceResult(List.of()))); resource, (exchange, req) -> Mono.just(new ReadResourceResult(List.of())));
@ -345,8 +367,13 @@ public abstract class AbstractMcpAsyncServerTests {
// Create a server without resource capabilities // Create a server without resource capabilities
McpAsyncServer serverWithoutResources = prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0").build(); McpAsyncServer serverWithoutResources = prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0").build();
Resource resource = new Resource(TEST_RESOURCE_URI, "Test Resource", "text/plain", "Test resource description", Resource resource = Resource.builder()
null); .uri(TEST_RESOURCE_URI)
.name("Test Resource")
.title("Test Resource")
.mimeType("text/plain")
.description("Test resource description")
.build();
McpServerFeatures.AsyncResourceSpecification specification = new McpServerFeatures.AsyncResourceSpecification( McpServerFeatures.AsyncResourceSpecification specification = new McpServerFeatures.AsyncResourceSpecification(
resource, (exchange, req) -> Mono.just(new ReadResourceResult(List.of()))); resource, (exchange, req) -> Mono.just(new ReadResourceResult(List.of())));
@ -373,8 +400,13 @@ public abstract class AbstractMcpAsyncServerTests {
.capabilities(ServerCapabilities.builder().resources(true, false).build()) .capabilities(ServerCapabilities.builder().resources(true, false).build())
.build(); .build();
Resource resource = new Resource(TEST_RESOURCE_URI, "Test Resource", "text/plain", "Test resource description", Resource resource = Resource.builder()
null); .uri(TEST_RESOURCE_URI)
.name("Test Resource")
.title("Test Resource")
.mimeType("text/plain")
.description("Test resource description")
.build();
McpServerFeatures.AsyncResourceSpecification specification = new McpServerFeatures.AsyncResourceSpecification( McpServerFeatures.AsyncResourceSpecification specification = new McpServerFeatures.AsyncResourceSpecification(
resource, (exchange, req) -> Mono.just(new ReadResourceResult(List.of()))); resource, (exchange, req) -> Mono.just(new ReadResourceResult(List.of())));
@ -392,8 +424,13 @@ public abstract class AbstractMcpAsyncServerTests {
.capabilities(ServerCapabilities.builder().resources(true, false).build()) .capabilities(ServerCapabilities.builder().resources(true, false).build())
.build(); .build();
Resource resource = new Resource(TEST_RESOURCE_URI, "Test Resource", "text/plain", "Test resource description", Resource resource = Resource.builder()
null); .uri(TEST_RESOURCE_URI)
.name("Test Resource")
.title("Test Resource")
.mimeType("text/plain")
.description("Test resource description")
.build();
McpServerFeatures.AsyncResourceSpecification specification = new McpServerFeatures.AsyncResourceSpecification( McpServerFeatures.AsyncResourceSpecification specification = new McpServerFeatures.AsyncResourceSpecification(
resource, (exchange, req) -> Mono.just(new ReadResourceResult(List.of()))); resource, (exchange, req) -> Mono.just(new ReadResourceResult(List.of())));

View file

@ -851,7 +851,7 @@ public abstract class AbstractMcpClientServerIntegrationTests {
@ParameterizedTest(name = "{0} : {displayName} ") @ParameterizedTest(name = "{0} : {displayName} ")
@MethodSource("clientsForTesting") @MethodSource("clientsForTesting")
void testToolCallSuccessWithTranportContextExtraction(String clientType) { void testToolCallSuccessWithTransportContextExtraction(String clientType) {
var clientBuilder = clientBuilders.get(clientType); var clientBuilder = clientBuilders.get(clientType);
@ -1077,7 +1077,10 @@ public abstract class AbstractMcpClientServerIntegrationTests {
.logger("test-logger") .logger("test-logger")
.data("Another error message") .data("Another error message")
.build())) .build()))
.thenReturn(new CallToolResult("Logging test completed", false)); .thenReturn(CallToolResult.builder()
.content(List.of(new McpSchema.TextContent("Logging test completed")))
.isError(false)
.build());
//@formatter:on //@formatter:on
}) })
.build(); .build();
@ -1172,7 +1175,10 @@ public abstract class AbstractMcpClientServerIntegrationTests {
0.0, 1.0, "Another processing started"))) 0.0, 1.0, "Another processing started")))
.then(exchange.progressNotification( .then(exchange.progressNotification(
new McpSchema.ProgressNotification(progressToken, 1.0, 1.0, "Processing completed"))) new McpSchema.ProgressNotification(progressToken, 1.0, 1.0, "Processing completed")))
.thenReturn(new CallToolResult(("Progress test completed"), false)); .thenReturn(CallToolResult.builder()
.content(List.of(new McpSchema.TextContent("Progress test completed")))
.isError(false)
.build());
}) })
.build(); .build();
@ -1326,7 +1332,10 @@ public abstract class AbstractMcpClientServerIntegrationTests {
assertThat(result).isNotNull(); assertThat(result).isNotNull();
}).then(Mono.fromCallable(() -> { }).then(Mono.fromCallable(() -> {
executionOrder.set(executionOrder.get() + "3"); executionOrder.set(executionOrder.get() + "3");
return new CallToolResult("Async ping test completed", false); return CallToolResult.builder()
.content(List.of(new McpSchema.TextContent("Async ping test completed")))
.isError(false)
.build();
})); }));
}) })
.build(); .build();

View file

@ -6,7 +6,6 @@ package io.modelcontextprotocol.server;
import java.util.List; import java.util.List;
import io.modelcontextprotocol.spec.McpError;
import io.modelcontextprotocol.spec.McpSchema; import io.modelcontextprotocol.spec.McpSchema;
import io.modelcontextprotocol.spec.McpSchema.CallToolResult; import io.modelcontextprotocol.spec.McpSchema.CallToolResult;
import io.modelcontextprotocol.spec.McpSchema.GetPromptResult; import io.modelcontextprotocol.spec.McpSchema.GetPromptResult;
@ -78,14 +77,14 @@ public abstract class AbstractMcpSyncServerTests {
void testGracefulShutdown() { void testGracefulShutdown() {
var mcpSyncServer = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0").build(); var mcpSyncServer = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0").build();
assertThatCode(() -> mcpSyncServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::closeGracefully).doesNotThrowAnyException();
} }
@Test @Test
void testImmediateClose() { void testImmediateClose() {
var mcpSyncServer = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0").build(); var mcpSyncServer = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0").build();
assertThatCode(() -> mcpSyncServer.close()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::close).doesNotThrowAnyException();
} }
@Test @Test
@ -94,7 +93,7 @@ public abstract class AbstractMcpSyncServerTests {
assertThat(mcpSyncServer.getAsyncServer()).isNotNull(); assertThat(mcpSyncServer.getAsyncServer()).isNotNull();
assertThatCode(() -> mcpSyncServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::closeGracefully).doesNotThrowAnyException();
} }
// --------------------------------------- // ---------------------------------------
@ -114,10 +113,10 @@ public abstract class AbstractMcpSyncServerTests {
.inputSchema(EMPTY_JSON_SCHEMA) .inputSchema(EMPTY_JSON_SCHEMA)
.build(); .build();
assertThatCode(() -> mcpSyncServer.addTool(new McpServerFeatures.SyncToolSpecification(newTool, assertThatCode(() -> mcpSyncServer.addTool(new McpServerFeatures.SyncToolSpecification(newTool,
(exchange, args) -> new CallToolResult(List.of(), false)))) (exchange, args) -> CallToolResult.builder().content(List.of()).isError(false).build())))
.doesNotThrowAnyException(); .doesNotThrowAnyException();
assertThatCode(() -> mcpSyncServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::closeGracefully).doesNotThrowAnyException();
} }
@Test @Test
@ -134,10 +133,10 @@ public abstract class AbstractMcpSyncServerTests {
assertThatCode(() -> mcpSyncServer.addTool(McpServerFeatures.SyncToolSpecification.builder() assertThatCode(() -> mcpSyncServer.addTool(McpServerFeatures.SyncToolSpecification.builder()
.tool(newTool) .tool(newTool)
.callHandler((exchange, request) -> new CallToolResult(List.of(), false)) .callHandler((exchange, request) -> CallToolResult.builder().content(List.of()).isError(false).build())
.build())).doesNotThrowAnyException(); .build())).doesNotThrowAnyException();
assertThatCode(() -> mcpSyncServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::closeGracefully).doesNotThrowAnyException();
} }
@Test @Test
@ -151,14 +150,14 @@ public abstract class AbstractMcpSyncServerTests {
var mcpSyncServer = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0") var mcpSyncServer = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0")
.capabilities(ServerCapabilities.builder().tools(true).build()) .capabilities(ServerCapabilities.builder().tools(true).build())
.tool(duplicateTool, (exchange, args) -> new CallToolResult(List.of(), false)) .tool(duplicateTool, (exchange, args) -> CallToolResult.builder().content(List.of()).isError(false).build())
.build(); .build();
assertThatCode(() -> mcpSyncServer.addTool(new McpServerFeatures.SyncToolSpecification(duplicateTool, assertThatCode(() -> mcpSyncServer.addTool(new McpServerFeatures.SyncToolSpecification(duplicateTool,
(exchange, args) -> new CallToolResult(List.of(), false)))) (exchange, args) -> CallToolResult.builder().content(List.of()).isError(false).build())))
.doesNotThrowAnyException(); .doesNotThrowAnyException();
assertThatCode(() -> mcpSyncServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::closeGracefully).doesNotThrowAnyException();
} }
@Test @Test
@ -171,15 +170,16 @@ public abstract class AbstractMcpSyncServerTests {
var mcpSyncServer = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0") var mcpSyncServer = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0")
.capabilities(ServerCapabilities.builder().tools(true).build()) .capabilities(ServerCapabilities.builder().tools(true).build())
.toolCall(duplicateTool, (exchange, request) -> new CallToolResult(List.of(), false)) .toolCall(duplicateTool,
(exchange, request) -> CallToolResult.builder().content(List.of()).isError(false).build())
.build(); .build();
assertThatCode(() -> mcpSyncServer.addTool(McpServerFeatures.SyncToolSpecification.builder() assertThatCode(() -> mcpSyncServer.addTool(McpServerFeatures.SyncToolSpecification.builder()
.tool(duplicateTool) .tool(duplicateTool)
.callHandler((exchange, request) -> new CallToolResult(List.of(), false)) .callHandler((exchange, request) -> CallToolResult.builder().content(List.of()).isError(false).build())
.build())).doesNotThrowAnyException(); .build())).doesNotThrowAnyException();
assertThatCode(() -> mcpSyncServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::closeGracefully).doesNotThrowAnyException();
} }
@Test @Test
@ -192,8 +192,10 @@ public abstract class AbstractMcpSyncServerTests {
assertThatThrownBy(() -> prepareSyncServerBuilder().serverInfo("test-server", "1.0.0") assertThatThrownBy(() -> prepareSyncServerBuilder().serverInfo("test-server", "1.0.0")
.capabilities(ServerCapabilities.builder().tools(true).build()) .capabilities(ServerCapabilities.builder().tools(true).build())
.toolCall(duplicateTool, (exchange, request) -> new CallToolResult(List.of(), false)) .toolCall(duplicateTool,
.toolCall(duplicateTool, (exchange, request) -> new CallToolResult(List.of(), false)) // Duplicate! (exchange, request) -> CallToolResult.builder().content(List.of()).isError(false).build())
.toolCall(duplicateTool,
(exchange, request) -> CallToolResult.builder().content(List.of()).isError(false).build()) // Duplicate!
.build()).isInstanceOf(IllegalArgumentException.class) .build()).isInstanceOf(IllegalArgumentException.class)
.hasMessage("Tool with name 'duplicate-build-toolcall' is already registered."); .hasMessage("Tool with name 'duplicate-build-toolcall' is already registered.");
} }
@ -208,11 +210,13 @@ public abstract class AbstractMcpSyncServerTests {
List<McpServerFeatures.SyncToolSpecification> specs = List.of( List<McpServerFeatures.SyncToolSpecification> specs = List.of(
McpServerFeatures.SyncToolSpecification.builder() McpServerFeatures.SyncToolSpecification.builder()
.tool(duplicateTool) .tool(duplicateTool)
.callHandler((exchange, request) -> new CallToolResult(List.of(), false)) .callHandler(
(exchange, request) -> CallToolResult.builder().content(List.of()).isError(false).build())
.build(), .build(),
McpServerFeatures.SyncToolSpecification.builder() McpServerFeatures.SyncToolSpecification.builder()
.tool(duplicateTool) .tool(duplicateTool)
.callHandler((exchange, request) -> new CallToolResult(List.of(), false)) .callHandler(
(exchange, request) -> CallToolResult.builder().content(List.of()).isError(false).build())
.build() // Duplicate! .build() // Duplicate!
); );
@ -235,11 +239,12 @@ public abstract class AbstractMcpSyncServerTests {
.capabilities(ServerCapabilities.builder().tools(true).build()) .capabilities(ServerCapabilities.builder().tools(true).build())
.tools(McpServerFeatures.SyncToolSpecification.builder() .tools(McpServerFeatures.SyncToolSpecification.builder()
.tool(duplicateTool) .tool(duplicateTool)
.callHandler((exchange, request) -> new CallToolResult(List.of(), false)) .callHandler((exchange, request) -> CallToolResult.builder().content(List.of()).isError(false).build())
.build(), .build(),
McpServerFeatures.SyncToolSpecification.builder() McpServerFeatures.SyncToolSpecification.builder()
.tool(duplicateTool) .tool(duplicateTool)
.callHandler((exchange, request) -> new CallToolResult(List.of(), false)) .callHandler((exchange,
request) -> CallToolResult.builder().content(List.of()).isError(false).build())
.build() // Duplicate! .build() // Duplicate!
) )
.build()).isInstanceOf(IllegalArgumentException.class) .build()).isInstanceOf(IllegalArgumentException.class)
@ -256,12 +261,12 @@ public abstract class AbstractMcpSyncServerTests {
var mcpSyncServer = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0") var mcpSyncServer = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0")
.capabilities(ServerCapabilities.builder().tools(true).build()) .capabilities(ServerCapabilities.builder().tools(true).build())
.toolCall(tool, (exchange, args) -> new CallToolResult(List.of(), false)) .toolCall(tool, (exchange, args) -> CallToolResult.builder().content(List.of()).isError(false).build())
.build(); .build();
assertThatCode(() -> mcpSyncServer.removeTool(TEST_TOOL_NAME)).doesNotThrowAnyException(); assertThatCode(() -> mcpSyncServer.removeTool(TEST_TOOL_NAME)).doesNotThrowAnyException();
assertThatCode(() -> mcpSyncServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::closeGracefully).doesNotThrowAnyException();
} }
@Test @Test
@ -272,16 +277,16 @@ public abstract class AbstractMcpSyncServerTests {
assertThatCode(() -> mcpSyncServer.removeTool("nonexistent-tool")).doesNotThrowAnyException(); assertThatCode(() -> mcpSyncServer.removeTool("nonexistent-tool")).doesNotThrowAnyException();
assertThatCode(() -> mcpSyncServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::closeGracefully).doesNotThrowAnyException();
} }
@Test @Test
void testNotifyToolsListChanged() { void testNotifyToolsListChanged() {
var mcpSyncServer = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0").build(); var mcpSyncServer = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0").build();
assertThatCode(() -> mcpSyncServer.notifyToolsListChanged()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::notifyToolsListChanged).doesNotThrowAnyException();
assertThatCode(() -> mcpSyncServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::closeGracefully).doesNotThrowAnyException();
} }
// --------------------------------------- // ---------------------------------------
@ -292,9 +297,9 @@ public abstract class AbstractMcpSyncServerTests {
void testNotifyResourcesListChanged() { void testNotifyResourcesListChanged() {
var mcpSyncServer = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0").build(); var mcpSyncServer = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0").build();
assertThatCode(() -> mcpSyncServer.notifyResourcesListChanged()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::notifyResourcesListChanged).doesNotThrowAnyException();
assertThatCode(() -> mcpSyncServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::closeGracefully).doesNotThrowAnyException();
} }
@Test @Test
@ -305,7 +310,7 @@ public abstract class AbstractMcpSyncServerTests {
.notifyResourcesUpdated(new McpSchema.ResourcesUpdatedNotification(TEST_RESOURCE_URI))) .notifyResourcesUpdated(new McpSchema.ResourcesUpdatedNotification(TEST_RESOURCE_URI)))
.doesNotThrowAnyException(); .doesNotThrowAnyException();
assertThatCode(() -> mcpSyncServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::closeGracefully).doesNotThrowAnyException();
} }
@Test @Test
@ -314,14 +319,18 @@ public abstract class AbstractMcpSyncServerTests {
.capabilities(ServerCapabilities.builder().resources(true, false).build()) .capabilities(ServerCapabilities.builder().resources(true, false).build())
.build(); .build();
Resource resource = new Resource(TEST_RESOURCE_URI, "Test Resource", "text/plain", "Test resource description", Resource resource = Resource.builder()
null); .uri(TEST_RESOURCE_URI)
.name("Test Resource")
.mimeType("text/plain")
.description("Test resource description")
.build();
McpServerFeatures.SyncResourceSpecification specification = new McpServerFeatures.SyncResourceSpecification( McpServerFeatures.SyncResourceSpecification specification = new McpServerFeatures.SyncResourceSpecification(
resource, (exchange, req) -> new ReadResourceResult(List.of())); resource, (exchange, req) -> new ReadResourceResult(List.of()));
assertThatCode(() -> mcpSyncServer.addResource(specification)).doesNotThrowAnyException(); assertThatCode(() -> mcpSyncServer.addResource(specification)).doesNotThrowAnyException();
assertThatCode(() -> mcpSyncServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::closeGracefully).doesNotThrowAnyException();
} }
@Test @Test
@ -334,15 +343,19 @@ public abstract class AbstractMcpSyncServerTests {
.isInstanceOf(IllegalArgumentException.class) .isInstanceOf(IllegalArgumentException.class)
.hasMessage("Resource must not be null"); .hasMessage("Resource must not be null");
assertThatCode(() -> mcpSyncServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::closeGracefully).doesNotThrowAnyException();
} }
@Test @Test
void testAddResourceWithoutCapability() { void testAddResourceWithoutCapability() {
var serverWithoutResources = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0").build(); var serverWithoutResources = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0").build();
Resource resource = new Resource(TEST_RESOURCE_URI, "Test Resource", "text/plain", "Test resource description", Resource resource = Resource.builder()
null); .uri(TEST_RESOURCE_URI)
.name("Test Resource")
.mimeType("text/plain")
.description("Test resource description")
.build();
McpServerFeatures.SyncResourceSpecification specification = new McpServerFeatures.SyncResourceSpecification( McpServerFeatures.SyncResourceSpecification specification = new McpServerFeatures.SyncResourceSpecification(
resource, (exchange, req) -> new ReadResourceResult(List.of())); resource, (exchange, req) -> new ReadResourceResult(List.of()));
@ -366,8 +379,12 @@ public abstract class AbstractMcpSyncServerTests {
.capabilities(ServerCapabilities.builder().resources(true, false).build()) .capabilities(ServerCapabilities.builder().resources(true, false).build())
.build(); .build();
Resource resource = new Resource(TEST_RESOURCE_URI, "Test Resource", "text/plain", "Test resource description", Resource resource = Resource.builder()
null); .uri(TEST_RESOURCE_URI)
.name("Test Resource")
.mimeType("text/plain")
.description("Test resource description")
.build();
McpServerFeatures.SyncResourceSpecification specification = new McpServerFeatures.SyncResourceSpecification( McpServerFeatures.SyncResourceSpecification specification = new McpServerFeatures.SyncResourceSpecification(
resource, (exchange, req) -> new ReadResourceResult(List.of())); resource, (exchange, req) -> new ReadResourceResult(List.of()));
@ -377,7 +394,7 @@ public abstract class AbstractMcpSyncServerTests {
assertThat(resources).hasSize(1); assertThat(resources).hasSize(1);
assertThat(resources.get(0).uri()).isEqualTo(TEST_RESOURCE_URI); assertThat(resources.get(0).uri()).isEqualTo(TEST_RESOURCE_URI);
assertThatCode(() -> mcpSyncServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::closeGracefully).doesNotThrowAnyException();
} }
@Test @Test
@ -386,15 +403,19 @@ public abstract class AbstractMcpSyncServerTests {
.capabilities(ServerCapabilities.builder().resources(true, false).build()) .capabilities(ServerCapabilities.builder().resources(true, false).build())
.build(); .build();
Resource resource = new Resource(TEST_RESOURCE_URI, "Test Resource", "text/plain", "Test resource description", Resource resource = Resource.builder()
null); .uri(TEST_RESOURCE_URI)
.name("Test Resource")
.mimeType("text/plain")
.description("Test resource description")
.build();
McpServerFeatures.SyncResourceSpecification specification = new McpServerFeatures.SyncResourceSpecification( McpServerFeatures.SyncResourceSpecification specification = new McpServerFeatures.SyncResourceSpecification(
resource, (exchange, req) -> new ReadResourceResult(List.of())); resource, (exchange, req) -> new ReadResourceResult(List.of()));
mcpSyncServer.addResource(specification); mcpSyncServer.addResource(specification);
assertThatCode(() -> mcpSyncServer.removeResource(TEST_RESOURCE_URI)).doesNotThrowAnyException(); assertThatCode(() -> mcpSyncServer.removeResource(TEST_RESOURCE_URI)).doesNotThrowAnyException();
assertThatCode(() -> mcpSyncServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::closeGracefully).doesNotThrowAnyException();
} }
@Test @Test
@ -407,7 +428,7 @@ public abstract class AbstractMcpSyncServerTests {
// as per the new implementation that just logs a warning // as per the new implementation that just logs a warning
assertThatCode(() -> mcpSyncServer.removeResource("nonexistent://resource")).doesNotThrowAnyException(); assertThatCode(() -> mcpSyncServer.removeResource("nonexistent://resource")).doesNotThrowAnyException();
assertThatCode(() -> mcpSyncServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::closeGracefully).doesNotThrowAnyException();
} }
// --------------------------------------- // ---------------------------------------
@ -432,7 +453,7 @@ public abstract class AbstractMcpSyncServerTests {
assertThatCode(() -> mcpSyncServer.addResourceTemplate(specification)).doesNotThrowAnyException(); assertThatCode(() -> mcpSyncServer.addResourceTemplate(specification)).doesNotThrowAnyException();
assertThatCode(() -> mcpSyncServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::closeGracefully).doesNotThrowAnyException();
} }
@Test @Test
@ -474,7 +495,7 @@ public abstract class AbstractMcpSyncServerTests {
assertThatCode(() -> mcpSyncServer.removeResourceTemplate("test://template/{id}")).doesNotThrowAnyException(); assertThatCode(() -> mcpSyncServer.removeResourceTemplate("test://template/{id}")).doesNotThrowAnyException();
assertThatCode(() -> mcpSyncServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::closeGracefully).doesNotThrowAnyException();
} }
@Test @Test
@ -496,7 +517,7 @@ public abstract class AbstractMcpSyncServerTests {
assertThatCode(() -> mcpSyncServer.removeResourceTemplate("nonexistent://template/{id}")) assertThatCode(() -> mcpSyncServer.removeResourceTemplate("nonexistent://template/{id}"))
.doesNotThrowAnyException(); .doesNotThrowAnyException();
assertThatCode(() -> mcpSyncServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::closeGracefully).doesNotThrowAnyException();
} }
@Test @Test
@ -520,7 +541,7 @@ public abstract class AbstractMcpSyncServerTests {
assertThat(templates).isNotNull(); assertThat(templates).isNotNull();
assertThatCode(() -> mcpSyncServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::closeGracefully).doesNotThrowAnyException();
} }
// --------------------------------------- // ---------------------------------------
@ -531,9 +552,9 @@ public abstract class AbstractMcpSyncServerTests {
void testNotifyPromptsListChanged() { void testNotifyPromptsListChanged() {
var mcpSyncServer = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0").build(); var mcpSyncServer = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0").build();
assertThatCode(() -> mcpSyncServer.notifyPromptsListChanged()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::notifyPromptsListChanged).doesNotThrowAnyException();
assertThatCode(() -> mcpSyncServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::closeGracefully).doesNotThrowAnyException();
} }
@Test @Test
@ -584,7 +605,7 @@ public abstract class AbstractMcpSyncServerTests {
assertThatCode(() -> mcpSyncServer.removePrompt(TEST_PROMPT_NAME)).doesNotThrowAnyException(); assertThatCode(() -> mcpSyncServer.removePrompt(TEST_PROMPT_NAME)).doesNotThrowAnyException();
assertThatCode(() -> mcpSyncServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::closeGracefully).doesNotThrowAnyException();
} }
@Test @Test
@ -595,7 +616,7 @@ public abstract class AbstractMcpSyncServerTests {
assertThatCode(() -> mcpSyncServer.removePrompt("nonexistent://template/{id}")).doesNotThrowAnyException(); assertThatCode(() -> mcpSyncServer.removePrompt("nonexistent://template/{id}")).doesNotThrowAnyException();
assertThatCode(() -> mcpSyncServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::closeGracefully).doesNotThrowAnyException();
} }
// --------------------------------------- // ---------------------------------------
@ -617,7 +638,7 @@ public abstract class AbstractMcpSyncServerTests {
})) }))
.build(); .build();
assertThat(singleConsumerServer).isNotNull(); assertThat(singleConsumerServer).isNotNull();
assertThatCode(() -> singleConsumerServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(singleConsumerServer::closeGracefully).doesNotThrowAnyException();
onClose(); onClose();
// Test with multiple consumers // Test with multiple consumers
@ -633,7 +654,7 @@ public abstract class AbstractMcpSyncServerTests {
.build(); .build();
assertThat(multipleConsumersServer).isNotNull(); assertThat(multipleConsumersServer).isNotNull();
assertThatCode(() -> multipleConsumersServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(multipleConsumersServer::closeGracefully).doesNotThrowAnyException();
onClose(); onClose();
// Test error handling // Test error handling
@ -644,14 +665,14 @@ public abstract class AbstractMcpSyncServerTests {
.build(); .build();
assertThat(errorHandlingServer).isNotNull(); assertThat(errorHandlingServer).isNotNull();
assertThatCode(() -> errorHandlingServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(errorHandlingServer::closeGracefully).doesNotThrowAnyException();
onClose(); onClose();
// Test without consumers // Test without consumers
var noConsumersServer = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0").build(); var noConsumersServer = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0").build();
assertThat(noConsumersServer).isNotNull(); assertThat(noConsumersServer).isNotNull();
assertThatCode(() -> noConsumersServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(noConsumersServer::closeGracefully).doesNotThrowAnyException();
} }
} }

View file

@ -40,7 +40,7 @@ class AsyncToolSpecificationBuilderTest {
McpServerFeatures.AsyncToolSpecification specification = McpServerFeatures.AsyncToolSpecification.builder() McpServerFeatures.AsyncToolSpecification specification = McpServerFeatures.AsyncToolSpecification.builder()
.tool(tool) .tool(tool)
.callHandler((exchange, request) -> Mono .callHandler((exchange, request) -> Mono
.just(new CallToolResult(List.of(new TextContent("Test result")), false))) .just(CallToolResult.builder().content(List.of(new TextContent("Test result"))).isError(false).build()))
.build(); .build();
assertThat(specification).isNotNull(); assertThat(specification).isNotNull();
@ -52,7 +52,8 @@ class AsyncToolSpecificationBuilderTest {
@Test @Test
void builderShouldThrowExceptionWhenToolIsNull() { void builderShouldThrowExceptionWhenToolIsNull() {
assertThatThrownBy(() -> McpServerFeatures.AsyncToolSpecification.builder() assertThatThrownBy(() -> McpServerFeatures.AsyncToolSpecification.builder()
.callHandler((exchange, request) -> Mono.just(new CallToolResult(List.of(), false))) .callHandler((exchange, request) -> Mono
.just(CallToolResult.builder().content(List.of()).isError(false).build()))
.build()).isInstanceOf(IllegalArgumentException.class).hasMessage("Tool must not be null"); .build()).isInstanceOf(IllegalArgumentException.class).hasMessage("Tool must not be null");
} }
@ -80,7 +81,8 @@ class AsyncToolSpecificationBuilderTest {
// Then - verify method chaining returns the same builder instance // Then - verify method chaining returns the same builder instance
assertThat(builder.tool(tool)).isSameAs(builder); assertThat(builder.tool(tool)).isSameAs(builder);
assertThat(builder.callHandler((exchange, request) -> Mono.just(new CallToolResult(List.of(), false)))) assertThat(builder.callHandler(
(exchange, request) -> Mono.just(CallToolResult.builder().content(List.of()).isError(false).build())))
.isSameAs(builder); .isSameAs(builder);
} }
@ -96,7 +98,10 @@ class AsyncToolSpecificationBuilderTest {
McpServerFeatures.AsyncToolSpecification specification = McpServerFeatures.AsyncToolSpecification.builder() McpServerFeatures.AsyncToolSpecification specification = McpServerFeatures.AsyncToolSpecification.builder()
.tool(tool) .tool(tool)
.callHandler((exchange, request) -> { .callHandler((exchange, request) -> {
return Mono.just(new CallToolResult(List.of(new TextContent(expectedResult)), false)); return Mono.just(CallToolResult.builder()
.content(List.of(new TextContent(expectedResult)))
.isError(false)
.build());
}) })
.build(); .build();
@ -124,8 +129,11 @@ class AsyncToolSpecificationBuilderTest {
// Test the deprecated constructor that takes a 'call' function // Test the deprecated constructor that takes a 'call' function
McpServerFeatures.AsyncToolSpecification specification = new McpServerFeatures.AsyncToolSpecification(tool, McpServerFeatures.AsyncToolSpecification specification = new McpServerFeatures.AsyncToolSpecification(tool,
(exchange, arguments) -> Mono (exchange,
.just(new CallToolResult(List.of(new TextContent(expectedResult)), false))); arguments) -> Mono.just(CallToolResult.builder()
.content(List.of(new TextContent(expectedResult)))
.isError(false)
.build()));
assertThat(specification).isNotNull(); assertThat(specification).isNotNull();
assertThat(specification.tool()).isEqualTo(tool); assertThat(specification.tool()).isEqualTo(tool);
@ -169,7 +177,10 @@ class AsyncToolSpecificationBuilderTest {
// Create a sync tool specification // Create a sync tool specification
McpServerFeatures.SyncToolSpecification syncSpec = McpServerFeatures.SyncToolSpecification.builder() McpServerFeatures.SyncToolSpecification syncSpec = McpServerFeatures.SyncToolSpecification.builder()
.tool(tool) .tool(tool)
.callHandler((exchange, request) -> new CallToolResult(List.of(new TextContent(expectedResult)), false)) .callHandler((exchange, request) -> CallToolResult.builder()
.content(List.of(new TextContent(expectedResult)))
.isError(false)
.build())
.build(); .build();
// Convert to async using fromSync // Convert to async using fromSync
@ -209,7 +220,10 @@ class AsyncToolSpecificationBuilderTest {
// Create a sync tool specification using the deprecated constructor // Create a sync tool specification using the deprecated constructor
McpServerFeatures.SyncToolSpecification syncSpec = new McpServerFeatures.SyncToolSpecification(tool, McpServerFeatures.SyncToolSpecification syncSpec = new McpServerFeatures.SyncToolSpecification(tool,
(exchange, arguments) -> new CallToolResult(List.of(new TextContent(expectedResult)), false)); (exchange, arguments) -> CallToolResult.builder()
.content(List.of(new TextContent(expectedResult)))
.isError(false)
.build());
// Convert to async using fromSync // Convert to async using fromSync
McpServerFeatures.AsyncToolSpecification asyncSpec = McpServerFeatures.AsyncToolSpecification McpServerFeatures.AsyncToolSpecification asyncSpec = McpServerFeatures.AsyncToolSpecification

View file

@ -114,7 +114,10 @@ class HttpServletStatelessIntegrationTests {
var clientBuilder = clientBuilders.get(clientType); var clientBuilder = clientBuilders.get(clientType);
var callResponse = new CallToolResult(List.of(new McpSchema.TextContent("CALL RESPONSE")), null); var callResponse = CallToolResult.builder()
.content(List.of(new McpSchema.TextContent("CALL RESPONSE")))
.isError(false)
.build();
McpStatelessServerFeatures.SyncToolSpecification tool1 = new McpStatelessServerFeatures.SyncToolSpecification( McpStatelessServerFeatures.SyncToolSpecification tool1 = new McpStatelessServerFeatures.SyncToolSpecification(
Tool.builder().name("tool1").title("tool1 description").inputSchema(EMPTY_JSON_SCHEMA).build(), Tool.builder().name("tool1").title("tool1 description").inputSchema(EMPTY_JSON_SCHEMA).build(),
(transportContext, request) -> { (transportContext, request) -> {

View file

@ -32,7 +32,10 @@ class SyncToolSpecificationBuilderTest {
McpServerFeatures.SyncToolSpecification specification = McpServerFeatures.SyncToolSpecification.builder() McpServerFeatures.SyncToolSpecification specification = McpServerFeatures.SyncToolSpecification.builder()
.tool(tool) .tool(tool)
.callHandler((exchange, request) -> new CallToolResult(List.of(new TextContent("Test result")), false)) .callHandler((exchange, request) -> CallToolResult.builder()
.content(List.of(new TextContent("Test result")))
.isError(false)
.build())
.build(); .build();
assertThat(specification).isNotNull(); assertThat(specification).isNotNull();
@ -44,7 +47,7 @@ class SyncToolSpecificationBuilderTest {
@Test @Test
void builderShouldThrowExceptionWhenToolIsNull() { void builderShouldThrowExceptionWhenToolIsNull() {
assertThatThrownBy(() -> McpServerFeatures.SyncToolSpecification.builder() assertThatThrownBy(() -> McpServerFeatures.SyncToolSpecification.builder()
.callHandler((exchange, request) -> new CallToolResult(List.of(), false)) .callHandler((exchange, request) -> CallToolResult.builder().content(List.of()).isError(false).build())
.build()).isInstanceOf(IllegalArgumentException.class).hasMessage("Tool must not be null"); .build()).isInstanceOf(IllegalArgumentException.class).hasMessage("Tool must not be null");
} }
@ -64,7 +67,9 @@ class SyncToolSpecificationBuilderTest {
// Then - verify method chaining returns the same builder instance // Then - verify method chaining returns the same builder instance
assertThat(builder.tool(tool)).isSameAs(builder); assertThat(builder.tool(tool)).isSameAs(builder);
assertThat(builder.callHandler((exchange, request) -> new CallToolResult(List.of(), false))).isSameAs(builder); assertThat(builder
.callHandler((exchange, request) -> CallToolResult.builder().content(List.of()).isError(false).build()))
.isSameAs(builder);
} }
@Test @Test
@ -80,7 +85,10 @@ class SyncToolSpecificationBuilderTest {
.tool(tool) .tool(tool)
.callHandler((exchange, request) -> { .callHandler((exchange, request) -> {
// Simple test implementation // Simple test implementation
return new CallToolResult(List.of(new TextContent(expectedResult)), false); return CallToolResult.builder()
.content(List.of(new TextContent(expectedResult)))
.isError(false)
.build();
}) })
.build(); .build();

View file

@ -1081,7 +1081,10 @@ public abstract class AbstractMcpClientServerIntegrationTests {
.logger("test-logger") .logger("test-logger")
.data("Another error message") .data("Another error message")
.build())) .build()))
.thenReturn(new CallToolResult("Logging test completed", false)); .thenReturn(CallToolResult.builder()
.content(List.of(new McpSchema.TextContent("Logging test completed")))
.isError(false)
.build());
//@formatter:on //@formatter:on
}) })
.build(); .build();
@ -1176,7 +1179,10 @@ public abstract class AbstractMcpClientServerIntegrationTests {
0.0, 1.0, "Another processing started"))) 0.0, 1.0, "Another processing started")))
.then(exchange.progressNotification( .then(exchange.progressNotification(
new McpSchema.ProgressNotification(progressToken, 1.0, 1.0, "Processing completed"))) new McpSchema.ProgressNotification(progressToken, 1.0, 1.0, "Processing completed")))
.thenReturn(new CallToolResult(("Progress test completed"), false)); .thenReturn(CallToolResult.builder()
.content(List.of(new McpSchema.TextContent("Progress test completed")))
.isError(false)
.build());
}) })
.build(); .build();
@ -1330,7 +1336,10 @@ public abstract class AbstractMcpClientServerIntegrationTests {
assertThat(result).isNotNull(); assertThat(result).isNotNull();
}).then(Mono.fromCallable(() -> { }).then(Mono.fromCallable(() -> {
executionOrder.set(executionOrder.get() + "3"); executionOrder.set(executionOrder.get() + "3");
return new CallToolResult("Async ping test completed", false); return CallToolResult.builder()
.content(List.of(new McpSchema.TextContent("Async ping test completed")))
.isError(false)
.build();
})); }));
}) })
.build(); .build();

View file

@ -7,7 +7,6 @@ package io.modelcontextprotocol.server;
import java.time.Duration; import java.time.Duration;
import java.util.List; import java.util.List;
import io.modelcontextprotocol.spec.McpError;
import io.modelcontextprotocol.spec.McpSchema; import io.modelcontextprotocol.spec.McpSchema;
import io.modelcontextprotocol.spec.McpSchema.CallToolResult; import io.modelcontextprotocol.spec.McpSchema.CallToolResult;
import io.modelcontextprotocol.spec.McpSchema.GetPromptResult; import io.modelcontextprotocol.spec.McpSchema.GetPromptResult;
@ -90,7 +89,7 @@ public abstract class AbstractMcpAsyncServerTests {
void testImmediateClose() { void testImmediateClose() {
var mcpAsyncServer = prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0").build(); var mcpAsyncServer = prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0").build();
assertThatCode(() -> mcpAsyncServer.close()).doesNotThrowAnyException(); assertThatCode(mcpAsyncServer::close).doesNotThrowAnyException();
} }
// --------------------------------------- // ---------------------------------------
@ -108,8 +107,9 @@ public abstract class AbstractMcpAsyncServerTests {
.capabilities(ServerCapabilities.builder().tools(true).build()) .capabilities(ServerCapabilities.builder().tools(true).build())
.build(); .build();
StepVerifier.create(mcpAsyncServer.addTool(new McpServerFeatures.AsyncToolSpecification(newTool, StepVerifier
(exchange, args) -> Mono.just(new CallToolResult(List.of(), false))))) .create(mcpAsyncServer.addTool(new McpServerFeatures.AsyncToolSpecification(newTool,
(exchange, args) -> Mono.just(CallToolResult.builder().content(List.of()).isError(false).build()))))
.verifyComplete(); .verifyComplete();
assertThatCode(() -> mcpAsyncServer.closeGracefully().block(Duration.ofSeconds(10))).doesNotThrowAnyException(); assertThatCode(() -> mcpAsyncServer.closeGracefully().block(Duration.ofSeconds(10))).doesNotThrowAnyException();
@ -129,7 +129,8 @@ public abstract class AbstractMcpAsyncServerTests {
StepVerifier.create(mcpAsyncServer.addTool(McpServerFeatures.AsyncToolSpecification.builder() StepVerifier.create(mcpAsyncServer.addTool(McpServerFeatures.AsyncToolSpecification.builder()
.tool(newTool) .tool(newTool)
.callHandler((exchange, request) -> Mono.just(new CallToolResult(List.of(), false))) .callHandler((exchange, request) -> Mono
.just(CallToolResult.builder().content(List.of()).isError(false).build()))
.build())).verifyComplete(); .build())).verifyComplete();
assertThatCode(() -> mcpAsyncServer.closeGracefully().block(Duration.ofSeconds(10))).doesNotThrowAnyException(); assertThatCode(() -> mcpAsyncServer.closeGracefully().block(Duration.ofSeconds(10))).doesNotThrowAnyException();
@ -146,11 +147,13 @@ public abstract class AbstractMcpAsyncServerTests {
var mcpAsyncServer = prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0") var mcpAsyncServer = prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0")
.capabilities(ServerCapabilities.builder().tools(true).build()) .capabilities(ServerCapabilities.builder().tools(true).build())
.tool(duplicateTool, (exchange, args) -> Mono.just(new CallToolResult(List.of(), false))) .tool(duplicateTool,
(exchange, args) -> Mono.just(CallToolResult.builder().content(List.of()).isError(false).build()))
.build(); .build();
StepVerifier.create(mcpAsyncServer.addTool(new McpServerFeatures.AsyncToolSpecification(duplicateTool, StepVerifier
(exchange, args) -> Mono.just(new CallToolResult(List.of(), false))))) .create(mcpAsyncServer.addTool(new McpServerFeatures.AsyncToolSpecification(duplicateTool,
(exchange, args) -> Mono.just(CallToolResult.builder().content(List.of()).isError(false).build()))))
.verifyComplete(); .verifyComplete();
assertThatCode(() -> mcpAsyncServer.closeGracefully().block(Duration.ofSeconds(10))).doesNotThrowAnyException(); assertThatCode(() -> mcpAsyncServer.closeGracefully().block(Duration.ofSeconds(10))).doesNotThrowAnyException();
@ -166,12 +169,15 @@ public abstract class AbstractMcpAsyncServerTests {
var mcpAsyncServer = prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0") var mcpAsyncServer = prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0")
.capabilities(ServerCapabilities.builder().tools(true).build()) .capabilities(ServerCapabilities.builder().tools(true).build())
.toolCall(duplicateTool, (exchange, request) -> Mono.just(new CallToolResult(List.of(), false))) .toolCall(duplicateTool,
(exchange, request) -> Mono
.just(CallToolResult.builder().content(List.of()).isError(false).build()))
.build(); .build();
StepVerifier.create(mcpAsyncServer.addTool(McpServerFeatures.AsyncToolSpecification.builder() StepVerifier.create(mcpAsyncServer.addTool(McpServerFeatures.AsyncToolSpecification.builder()
.tool(duplicateTool) .tool(duplicateTool)
.callHandler((exchange, request) -> Mono.just(new CallToolResult(List.of(), false))) .callHandler((exchange, request) -> Mono
.just(CallToolResult.builder().content(List.of()).isError(false).build()))
.build())).verifyComplete(); .build())).verifyComplete();
assertThatCode(() -> mcpAsyncServer.closeGracefully().block(Duration.ofSeconds(10))).doesNotThrowAnyException(); assertThatCode(() -> mcpAsyncServer.closeGracefully().block(Duration.ofSeconds(10))).doesNotThrowAnyException();
@ -187,8 +193,12 @@ public abstract class AbstractMcpAsyncServerTests {
assertThatThrownBy(() -> prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0") assertThatThrownBy(() -> prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0")
.capabilities(ServerCapabilities.builder().tools(true).build()) .capabilities(ServerCapabilities.builder().tools(true).build())
.toolCall(duplicateTool, (exchange, request) -> Mono.just(new CallToolResult(List.of(), false))) .toolCall(duplicateTool,
.toolCall(duplicateTool, (exchange, request) -> Mono.just(new CallToolResult(List.of(), false))) // Duplicate! (exchange, request) -> Mono
.just(CallToolResult.builder().content(List.of()).isError(false).build()))
.toolCall(duplicateTool,
(exchange, request) -> Mono
.just(CallToolResult.builder().content(List.of()).isError(false).build())) // Duplicate!
.build()).isInstanceOf(IllegalArgumentException.class) .build()).isInstanceOf(IllegalArgumentException.class)
.hasMessage("Tool with name 'duplicate-build-toolcall' is already registered."); .hasMessage("Tool with name 'duplicate-build-toolcall' is already registered.");
} }
@ -204,11 +214,13 @@ public abstract class AbstractMcpAsyncServerTests {
List<McpServerFeatures.AsyncToolSpecification> specs = List.of( List<McpServerFeatures.AsyncToolSpecification> specs = List.of(
McpServerFeatures.AsyncToolSpecification.builder() McpServerFeatures.AsyncToolSpecification.builder()
.tool(duplicateTool) .tool(duplicateTool)
.callHandler((exchange, request) -> Mono.just(new CallToolResult(List.of(), false))) .callHandler((exchange, request) -> Mono
.just(CallToolResult.builder().content(List.of()).isError(false).build()))
.build(), .build(),
McpServerFeatures.AsyncToolSpecification.builder() McpServerFeatures.AsyncToolSpecification.builder()
.tool(duplicateTool) .tool(duplicateTool)
.callHandler((exchange, request) -> Mono.just(new CallToolResult(List.of(), false))) .callHandler((exchange, request) -> Mono
.just(CallToolResult.builder().content(List.of()).isError(false).build()))
.build() // Duplicate! .build() // Duplicate!
); );
@ -231,11 +243,13 @@ public abstract class AbstractMcpAsyncServerTests {
.capabilities(ServerCapabilities.builder().tools(true).build()) .capabilities(ServerCapabilities.builder().tools(true).build())
.tools(McpServerFeatures.AsyncToolSpecification.builder() .tools(McpServerFeatures.AsyncToolSpecification.builder()
.tool(duplicateTool) .tool(duplicateTool)
.callHandler((exchange, request) -> Mono.just(new CallToolResult(List.of(), false))) .callHandler((exchange, request) -> Mono
.just(CallToolResult.builder().content(List.of()).isError(false).build()))
.build(), .build(),
McpServerFeatures.AsyncToolSpecification.builder() McpServerFeatures.AsyncToolSpecification.builder()
.tool(duplicateTool) .tool(duplicateTool)
.callHandler((exchange, request) -> Mono.just(new CallToolResult(List.of(), false))) .callHandler((exchange, request) -> Mono
.just(CallToolResult.builder().content(List.of()).isError(false).build()))
.build() // Duplicate! .build() // Duplicate!
) )
.build()).isInstanceOf(IllegalArgumentException.class) .build()).isInstanceOf(IllegalArgumentException.class)
@ -252,7 +266,9 @@ public abstract class AbstractMcpAsyncServerTests {
var mcpAsyncServer = prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0") var mcpAsyncServer = prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0")
.capabilities(ServerCapabilities.builder().tools(true).build()) .capabilities(ServerCapabilities.builder().tools(true).build())
.toolCall(too, (exchange, request) -> Mono.just(new CallToolResult(List.of(), false))) .toolCall(too,
(exchange, request) -> Mono
.just(CallToolResult.builder().content(List.of()).isError(false).build()))
.build(); .build();
StepVerifier.create(mcpAsyncServer.removeTool(TEST_TOOL_NAME)).verifyComplete(); StepVerifier.create(mcpAsyncServer.removeTool(TEST_TOOL_NAME)).verifyComplete();
@ -281,7 +297,8 @@ public abstract class AbstractMcpAsyncServerTests {
var mcpAsyncServer = prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0") var mcpAsyncServer = prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0")
.capabilities(ServerCapabilities.builder().tools(true).build()) .capabilities(ServerCapabilities.builder().tools(true).build())
.toolCall(too, (exchange, args) -> Mono.just(new CallToolResult(List.of(), false))) .toolCall(too,
(exchange, args) -> Mono.just(CallToolResult.builder().content(List.of()).isError(false).build()))
.build(); .build();
StepVerifier.create(mcpAsyncServer.notifyToolsListChanged()).verifyComplete(); StepVerifier.create(mcpAsyncServer.notifyToolsListChanged()).verifyComplete();
@ -320,8 +337,13 @@ public abstract class AbstractMcpAsyncServerTests {
.capabilities(ServerCapabilities.builder().resources(true, false).build()) .capabilities(ServerCapabilities.builder().resources(true, false).build())
.build(); .build();
Resource resource = new Resource(TEST_RESOURCE_URI, "Test Resource", "text/plain", "Test resource description", Resource resource = Resource.builder()
null); .uri(TEST_RESOURCE_URI)
.name("Test Resource")
.title("Test Resource")
.mimeType("text/plain")
.description("Test resource description")
.build();
McpServerFeatures.AsyncResourceSpecification specification = new McpServerFeatures.AsyncResourceSpecification( McpServerFeatures.AsyncResourceSpecification specification = new McpServerFeatures.AsyncResourceSpecification(
resource, (exchange, req) -> Mono.just(new ReadResourceResult(List.of()))); resource, (exchange, req) -> Mono.just(new ReadResourceResult(List.of())));
@ -349,8 +371,13 @@ public abstract class AbstractMcpAsyncServerTests {
// Create a server without resource capabilities // Create a server without resource capabilities
McpAsyncServer serverWithoutResources = prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0").build(); McpAsyncServer serverWithoutResources = prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0").build();
Resource resource = new Resource(TEST_RESOURCE_URI, "Test Resource", "text/plain", "Test resource description", Resource resource = Resource.builder()
null); .uri(TEST_RESOURCE_URI)
.name("Test Resource")
.title("Test Resource")
.mimeType("text/plain")
.description("Test resource description")
.build();
McpServerFeatures.AsyncResourceSpecification specification = new McpServerFeatures.AsyncResourceSpecification( McpServerFeatures.AsyncResourceSpecification specification = new McpServerFeatures.AsyncResourceSpecification(
resource, (exchange, req) -> Mono.just(new ReadResourceResult(List.of()))); resource, (exchange, req) -> Mono.just(new ReadResourceResult(List.of())));
@ -377,8 +404,13 @@ public abstract class AbstractMcpAsyncServerTests {
.capabilities(ServerCapabilities.builder().resources(true, false).build()) .capabilities(ServerCapabilities.builder().resources(true, false).build())
.build(); .build();
Resource resource = new Resource(TEST_RESOURCE_URI, "Test Resource", "text/plain", "Test resource description", Resource resource = Resource.builder()
null); .uri(TEST_RESOURCE_URI)
.name("Test Resource")
.title("Test Resource")
.mimeType("text/plain")
.description("Test resource description")
.build();
McpServerFeatures.AsyncResourceSpecification specification = new McpServerFeatures.AsyncResourceSpecification( McpServerFeatures.AsyncResourceSpecification specification = new McpServerFeatures.AsyncResourceSpecification(
resource, (exchange, req) -> Mono.just(new ReadResourceResult(List.of()))); resource, (exchange, req) -> Mono.just(new ReadResourceResult(List.of())));
@ -396,8 +428,13 @@ public abstract class AbstractMcpAsyncServerTests {
.capabilities(ServerCapabilities.builder().resources(true, false).build()) .capabilities(ServerCapabilities.builder().resources(true, false).build())
.build(); .build();
Resource resource = new Resource(TEST_RESOURCE_URI, "Test Resource", "text/plain", "Test resource description", Resource resource = Resource.builder()
null); .uri(TEST_RESOURCE_URI)
.name("Test Resource")
.title("Test Resource")
.mimeType("text/plain")
.description("Test resource description")
.build();
McpServerFeatures.AsyncResourceSpecification specification = new McpServerFeatures.AsyncResourceSpecification( McpServerFeatures.AsyncResourceSpecification specification = new McpServerFeatures.AsyncResourceSpecification(
resource, (exchange, req) -> Mono.just(new ReadResourceResult(List.of()))); resource, (exchange, req) -> Mono.just(new ReadResourceResult(List.of())));

View file

@ -6,7 +6,6 @@ package io.modelcontextprotocol.server;
import java.util.List; import java.util.List;
import io.modelcontextprotocol.spec.McpError;
import io.modelcontextprotocol.spec.McpSchema; import io.modelcontextprotocol.spec.McpSchema;
import io.modelcontextprotocol.spec.McpSchema.CallToolResult; import io.modelcontextprotocol.spec.McpSchema.CallToolResult;
import io.modelcontextprotocol.spec.McpSchema.GetPromptResult; import io.modelcontextprotocol.spec.McpSchema.GetPromptResult;
@ -77,14 +76,14 @@ public abstract class AbstractMcpSyncServerTests {
void testGracefulShutdown() { void testGracefulShutdown() {
var mcpSyncServer = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0").build(); var mcpSyncServer = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0").build();
assertThatCode(() -> mcpSyncServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::closeGracefully).doesNotThrowAnyException();
} }
@Test @Test
void testImmediateClose() { void testImmediateClose() {
var mcpSyncServer = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0").build(); var mcpSyncServer = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0").build();
assertThatCode(() -> mcpSyncServer.close()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::close).doesNotThrowAnyException();
} }
@Test @Test
@ -93,7 +92,7 @@ public abstract class AbstractMcpSyncServerTests {
assertThat(mcpSyncServer.getAsyncServer()).isNotNull(); assertThat(mcpSyncServer.getAsyncServer()).isNotNull();
assertThatCode(() -> mcpSyncServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::closeGracefully).doesNotThrowAnyException();
} }
// --------------------------------------- // ---------------------------------------
@ -113,10 +112,10 @@ public abstract class AbstractMcpSyncServerTests {
.inputSchema(EMPTY_JSON_SCHEMA) .inputSchema(EMPTY_JSON_SCHEMA)
.build(); .build();
assertThatCode(() -> mcpSyncServer.addTool(new McpServerFeatures.SyncToolSpecification(newTool, assertThatCode(() -> mcpSyncServer.addTool(new McpServerFeatures.SyncToolSpecification(newTool,
(exchange, args) -> new CallToolResult(List.of(), false)))) (exchange, args) -> CallToolResult.builder().content(List.of()).isError(false).build())))
.doesNotThrowAnyException(); .doesNotThrowAnyException();
assertThatCode(() -> mcpSyncServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::closeGracefully).doesNotThrowAnyException();
} }
@Test @Test
@ -133,10 +132,10 @@ public abstract class AbstractMcpSyncServerTests {
assertThatCode(() -> mcpSyncServer.addTool(McpServerFeatures.SyncToolSpecification.builder() assertThatCode(() -> mcpSyncServer.addTool(McpServerFeatures.SyncToolSpecification.builder()
.tool(newTool) .tool(newTool)
.callHandler((exchange, request) -> new CallToolResult(List.of(), false)) .callHandler((exchange, request) -> CallToolResult.builder().content(List.of()).isError(false).build())
.build())).doesNotThrowAnyException(); .build())).doesNotThrowAnyException();
assertThatCode(() -> mcpSyncServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::closeGracefully).doesNotThrowAnyException();
} }
@Test @Test
@ -150,14 +149,14 @@ public abstract class AbstractMcpSyncServerTests {
var mcpSyncServer = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0") var mcpSyncServer = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0")
.capabilities(ServerCapabilities.builder().tools(true).build()) .capabilities(ServerCapabilities.builder().tools(true).build())
.tool(duplicateTool, (exchange, args) -> new CallToolResult(List.of(), false)) .tool(duplicateTool, (exchange, args) -> CallToolResult.builder().content(List.of()).isError(false).build())
.build(); .build();
assertThatCode(() -> mcpSyncServer.addTool(new McpServerFeatures.SyncToolSpecification(duplicateTool, assertThatCode(() -> mcpSyncServer.addTool(new McpServerFeatures.SyncToolSpecification(duplicateTool,
(exchange, args) -> new CallToolResult(List.of(), false)))) (exchange, args) -> CallToolResult.builder().content(List.of()).isError(false).build())))
.doesNotThrowAnyException(); .doesNotThrowAnyException();
assertThatCode(() -> mcpSyncServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::closeGracefully).doesNotThrowAnyException();
} }
@Test @Test
@ -170,15 +169,16 @@ public abstract class AbstractMcpSyncServerTests {
var mcpSyncServer = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0") var mcpSyncServer = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0")
.capabilities(ServerCapabilities.builder().tools(true).build()) .capabilities(ServerCapabilities.builder().tools(true).build())
.toolCall(duplicateTool, (exchange, request) -> new CallToolResult(List.of(), false)) .toolCall(duplicateTool,
(exchange, request) -> CallToolResult.builder().content(List.of()).isError(false).build())
.build(); .build();
assertThatCode(() -> mcpSyncServer.addTool(McpServerFeatures.SyncToolSpecification.builder() assertThatCode(() -> mcpSyncServer.addTool(McpServerFeatures.SyncToolSpecification.builder()
.tool(duplicateTool) .tool(duplicateTool)
.callHandler((exchange, request) -> new CallToolResult(List.of(), false)) .callHandler((exchange, request) -> CallToolResult.builder().content(List.of()).isError(false).build())
.build())).doesNotThrowAnyException(); .build())).doesNotThrowAnyException();
assertThatCode(() -> mcpSyncServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::closeGracefully).doesNotThrowAnyException();
} }
@Test @Test
@ -191,8 +191,10 @@ public abstract class AbstractMcpSyncServerTests {
assertThatThrownBy(() -> prepareSyncServerBuilder().serverInfo("test-server", "1.0.0") assertThatThrownBy(() -> prepareSyncServerBuilder().serverInfo("test-server", "1.0.0")
.capabilities(ServerCapabilities.builder().tools(true).build()) .capabilities(ServerCapabilities.builder().tools(true).build())
.toolCall(duplicateTool, (exchange, request) -> new CallToolResult(List.of(), false)) .toolCall(duplicateTool,
.toolCall(duplicateTool, (exchange, request) -> new CallToolResult(List.of(), false)) // Duplicate! (exchange, request) -> CallToolResult.builder().content(List.of()).isError(false).build())
.toolCall(duplicateTool,
(exchange, request) -> CallToolResult.builder().content(List.of()).isError(false).build()) // Duplicate!
.build()).isInstanceOf(IllegalArgumentException.class) .build()).isInstanceOf(IllegalArgumentException.class)
.hasMessage("Tool with name 'duplicate-build-toolcall' is already registered."); .hasMessage("Tool with name 'duplicate-build-toolcall' is already registered.");
} }
@ -207,11 +209,13 @@ public abstract class AbstractMcpSyncServerTests {
List<McpServerFeatures.SyncToolSpecification> specs = List.of( List<McpServerFeatures.SyncToolSpecification> specs = List.of(
McpServerFeatures.SyncToolSpecification.builder() McpServerFeatures.SyncToolSpecification.builder()
.tool(duplicateTool) .tool(duplicateTool)
.callHandler((exchange, request) -> new CallToolResult(List.of(), false)) .callHandler(
(exchange, request) -> CallToolResult.builder().content(List.of()).isError(false).build())
.build(), .build(),
McpServerFeatures.SyncToolSpecification.builder() McpServerFeatures.SyncToolSpecification.builder()
.tool(duplicateTool) .tool(duplicateTool)
.callHandler((exchange, request) -> new CallToolResult(List.of(), false)) .callHandler(
(exchange, request) -> CallToolResult.builder().content(List.of()).isError(false).build())
.build() // Duplicate! .build() // Duplicate!
); );
@ -234,11 +238,12 @@ public abstract class AbstractMcpSyncServerTests {
.capabilities(ServerCapabilities.builder().tools(true).build()) .capabilities(ServerCapabilities.builder().tools(true).build())
.tools(McpServerFeatures.SyncToolSpecification.builder() .tools(McpServerFeatures.SyncToolSpecification.builder()
.tool(duplicateTool) .tool(duplicateTool)
.callHandler((exchange, request) -> new CallToolResult(List.of(), false)) .callHandler((exchange, request) -> CallToolResult.builder().content(List.of()).isError(false).build())
.build(), .build(),
McpServerFeatures.SyncToolSpecification.builder() McpServerFeatures.SyncToolSpecification.builder()
.tool(duplicateTool) .tool(duplicateTool)
.callHandler((exchange, request) -> new CallToolResult(List.of(), false)) .callHandler((exchange,
request) -> CallToolResult.builder().content(List.of()).isError(false).build())
.build() // Duplicate! .build() // Duplicate!
) )
.build()).isInstanceOf(IllegalArgumentException.class) .build()).isInstanceOf(IllegalArgumentException.class)
@ -255,12 +260,12 @@ public abstract class AbstractMcpSyncServerTests {
var mcpSyncServer = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0") var mcpSyncServer = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0")
.capabilities(ServerCapabilities.builder().tools(true).build()) .capabilities(ServerCapabilities.builder().tools(true).build())
.toolCall(tool, (exchange, args) -> new CallToolResult(List.of(), false)) .toolCall(tool, (exchange, args) -> CallToolResult.builder().content(List.of()).isError(false).build())
.build(); .build();
assertThatCode(() -> mcpSyncServer.removeTool(TEST_TOOL_NAME)).doesNotThrowAnyException(); assertThatCode(() -> mcpSyncServer.removeTool(TEST_TOOL_NAME)).doesNotThrowAnyException();
assertThatCode(() -> mcpSyncServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::closeGracefully).doesNotThrowAnyException();
} }
@Test @Test
@ -271,16 +276,16 @@ public abstract class AbstractMcpSyncServerTests {
assertThatCode(() -> mcpSyncServer.removeTool("nonexistent-tool")).doesNotThrowAnyException(); assertThatCode(() -> mcpSyncServer.removeTool("nonexistent-tool")).doesNotThrowAnyException();
assertThatCode(() -> mcpSyncServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::closeGracefully).doesNotThrowAnyException();
} }
@Test @Test
void testNotifyToolsListChanged() { void testNotifyToolsListChanged() {
var mcpSyncServer = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0").build(); var mcpSyncServer = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0").build();
assertThatCode(() -> mcpSyncServer.notifyToolsListChanged()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::notifyToolsListChanged).doesNotThrowAnyException();
assertThatCode(() -> mcpSyncServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::closeGracefully).doesNotThrowAnyException();
} }
// --------------------------------------- // ---------------------------------------
@ -291,9 +296,9 @@ public abstract class AbstractMcpSyncServerTests {
void testNotifyResourcesListChanged() { void testNotifyResourcesListChanged() {
var mcpSyncServer = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0").build(); var mcpSyncServer = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0").build();
assertThatCode(() -> mcpSyncServer.notifyResourcesListChanged()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::notifyResourcesListChanged).doesNotThrowAnyException();
assertThatCode(() -> mcpSyncServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::closeGracefully).doesNotThrowAnyException();
} }
@Test @Test
@ -304,7 +309,7 @@ public abstract class AbstractMcpSyncServerTests {
.notifyResourcesUpdated(new McpSchema.ResourcesUpdatedNotification(TEST_RESOURCE_URI))) .notifyResourcesUpdated(new McpSchema.ResourcesUpdatedNotification(TEST_RESOURCE_URI)))
.doesNotThrowAnyException(); .doesNotThrowAnyException();
assertThatCode(() -> mcpSyncServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::closeGracefully).doesNotThrowAnyException();
} }
@Test @Test
@ -313,14 +318,19 @@ public abstract class AbstractMcpSyncServerTests {
.capabilities(ServerCapabilities.builder().resources(true, false).build()) .capabilities(ServerCapabilities.builder().resources(true, false).build())
.build(); .build();
Resource resource = new Resource(TEST_RESOURCE_URI, "Test Resource", "text/plain", "Test resource description", Resource resource = Resource.builder()
null); .uri(TEST_RESOURCE_URI)
.name("Test Resource")
.title("Test Resource")
.mimeType("text/plain")
.description("Test resource description")
.build();
McpServerFeatures.SyncResourceSpecification specification = new McpServerFeatures.SyncResourceSpecification( McpServerFeatures.SyncResourceSpecification specification = new McpServerFeatures.SyncResourceSpecification(
resource, (exchange, req) -> new ReadResourceResult(List.of())); resource, (exchange, req) -> new ReadResourceResult(List.of()));
assertThatCode(() -> mcpSyncServer.addResource(specification)).doesNotThrowAnyException(); assertThatCode(() -> mcpSyncServer.addResource(specification)).doesNotThrowAnyException();
assertThatCode(() -> mcpSyncServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::closeGracefully).doesNotThrowAnyException();
} }
@Test @Test
@ -333,15 +343,20 @@ public abstract class AbstractMcpSyncServerTests {
.isInstanceOf(IllegalArgumentException.class) .isInstanceOf(IllegalArgumentException.class)
.hasMessage("Resource must not be null"); .hasMessage("Resource must not be null");
assertThatCode(() -> mcpSyncServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::closeGracefully).doesNotThrowAnyException();
} }
@Test @Test
void testAddResourceWithoutCapability() { void testAddResourceWithoutCapability() {
var serverWithoutResources = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0").build(); var serverWithoutResources = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0").build();
Resource resource = new Resource(TEST_RESOURCE_URI, "Test Resource", "text/plain", "Test resource description", Resource resource = Resource.builder()
null); .uri(TEST_RESOURCE_URI)
.name("Test Resource")
.title("Test Resource")
.mimeType("text/plain")
.description("Test resource description")
.build();
McpServerFeatures.SyncResourceSpecification specification = new McpServerFeatures.SyncResourceSpecification( McpServerFeatures.SyncResourceSpecification specification = new McpServerFeatures.SyncResourceSpecification(
resource, (exchange, req) -> new ReadResourceResult(List.of())); resource, (exchange, req) -> new ReadResourceResult(List.of()));
@ -365,8 +380,13 @@ public abstract class AbstractMcpSyncServerTests {
.capabilities(ServerCapabilities.builder().resources(true, false).build()) .capabilities(ServerCapabilities.builder().resources(true, false).build())
.build(); .build();
Resource resource = new Resource(TEST_RESOURCE_URI, "Test Resource", "text/plain", "Test resource description", Resource resource = Resource.builder()
null); .uri(TEST_RESOURCE_URI)
.name("Test Resource")
.title("Test Resource")
.mimeType("text/plain")
.description("Test resource description")
.build();
McpServerFeatures.SyncResourceSpecification specification = new McpServerFeatures.SyncResourceSpecification( McpServerFeatures.SyncResourceSpecification specification = new McpServerFeatures.SyncResourceSpecification(
resource, (exchange, req) -> new ReadResourceResult(List.of())); resource, (exchange, req) -> new ReadResourceResult(List.of()));
@ -376,7 +396,7 @@ public abstract class AbstractMcpSyncServerTests {
assertThat(resources).hasSize(1); assertThat(resources).hasSize(1);
assertThat(resources.get(0).uri()).isEqualTo(TEST_RESOURCE_URI); assertThat(resources.get(0).uri()).isEqualTo(TEST_RESOURCE_URI);
assertThatCode(() -> mcpSyncServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::closeGracefully).doesNotThrowAnyException();
} }
@Test @Test
@ -385,15 +405,20 @@ public abstract class AbstractMcpSyncServerTests {
.capabilities(ServerCapabilities.builder().resources(true, false).build()) .capabilities(ServerCapabilities.builder().resources(true, false).build())
.build(); .build();
Resource resource = new Resource(TEST_RESOURCE_URI, "Test Resource", "text/plain", "Test resource description", Resource resource = Resource.builder()
null); .uri(TEST_RESOURCE_URI)
.name("Test Resource")
.title("Test Resource")
.mimeType("text/plain")
.description("Test resource description")
.build();
McpServerFeatures.SyncResourceSpecification specification = new McpServerFeatures.SyncResourceSpecification( McpServerFeatures.SyncResourceSpecification specification = new McpServerFeatures.SyncResourceSpecification(
resource, (exchange, req) -> new ReadResourceResult(List.of())); resource, (exchange, req) -> new ReadResourceResult(List.of()));
mcpSyncServer.addResource(specification); mcpSyncServer.addResource(specification);
assertThatCode(() -> mcpSyncServer.removeResource(TEST_RESOURCE_URI)).doesNotThrowAnyException(); assertThatCode(() -> mcpSyncServer.removeResource(TEST_RESOURCE_URI)).doesNotThrowAnyException();
assertThatCode(() -> mcpSyncServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::closeGracefully).doesNotThrowAnyException();
} }
@Test @Test
@ -406,7 +431,7 @@ public abstract class AbstractMcpSyncServerTests {
// as per the new implementation that just logs a warning // as per the new implementation that just logs a warning
assertThatCode(() -> mcpSyncServer.removeResource("nonexistent://resource")).doesNotThrowAnyException(); assertThatCode(() -> mcpSyncServer.removeResource("nonexistent://resource")).doesNotThrowAnyException();
assertThatCode(() -> mcpSyncServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::closeGracefully).doesNotThrowAnyException();
} }
// --------------------------------------- // ---------------------------------------
@ -431,7 +456,7 @@ public abstract class AbstractMcpSyncServerTests {
assertThatCode(() -> mcpSyncServer.addResourceTemplate(specification)).doesNotThrowAnyException(); assertThatCode(() -> mcpSyncServer.addResourceTemplate(specification)).doesNotThrowAnyException();
assertThatCode(() -> mcpSyncServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::closeGracefully).doesNotThrowAnyException();
} }
@Test @Test
@ -473,7 +498,7 @@ public abstract class AbstractMcpSyncServerTests {
assertThatCode(() -> mcpSyncServer.removeResourceTemplate("test://template/{id}")).doesNotThrowAnyException(); assertThatCode(() -> mcpSyncServer.removeResourceTemplate("test://template/{id}")).doesNotThrowAnyException();
assertThatCode(() -> mcpSyncServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::closeGracefully).doesNotThrowAnyException();
} }
@Test @Test
@ -495,7 +520,7 @@ public abstract class AbstractMcpSyncServerTests {
assertThatCode(() -> mcpSyncServer.removeResourceTemplate("nonexistent://template/{id}")) assertThatCode(() -> mcpSyncServer.removeResourceTemplate("nonexistent://template/{id}"))
.doesNotThrowAnyException(); .doesNotThrowAnyException();
assertThatCode(() -> mcpSyncServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::closeGracefully).doesNotThrowAnyException();
} }
@Test @Test
@ -519,7 +544,7 @@ public abstract class AbstractMcpSyncServerTests {
assertThat(templates).isNotNull(); assertThat(templates).isNotNull();
assertThatCode(() -> mcpSyncServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::closeGracefully).doesNotThrowAnyException();
} }
// --------------------------------------- // ---------------------------------------
@ -530,9 +555,9 @@ public abstract class AbstractMcpSyncServerTests {
void testNotifyPromptsListChanged() { void testNotifyPromptsListChanged() {
var mcpSyncServer = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0").build(); var mcpSyncServer = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0").build();
assertThatCode(() -> mcpSyncServer.notifyPromptsListChanged()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::notifyPromptsListChanged).doesNotThrowAnyException();
assertThatCode(() -> mcpSyncServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::closeGracefully).doesNotThrowAnyException();
} }
@Test @Test
@ -583,7 +608,7 @@ public abstract class AbstractMcpSyncServerTests {
assertThatCode(() -> mcpSyncServer.removePrompt(TEST_PROMPT_NAME)).doesNotThrowAnyException(); assertThatCode(() -> mcpSyncServer.removePrompt(TEST_PROMPT_NAME)).doesNotThrowAnyException();
assertThatCode(() -> mcpSyncServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::closeGracefully).doesNotThrowAnyException();
} }
@Test @Test
@ -594,7 +619,7 @@ public abstract class AbstractMcpSyncServerTests {
assertThatCode(() -> mcpSyncServer.removePrompt("nonexistent://template/{id}")).doesNotThrowAnyException(); assertThatCode(() -> mcpSyncServer.removePrompt("nonexistent://template/{id}")).doesNotThrowAnyException();
assertThatCode(() -> mcpSyncServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(mcpSyncServer::closeGracefully).doesNotThrowAnyException();
} }
// --------------------------------------- // ---------------------------------------
@ -616,7 +641,7 @@ public abstract class AbstractMcpSyncServerTests {
})) }))
.build(); .build();
assertThat(singleConsumerServer).isNotNull(); assertThat(singleConsumerServer).isNotNull();
assertThatCode(() -> singleConsumerServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(singleConsumerServer::closeGracefully).doesNotThrowAnyException();
onClose(); onClose();
// Test with multiple consumers // Test with multiple consumers
@ -632,7 +657,7 @@ public abstract class AbstractMcpSyncServerTests {
.build(); .build();
assertThat(multipleConsumersServer).isNotNull(); assertThat(multipleConsumersServer).isNotNull();
assertThatCode(() -> multipleConsumersServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(multipleConsumersServer::closeGracefully).doesNotThrowAnyException();
onClose(); onClose();
// Test error handling // Test error handling
@ -643,14 +668,14 @@ public abstract class AbstractMcpSyncServerTests {
.build(); .build();
assertThat(errorHandlingServer).isNotNull(); assertThat(errorHandlingServer).isNotNull();
assertThatCode(() -> errorHandlingServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(errorHandlingServer::closeGracefully).doesNotThrowAnyException();
onClose(); onClose();
// Test without consumers // Test without consumers
var noConsumersServer = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0").build(); var noConsumersServer = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0").build();
assertThat(noConsumersServer).isNotNull(); assertThat(noConsumersServer).isNotNull();
assertThatCode(() -> noConsumersServer.closeGracefully()).doesNotThrowAnyException(); assertThatCode(noConsumersServer::closeGracefully).doesNotThrowAnyException();
} }
} }