feat!: enforce required MCP spec fields in McpSchema; lenient wire deserialization (#928)
Every wire-serialized record in McpSchema now validates spec-required
fields at construction time. Wire deserialization is intentionally
lenient: a missing required field is replaced with a documented default
and a WARN is logged, instead of failing the parse. A required-first
builder convention is introduced across the schema so it is no longer
possible to obtain a builder that is missing required state.
Required-field guards
---------------------
Every wire record's compact constructor asserts non-null (and non-empty
for String identifiers like name, uri, uriTemplate, version) on its
spec-required components. Passing null now throws
IllegalArgumentException at construction time instead of silently
producing invalid JSON via @JsonInclude(NON_ABSENT). This applies to
the JSON-RPC envelopes, lifecycle types, resource/prompt/tool requests
and results, sampling and elicitation, content records, root, complete,
logging and progress notifications, and the two CompleteReference
implementations. See MIGRATION-2.0.md for the full list.
Lenient wire deserialization
----------------------------
For each of those records (except JSONRPCResponse.JSONRPCError, which
still fails fast) a @JsonCreator static `fromJson` factory substitutes
a documented default for any absent required field — "" for strings,
[] for collections, {} for maps, 0 / 0.0 for numerics, INFO for
LoggingLevel, USER for SamplingMessage.role, ASSISTANT for
CreateMessageResult.role, CANCEL for ElicitResult.action, {values=[]}
for CompleteResult.completion — and logs a WARN naming the field and
the value used. Application code can still observe a malformed message
and react, but the SDK no longer halts the conversation.
Builder convention
------------------
Records that have a builder gain a required-first factory method
`builder(req1, req2, …)`; setters for required fields are removed from
the builder so it cannot be left in an invalid state. Existing no-arg
`builder()` factories and required-field setters are kept where source
compatibility demands it but are marked @Deprecated. New builders are
also added for several records that previously had none (ProgressNotification,
JSONRPCError, CompleteRequest, list/result types, content records, ...).
JSON-RPC envelope ergonomics
----------------------------
Previously every JSON-RPC envelope had to be constructed via the
canonical record constructor and the literal "2.0" string had to be
threaded through every call site, e.g.
new JSONRPCRequest("2.0", "tools/call", id, params)
new JSONRPCResponse("2.0", id, result, null)
new JSONRPCResponse("2.0", id, null, new JSONRPCError(code, message, null))
Now:
new JSONRPCRequest("tools/call", id, params) // jsonrpc defaulted
new JSONRPCNotification("notifications/initialized") // params optional
JSONRPCResponse.result(id, result) // factory
JSONRPCResponse.error(id, new JSONRPCError(code, message)) // 2-arg error
JSONRPCResponse's compact constructor additionally enforces the
JSON-RPC invariant that exactly one of `result` / `error` is set —
previously the SDK could build envelopes that violated the protocol.
CompleteReference changes
-------------------------
- PromptReference.equals/hashCode now key on `name` only (previously
derived from identifier()+type()). Two refs with the same name but
different titles now compare equal — code using PromptReference as a
map/set key should be audited.
- PromptReference's compact constructor pins `type` to "ref/prompt"
and logs a WARN if the caller supplies a different non-null value.
The legacy two-arg `PromptReference(String type, String name)`
constructor remains @Deprecated.
- ResourceReference's record components are reduced from (type, uri)
to (uri) — positional construction breaks. The legacy
`ResourceReference(String type, String uri)` constructor stays
@Deprecated and ignores `type`.
- CompleteReference.identifier() is @Deprecated and now returns null
via a default method on the interface.
Tests / refactor
----------------
Conformance harness, integration tests, sample apps, and internal
callers were migrated to the new builder factories and convenience
constructors. No semantic changes to client/server runtime behaviour
beyond the McpSchema changes above.
Docs
----
- MIGRATION-2.0.md: required-field section now covers the broader
record set and the lenient-deserialization behaviour; PromptReference
WARN behaviour and ResourceReference component reduction are
documented; the JSON-RPC envelope section is rewritten to compare the
pre-2.0 surface with the new one.
- CONTRIBUTING.md: the "Evolving wire-serialized records" recipe is
split into two cases — adding a new optional field (existing rules)
and adding/maintaining a spec-required field (new rules covering
Assert in compact constructor, @JsonCreator fromJson with defaults
and WARN, required-first builder factory).
Signed-off-by: Dariusz Jędrzejczyk <2554306+chemicL@users.noreply.github.com>
This commit is contained in:
parent
599b43cac4
commit
22a0efa577
28 changed files with 4258 additions and 1688 deletions
|
|
@ -87,7 +87,8 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
.build();
|
||||
try (
|
||||
// Create client without sampling capabilities
|
||||
var client = clientBuilder.clientInfo(new McpSchema.Implementation("Sample " + "client", "0.0.0"))
|
||||
var client = clientBuilder
|
||||
.clientInfo(McpSchema.Implementation.builder("Sample " + "client", "0.0.0").build())
|
||||
.requestTimeout(Duration.ofSeconds(1000))
|
||||
.build()) {
|
||||
|
||||
|
|
@ -109,7 +110,7 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
var clientBuilder = clientBuilders.get(clientType);
|
||||
|
||||
McpServerFeatures.AsyncToolSpecification tool = McpServerFeatures.AsyncToolSpecification.builder()
|
||||
.tool(Tool.builder().name("tool1").description("tool1 description").inputSchema(EMPTY_JSON_SCHEMA).build())
|
||||
.tool(Tool.builder("tool1", EMPTY_JSON_SCHEMA).description("tool1 description").build())
|
||||
.callHandler((exchange, request) -> {
|
||||
return exchange.createMessage(mock(McpSchema.CreateMessageRequest.class))
|
||||
.then(Mono.just(mock(CallToolResult.class)));
|
||||
|
|
@ -120,13 +121,14 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
|
||||
try (
|
||||
// Create client without sampling capabilities
|
||||
var client = clientBuilder.clientInfo(new McpSchema.Implementation("Sample " + "client", "0.0.0"))
|
||||
var client = clientBuilder
|
||||
.clientInfo(McpSchema.Implementation.builder("Sample " + "client", "0.0.0").build())
|
||||
.build()) {
|
||||
|
||||
assertThat(client.initialize()).isNotNull();
|
||||
|
||||
try {
|
||||
client.callTool(new McpSchema.CallToolRequest("tool1", Map.of()));
|
||||
client.callTool(McpSchema.CallToolRequest.builder("tool1").arguments(Map.of()).build());
|
||||
}
|
||||
catch (McpError e) {
|
||||
assertThat(e).isInstanceOf(McpError.class)
|
||||
|
|
@ -148,23 +150,26 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
assertThat(request.messages()).hasSize(1);
|
||||
assertThat(request.messages().get(0).content()).isInstanceOf(McpSchema.TextContent.class);
|
||||
|
||||
return new CreateMessageResult(Role.USER, new McpSchema.TextContent("Test message"), "MockModelName",
|
||||
CreateMessageResult.StopReason.STOP_SEQUENCE);
|
||||
return CreateMessageResult
|
||||
.builder(Role.USER, McpSchema.TextContent.builder("Test message").build(), "MockModelName")
|
||||
.stopReason(CreateMessageResult.StopReason.STOP_SEQUENCE)
|
||||
.build();
|
||||
};
|
||||
|
||||
CallToolResult callResponse = McpSchema.CallToolResult.builder()
|
||||
.addContent(new McpSchema.TextContent("CALL RESPONSE"))
|
||||
.addContent(McpSchema.TextContent.builder("CALL RESPONSE").build())
|
||||
.build();
|
||||
|
||||
AtomicReference<CreateMessageResult> samplingResult = new AtomicReference<>();
|
||||
|
||||
McpServerFeatures.AsyncToolSpecification tool = McpServerFeatures.AsyncToolSpecification.builder()
|
||||
.tool(Tool.builder().name("tool1").description("tool1 description").inputSchema(EMPTY_JSON_SCHEMA).build())
|
||||
.tool(Tool.builder("tool1", EMPTY_JSON_SCHEMA).description("tool1 description").build())
|
||||
.callHandler((exchange, request) -> {
|
||||
|
||||
var createMessageRequest = McpSchema.CreateMessageRequest.builder()
|
||||
.messages(List.of(new McpSchema.SamplingMessage(McpSchema.Role.USER,
|
||||
new McpSchema.TextContent("Test message"))))
|
||||
var createMessageRequest = McpSchema.CreateMessageRequest
|
||||
.builder(List.of(McpSchema.SamplingMessage
|
||||
.builder(McpSchema.Role.USER, McpSchema.TextContent.builder("Test message").build())
|
||||
.build()), 1000)
|
||||
.modelPreferences(ModelPreferences.builder()
|
||||
.hints(List.of())
|
||||
.costPriority(1.0)
|
||||
|
|
@ -181,7 +186,8 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
|
||||
var mcpServer = prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0").tools(tool).build();
|
||||
|
||||
try (var mcpClient = clientBuilder.clientInfo(new McpSchema.Implementation("Sample client", "0.0.0"))
|
||||
try (var mcpClient = clientBuilder
|
||||
.clientInfo(McpSchema.Implementation.builder("Sample client", "0.0.0").build())
|
||||
.capabilities(ClientCapabilities.builder().sampling().build())
|
||||
.sampling(samplingHandler)
|
||||
.build()) {
|
||||
|
|
@ -189,7 +195,8 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
InitializeResult initResult = mcpClient.initialize();
|
||||
assertThat(initResult).isNotNull();
|
||||
|
||||
CallToolResult response = mcpClient.callTool(new McpSchema.CallToolRequest("tool1", Map.of()));
|
||||
CallToolResult response = mcpClient
|
||||
.callTool(McpSchema.CallToolRequest.builder("tool1").arguments(Map.of()).build());
|
||||
|
||||
assertThat(response).isNotNull();
|
||||
assertThat(response).isEqualTo(callResponse);
|
||||
|
|
@ -225,25 +232,28 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return new CreateMessageResult(Role.USER, new McpSchema.TextContent("Test message"), "MockModelName",
|
||||
CreateMessageResult.StopReason.STOP_SEQUENCE);
|
||||
return CreateMessageResult
|
||||
.builder(Role.USER, McpSchema.TextContent.builder("Test message").build(), "MockModelName")
|
||||
.stopReason(CreateMessageResult.StopReason.STOP_SEQUENCE)
|
||||
.build();
|
||||
};
|
||||
|
||||
// Server
|
||||
|
||||
CallToolResult callResponse = McpSchema.CallToolResult.builder()
|
||||
.addContent(new McpSchema.TextContent("CALL RESPONSE"))
|
||||
.addContent(McpSchema.TextContent.builder("CALL RESPONSE").build())
|
||||
.build();
|
||||
|
||||
AtomicReference<CreateMessageResult> samplingResult = new AtomicReference<>();
|
||||
|
||||
McpServerFeatures.AsyncToolSpecification tool = McpServerFeatures.AsyncToolSpecification.builder()
|
||||
.tool(Tool.builder().name("tool1").description("tool1 description").inputSchema(EMPTY_JSON_SCHEMA).build())
|
||||
.tool(Tool.builder("tool1", EMPTY_JSON_SCHEMA).description("tool1 description").build())
|
||||
.callHandler((exchange, request) -> {
|
||||
|
||||
var createMessageRequest = McpSchema.CreateMessageRequest.builder()
|
||||
.messages(List.of(new McpSchema.SamplingMessage(McpSchema.Role.USER,
|
||||
new McpSchema.TextContent("Test message"))))
|
||||
var createMessageRequest = McpSchema.CreateMessageRequest
|
||||
.builder(List.of(McpSchema.SamplingMessage
|
||||
.builder(McpSchema.Role.USER, McpSchema.TextContent.builder("Test message").build())
|
||||
.build()), 1000)
|
||||
.modelPreferences(ModelPreferences.builder()
|
||||
.hints(List.of())
|
||||
.costPriority(1.0)
|
||||
|
|
@ -262,7 +272,8 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
.requestTimeout(Duration.ofSeconds(4))
|
||||
.tools(tool)
|
||||
.build();
|
||||
try (var mcpClient = clientBuilder.clientInfo(new McpSchema.Implementation("Sample client", "0.0.0"))
|
||||
try (var mcpClient = clientBuilder
|
||||
.clientInfo(McpSchema.Implementation.builder("Sample client", "0.0.0").build())
|
||||
.capabilities(ClientCapabilities.builder().sampling().build())
|
||||
.sampling(samplingHandler)
|
||||
.build()) {
|
||||
|
|
@ -270,7 +281,8 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
InitializeResult initResult = mcpClient.initialize();
|
||||
assertThat(initResult).isNotNull();
|
||||
|
||||
CallToolResult response = mcpClient.callTool(new McpSchema.CallToolRequest("tool1", Map.of()));
|
||||
CallToolResult response = mcpClient
|
||||
.callTool(McpSchema.CallToolRequest.builder("tool1").arguments(Map.of()).build());
|
||||
|
||||
assertThat(response).isNotNull();
|
||||
assertThat(response).isEqualTo(callResponse);
|
||||
|
|
@ -304,21 +316,24 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return new CreateMessageResult(Role.USER, new McpSchema.TextContent("Test message"), "MockModelName",
|
||||
CreateMessageResult.StopReason.STOP_SEQUENCE);
|
||||
return CreateMessageResult
|
||||
.builder(Role.USER, McpSchema.TextContent.builder("Test message").build(), "MockModelName")
|
||||
.stopReason(CreateMessageResult.StopReason.STOP_SEQUENCE)
|
||||
.build();
|
||||
};
|
||||
|
||||
CallToolResult callResponse = McpSchema.CallToolResult.builder()
|
||||
.addContent(new McpSchema.TextContent("CALL RESPONSE"))
|
||||
.addContent(McpSchema.TextContent.builder("CALL RESPONSE").build())
|
||||
.build();
|
||||
|
||||
McpServerFeatures.AsyncToolSpecification tool = McpServerFeatures.AsyncToolSpecification.builder()
|
||||
.tool(Tool.builder().name("tool1").description("tool1 description").inputSchema(EMPTY_JSON_SCHEMA).build())
|
||||
.tool(Tool.builder("tool1", EMPTY_JSON_SCHEMA).description("tool1 description").build())
|
||||
.callHandler((exchange, request) -> {
|
||||
|
||||
var createMessageRequest = McpSchema.CreateMessageRequest.builder()
|
||||
.messages(List.of(new McpSchema.SamplingMessage(McpSchema.Role.USER,
|
||||
new McpSchema.TextContent("Test message"))))
|
||||
var createMessageRequest = McpSchema.CreateMessageRequest
|
||||
.builder(List.of(McpSchema.SamplingMessage
|
||||
.builder(McpSchema.Role.USER, McpSchema.TextContent.builder("Test message").build())
|
||||
.build()), 1000)
|
||||
.modelPreferences(ModelPreferences.builder()
|
||||
.hints(List.of())
|
||||
.costPriority(1.0)
|
||||
|
|
@ -336,7 +351,8 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
.tools(tool)
|
||||
.build();
|
||||
|
||||
try (var mcpClient = clientBuilder.clientInfo(new McpSchema.Implementation("Sample client", "0.0.0"))
|
||||
try (var mcpClient = clientBuilder
|
||||
.clientInfo(McpSchema.Implementation.builder("Sample client", "0.0.0").build())
|
||||
.capabilities(ClientCapabilities.builder().sampling().build())
|
||||
.sampling(samplingHandler)
|
||||
.build()) {
|
||||
|
|
@ -345,7 +361,7 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
assertThat(initResult).isNotNull();
|
||||
|
||||
assertThatExceptionOfType(McpError.class).isThrownBy(() -> {
|
||||
mcpClient.callTool(new McpSchema.CallToolRequest("tool1", Map.of()));
|
||||
mcpClient.callTool(McpSchema.CallToolRequest.builder("tool1").arguments(Map.of()).build());
|
||||
}).withMessageContaining("1000ms");
|
||||
}
|
||||
finally {
|
||||
|
|
@ -363,7 +379,7 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
var clientBuilder = clientBuilders.get(clientType);
|
||||
|
||||
McpServerFeatures.AsyncToolSpecification tool = McpServerFeatures.AsyncToolSpecification.builder()
|
||||
.tool(Tool.builder().name("tool1").description("tool1 description").inputSchema(EMPTY_JSON_SCHEMA).build())
|
||||
.tool(Tool.builder("tool1", EMPTY_JSON_SCHEMA).description("tool1 description").build())
|
||||
.callHandler((exchange, request) -> exchange.createElicitation(mock(ElicitRequest.class))
|
||||
.then(Mono.just(mock(CallToolResult.class))))
|
||||
.build();
|
||||
|
|
@ -371,12 +387,13 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
var server = prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0").tools(tool).build();
|
||||
|
||||
// Create client without elicitation capabilities
|
||||
try (var client = clientBuilder.clientInfo(new McpSchema.Implementation("Sample client", "0.0.0")).build()) {
|
||||
try (var client = clientBuilder.clientInfo(McpSchema.Implementation.builder("Sample client", "0.0.0").build())
|
||||
.build()) {
|
||||
|
||||
assertThat(client.initialize()).isNotNull();
|
||||
|
||||
try {
|
||||
client.callTool(new McpSchema.CallToolRequest("tool1", Map.of()));
|
||||
client.callTool(McpSchema.CallToolRequest.builder("tool1").arguments(Map.of()).build());
|
||||
}
|
||||
catch (McpError e) {
|
||||
assertThat(e).isInstanceOf(McpError.class)
|
||||
|
|
@ -398,23 +415,23 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
assertThat(request.message()).isNotEmpty();
|
||||
assertThat(request.requestedSchema()).isNotNull();
|
||||
|
||||
return new McpSchema.ElicitResult(McpSchema.ElicitResult.Action.ACCEPT,
|
||||
Map.of("message", request.message()));
|
||||
return McpSchema.ElicitResult.builder(McpSchema.ElicitResult.Action.ACCEPT)
|
||||
.content(Map.of("message", request.message()))
|
||||
.build();
|
||||
};
|
||||
|
||||
CallToolResult callResponse = McpSchema.CallToolResult.builder()
|
||||
.addContent(new McpSchema.TextContent("CALL RESPONSE"))
|
||||
.addContent(McpSchema.TextContent.builder("CALL RESPONSE").build())
|
||||
.build();
|
||||
|
||||
AtomicReference<McpSchema.ElicitResult> elicitResultRef = new AtomicReference<>();
|
||||
|
||||
McpServerFeatures.AsyncToolSpecification tool = McpServerFeatures.AsyncToolSpecification.builder()
|
||||
.tool(Tool.builder().name("tool1").description("tool1 description").inputSchema(EMPTY_JSON_SCHEMA).build())
|
||||
.tool(Tool.builder("tool1", EMPTY_JSON_SCHEMA).description("tool1 description").build())
|
||||
.callHandler((exchange, request) -> {
|
||||
|
||||
var elicitationRequest = McpSchema.ElicitRequest.builder()
|
||||
.message("Test message")
|
||||
.requestedSchema(
|
||||
var elicitationRequest = McpSchema.ElicitRequest
|
||||
.builder("Test message",
|
||||
Map.of("type", "object", "properties", Map.of("message", Map.of("type", "string"))))
|
||||
.build();
|
||||
|
||||
|
|
@ -426,7 +443,8 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
|
||||
var mcpServer = prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0").tools(tool).build();
|
||||
|
||||
try (var mcpClient = clientBuilder.clientInfo(new McpSchema.Implementation("Sample client", "0.0.0"))
|
||||
try (var mcpClient = clientBuilder
|
||||
.clientInfo(McpSchema.Implementation.builder("Sample client", "0.0.0").build())
|
||||
.capabilities(ClientCapabilities.builder().elicitation().build())
|
||||
.elicitation(elicitationHandler)
|
||||
.build()) {
|
||||
|
|
@ -434,7 +452,8 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
InitializeResult initResult = mcpClient.initialize();
|
||||
assertThat(initResult).isNotNull();
|
||||
|
||||
CallToolResult response = mcpClient.callTool(new McpSchema.CallToolRequest("tool1", Map.of()));
|
||||
CallToolResult response = mcpClient
|
||||
.callTool(McpSchema.CallToolRequest.builder("tool1").arguments(Map.of()).build());
|
||||
|
||||
assertThat(response).isNotNull();
|
||||
assertThat(response).isEqualTo(callResponse);
|
||||
|
|
@ -458,22 +477,23 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
Function<ElicitRequest, ElicitResult> elicitationHandler = request -> {
|
||||
assertThat(request.message()).isNotEmpty();
|
||||
assertThat(request.requestedSchema()).isNotNull();
|
||||
return new ElicitResult(ElicitResult.Action.ACCEPT, Map.of("message", request.message()));
|
||||
return ElicitResult.builder(ElicitResult.Action.ACCEPT)
|
||||
.content(Map.of("message", request.message()))
|
||||
.build();
|
||||
};
|
||||
|
||||
CallToolResult callResponse = McpSchema.CallToolResult.builder()
|
||||
.addContent(new McpSchema.TextContent("CALL RESPONSE"))
|
||||
.addContent(McpSchema.TextContent.builder("CALL RESPONSE").build())
|
||||
.build();
|
||||
|
||||
AtomicReference<ElicitResult> resultRef = new AtomicReference<>();
|
||||
|
||||
McpServerFeatures.AsyncToolSpecification tool = McpServerFeatures.AsyncToolSpecification.builder()
|
||||
.tool(Tool.builder().name("tool1").description("tool1 description").inputSchema(EMPTY_JSON_SCHEMA).build())
|
||||
.tool(Tool.builder("tool1", EMPTY_JSON_SCHEMA).description("tool1 description").build())
|
||||
.callHandler((exchange, request) -> {
|
||||
|
||||
var elicitationRequest = McpSchema.ElicitRequest.builder()
|
||||
.message("Test message")
|
||||
.requestedSchema(
|
||||
var elicitationRequest = McpSchema.ElicitRequest
|
||||
.builder("Test message",
|
||||
Map.of("type", "object", "properties", Map.of("message", Map.of("type", "string"))))
|
||||
.build();
|
||||
|
||||
|
|
@ -488,7 +508,8 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
.tools(tool)
|
||||
.build();
|
||||
|
||||
try (var mcpClient = clientBuilder.clientInfo(new McpSchema.Implementation("Sample client", "0.0.0"))
|
||||
try (var mcpClient = clientBuilder
|
||||
.clientInfo(McpSchema.Implementation.builder("Sample client", "0.0.0").build())
|
||||
.capabilities(ClientCapabilities.builder().elicitation().build())
|
||||
.elicitation(elicitationHandler)
|
||||
.build()) {
|
||||
|
|
@ -496,7 +517,8 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
InitializeResult initResult = mcpClient.initialize();
|
||||
assertThat(initResult).isNotNull();
|
||||
|
||||
CallToolResult response = mcpClient.callTool(new McpSchema.CallToolRequest("tool1", Map.of()));
|
||||
CallToolResult response = mcpClient
|
||||
.callTool(McpSchema.CallToolRequest.builder("tool1").arguments(Map.of()).build());
|
||||
|
||||
assertThat(response).isNotNull();
|
||||
assertThat(response).isEqualTo(callResponse);
|
||||
|
|
@ -531,20 +553,23 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return new ElicitResult(ElicitResult.Action.ACCEPT, Map.of("message", request.message()));
|
||||
return ElicitResult.builder(ElicitResult.Action.ACCEPT)
|
||||
.content(Map.of("message", request.message()))
|
||||
.build();
|
||||
};
|
||||
|
||||
CallToolResult callResponse = CallToolResult.builder().addContent(new TextContent("CALL RESPONSE")).build();
|
||||
CallToolResult callResponse = CallToolResult.builder()
|
||||
.addContent(TextContent.builder("CALL RESPONSE").build())
|
||||
.build();
|
||||
|
||||
AtomicReference<ElicitResult> resultRef = new AtomicReference<>();
|
||||
|
||||
McpServerFeatures.AsyncToolSpecification tool = McpServerFeatures.AsyncToolSpecification.builder()
|
||||
.tool(Tool.builder().name("tool1").description("tool1 description").inputSchema(EMPTY_JSON_SCHEMA).build())
|
||||
.tool(Tool.builder("tool1", EMPTY_JSON_SCHEMA).description("tool1 description").build())
|
||||
.callHandler((exchange, request) -> {
|
||||
|
||||
var elicitationRequest = ElicitRequest.builder()
|
||||
.message("Test message")
|
||||
.requestedSchema(
|
||||
var elicitationRequest = ElicitRequest
|
||||
.builder("Test message",
|
||||
Map.of("type", "object", "properties", Map.of("message", Map.of("type", "string"))))
|
||||
.build();
|
||||
|
||||
|
|
@ -559,7 +584,8 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
.tools(tool)
|
||||
.build();
|
||||
|
||||
try (var mcpClient = clientBuilder.clientInfo(new McpSchema.Implementation("Sample client", "0.0.0"))
|
||||
try (var mcpClient = clientBuilder
|
||||
.clientInfo(McpSchema.Implementation.builder("Sample client", "0.0.0").build())
|
||||
.capabilities(ClientCapabilities.builder().elicitation().build())
|
||||
.elicitation(elicitationHandler)
|
||||
.build()) {
|
||||
|
|
@ -568,7 +594,7 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
assertThat(initResult).isNotNull();
|
||||
|
||||
assertThatExceptionOfType(McpError.class).isThrownBy(() -> {
|
||||
mcpClient.callTool(new McpSchema.CallToolRequest("tool1", Map.of()));
|
||||
mcpClient.callTool(McpSchema.CallToolRequest.builder("tool1").arguments(Map.of()).build());
|
||||
}).withMessageContaining("within 1000ms");
|
||||
|
||||
ElicitResult elicitResult = resultRef.get();
|
||||
|
|
@ -587,7 +613,8 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
void testRootsSuccess(String clientType) {
|
||||
var clientBuilder = clientBuilders.get(clientType);
|
||||
|
||||
List<Root> roots = List.of(new Root("uri1://", "root1"), new Root("uri2://", "root2"));
|
||||
List<Root> roots = List.of(Root.builder("uri1://").name("root1").build(),
|
||||
Root.builder("uri2://").name("root2").build());
|
||||
|
||||
AtomicReference<List<Root>> rootsRef = new AtomicReference<>();
|
||||
|
||||
|
|
@ -618,7 +645,7 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
});
|
||||
|
||||
// Add a new root
|
||||
var root3 = new Root("uri3://", "root3");
|
||||
var root3 = Root.builder("uri3://").name("root3").build();
|
||||
mcpClient.addRoot(root3);
|
||||
|
||||
await().atMost(Duration.ofSeconds(5)).untilAsserted(() -> {
|
||||
|
|
@ -637,7 +664,7 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
var clientBuilder = clientBuilders.get(clientType);
|
||||
|
||||
McpServerFeatures.SyncToolSpecification tool = McpServerFeatures.SyncToolSpecification.builder()
|
||||
.tool(Tool.builder().name("tool1").description("tool1 description").inputSchema(EMPTY_JSON_SCHEMA).build())
|
||||
.tool(Tool.builder("tool1", EMPTY_JSON_SCHEMA).description("tool1 description").build())
|
||||
.callHandler((exchange, request) -> {
|
||||
|
||||
exchange.listRoots(); // try to list roots
|
||||
|
|
@ -658,7 +685,7 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
|
||||
// Attempt to list roots should fail
|
||||
try {
|
||||
mcpClient.callTool(new McpSchema.CallToolRequest("tool1", Map.of()));
|
||||
mcpClient.callTool(McpSchema.CallToolRequest.builder("tool1").arguments(Map.of()).build());
|
||||
}
|
||||
catch (McpError e) {
|
||||
assertThat(e).isInstanceOf(McpError.class).hasMessage("Roots not supported");
|
||||
|
|
@ -705,7 +732,7 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
|
||||
var clientBuilder = clientBuilders.get(clientType);
|
||||
|
||||
List<Root> roots = List.of(new Root("uri1://", "root1"));
|
||||
List<Root> roots = List.of(Root.builder("uri1://").name("root1").build());
|
||||
|
||||
AtomicReference<List<Root>> rootsRef1 = new AtomicReference<>();
|
||||
AtomicReference<List<Root>> rootsRef2 = new AtomicReference<>();
|
||||
|
|
@ -739,7 +766,7 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
|
||||
var clientBuilder = clientBuilders.get(clientType);
|
||||
|
||||
List<Root> roots = List.of(new Root("uri1://", "root1"));
|
||||
List<Root> roots = List.of(Root.builder("uri1://").name("root1").build());
|
||||
|
||||
AtomicReference<List<Root>> rootsRef = new AtomicReference<>();
|
||||
|
||||
|
|
@ -776,10 +803,10 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
|
||||
var responseBodyIsNullOrBlank = new AtomicBoolean(false);
|
||||
var callResponse = McpSchema.CallToolResult.builder()
|
||||
.addContent(new McpSchema.TextContent("CALL RESPONSE; ctx=importantValue"))
|
||||
.addContent(McpSchema.TextContent.builder("CALL RESPONSE; ctx=importantValue").build())
|
||||
.build();
|
||||
McpServerFeatures.SyncToolSpecification tool1 = McpServerFeatures.SyncToolSpecification.builder()
|
||||
.tool(Tool.builder().name("tool1").description("tool1 description").inputSchema(EMPTY_JSON_SCHEMA).build())
|
||||
.tool(Tool.builder("tool1", EMPTY_JSON_SCHEMA).description("tool1 description").build())
|
||||
.callHandler((exchange, request) -> {
|
||||
|
||||
try {
|
||||
|
|
@ -811,7 +838,8 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
|
||||
assertThat(mcpClient.listTools().tools()).contains(tool1.tool());
|
||||
|
||||
CallToolResult response = mcpClient.callTool(new McpSchema.CallToolRequest("tool1", Map.of()));
|
||||
CallToolResult response = mcpClient
|
||||
.callTool(McpSchema.CallToolRequest.builder("tool1").arguments(Map.of()).build());
|
||||
|
||||
assertThat(responseBodyIsNullOrBlank.get()).isFalse();
|
||||
assertThat(response).isNotNull().isEqualTo(callResponse);
|
||||
|
|
@ -830,11 +858,7 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
McpSyncServer mcpServer = prepareSyncServerBuilder()
|
||||
.capabilities(ServerCapabilities.builder().tools(true).build())
|
||||
.tools(McpServerFeatures.SyncToolSpecification.builder()
|
||||
.tool(Tool.builder()
|
||||
.name("tool1")
|
||||
.description("tool1 description")
|
||||
.inputSchema(EMPTY_JSON_SCHEMA)
|
||||
.build())
|
||||
.tool(Tool.builder("tool1", EMPTY_JSON_SCHEMA).description("tool1 description").build())
|
||||
.callHandler((exchange, request) -> {
|
||||
// We trigger a timeout on blocking read, raising an exception
|
||||
Mono.never().block(Duration.ofSeconds(1));
|
||||
|
|
@ -849,8 +873,8 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
|
||||
// We expect the tool call to fail immediately with the exception raised by
|
||||
// the offending tool instead of getting back a timeout.
|
||||
assertThatExceptionOfType(McpError.class)
|
||||
.isThrownBy(() -> mcpClient.callTool(new McpSchema.CallToolRequest("tool1", Map.of())))
|
||||
assertThatExceptionOfType(McpError.class).isThrownBy(
|
||||
() -> mcpClient.callTool(McpSchema.CallToolRequest.builder("tool1").arguments(Map.of()).build()))
|
||||
.withMessageContaining("Timeout on blocking read");
|
||||
}
|
||||
finally {
|
||||
|
|
@ -869,10 +893,10 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
var responseBodyIsNullOrBlank = new AtomicBoolean(false);
|
||||
|
||||
var expectedCallResponse = McpSchema.CallToolResult.builder()
|
||||
.addContent(new McpSchema.TextContent("CALL RESPONSE; ctx=value"))
|
||||
.addContent(McpSchema.TextContent.builder("CALL RESPONSE; ctx=value").build())
|
||||
.build();
|
||||
McpServerFeatures.SyncToolSpecification tool1 = McpServerFeatures.SyncToolSpecification.builder()
|
||||
.tool(Tool.builder().name("tool1").description("tool1 description").inputSchema(EMPTY_JSON_SCHEMA).build())
|
||||
.tool(Tool.builder("tool1", EMPTY_JSON_SCHEMA).description("tool1 description").build())
|
||||
.callHandler((exchange, request) -> {
|
||||
|
||||
McpTransportContext transportContext = exchange.transportContext();
|
||||
|
|
@ -889,7 +913,7 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
}
|
||||
|
||||
return McpSchema.CallToolResult.builder()
|
||||
.addContent(new McpSchema.TextContent("CALL RESPONSE; ctx=" + ctxValue))
|
||||
.addContent(McpSchema.TextContent.builder("CALL RESPONSE; ctx=" + ctxValue).build())
|
||||
.build();
|
||||
})
|
||||
.build();
|
||||
|
|
@ -905,7 +929,8 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
|
||||
assertThat(mcpClient.listTools().tools()).contains(tool1.tool());
|
||||
|
||||
CallToolResult response = mcpClient.callTool(new McpSchema.CallToolRequest("tool1", Map.of()));
|
||||
CallToolResult response = mcpClient
|
||||
.callTool(McpSchema.CallToolRequest.builder("tool1").arguments(Map.of()).build());
|
||||
|
||||
assertThat(transportContextIsNull.get()).isFalse();
|
||||
assertThat(transportContextIsEmpty.get()).isFalse();
|
||||
|
|
@ -933,15 +958,11 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
""";
|
||||
|
||||
McpServerFeatures.SyncToolSpecification nonAsciiTool = McpServerFeatures.SyncToolSpecification.builder()
|
||||
.tool(Tool.builder()
|
||||
.name("greeter")
|
||||
.description("打招呼")
|
||||
.inputSchema(McpJsonDefaults.getMapper(), inputSchema)
|
||||
.build())
|
||||
.tool(Tool.builder("greeter", McpJsonDefaults.getMapper(), inputSchema).description("打招呼").build())
|
||||
.callHandler((exchange, request) -> {
|
||||
String username = (String) request.arguments().get("username");
|
||||
return McpSchema.CallToolResult.builder()
|
||||
.addContent(new McpSchema.TextContent("Hello " + username))
|
||||
.addContent(McpSchema.TextContent.builder("Hello " + username).build())
|
||||
.build();
|
||||
})
|
||||
.build();
|
||||
|
|
@ -961,7 +982,7 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
assertThat(tools.get(0).description()).isEqualTo("打招呼");
|
||||
|
||||
CallToolResult response = mcpClient
|
||||
.callTool(new McpSchema.CallToolRequest("greeter", Map.of("username", "测试用户")));
|
||||
.callTool(McpSchema.CallToolRequest.builder("greeter").arguments(Map.of("username", "测试用户")).build());
|
||||
|
||||
assertThat(response).isNotNull();
|
||||
assertThat(response.isError()).isFalse();
|
||||
|
|
@ -980,11 +1001,11 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
var clientBuilder = clientBuilders.get(clientType);
|
||||
|
||||
var callResponse = McpSchema.CallToolResult.builder()
|
||||
.addContent(new McpSchema.TextContent("CALL RESPONSE"))
|
||||
.addContent(McpSchema.TextContent.builder("CALL RESPONSE").build())
|
||||
.build();
|
||||
|
||||
McpServerFeatures.SyncToolSpecification tool1 = McpServerFeatures.SyncToolSpecification.builder()
|
||||
.tool(Tool.builder().name("tool1").description("tool1 description").inputSchema(EMPTY_JSON_SCHEMA).build())
|
||||
.tool(Tool.builder("tool1", EMPTY_JSON_SCHEMA).description("tool1 description").build())
|
||||
.callHandler((exchange, request) -> {
|
||||
// perform a blocking call to a remote service
|
||||
try {
|
||||
|
|
@ -1050,11 +1071,7 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
|
||||
// Add a new tool
|
||||
McpServerFeatures.SyncToolSpecification tool2 = McpServerFeatures.SyncToolSpecification.builder()
|
||||
.tool(Tool.builder()
|
||||
.name("tool2")
|
||||
.description("tool2 description")
|
||||
.inputSchema(EMPTY_JSON_SCHEMA)
|
||||
.build())
|
||||
.tool(Tool.builder("tool2", EMPTY_JSON_SCHEMA).description("tool2 description").build())
|
||||
.callHandler((exchange, request) -> callResponse)
|
||||
.build();
|
||||
|
||||
|
|
@ -1102,48 +1119,39 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
|
||||
// Create server with a tool that sends logging notifications
|
||||
McpServerFeatures.AsyncToolSpecification tool = McpServerFeatures.AsyncToolSpecification.builder()
|
||||
.tool(Tool.builder()
|
||||
.name("logging-test")
|
||||
.description("Test logging notifications")
|
||||
.inputSchema(EMPTY_JSON_SCHEMA)
|
||||
.build())
|
||||
.tool(Tool.builder("logging-test", EMPTY_JSON_SCHEMA).description("Test logging notifications").build())
|
||||
.callHandler((exchange, request) -> {
|
||||
|
||||
// Create and send notifications with different levels
|
||||
|
||||
//@formatter:off
|
||||
return exchange // This should be filtered out (DEBUG < NOTICE)
|
||||
.loggingNotification(McpSchema.LoggingMessageNotification.builder()
|
||||
.level(McpSchema.LoggingLevel.DEBUG)
|
||||
.loggingNotification(McpSchema.LoggingMessageNotification
|
||||
.builder(McpSchema.LoggingLevel.DEBUG, "Debug message")
|
||||
.logger("test-logger")
|
||||
.data("Debug message")
|
||||
.build())
|
||||
.then(exchange // This should be sent (NOTICE >= NOTICE)
|
||||
.loggingNotification(McpSchema.LoggingMessageNotification.builder()
|
||||
.level(McpSchema.LoggingLevel.NOTICE)
|
||||
.loggingNotification(McpSchema.LoggingMessageNotification
|
||||
.builder(McpSchema.LoggingLevel.NOTICE, "Notice message")
|
||||
.logger("test-logger")
|
||||
.data("Notice message")
|
||||
.build()))
|
||||
.then(exchange // This should be sent (ERROR > NOTICE)
|
||||
.loggingNotification(McpSchema.LoggingMessageNotification.builder()
|
||||
.level(McpSchema.LoggingLevel.ERROR)
|
||||
.loggingNotification(McpSchema.LoggingMessageNotification
|
||||
.builder(McpSchema.LoggingLevel.ERROR, "Error message")
|
||||
.logger("test-logger")
|
||||
.data("Error message")
|
||||
.build()))
|
||||
.then(exchange // This should be filtered out (INFO < NOTICE)
|
||||
.loggingNotification(McpSchema.LoggingMessageNotification.builder()
|
||||
.level(McpSchema.LoggingLevel.INFO)
|
||||
.loggingNotification(McpSchema.LoggingMessageNotification
|
||||
.builder(McpSchema.LoggingLevel.INFO, "Another info message")
|
||||
.logger("test-logger")
|
||||
.data("Another info message")
|
||||
.build()))
|
||||
.then(exchange // This should be sent (ERROR >= NOTICE)
|
||||
.loggingNotification(McpSchema.LoggingMessageNotification.builder()
|
||||
.level(McpSchema.LoggingLevel.ERROR)
|
||||
.loggingNotification(McpSchema.LoggingMessageNotification
|
||||
.builder(McpSchema.LoggingLevel.ERROR, "Another error message")
|
||||
.logger("test-logger")
|
||||
.data("Another error message")
|
||||
.build()))
|
||||
.thenReturn(CallToolResult.builder()
|
||||
.content(List.of(new McpSchema.TextContent("Logging test completed")))
|
||||
.content(List.of(McpSchema.TextContent.builder("Logging test completed").build()))
|
||||
.isError(false)
|
||||
.build());
|
||||
//@formatter:on
|
||||
|
|
@ -1170,7 +1178,8 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
mcpClient.setLoggingLevel(McpSchema.LoggingLevel.NOTICE);
|
||||
|
||||
// Call the tool that sends logging notifications
|
||||
CallToolResult result = mcpClient.callTool(new McpSchema.CallToolRequest("logging-test", Map.of()));
|
||||
CallToolResult result = mcpClient
|
||||
.callTool(McpSchema.CallToolRequest.builder("logging-test").arguments(Map.of()).build());
|
||||
assertThat(result).isNotNull();
|
||||
assertThat(result.content().get(0)).isInstanceOf(McpSchema.TextContent.class);
|
||||
assertThat(((McpSchema.TextContent) result.content().get(0)).text()).isEqualTo("Logging test completed");
|
||||
|
|
@ -1219,10 +1228,8 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
|
||||
// Create server with a tool that sends logging notifications
|
||||
McpServerFeatures.AsyncToolSpecification tool = McpServerFeatures.AsyncToolSpecification.builder()
|
||||
.tool(McpSchema.Tool.builder()
|
||||
.name("progress-test")
|
||||
.tool(McpSchema.Tool.builder("progress-test", EMPTY_JSON_SCHEMA)
|
||||
.description("Test progress notifications")
|
||||
.inputSchema(EMPTY_JSON_SCHEMA)
|
||||
.build())
|
||||
.callHandler((exchange, request) -> {
|
||||
|
||||
|
|
@ -1230,18 +1237,25 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
var progressToken = (String) request.meta().get("progressToken");
|
||||
|
||||
return exchange
|
||||
.progressNotification(
|
||||
new McpSchema.ProgressNotification(progressToken, 0.0, 1.0, "Processing started"))
|
||||
.then(exchange.progressNotification(
|
||||
new McpSchema.ProgressNotification(progressToken, 0.5, 1.0, "Processing data")))
|
||||
.then(// Send a progress notification with another progress value
|
||||
// should
|
||||
exchange.progressNotification(new McpSchema.ProgressNotification("another-progress-token",
|
||||
0.0, 1.0, "Another processing started")))
|
||||
.then(exchange.progressNotification(
|
||||
new McpSchema.ProgressNotification(progressToken, 1.0, 1.0, "Processing completed")))
|
||||
.progressNotification(McpSchema.ProgressNotification.builder(progressToken, 0.0)
|
||||
.total(1.0)
|
||||
.message("Processing started")
|
||||
.build())
|
||||
.then(exchange.progressNotification(McpSchema.ProgressNotification.builder(progressToken, 0.5)
|
||||
.total(1.0)
|
||||
.message("Processing data")
|
||||
.build()))
|
||||
.then(exchange
|
||||
.progressNotification(McpSchema.ProgressNotification.builder("another-progress-token", 0.0)
|
||||
.total(1.0)
|
||||
.message("Another processing started")
|
||||
.build()))
|
||||
.then(exchange.progressNotification(McpSchema.ProgressNotification.builder(progressToken, 1.0)
|
||||
.total(1.0)
|
||||
.message("Processing completed")
|
||||
.build()))
|
||||
.thenReturn(CallToolResult.builder()
|
||||
.content(List.of(new McpSchema.TextContent("Progress test completed")))
|
||||
.content(List.of(McpSchema.TextContent.builder("Progress test completed").build()))
|
||||
.isError(false)
|
||||
.build());
|
||||
})
|
||||
|
|
@ -1321,9 +1335,8 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
var clientBuilder = clientBuilders.get(clientType);
|
||||
|
||||
var expectedValues = List.of("python", "pytorch", "pyside");
|
||||
var completionResponse = new McpSchema.CompleteResult(new CompleteResult.CompleteCompletion(expectedValues, 10, // total
|
||||
true // hasMore
|
||||
));
|
||||
var completionResponse = new McpSchema.CompleteResult(
|
||||
new CompleteResult.CompleteCompletion(expectedValues, 10, true));
|
||||
|
||||
AtomicReference<CompleteRequest> samplingRequest = new AtomicReference<>();
|
||||
BiFunction<McpSyncServerExchange, CompleteRequest, CompleteResult> completionHandler = (mcpSyncServerExchange,
|
||||
|
|
@ -1333,13 +1346,17 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
};
|
||||
|
||||
var mcpServer = prepareSyncServerBuilder().capabilities(ServerCapabilities.builder().completions().build())
|
||||
.prompts(new McpServerFeatures.SyncPromptSpecification(
|
||||
new Prompt("code_review", "Code review", "this is code review prompt",
|
||||
List.of(new PromptArgument("language", "Language", "string", false))),
|
||||
(mcpSyncServerExchange, getPromptRequest) -> null))
|
||||
.prompts(new McpServerFeatures.SyncPromptSpecification(Prompt.builder("code_review")
|
||||
.title("Code review")
|
||||
.description("this is code review prompt")
|
||||
.arguments(List.of(PromptArgument.builder("language")
|
||||
.title("Language")
|
||||
.description("string")
|
||||
.required(false)
|
||||
.build()))
|
||||
.build(), (mcpSyncServerExchange, getPromptRequest) -> null))
|
||||
.completions(new McpServerFeatures.SyncCompletionSpecification(
|
||||
new McpSchema.PromptReference(PromptReference.TYPE, "code_review", "Code review"),
|
||||
completionHandler))
|
||||
McpSchema.PromptReference.builder("code_review").title("Code review").build(), completionHandler))
|
||||
.build();
|
||||
|
||||
try (var mcpClient = clientBuilder.build()) {
|
||||
|
|
@ -1347,9 +1364,10 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
InitializeResult initResult = mcpClient.initialize();
|
||||
assertThat(initResult).isNotNull();
|
||||
|
||||
CompleteRequest request = new CompleteRequest(
|
||||
new PromptReference(PromptReference.TYPE, "code_review", "Code review"),
|
||||
new CompleteRequest.CompleteArgument("language", "py"));
|
||||
CompleteRequest request = CompleteRequest
|
||||
.builder(PromptReference.builder("code_review").title("Code review").build(),
|
||||
new CompleteRequest.CompleteArgument("language", "py"))
|
||||
.build();
|
||||
|
||||
CompleteResult result = mcpClient.completeCompletion(request);
|
||||
|
||||
|
|
@ -1377,11 +1395,7 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
AtomicReference<String> executionOrder = new AtomicReference<>("");
|
||||
|
||||
McpServerFeatures.AsyncToolSpecification tool = McpServerFeatures.AsyncToolSpecification.builder()
|
||||
.tool(Tool.builder()
|
||||
.name("ping-async-test")
|
||||
.description("Test ping async behavior")
|
||||
.inputSchema(EMPTY_JSON_SCHEMA)
|
||||
.build())
|
||||
.tool(Tool.builder("ping-async-test", EMPTY_JSON_SCHEMA).description("Test ping async behavior").build())
|
||||
.callHandler((exchange, request) -> {
|
||||
|
||||
executionOrder.set(executionOrder.get() + "1");
|
||||
|
|
@ -1398,7 +1412,7 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
}).then(Mono.fromCallable(() -> {
|
||||
executionOrder.set(executionOrder.get() + "3");
|
||||
return CallToolResult.builder()
|
||||
.content(List.of(new McpSchema.TextContent("Async ping test completed")))
|
||||
.content(List.of(McpSchema.TextContent.builder("Async ping test completed").build()))
|
||||
.isError(false)
|
||||
.build();
|
||||
}));
|
||||
|
|
@ -1417,7 +1431,8 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
assertThat(initResult).isNotNull();
|
||||
|
||||
// Call the tool that tests ping async behavior
|
||||
CallToolResult result = mcpClient.callTool(new McpSchema.CallToolRequest("ping-async-test", Map.of()));
|
||||
CallToolResult result = mcpClient
|
||||
.callTool(McpSchema.CallToolRequest.builder("ping-async-test").arguments(Map.of()).build());
|
||||
assertThat(result).isNotNull();
|
||||
assertThat(result.content().get(0)).isInstanceOf(McpSchema.TextContent.class);
|
||||
assertThat(((McpSchema.TextContent) result.content().get(0)).text()).isEqualTo("Async ping test completed");
|
||||
|
|
@ -1444,8 +1459,7 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
Map.of("type", "string"), "timestamp", Map.of("type", "string")),
|
||||
"required", List.of("result", "operation"));
|
||||
|
||||
Tool calculatorTool = Tool.builder()
|
||||
.name("calculator")
|
||||
Tool calculatorTool = Tool.builder("calculator")
|
||||
.description("Performs mathematical calculations")
|
||||
.outputSchema(outputSchema)
|
||||
.build();
|
||||
|
|
@ -1478,8 +1492,8 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
// Note: outputSchema might be null in sync server, but validation still works
|
||||
|
||||
// Call tool with valid structured output
|
||||
CallToolResult response = mcpClient
|
||||
.callTool(new McpSchema.CallToolRequest("calculator", Map.of("expression", "2 + 3")));
|
||||
CallToolResult response = mcpClient.callTool(
|
||||
McpSchema.CallToolRequest.builder("calculator").arguments(Map.of("expression", "2 + 3")).build());
|
||||
|
||||
assertThat(response).isNotNull();
|
||||
assertThat(response.isError()).isFalse();
|
||||
|
|
@ -1523,8 +1537,7 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
"age", Map.of("type", "number")),
|
||||
"required", List.of("name", "age"))); // @formatter:on
|
||||
|
||||
Tool calculatorTool = Tool.builder()
|
||||
.name("getMembers")
|
||||
Tool calculatorTool = Tool.builder("getMembers")
|
||||
.description("Returns a list of members")
|
||||
.outputSchema(outputSchema)
|
||||
.build();
|
||||
|
|
@ -1547,7 +1560,8 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
assertThat(mcpClient.initialize()).isNotNull();
|
||||
|
||||
// Call tool with valid structured output of type array
|
||||
CallToolResult response = mcpClient.callTool(new McpSchema.CallToolRequest("getMembers", Map.of()));
|
||||
CallToolResult response = mcpClient
|
||||
.callTool(McpSchema.CallToolRequest.builder("getMembers").arguments(Map.of()).build());
|
||||
|
||||
assertThat(response).isNotNull();
|
||||
assertThat(response.isError()).isFalse();
|
||||
|
|
@ -1577,8 +1591,7 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
Map.of("type", "string"), "timestamp", Map.of("type", "string")),
|
||||
"required", List.of("result", "operation"));
|
||||
|
||||
Tool calculatorTool = Tool.builder()
|
||||
.name("calculator")
|
||||
Tool calculatorTool = Tool.builder("calculator")
|
||||
.description("Performs mathematical calculations")
|
||||
.outputSchema(outputSchema)
|
||||
.build();
|
||||
|
|
@ -1588,7 +1601,7 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
.tool(calculatorTool)
|
||||
.callHandler((exchange, request) -> CallToolResult.builder()
|
||||
.isError(true)
|
||||
.content(List.of(new TextContent("Error calling tool: Simulated in-handler error")))
|
||||
.content(List.of(TextContent.builder("Error calling tool: Simulated in-handler error").build()))
|
||||
.build())
|
||||
.build();
|
||||
|
||||
|
|
@ -1608,14 +1621,14 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
// Note: outputSchema might be null in sync server, but validation still works
|
||||
|
||||
// Call tool with valid structured output
|
||||
CallToolResult response = mcpClient
|
||||
.callTool(new McpSchema.CallToolRequest("calculator", Map.of("expression", "2 + 3")));
|
||||
CallToolResult response = mcpClient.callTool(
|
||||
McpSchema.CallToolRequest.builder("calculator").arguments(Map.of("expression", "2 + 3")).build());
|
||||
|
||||
assertThat(response).isNotNull();
|
||||
assertThat(response.isError()).isTrue();
|
||||
assertThat(response.content()).isNotEmpty();
|
||||
assertThat(response.content())
|
||||
.containsExactly(new McpSchema.TextContent("Error calling tool: Simulated in-handler error"));
|
||||
assertThat(response.content()).containsExactly(
|
||||
McpSchema.TextContent.builder("Error calling tool: Simulated in-handler error").build());
|
||||
assertThat(response.structuredContent()).isNull();
|
||||
}
|
||||
finally {
|
||||
|
|
@ -1634,8 +1647,7 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
Map.of("result", Map.of("type", "number"), "operation", Map.of("type", "string")), "required",
|
||||
List.of("result", "operation"));
|
||||
|
||||
Tool calculatorTool = Tool.builder()
|
||||
.name("calculator")
|
||||
Tool calculatorTool = Tool.builder("calculator")
|
||||
.description("Performs mathematical calculations")
|
||||
.outputSchema(outputSchema)
|
||||
.build();
|
||||
|
|
@ -1662,8 +1674,8 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
assertThat(initResult).isNotNull();
|
||||
|
||||
// Call tool with invalid structured output
|
||||
CallToolResult response = mcpClient
|
||||
.callTool(new McpSchema.CallToolRequest("calculator", Map.of("expression", "2 + 3")));
|
||||
CallToolResult response = mcpClient.callTool(
|
||||
McpSchema.CallToolRequest.builder("calculator").arguments(Map.of("expression", "2 + 3")).build());
|
||||
|
||||
assertThat(response).isNotNull();
|
||||
assertThat(response.isError()).isTrue();
|
||||
|
|
@ -1688,8 +1700,7 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
Map<String, Object> outputSchema = Map.of("type", "object", "properties",
|
||||
Map.of("result", Map.of("type", "number")), "required", List.of("result"));
|
||||
|
||||
Tool calculatorTool = Tool.builder()
|
||||
.name("calculator")
|
||||
Tool calculatorTool = Tool.builder("calculator")
|
||||
.description("Performs mathematical calculations")
|
||||
.outputSchema(outputSchema)
|
||||
.build();
|
||||
|
|
@ -1712,8 +1723,8 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
assertThat(initResult).isNotNull();
|
||||
|
||||
// Call tool that should return structured content but doesn't
|
||||
CallToolResult response = mcpClient
|
||||
.callTool(new McpSchema.CallToolRequest("calculator", Map.of("expression", "2 + 3")));
|
||||
CallToolResult response = mcpClient.callTool(
|
||||
McpSchema.CallToolRequest.builder("calculator").arguments(Map.of("expression", "2 + 3")).build());
|
||||
|
||||
assertThat(response).isNotNull();
|
||||
assertThat(response.isError()).isTrue();
|
||||
|
|
@ -1752,8 +1763,7 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
Map.of("message", Map.of("type", "string"), "count", Map.of("type", "integer")), "required",
|
||||
List.of("message", "count"));
|
||||
|
||||
Tool dynamicTool = Tool.builder()
|
||||
.name("dynamic-tool")
|
||||
Tool dynamicTool = Tool.builder("dynamic-tool")
|
||||
.description("Dynamically added tool")
|
||||
.outputSchema(outputSchema)
|
||||
.build();
|
||||
|
|
@ -1785,7 +1795,7 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
|
||||
// Call dynamically added tool
|
||||
CallToolResult response = mcpClient
|
||||
.callTool(new McpSchema.CallToolRequest("dynamic-tool", Map.of("count", 3)));
|
||||
.callTool(McpSchema.CallToolRequest.builder("dynamic-tool").arguments(Map.of("count", 3)).build());
|
||||
|
||||
assertThat(response).isNotNull();
|
||||
assertThat(response.isError()).isFalse();
|
||||
|
|
@ -1822,13 +1832,12 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
var latch = new CountDownLatch(1);
|
||||
|
||||
McpServerFeatures.SyncResourceSpecification resourceSpec = new McpServerFeatures.SyncResourceSpecification(
|
||||
McpSchema.Resource.builder()
|
||||
.uri(resourceUri)
|
||||
.name("Subscribable Resource")
|
||||
.mimeType("text/plain")
|
||||
.build(),
|
||||
(exchange, req) -> new McpSchema.ReadResourceResult(
|
||||
List.of(new McpSchema.TextResourceContents(resourceUri, "text/plain", "initial content"))));
|
||||
McpSchema.Resource.builder(resourceUri, "Subscribable Resource").mimeType("text/plain").build(),
|
||||
(exchange, req) -> McpSchema.ReadResourceResult
|
||||
.builder(List.of(McpSchema.TextResourceContents.builder(resourceUri, "initial content")
|
||||
.mimeType("text/plain")
|
||||
.build()))
|
||||
.build());
|
||||
|
||||
McpSyncServer mcpServer = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0")
|
||||
.capabilities(McpSchema.ServerCapabilities.builder().resources(true, false).build())
|
||||
|
|
@ -1842,7 +1851,7 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
|
||||
mcpClient.initialize();
|
||||
|
||||
mcpClient.subscribeResource(new McpSchema.SubscribeRequest(resourceUri));
|
||||
mcpClient.subscribeResource(McpSchema.SubscribeRequest.builder(resourceUri).build());
|
||||
|
||||
mcpServer.notifyResourcesUpdated(new McpSchema.ResourcesUpdatedNotification(resourceUri));
|
||||
|
||||
|
|
@ -1866,13 +1875,10 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
var notificationCount = new java.util.concurrent.atomic.AtomicInteger(0);
|
||||
|
||||
McpServerFeatures.SyncResourceSpecification resourceSpec = new McpServerFeatures.SyncResourceSpecification(
|
||||
McpSchema.Resource.builder()
|
||||
.uri(resourceUri)
|
||||
.name("Subscribable Resource")
|
||||
.mimeType("text/plain")
|
||||
.build(),
|
||||
(exchange, req) -> new McpSchema.ReadResourceResult(
|
||||
List.of(new McpSchema.TextResourceContents(resourceUri, "text/plain", "content"))));
|
||||
McpSchema.Resource.builder(resourceUri, "Subscribable Resource").mimeType("text/plain").build(),
|
||||
(exchange, req) -> McpSchema.ReadResourceResult.builder(List
|
||||
.of(McpSchema.TextResourceContents.builder(resourceUri, "content").mimeType("text/plain").build()))
|
||||
.build());
|
||||
|
||||
McpSyncServer mcpServer = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0")
|
||||
.capabilities(McpSchema.ServerCapabilities.builder().resources(true, false).build())
|
||||
|
|
@ -1884,8 +1890,8 @@ public abstract class AbstractMcpClientServerIntegrationTests {
|
|||
|
||||
mcpClient.initialize();
|
||||
|
||||
mcpClient.subscribeResource(new McpSchema.SubscribeRequest(resourceUri));
|
||||
mcpClient.unsubscribeResource(new McpSchema.UnsubscribeRequest(resourceUri));
|
||||
mcpClient.subscribeResource(McpSchema.SubscribeRequest.builder(resourceUri).build());
|
||||
mcpClient.unsubscribeResource(McpSchema.UnsubscribeRequest.builder(resourceUri).build());
|
||||
|
||||
mcpServer.notifyResourcesUpdated(new McpSchema.ResourcesUpdatedNotification(resourceUri));
|
||||
|
||||
|
|
|
|||
|
|
@ -62,7 +62,8 @@ public abstract class AbstractStatelessIntegrationTests {
|
|||
|
||||
try (
|
||||
// Create client without sampling capabilities
|
||||
var client = clientBuilder.clientInfo(new McpSchema.Implementation("Sample " + "client", "0.0.0"))
|
||||
var client = clientBuilder
|
||||
.clientInfo(McpSchema.Implementation.builder("Sample " + "client", "0.0.0").build())
|
||||
.requestTimeout(Duration.ofSeconds(1000))
|
||||
.build()) {
|
||||
|
||||
|
|
@ -84,12 +85,12 @@ public abstract class AbstractStatelessIntegrationTests {
|
|||
var clientBuilder = clientBuilders.get(clientType);
|
||||
|
||||
var callResponse = McpSchema.CallToolResult.builder()
|
||||
.content(List.of(new McpSchema.TextContent("CALL RESPONSE")))
|
||||
.content(List.of(McpSchema.TextContent.builder("CALL RESPONSE").build()))
|
||||
.isError(false)
|
||||
.build();
|
||||
McpStatelessServerFeatures.SyncToolSpecification tool1 = McpStatelessServerFeatures.SyncToolSpecification
|
||||
.builder()
|
||||
.tool(Tool.builder().name("tool1").description("tool1 description").inputSchema(EMPTY_JSON_SCHEMA).build())
|
||||
.tool(Tool.builder("tool1", EMPTY_JSON_SCHEMA).description("tool1 description").build())
|
||||
.callHandler((ctx, request) -> {
|
||||
|
||||
try {
|
||||
|
|
@ -121,7 +122,8 @@ public abstract class AbstractStatelessIntegrationTests {
|
|||
|
||||
assertThat(mcpClient.listTools().tools()).contains(tool1.tool());
|
||||
|
||||
CallToolResult response = mcpClient.callTool(new McpSchema.CallToolRequest("tool1", Map.of()));
|
||||
CallToolResult response = mcpClient
|
||||
.callTool(McpSchema.CallToolRequest.builder("tool1").arguments(Map.of()).build());
|
||||
|
||||
assertThat(response).isNotNull().isEqualTo(callResponse);
|
||||
}
|
||||
|
|
@ -139,11 +141,7 @@ public abstract class AbstractStatelessIntegrationTests {
|
|||
McpStatelessSyncServer mcpServer = prepareSyncServerBuilder()
|
||||
.capabilities(ServerCapabilities.builder().tools(true).build())
|
||||
.tools(McpStatelessServerFeatures.SyncToolSpecification.builder()
|
||||
.tool(Tool.builder()
|
||||
.name("tool1")
|
||||
.description("tool1 description")
|
||||
.inputSchema(EMPTY_JSON_SCHEMA)
|
||||
.build())
|
||||
.tool(Tool.builder("tool1", EMPTY_JSON_SCHEMA).description("tool1 description").build())
|
||||
.callHandler((context, request) -> {
|
||||
// We trigger a timeout on blocking read, raising an exception
|
||||
Mono.never().block(Duration.ofSeconds(1));
|
||||
|
|
@ -159,8 +157,8 @@ public abstract class AbstractStatelessIntegrationTests {
|
|||
// We expect the tool call to fail immediately with the exception raised by
|
||||
// the offending tool
|
||||
// instead of getting back a timeout.
|
||||
assertThatExceptionOfType(McpError.class)
|
||||
.isThrownBy(() -> mcpClient.callTool(new McpSchema.CallToolRequest("tool1", Map.of())))
|
||||
assertThatExceptionOfType(McpError.class).isThrownBy(
|
||||
() -> mcpClient.callTool(McpSchema.CallToolRequest.builder("tool1").arguments(Map.of()).build()))
|
||||
.withMessageContaining("Timeout on blocking read");
|
||||
}
|
||||
finally {
|
||||
|
|
@ -175,12 +173,12 @@ public abstract class AbstractStatelessIntegrationTests {
|
|||
var clientBuilder = clientBuilders.get(clientType);
|
||||
|
||||
var callResponse = McpSchema.CallToolResult.builder()
|
||||
.content(List.of(new McpSchema.TextContent("CALL RESPONSE")))
|
||||
.content(List.of(McpSchema.TextContent.builder("CALL RESPONSE").build()))
|
||||
.isError(false)
|
||||
.build();
|
||||
McpStatelessServerFeatures.SyncToolSpecification tool1 = McpStatelessServerFeatures.SyncToolSpecification
|
||||
.builder()
|
||||
.tool(Tool.builder().name("tool1").description("tool1 description").inputSchema(EMPTY_JSON_SCHEMA).build())
|
||||
.tool(Tool.builder("tool1", EMPTY_JSON_SCHEMA).description("tool1 description").build())
|
||||
.callHandler((ctx, request) -> {
|
||||
// perform a blocking call to a remote service
|
||||
try {
|
||||
|
|
@ -238,11 +236,7 @@ public abstract class AbstractStatelessIntegrationTests {
|
|||
// Add a new tool
|
||||
McpStatelessServerFeatures.SyncToolSpecification tool2 = McpStatelessServerFeatures.SyncToolSpecification
|
||||
.builder()
|
||||
.tool(Tool.builder()
|
||||
.name("tool2")
|
||||
.description("tool2 description")
|
||||
.inputSchema(EMPTY_JSON_SCHEMA)
|
||||
.build())
|
||||
.tool(Tool.builder("tool2", EMPTY_JSON_SCHEMA).description("tool2 description").build())
|
||||
.callHandler((exchange, request) -> callResponse)
|
||||
.build();
|
||||
|
||||
|
|
@ -285,8 +279,7 @@ public abstract class AbstractStatelessIntegrationTests {
|
|||
Map.of("type", "string"), "timestamp", Map.of("type", "string")),
|
||||
"required", List.of("result", "operation"));
|
||||
|
||||
Tool calculatorTool = Tool.builder()
|
||||
.name("calculator")
|
||||
Tool calculatorTool = Tool.builder("calculator")
|
||||
.description("Performs mathematical calculations")
|
||||
.outputSchema(outputSchema)
|
||||
.build();
|
||||
|
|
@ -320,8 +313,8 @@ public abstract class AbstractStatelessIntegrationTests {
|
|||
// Note: outputSchema might be null in sync server, but validation still works
|
||||
|
||||
// Call tool with valid structured output
|
||||
CallToolResult response = mcpClient
|
||||
.callTool(new McpSchema.CallToolRequest("calculator", Map.of("expression", "2 + 3")));
|
||||
CallToolResult response = mcpClient.callTool(
|
||||
McpSchema.CallToolRequest.builder("calculator").arguments(Map.of("expression", "2 + 3")).build());
|
||||
|
||||
assertThat(response).isNotNull();
|
||||
assertThat(response.isError()).isFalse();
|
||||
|
|
@ -365,8 +358,7 @@ public abstract class AbstractStatelessIntegrationTests {
|
|||
"age", Map.of("type", "number")),
|
||||
"required", List.of("name", "age"))); // @formatter:on
|
||||
|
||||
Tool calculatorTool = Tool.builder()
|
||||
.name("getMembers")
|
||||
Tool calculatorTool = Tool.builder("getMembers")
|
||||
.description("Returns a list of members")
|
||||
.outputSchema(outputSchema)
|
||||
.build();
|
||||
|
|
@ -390,7 +382,8 @@ public abstract class AbstractStatelessIntegrationTests {
|
|||
assertThat(mcpClient.initialize()).isNotNull();
|
||||
|
||||
// Call tool with valid structured output of type array
|
||||
CallToolResult response = mcpClient.callTool(new McpSchema.CallToolRequest("getMembers", Map.of()));
|
||||
CallToolResult response = mcpClient
|
||||
.callTool(McpSchema.CallToolRequest.builder("getMembers").arguments(Map.of()).build());
|
||||
|
||||
assertThat(response).isNotNull();
|
||||
assertThat(response.isError()).isFalse();
|
||||
|
|
@ -420,8 +413,7 @@ public abstract class AbstractStatelessIntegrationTests {
|
|||
Map.of("type", "string"), "timestamp", Map.of("type", "string")),
|
||||
"required", List.of("result", "operation"));
|
||||
|
||||
Tool calculatorTool = Tool.builder()
|
||||
.name("calculator")
|
||||
Tool calculatorTool = Tool.builder("calculator")
|
||||
.description("Performs mathematical calculations")
|
||||
.outputSchema(outputSchema)
|
||||
.build();
|
||||
|
|
@ -432,7 +424,7 @@ public abstract class AbstractStatelessIntegrationTests {
|
|||
.tool(calculatorTool)
|
||||
.callHandler((exchange, request) -> CallToolResult.builder()
|
||||
.isError(true)
|
||||
.content(List.of(new TextContent("Error calling tool: Simulated in-handler error")))
|
||||
.content(List.of(TextContent.builder("Error calling tool: Simulated in-handler error").build()))
|
||||
.build())
|
||||
.build();
|
||||
|
||||
|
|
@ -452,14 +444,14 @@ public abstract class AbstractStatelessIntegrationTests {
|
|||
// Note: outputSchema might be null in sync server, but validation still works
|
||||
|
||||
// Call tool with valid structured output
|
||||
CallToolResult response = mcpClient
|
||||
.callTool(new McpSchema.CallToolRequest("calculator", Map.of("expression", "2 + 3")));
|
||||
CallToolResult response = mcpClient.callTool(
|
||||
McpSchema.CallToolRequest.builder("calculator").arguments(Map.of("expression", "2 + 3")).build());
|
||||
|
||||
assertThat(response).isNotNull();
|
||||
assertThat(response.isError()).isTrue();
|
||||
assertThat(response.content()).isNotEmpty();
|
||||
assertThat(response.content())
|
||||
.containsExactly(new McpSchema.TextContent("Error calling tool: Simulated in-handler error"));
|
||||
assertThat(response.content()).containsExactly(
|
||||
McpSchema.TextContent.builder("Error calling tool: Simulated in-handler error").build());
|
||||
assertThat(response.structuredContent()).isNull();
|
||||
}
|
||||
finally {
|
||||
|
|
@ -478,8 +470,7 @@ public abstract class AbstractStatelessIntegrationTests {
|
|||
Map.of("result", Map.of("type", "number"), "operation", Map.of("type", "string")), "required",
|
||||
List.of("result", "operation"));
|
||||
|
||||
Tool calculatorTool = Tool.builder()
|
||||
.name("calculator")
|
||||
Tool calculatorTool = Tool.builder("calculator")
|
||||
.description("Performs mathematical calculations")
|
||||
.outputSchema(outputSchema)
|
||||
.build();
|
||||
|
|
@ -507,8 +498,8 @@ public abstract class AbstractStatelessIntegrationTests {
|
|||
assertThat(initResult).isNotNull();
|
||||
|
||||
// Call tool with invalid structured output
|
||||
CallToolResult response = mcpClient
|
||||
.callTool(new McpSchema.CallToolRequest("calculator", Map.of("expression", "2 + 3")));
|
||||
CallToolResult response = mcpClient.callTool(
|
||||
McpSchema.CallToolRequest.builder("calculator").arguments(Map.of("expression", "2 + 3")).build());
|
||||
|
||||
assertThat(response).isNotNull();
|
||||
assertThat(response.isError()).isTrue();
|
||||
|
|
@ -533,8 +524,7 @@ public abstract class AbstractStatelessIntegrationTests {
|
|||
Map<String, Object> outputSchema = Map.of("type", "object", "properties",
|
||||
Map.of("result", Map.of("type", "number")), "required", List.of("result"));
|
||||
|
||||
Tool calculatorTool = Tool.builder()
|
||||
.name("calculator")
|
||||
Tool calculatorTool = Tool.builder("calculator")
|
||||
.description("Performs mathematical calculations")
|
||||
.outputSchema(outputSchema)
|
||||
.build();
|
||||
|
|
@ -557,8 +547,8 @@ public abstract class AbstractStatelessIntegrationTests {
|
|||
assertThat(initResult).isNotNull();
|
||||
|
||||
// Call tool that should return structured content but doesn't
|
||||
CallToolResult response = mcpClient
|
||||
.callTool(new McpSchema.CallToolRequest("calculator", Map.of("expression", "2 + 3")));
|
||||
CallToolResult response = mcpClient.callTool(
|
||||
McpSchema.CallToolRequest.builder("calculator").arguments(Map.of("expression", "2 + 3")).build());
|
||||
|
||||
assertThat(response).isNotNull();
|
||||
assertThat(response.isError()).isTrue();
|
||||
|
|
@ -597,8 +587,7 @@ public abstract class AbstractStatelessIntegrationTests {
|
|||
Map.of("message", Map.of("type", "string"), "count", Map.of("type", "integer")), "required",
|
||||
List.of("message", "count"));
|
||||
|
||||
Tool dynamicTool = Tool.builder()
|
||||
.name("dynamic-tool")
|
||||
Tool dynamicTool = Tool.builder("dynamic-tool")
|
||||
.description("Dynamically added tool")
|
||||
.outputSchema(outputSchema)
|
||||
.build();
|
||||
|
|
@ -630,7 +619,7 @@ public abstract class AbstractStatelessIntegrationTests {
|
|||
|
||||
// Call dynamically added tool
|
||||
CallToolResult response = mcpClient
|
||||
.callTool(new McpSchema.CallToolRequest("dynamic-tool", Map.of("count", 3)));
|
||||
.callTool(McpSchema.CallToolRequest.builder("dynamic-tool").arguments(Map.of("count", 3)).build());
|
||||
|
||||
assertThat(response).isNotNull();
|
||||
assertThat(response.isError()).isFalse();
|
||||
|
|
|
|||
|
|
@ -205,7 +205,9 @@ public abstract class AbstractMcpAsyncClientResiliencyTests {
|
|||
|
||||
String name = tools.get().get(0).name();
|
||||
// Assuming this is the echo tool
|
||||
McpSchema.CallToolRequest request = new McpSchema.CallToolRequest(name, Map.of("message", "hello"));
|
||||
McpSchema.CallToolRequest request = McpSchema.CallToolRequest.builder(name)
|
||||
.arguments(Map.of("message", "hello"))
|
||||
.build();
|
||||
StepVerifier.create(mcpAsyncClient.callTool(request)).expectError().verify();
|
||||
|
||||
reconnect();
|
||||
|
|
|
|||
|
|
@ -85,8 +85,10 @@ public abstract class AbstractMcpAsyncClientTests {
|
|||
McpClient.AsyncSpec builder = McpClient.async(transport)
|
||||
.requestTimeout(getRequestTimeout())
|
||||
.initializationTimeout(getInitializationTimeout())
|
||||
.sampling(req -> Mono.just(new CreateMessageResult(McpSchema.Role.USER,
|
||||
new McpSchema.TextContent("Oh, hi!"), "modelId", CreateMessageResult.StopReason.END_TURN)))
|
||||
.sampling(req -> Mono.just(CreateMessageResult
|
||||
.builder(McpSchema.Role.USER, McpSchema.TextContent.builder("Oh, hi!").build(), "modelId")
|
||||
.stopReason(CreateMessageResult.StopReason.END_TURN)
|
||||
.build()))
|
||||
.capabilities(ClientCapabilities.builder().roots(true).sampling().build());
|
||||
builder = customizer.apply(builder);
|
||||
client.set(builder.build());
|
||||
|
|
@ -176,11 +178,7 @@ public abstract class AbstractMcpAsyncClientTests {
|
|||
assertThat(result.tools()).isNotNull();
|
||||
// Verify that the returned list is immutable
|
||||
assertThatThrownBy(() -> result.tools()
|
||||
.add(Tool.builder()
|
||||
.name("test")
|
||||
.title("test")
|
||||
.inputSchema(JSON_MAPPER, "{\"type\":\"object\"}")
|
||||
.build()))
|
||||
.add(Tool.builder("test", JSON_MAPPER, "{\"type\":\"object\"}").title("test").build()))
|
||||
.isInstanceOf(UnsupportedOperationException.class);
|
||||
})
|
||||
.verifyComplete();
|
||||
|
|
@ -203,14 +201,18 @@ public abstract class AbstractMcpAsyncClientTests {
|
|||
|
||||
@Test
|
||||
void testCallToolWithoutInitialization() {
|
||||
CallToolRequest callToolRequest = new CallToolRequest("echo", Map.of("message", ECHO_TEST_MESSAGE));
|
||||
CallToolRequest callToolRequest = CallToolRequest.builder("echo")
|
||||
.arguments(Map.of("message", ECHO_TEST_MESSAGE))
|
||||
.build();
|
||||
verifyCallSucceedsWithImplicitInitialization(client -> client.callTool(callToolRequest), "calling tools");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCallTool() {
|
||||
withClient(createMcpTransport(), mcpAsyncClient -> {
|
||||
CallToolRequest callToolRequest = new CallToolRequest("echo", Map.of("message", ECHO_TEST_MESSAGE));
|
||||
CallToolRequest callToolRequest = CallToolRequest.builder("echo")
|
||||
.arguments(Map.of("message", ECHO_TEST_MESSAGE))
|
||||
.build();
|
||||
|
||||
StepVerifier.create(mcpAsyncClient.initialize().then(mcpAsyncClient.callTool(callToolRequest)))
|
||||
.consumeNextWith(callToolResult -> {
|
||||
|
|
@ -226,8 +228,9 @@ public abstract class AbstractMcpAsyncClientTests {
|
|||
@Test
|
||||
void testCallToolWithInvalidTool() {
|
||||
withClient(createMcpTransport(), mcpAsyncClient -> {
|
||||
CallToolRequest invalidRequest = new CallToolRequest("nonexistent_tool",
|
||||
Map.of("message", ECHO_TEST_MESSAGE));
|
||||
CallToolRequest invalidRequest = CallToolRequest.builder("nonexistent_tool")
|
||||
.arguments(Map.of("message", ECHO_TEST_MESSAGE))
|
||||
.build();
|
||||
|
||||
StepVerifier.create(mcpAsyncClient.initialize().then(mcpAsyncClient.callTool(invalidRequest)))
|
||||
.consumeErrorWith(
|
||||
|
|
@ -243,8 +246,9 @@ public abstract class AbstractMcpAsyncClientTests {
|
|||
|
||||
withClient(transport, mcpAsyncClient -> {
|
||||
StepVerifier.create(mcpAsyncClient.initialize()
|
||||
.then(mcpAsyncClient.callTool(new McpSchema.CallToolRequest("annotatedMessage",
|
||||
Map.of("messageType", messageType, "includeImage", true)))))
|
||||
.then(mcpAsyncClient.callTool(McpSchema.CallToolRequest.builder("annotatedMessage")
|
||||
.arguments(Map.of("messageType", messageType, "includeImage", true))
|
||||
.build())))
|
||||
.consumeNextWith(result -> {
|
||||
assertThat(result).isNotNull();
|
||||
assertThat(result.isError()).isNotEqualTo(true);
|
||||
|
|
@ -345,8 +349,7 @@ public abstract class AbstractMcpAsyncClientTests {
|
|||
.consumeNextWith(result -> {
|
||||
assertThat(result.resources()).isNotNull();
|
||||
// Verify that the returned list is immutable
|
||||
assertThatThrownBy(
|
||||
() -> result.resources().add(Resource.builder().uri("test://uri").name("test").build()))
|
||||
assertThatThrownBy(() -> result.resources().add(Resource.builder("test://uri", "test").build()))
|
||||
.isInstanceOf(UnsupportedOperationException.class);
|
||||
})
|
||||
.verifyComplete();
|
||||
|
|
@ -411,7 +414,8 @@ public abstract class AbstractMcpAsyncClientTests {
|
|||
.consumeNextWith(result -> {
|
||||
assertThat(result.prompts()).isNotNull();
|
||||
// Verify that the returned list is immutable
|
||||
assertThatThrownBy(() -> result.prompts().add(new Prompt("test", "test", "test", null)))
|
||||
assertThatThrownBy(() -> result.prompts()
|
||||
.add(Prompt.builder("test").title("test").description("test").build()))
|
||||
.isInstanceOf(UnsupportedOperationException.class);
|
||||
})
|
||||
.verifyComplete();
|
||||
|
|
@ -420,7 +424,7 @@ public abstract class AbstractMcpAsyncClientTests {
|
|||
|
||||
@Test
|
||||
void testGetPromptWithoutInitialization() {
|
||||
GetPromptRequest request = new GetPromptRequest("simple_prompt", Map.of());
|
||||
GetPromptRequest request = GetPromptRequest.builder("simple_prompt").arguments(Map.of()).build();
|
||||
verifyCallSucceedsWithImplicitInitialization(client -> client.getPrompt(request), "getting " + "prompts");
|
||||
}
|
||||
|
||||
|
|
@ -429,7 +433,8 @@ public abstract class AbstractMcpAsyncClientTests {
|
|||
withClient(createMcpTransport(), mcpAsyncClient -> {
|
||||
StepVerifier
|
||||
.create(mcpAsyncClient.initialize()
|
||||
.then(mcpAsyncClient.getPrompt(new GetPromptRequest("simple_prompt", Map.of()))))
|
||||
.then(mcpAsyncClient
|
||||
.getPrompt(GetPromptRequest.builder("simple_prompt").arguments(Map.of()).build())))
|
||||
.consumeNextWith(prompt -> {
|
||||
assertThat(prompt).isNotNull().satisfies(result -> {
|
||||
assertThat(result.messages()).isNotEmpty();
|
||||
|
|
@ -456,8 +461,8 @@ public abstract class AbstractMcpAsyncClientTests {
|
|||
|
||||
@Test
|
||||
void testInitializeWithRootsListProviders() {
|
||||
withClient(createMcpTransport(), builder -> builder.roots(new Root("file:///test/path", "test-root")),
|
||||
client -> {
|
||||
withClient(createMcpTransport(),
|
||||
builder -> builder.roots(Root.builder("file:///test/path").name("test-root").build()), client -> {
|
||||
StepVerifier.create(client.initialize().then(client.closeGracefully())).verifyComplete();
|
||||
});
|
||||
}
|
||||
|
|
@ -465,7 +470,7 @@ public abstract class AbstractMcpAsyncClientTests {
|
|||
@Test
|
||||
void testAddRoot() {
|
||||
withClient(createMcpTransport(), mcpAsyncClient -> {
|
||||
Root newRoot = new Root("file:///new/test/path", "new-test-root");
|
||||
Root newRoot = Root.builder("file:///new/test/path").name("new-test-root").build();
|
||||
StepVerifier.create(mcpAsyncClient.addRoot(newRoot)).verifyComplete();
|
||||
});
|
||||
}
|
||||
|
|
@ -483,7 +488,7 @@ public abstract class AbstractMcpAsyncClientTests {
|
|||
@Test
|
||||
void testRemoveRoot() {
|
||||
withClient(createMcpTransport(), mcpAsyncClient -> {
|
||||
Root root = new Root("file:///test/path/to/remove", "root-to-remove");
|
||||
Root root = Root.builder("file:///test/path/to/remove").name("root-to-remove").build();
|
||||
StepVerifier.create(mcpAsyncClient.addRoot(root)).verifyComplete();
|
||||
|
||||
StepVerifier.create(mcpAsyncClient.removeRoot(root.uri())).verifyComplete();
|
||||
|
|
@ -603,7 +608,7 @@ public abstract class AbstractMcpAsyncClientTests {
|
|||
assertThat(result.resourceTemplates()).isNotNull();
|
||||
// Verify that the returned list is immutable
|
||||
assertThatThrownBy(() -> result.resourceTemplates()
|
||||
.add(new McpSchema.ResourceTemplate("test://template", "test", "test", null, null, null)))
|
||||
.add(McpSchema.ResourceTemplate.builder("test://template", "test").title("test").build()))
|
||||
.isInstanceOf(UnsupportedOperationException.class);
|
||||
})
|
||||
.verifyComplete();
|
||||
|
|
@ -618,8 +623,8 @@ public abstract class AbstractMcpAsyncClientTests {
|
|||
return Mono.empty();
|
||||
}
|
||||
Resource firstResource = resources.resources().get(0);
|
||||
return mcpAsyncClient.subscribeResource(new SubscribeRequest(firstResource.uri()))
|
||||
.then(mcpAsyncClient.unsubscribeResource(new UnsubscribeRequest(firstResource.uri())));
|
||||
return mcpAsyncClient.subscribeResource(SubscribeRequest.builder(firstResource.uri()).build())
|
||||
.then(mcpAsyncClient.unsubscribeResource(UnsubscribeRequest.builder(firstResource.uri()).build()));
|
||||
})).verifyComplete();
|
||||
});
|
||||
}
|
||||
|
|
@ -646,9 +651,8 @@ public abstract class AbstractMcpAsyncClientTests {
|
|||
@Test
|
||||
void testInitializeWithSamplingCapability() {
|
||||
ClientCapabilities capabilities = ClientCapabilities.builder().sampling().build();
|
||||
CreateMessageResult createMessageResult = CreateMessageResult.builder()
|
||||
.message("test")
|
||||
.model("test-model")
|
||||
CreateMessageResult createMessageResult = CreateMessageResult
|
||||
.builder(McpSchema.Role.ASSISTANT, "test", "test-model")
|
||||
.build();
|
||||
withClient(createMcpTransport(),
|
||||
builder -> builder.capabilities(capabilities).sampling(request -> Mono.just(createMessageResult)),
|
||||
|
|
@ -660,8 +664,7 @@ public abstract class AbstractMcpAsyncClientTests {
|
|||
@Test
|
||||
void testInitializeWithElicitationCapability() {
|
||||
ClientCapabilities capabilities = ClientCapabilities.builder().elicitation().build();
|
||||
ElicitResult elicitResult = ElicitResult.builder()
|
||||
.message(ElicitResult.Action.ACCEPT)
|
||||
ElicitResult elicitResult = ElicitResult.builder(ElicitResult.Action.ACCEPT)
|
||||
.content(Map.of("foo", "bar"))
|
||||
.build();
|
||||
withClient(createMcpTransport(),
|
||||
|
|
@ -680,10 +683,10 @@ public abstract class AbstractMcpAsyncClientTests {
|
|||
.build();
|
||||
|
||||
Function<CreateMessageRequest, Mono<CreateMessageResult>> samplingHandler = request -> Mono
|
||||
.just(CreateMessageResult.builder().message("test").model("test-model").build());
|
||||
.just(CreateMessageResult.builder(McpSchema.Role.ASSISTANT, "test", "test-model").build());
|
||||
|
||||
Function<ElicitRequest, Mono<ElicitResult>> elicitationHandler = request -> Mono
|
||||
.just(ElicitResult.builder().message(ElicitResult.Action.ACCEPT).content(Map.of("foo", "bar")).build());
|
||||
.just(ElicitResult.builder(ElicitResult.Action.ACCEPT).content(Map.of("foo", "bar")).build());
|
||||
|
||||
withClient(createMcpTransport(),
|
||||
builder -> builder.capabilities(capabilities).sampling(samplingHandler).elicitation(elicitationHandler),
|
||||
|
|
@ -757,15 +760,16 @@ public abstract class AbstractMcpAsyncClientTests {
|
|||
receivedMessage.set(messageText.text());
|
||||
receivedMaxTokens.set(request.maxTokens());
|
||||
|
||||
return Mono
|
||||
.just(new McpSchema.CreateMessageResult(McpSchema.Role.USER, new McpSchema.TextContent(response),
|
||||
"modelId", McpSchema.CreateMessageResult.StopReason.END_TURN));
|
||||
return Mono.just(McpSchema.CreateMessageResult
|
||||
.builder(McpSchema.Role.USER, McpSchema.TextContent.builder(response).build(), "modelId")
|
||||
.stopReason(McpSchema.CreateMessageResult.StopReason.END_TURN)
|
||||
.build());
|
||||
}), client -> {
|
||||
StepVerifier.create(client.initialize()).expectNextMatches(Objects::nonNull).verifyComplete();
|
||||
|
||||
StepVerifier.create(client.callTool(
|
||||
new McpSchema.CallToolRequest("sampleLLM", Map.of("prompt", message, "maxTokens", maxTokens))))
|
||||
.consumeNextWith(result -> {
|
||||
StepVerifier.create(client.callTool(McpSchema.CallToolRequest.builder("sampleLLM")
|
||||
.arguments(Map.of("prompt", message, "maxTokens", maxTokens))
|
||||
.build())).consumeNextWith(result -> {
|
||||
// Verify tool response to ensure our sampling response was passed
|
||||
// through
|
||||
assertThat(result.content()).hasAtLeastOneElementOfType(McpSchema.TextContent.class);
|
||||
|
|
@ -780,8 +784,7 @@ public abstract class AbstractMcpAsyncClientTests {
|
|||
assertThat(receivedPrompt.get()).isNotEmpty();
|
||||
assertThat(receivedMessage.get()).endsWith(message); // Prefixed
|
||||
assertThat(receivedMaxTokens.get()).isEqualTo(maxTokens);
|
||||
})
|
||||
.verifyComplete();
|
||||
}).verifyComplete();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -186,14 +186,16 @@ public abstract class AbstractMcpSyncClientTests {
|
|||
@Test
|
||||
void testCallToolsWithoutInitialization() {
|
||||
verifyCallSucceedsWithImplicitInitialization(
|
||||
client -> client.callTool(new CallToolRequest("add", Map.of("a", 3, "b", 4))), "calling tools");
|
||||
client -> client.callTool(CallToolRequest.builder("add").arguments(Map.of("a", 3, "b", 4)).build()),
|
||||
"calling tools");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCallTools() {
|
||||
withClient(createMcpTransport(), mcpSyncClient -> {
|
||||
mcpSyncClient.initialize();
|
||||
CallToolResult toolResult = mcpSyncClient.callTool(new CallToolRequest("add", Map.of("a", 3, "b", 4)));
|
||||
CallToolResult toolResult = mcpSyncClient
|
||||
.callTool(CallToolRequest.builder("add").arguments(Map.of("a", 3, "b", 4)).build());
|
||||
|
||||
assertThat(toolResult).isNotNull().satisfies(result -> {
|
||||
|
||||
|
|
@ -223,7 +225,9 @@ public abstract class AbstractMcpSyncClientTests {
|
|||
|
||||
@Test
|
||||
void testCallToolWithoutInitialization() {
|
||||
CallToolRequest callToolRequest = new CallToolRequest("echo", Map.of("message", TEST_MESSAGE));
|
||||
CallToolRequest callToolRequest = CallToolRequest.builder("echo")
|
||||
.arguments(Map.of("message", TEST_MESSAGE))
|
||||
.build();
|
||||
verifyCallSucceedsWithImplicitInitialization(client -> client.callTool(callToolRequest), "calling tools");
|
||||
}
|
||||
|
||||
|
|
@ -231,7 +235,9 @@ public abstract class AbstractMcpSyncClientTests {
|
|||
void testCallTool() {
|
||||
withClient(createMcpTransport(), mcpSyncClient -> {
|
||||
mcpSyncClient.initialize();
|
||||
CallToolRequest callToolRequest = new CallToolRequest("echo", Map.of("message", TEST_MESSAGE));
|
||||
CallToolRequest callToolRequest = CallToolRequest.builder("echo")
|
||||
.arguments(Map.of("message", TEST_MESSAGE))
|
||||
.build();
|
||||
|
||||
CallToolResult callToolResult = mcpSyncClient.callTool(callToolRequest);
|
||||
|
||||
|
|
@ -245,7 +251,9 @@ public abstract class AbstractMcpSyncClientTests {
|
|||
@Test
|
||||
void testCallToolWithInvalidTool() {
|
||||
withClient(createMcpTransport(), mcpSyncClient -> {
|
||||
CallToolRequest invalidRequest = new CallToolRequest("nonexistent_tool", Map.of("message", TEST_MESSAGE));
|
||||
CallToolRequest invalidRequest = CallToolRequest.builder("nonexistent_tool")
|
||||
.arguments(Map.of("message", TEST_MESSAGE))
|
||||
.build();
|
||||
|
||||
assertThatThrownBy(() -> mcpSyncClient.callTool(invalidRequest)).isInstanceOf(Exception.class);
|
||||
});
|
||||
|
|
@ -259,8 +267,9 @@ public abstract class AbstractMcpSyncClientTests {
|
|||
withClient(transport, client -> {
|
||||
client.initialize();
|
||||
|
||||
McpSchema.CallToolResult result = client.callTool(new McpSchema.CallToolRequest("annotatedMessage",
|
||||
Map.of("messageType", messageType, "includeImage", true)));
|
||||
McpSchema.CallToolResult result = client.callTool(McpSchema.CallToolRequest.builder("annotatedMessage")
|
||||
.arguments(Map.of("messageType", messageType, "includeImage", true))
|
||||
.build());
|
||||
|
||||
assertThat(result).isNotNull();
|
||||
assertThat(result.isError()).isNotEqualTo(true);
|
||||
|
|
@ -370,7 +379,8 @@ public abstract class AbstractMcpSyncClientTests {
|
|||
|
||||
@Test
|
||||
void testInitializeWithRootsListProviders() {
|
||||
withClient(createMcpTransport(), builder -> builder.roots(new Root("file:///test/path", "test-root")),
|
||||
withClient(createMcpTransport(),
|
||||
builder -> builder.roots(Root.builder("file:///test/path").name("test-root").build()),
|
||||
mcpSyncClient -> {
|
||||
|
||||
assertThatCode(() -> {
|
||||
|
|
@ -383,7 +393,7 @@ public abstract class AbstractMcpSyncClientTests {
|
|||
@Test
|
||||
void testAddRoot() {
|
||||
withClient(createMcpTransport(), mcpSyncClient -> {
|
||||
Root newRoot = new Root("file:///new/test/path", "new-test-root");
|
||||
Root newRoot = Root.builder("file:///new/test/path").name("new-test-root").build();
|
||||
assertThatCode(() -> mcpSyncClient.addRoot(newRoot)).doesNotThrowAnyException();
|
||||
});
|
||||
}
|
||||
|
|
@ -398,7 +408,7 @@ public abstract class AbstractMcpSyncClientTests {
|
|||
@Test
|
||||
void testRemoveRoot() {
|
||||
withClient(createMcpTransport(), mcpSyncClient -> {
|
||||
Root root = new Root("file:///test/path/to/remove", "root-to-remove");
|
||||
Root root = Root.builder("file:///test/path/to/remove").name("root-to-remove").build();
|
||||
assertThatCode(() -> {
|
||||
mcpSyncClient.addRoot(root);
|
||||
mcpSyncClient.removeRoot(root.uri());
|
||||
|
|
@ -533,11 +543,13 @@ public abstract class AbstractMcpSyncClientTests {
|
|||
Resource firstResource = resources.resources().get(0);
|
||||
|
||||
// Test subscribe
|
||||
assertThatCode(() -> mcpSyncClient.subscribeResource(new SubscribeRequest(firstResource.uri())))
|
||||
assertThatCode(
|
||||
() -> mcpSyncClient.subscribeResource(SubscribeRequest.builder(firstResource.uri()).build()))
|
||||
.doesNotThrowAnyException();
|
||||
|
||||
// Test unsubscribe
|
||||
assertThatCode(() -> mcpSyncClient.unsubscribeResource(new UnsubscribeRequest(firstResource.uri())))
|
||||
assertThatCode(() -> mcpSyncClient
|
||||
.unsubscribeResource(UnsubscribeRequest.builder(firstResource.uri()).build()))
|
||||
.doesNotThrowAnyException();
|
||||
}
|
||||
});
|
||||
|
|
@ -623,13 +635,16 @@ public abstract class AbstractMcpSyncClientTests {
|
|||
receivedMessage.set(messageText.text());
|
||||
receivedMaxTokens.set(request.maxTokens());
|
||||
|
||||
return new McpSchema.CreateMessageResult(McpSchema.Role.USER, new McpSchema.TextContent(response),
|
||||
"modelId", McpSchema.CreateMessageResult.StopReason.END_TURN);
|
||||
return McpSchema.CreateMessageResult
|
||||
.builder(McpSchema.Role.USER, McpSchema.TextContent.builder(response).build(), "modelId")
|
||||
.stopReason(McpSchema.CreateMessageResult.StopReason.END_TURN)
|
||||
.build();
|
||||
}), client -> {
|
||||
client.initialize();
|
||||
|
||||
McpSchema.CallToolResult result = client.callTool(
|
||||
new McpSchema.CallToolRequest("sampleLLM", Map.of("prompt", message, "maxTokens", maxTokens)));
|
||||
McpSchema.CallToolResult result = client.callTool(McpSchema.CallToolRequest.builder("sampleLLM")
|
||||
.arguments(Map.of("prompt", message, "maxTokens", maxTokens))
|
||||
.build());
|
||||
|
||||
// Verify tool response to ensure our sampling response was passed through
|
||||
assertThat(result.content()).hasAtLeastOneElementOfType(McpSchema.TextContent.class);
|
||||
|
|
|
|||
|
|
@ -99,11 +99,7 @@ public abstract class AbstractMcpAsyncServerTests {
|
|||
// ---------------------------------------
|
||||
@Test
|
||||
void testAddToolCall() {
|
||||
Tool newTool = McpSchema.Tool.builder()
|
||||
.name("new-tool")
|
||||
.title("New test tool")
|
||||
.inputSchema(EMPTY_JSON_SCHEMA)
|
||||
.build();
|
||||
Tool newTool = McpSchema.Tool.builder("new-tool", EMPTY_JSON_SCHEMA).title("New test tool").build();
|
||||
|
||||
var mcpAsyncServer = prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0")
|
||||
.capabilities(ServerCapabilities.builder().tools(true).build())
|
||||
|
|
@ -120,11 +116,7 @@ public abstract class AbstractMcpAsyncServerTests {
|
|||
|
||||
@Test
|
||||
void testAddDuplicateToolCall() {
|
||||
Tool duplicateTool = McpSchema.Tool.builder()
|
||||
.name(TEST_TOOL_NAME)
|
||||
.title("Duplicate tool")
|
||||
.inputSchema(EMPTY_JSON_SCHEMA)
|
||||
.build();
|
||||
Tool duplicateTool = McpSchema.Tool.builder(TEST_TOOL_NAME, EMPTY_JSON_SCHEMA).title("Duplicate tool").build();
|
||||
|
||||
var mcpAsyncServer = prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0")
|
||||
.capabilities(ServerCapabilities.builder().tools(true).build())
|
||||
|
|
@ -144,10 +136,8 @@ public abstract class AbstractMcpAsyncServerTests {
|
|||
|
||||
@Test
|
||||
void testDuplicateToolCallDuringBuilding() {
|
||||
Tool duplicateTool = McpSchema.Tool.builder()
|
||||
.name("duplicate-build-toolcall")
|
||||
Tool duplicateTool = McpSchema.Tool.builder("duplicate-build-toolcall", EMPTY_JSON_SCHEMA)
|
||||
.title("Duplicate toolcall during building")
|
||||
.inputSchema(EMPTY_JSON_SCHEMA)
|
||||
.build();
|
||||
|
||||
assertThatThrownBy(() -> prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0")
|
||||
|
|
@ -164,10 +154,8 @@ public abstract class AbstractMcpAsyncServerTests {
|
|||
|
||||
@Test
|
||||
void testDuplicateToolsInBatchListRegistration() {
|
||||
Tool duplicateTool = McpSchema.Tool.builder()
|
||||
.name("batch-list-tool")
|
||||
Tool duplicateTool = McpSchema.Tool.builder("batch-list-tool", EMPTY_JSON_SCHEMA)
|
||||
.title("Duplicate tool in batch list")
|
||||
.inputSchema(EMPTY_JSON_SCHEMA)
|
||||
.build();
|
||||
|
||||
List<McpServerFeatures.AsyncToolSpecification> specs = List.of(
|
||||
|
|
@ -192,10 +180,8 @@ public abstract class AbstractMcpAsyncServerTests {
|
|||
|
||||
@Test
|
||||
void testDuplicateToolsInBatchVarargsRegistration() {
|
||||
Tool duplicateTool = McpSchema.Tool.builder()
|
||||
.name("batch-varargs-tool")
|
||||
Tool duplicateTool = McpSchema.Tool.builder("batch-varargs-tool", EMPTY_JSON_SCHEMA)
|
||||
.title("Duplicate tool in batch varargs")
|
||||
.inputSchema(EMPTY_JSON_SCHEMA)
|
||||
.build();
|
||||
|
||||
assertThatThrownBy(() -> prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0")
|
||||
|
|
@ -217,11 +203,7 @@ public abstract class AbstractMcpAsyncServerTests {
|
|||
|
||||
@Test
|
||||
void testRemoveTool() {
|
||||
Tool too = McpSchema.Tool.builder()
|
||||
.name(TEST_TOOL_NAME)
|
||||
.title("Duplicate tool")
|
||||
.inputSchema(EMPTY_JSON_SCHEMA)
|
||||
.build();
|
||||
Tool too = McpSchema.Tool.builder(TEST_TOOL_NAME, EMPTY_JSON_SCHEMA).title("Duplicate tool").build();
|
||||
|
||||
var mcpAsyncServer = prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0")
|
||||
.capabilities(ServerCapabilities.builder().tools(true).build())
|
||||
|
|
@ -248,11 +230,7 @@ public abstract class AbstractMcpAsyncServerTests {
|
|||
|
||||
@Test
|
||||
void testNotifyToolsListChanged() {
|
||||
Tool too = McpSchema.Tool.builder()
|
||||
.name(TEST_TOOL_NAME)
|
||||
.title("Duplicate tool")
|
||||
.inputSchema(EMPTY_JSON_SCHEMA)
|
||||
.build();
|
||||
Tool too = McpSchema.Tool.builder(TEST_TOOL_NAME, EMPTY_JSON_SCHEMA).title("Duplicate tool").build();
|
||||
|
||||
var mcpAsyncServer = prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0")
|
||||
.capabilities(ServerCapabilities.builder().tools(true).build())
|
||||
|
|
@ -296,15 +274,13 @@ public abstract class AbstractMcpAsyncServerTests {
|
|||
.capabilities(ServerCapabilities.builder().resources(true, false).build())
|
||||
.build();
|
||||
|
||||
Resource resource = Resource.builder()
|
||||
.uri(TEST_RESOURCE_URI)
|
||||
.name("Test Resource")
|
||||
Resource resource = Resource.builder(TEST_RESOURCE_URI, "Test Resource")
|
||||
.title("Test Resource")
|
||||
.mimeType("text/plain")
|
||||
.description("Test resource description")
|
||||
.build();
|
||||
McpServerFeatures.AsyncResourceSpecification specification = new McpServerFeatures.AsyncResourceSpecification(
|
||||
resource, (exchange, req) -> Mono.just(new ReadResourceResult(List.of())));
|
||||
resource, (exchange, req) -> Mono.just(ReadResourceResult.builder(List.of()).build()));
|
||||
|
||||
StepVerifier.create(mcpAsyncServer.addResource(specification)).verifyComplete();
|
||||
|
||||
|
|
@ -330,15 +306,13 @@ public abstract class AbstractMcpAsyncServerTests {
|
|||
// Create a server without resource capabilities
|
||||
McpAsyncServer serverWithoutResources = prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0").build();
|
||||
|
||||
Resource resource = Resource.builder()
|
||||
.uri(TEST_RESOURCE_URI)
|
||||
.name("Test Resource")
|
||||
Resource resource = Resource.builder(TEST_RESOURCE_URI, "Test Resource")
|
||||
.title("Test Resource")
|
||||
.mimeType("text/plain")
|
||||
.description("Test resource description")
|
||||
.build();
|
||||
McpServerFeatures.AsyncResourceSpecification specification = new McpServerFeatures.AsyncResourceSpecification(
|
||||
resource, (exchange, req) -> Mono.just(new ReadResourceResult(List.of())));
|
||||
resource, (exchange, req) -> Mono.just(ReadResourceResult.builder(List.of()).build()));
|
||||
|
||||
StepVerifier.create(serverWithoutResources.addResource(specification)).verifyErrorSatisfies(error -> {
|
||||
assertThat(error).isInstanceOf(IllegalStateException.class)
|
||||
|
|
@ -363,15 +337,13 @@ public abstract class AbstractMcpAsyncServerTests {
|
|||
.capabilities(ServerCapabilities.builder().resources(true, false).build())
|
||||
.build();
|
||||
|
||||
Resource resource = Resource.builder()
|
||||
.uri(TEST_RESOURCE_URI)
|
||||
.name("Test Resource")
|
||||
Resource resource = Resource.builder(TEST_RESOURCE_URI, "Test Resource")
|
||||
.title("Test Resource")
|
||||
.mimeType("text/plain")
|
||||
.description("Test resource description")
|
||||
.build();
|
||||
McpServerFeatures.AsyncResourceSpecification specification = new McpServerFeatures.AsyncResourceSpecification(
|
||||
resource, (exchange, req) -> Mono.just(new ReadResourceResult(List.of())));
|
||||
resource, (exchange, req) -> Mono.just(ReadResourceResult.builder(List.of()).build()));
|
||||
|
||||
StepVerifier
|
||||
.create(mcpAsyncServer.addResource(specification).then(mcpAsyncServer.listResources().collectList()))
|
||||
|
|
@ -387,15 +359,13 @@ public abstract class AbstractMcpAsyncServerTests {
|
|||
.capabilities(ServerCapabilities.builder().resources(true, false).build())
|
||||
.build();
|
||||
|
||||
Resource resource = Resource.builder()
|
||||
.uri(TEST_RESOURCE_URI)
|
||||
.name("Test Resource")
|
||||
Resource resource = Resource.builder(TEST_RESOURCE_URI, "Test Resource")
|
||||
.title("Test Resource")
|
||||
.mimeType("text/plain")
|
||||
.description("Test resource description")
|
||||
.build();
|
||||
McpServerFeatures.AsyncResourceSpecification specification = new McpServerFeatures.AsyncResourceSpecification(
|
||||
resource, (exchange, req) -> Mono.just(new ReadResourceResult(List.of())));
|
||||
resource, (exchange, req) -> Mono.just(ReadResourceResult.builder(List.of()).build()));
|
||||
|
||||
StepVerifier
|
||||
.create(mcpAsyncServer.addResource(specification).then(mcpAsyncServer.removeResource(TEST_RESOURCE_URI)))
|
||||
|
|
@ -427,15 +397,14 @@ public abstract class AbstractMcpAsyncServerTests {
|
|||
.capabilities(ServerCapabilities.builder().resources(true, false).build())
|
||||
.build();
|
||||
|
||||
McpSchema.ResourceTemplate template = McpSchema.ResourceTemplate.builder()
|
||||
.uriTemplate("test://template/{id}")
|
||||
.name("test-template")
|
||||
McpSchema.ResourceTemplate template = McpSchema.ResourceTemplate
|
||||
.builder("test://template/{id}", "test-template")
|
||||
.description("Test resource template")
|
||||
.mimeType("text/plain")
|
||||
.build();
|
||||
|
||||
McpServerFeatures.AsyncResourceTemplateSpecification specification = new McpServerFeatures.AsyncResourceTemplateSpecification(
|
||||
template, (exchange, req) -> Mono.just(new ReadResourceResult(List.of())));
|
||||
template, (exchange, req) -> Mono.just(ReadResourceResult.builder(List.of()).build()));
|
||||
|
||||
StepVerifier.create(mcpAsyncServer.addResourceTemplate(specification)).verifyComplete();
|
||||
|
||||
|
|
@ -447,15 +416,14 @@ public abstract class AbstractMcpAsyncServerTests {
|
|||
// Create a server without resource capabilities
|
||||
McpAsyncServer serverWithoutResources = prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0").build();
|
||||
|
||||
McpSchema.ResourceTemplate template = McpSchema.ResourceTemplate.builder()
|
||||
.uriTemplate("test://template/{id}")
|
||||
.name("test-template")
|
||||
McpSchema.ResourceTemplate template = McpSchema.ResourceTemplate
|
||||
.builder("test://template/{id}", "test-template")
|
||||
.description("Test resource template")
|
||||
.mimeType("text/plain")
|
||||
.build();
|
||||
|
||||
McpServerFeatures.AsyncResourceTemplateSpecification specification = new McpServerFeatures.AsyncResourceTemplateSpecification(
|
||||
template, (exchange, req) -> Mono.just(new ReadResourceResult(List.of())));
|
||||
template, (exchange, req) -> Mono.just(ReadResourceResult.builder(List.of()).build()));
|
||||
|
||||
StepVerifier.create(serverWithoutResources.addResourceTemplate(specification)).verifyErrorSatisfies(error -> {
|
||||
assertThat(error).isInstanceOf(IllegalStateException.class)
|
||||
|
|
@ -465,15 +433,14 @@ public abstract class AbstractMcpAsyncServerTests {
|
|||
|
||||
@Test
|
||||
void testRemoveResourceTemplate() {
|
||||
McpSchema.ResourceTemplate template = McpSchema.ResourceTemplate.builder()
|
||||
.uriTemplate("test://template/{id}")
|
||||
.name("test-template")
|
||||
McpSchema.ResourceTemplate template = McpSchema.ResourceTemplate
|
||||
.builder("test://template/{id}", "test-template")
|
||||
.description("Test resource template")
|
||||
.mimeType("text/plain")
|
||||
.build();
|
||||
|
||||
McpServerFeatures.AsyncResourceTemplateSpecification specification = new McpServerFeatures.AsyncResourceTemplateSpecification(
|
||||
template, (exchange, req) -> Mono.just(new ReadResourceResult(List.of())));
|
||||
template, (exchange, req) -> Mono.just(ReadResourceResult.builder(List.of()).build()));
|
||||
|
||||
var mcpAsyncServer = prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0")
|
||||
.capabilities(ServerCapabilities.builder().resources(true, false).build())
|
||||
|
|
@ -510,15 +477,14 @@ public abstract class AbstractMcpAsyncServerTests {
|
|||
|
||||
@Test
|
||||
void testListResourceTemplates() {
|
||||
McpSchema.ResourceTemplate template = McpSchema.ResourceTemplate.builder()
|
||||
.uriTemplate("test://template/{id}")
|
||||
.name("test-template")
|
||||
McpSchema.ResourceTemplate template = McpSchema.ResourceTemplate
|
||||
.builder("test://template/{id}", "test-template")
|
||||
.description("Test resource template")
|
||||
.mimeType("text/plain")
|
||||
.build();
|
||||
|
||||
McpServerFeatures.AsyncResourceTemplateSpecification specification = new McpServerFeatures.AsyncResourceTemplateSpecification(
|
||||
template, (exchange, req) -> Mono.just(new ReadResourceResult(List.of())));
|
||||
template, (exchange, req) -> Mono.just(ReadResourceResult.builder(List.of()).build()));
|
||||
|
||||
var mcpAsyncServer = prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0")
|
||||
.capabilities(ServerCapabilities.builder().resources(true, false).build())
|
||||
|
|
@ -568,10 +534,22 @@ public abstract class AbstractMcpAsyncServerTests {
|
|||
// Create a server without prompt capabilities
|
||||
McpAsyncServer serverWithoutPrompts = prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0").build();
|
||||
|
||||
Prompt prompt = new Prompt(TEST_PROMPT_NAME, "Test Prompt", "Test Prompt", List.of());
|
||||
Prompt prompt = Prompt.builder(TEST_PROMPT_NAME)
|
||||
.title("Test Prompt")
|
||||
.description("Test Prompt")
|
||||
.arguments(List.of())
|
||||
.build();
|
||||
McpServerFeatures.AsyncPromptSpecification specification = new McpServerFeatures.AsyncPromptSpecification(
|
||||
prompt, (exchange, req) -> Mono.just(new GetPromptResult("Test prompt description", List
|
||||
.of(new PromptMessage(McpSchema.Role.ASSISTANT, new McpSchema.TextContent("Test content"))))));
|
||||
prompt,
|
||||
(exchange, req) -> Mono.just(
|
||||
GetPromptResult
|
||||
.builder(
|
||||
List.of(PromptMessage
|
||||
.builder(McpSchema.Role.ASSISTANT,
|
||||
McpSchema.TextContent.builder("Test content").build())
|
||||
.build()))
|
||||
.description("Test prompt description")
|
||||
.build()));
|
||||
|
||||
StepVerifier.create(serverWithoutPrompts.addPrompt(specification)).verifyErrorSatisfies(error -> {
|
||||
assertThat(error).isInstanceOf(IllegalStateException.class)
|
||||
|
|
@ -594,10 +572,22 @@ public abstract class AbstractMcpAsyncServerTests {
|
|||
void testRemovePrompt() {
|
||||
String TEST_PROMPT_NAME_TO_REMOVE = "TEST_PROMPT_NAME678";
|
||||
|
||||
Prompt prompt = new Prompt(TEST_PROMPT_NAME_TO_REMOVE, "Test Prompt", "Test Prompt", List.of());
|
||||
Prompt prompt = Prompt.builder(TEST_PROMPT_NAME_TO_REMOVE)
|
||||
.title("Test Prompt")
|
||||
.description("Test Prompt")
|
||||
.arguments(List.of())
|
||||
.build();
|
||||
McpServerFeatures.AsyncPromptSpecification specification = new McpServerFeatures.AsyncPromptSpecification(
|
||||
prompt, (exchange, req) -> Mono.just(new GetPromptResult("Test prompt description", List
|
||||
.of(new PromptMessage(McpSchema.Role.ASSISTANT, new McpSchema.TextContent("Test content"))))));
|
||||
prompt,
|
||||
(exchange, req) -> Mono.just(
|
||||
GetPromptResult
|
||||
.builder(
|
||||
List.of(PromptMessage
|
||||
.builder(McpSchema.Role.ASSISTANT,
|
||||
McpSchema.TextContent.builder("Test content").build())
|
||||
.build()))
|
||||
.description("Test prompt description")
|
||||
.build()));
|
||||
|
||||
var mcpAsyncServer = prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0")
|
||||
.capabilities(ServerCapabilities.builder().prompts(true).build())
|
||||
|
|
|
|||
|
|
@ -107,11 +107,7 @@ public abstract class AbstractMcpSyncServerTests {
|
|||
.capabilities(ServerCapabilities.builder().tools(true).build())
|
||||
.build();
|
||||
|
||||
Tool newTool = McpSchema.Tool.builder()
|
||||
.name("new-tool")
|
||||
.title("New test tool")
|
||||
.inputSchema(EMPTY_JSON_SCHEMA)
|
||||
.build();
|
||||
Tool newTool = McpSchema.Tool.builder("new-tool", EMPTY_JSON_SCHEMA).title("New test tool").build();
|
||||
|
||||
assertThatCode(() -> mcpSyncServer.addTool(McpServerFeatures.SyncToolSpecification.builder()
|
||||
.tool(newTool)
|
||||
|
|
@ -123,11 +119,7 @@ public abstract class AbstractMcpSyncServerTests {
|
|||
|
||||
@Test
|
||||
void testAddDuplicateToolCall() {
|
||||
Tool duplicateTool = McpSchema.Tool.builder()
|
||||
.name(TEST_TOOL_NAME)
|
||||
.title("Duplicate tool")
|
||||
.inputSchema(EMPTY_JSON_SCHEMA)
|
||||
.build();
|
||||
Tool duplicateTool = McpSchema.Tool.builder(TEST_TOOL_NAME, EMPTY_JSON_SCHEMA).title("Duplicate tool").build();
|
||||
|
||||
var mcpSyncServer = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0")
|
||||
.capabilities(ServerCapabilities.builder().tools(true).build())
|
||||
|
|
@ -145,10 +137,8 @@ public abstract class AbstractMcpSyncServerTests {
|
|||
|
||||
@Test
|
||||
void testDuplicateToolCallDuringBuilding() {
|
||||
Tool duplicateTool = McpSchema.Tool.builder()
|
||||
.name("duplicate-build-toolcall")
|
||||
Tool duplicateTool = McpSchema.Tool.builder("duplicate-build-toolcall", EMPTY_JSON_SCHEMA)
|
||||
.title("Duplicate toolcall during building")
|
||||
.inputSchema(EMPTY_JSON_SCHEMA)
|
||||
.build();
|
||||
|
||||
assertThatThrownBy(() -> prepareSyncServerBuilder().serverInfo("test-server", "1.0.0")
|
||||
|
|
@ -163,10 +153,8 @@ public abstract class AbstractMcpSyncServerTests {
|
|||
|
||||
@Test
|
||||
void testDuplicateToolsInBatchListRegistration() {
|
||||
Tool duplicateTool = McpSchema.Tool.builder()
|
||||
.name("batch-list-tool")
|
||||
Tool duplicateTool = McpSchema.Tool.builder("batch-list-tool", EMPTY_JSON_SCHEMA)
|
||||
.title("Duplicate tool in batch list")
|
||||
.inputSchema(EMPTY_JSON_SCHEMA)
|
||||
.build();
|
||||
List<McpServerFeatures.SyncToolSpecification> specs = List.of(
|
||||
McpServerFeatures.SyncToolSpecification.builder()
|
||||
|
|
@ -190,10 +178,8 @@ public abstract class AbstractMcpSyncServerTests {
|
|||
|
||||
@Test
|
||||
void testDuplicateToolsInBatchVarargsRegistration() {
|
||||
Tool duplicateTool = McpSchema.Tool.builder()
|
||||
.name("batch-varargs-tool")
|
||||
Tool duplicateTool = McpSchema.Tool.builder("batch-varargs-tool", EMPTY_JSON_SCHEMA)
|
||||
.title("Duplicate tool in batch varargs")
|
||||
.inputSchema(EMPTY_JSON_SCHEMA)
|
||||
.build();
|
||||
|
||||
assertThatThrownBy(() -> prepareSyncServerBuilder().serverInfo("test-server", "1.0.0")
|
||||
|
|
@ -214,11 +200,7 @@ public abstract class AbstractMcpSyncServerTests {
|
|||
|
||||
@Test
|
||||
void testRemoveTool() {
|
||||
Tool tool = McpSchema.Tool.builder()
|
||||
.name(TEST_TOOL_NAME)
|
||||
.title("Test tool")
|
||||
.inputSchema(EMPTY_JSON_SCHEMA)
|
||||
.build();
|
||||
Tool tool = McpSchema.Tool.builder(TEST_TOOL_NAME, EMPTY_JSON_SCHEMA).title("Test tool").build();
|
||||
|
||||
var mcpSyncServer = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0")
|
||||
.capabilities(ServerCapabilities.builder().tools(true).build())
|
||||
|
|
@ -280,15 +262,13 @@ public abstract class AbstractMcpSyncServerTests {
|
|||
.capabilities(ServerCapabilities.builder().resources(true, false).build())
|
||||
.build();
|
||||
|
||||
Resource resource = Resource.builder()
|
||||
.uri(TEST_RESOURCE_URI)
|
||||
.name("Test Resource")
|
||||
Resource resource = Resource.builder(TEST_RESOURCE_URI, "Test Resource")
|
||||
.title("Test Resource")
|
||||
.mimeType("text/plain")
|
||||
.description("Test resource description")
|
||||
.build();
|
||||
McpServerFeatures.SyncResourceSpecification specification = new McpServerFeatures.SyncResourceSpecification(
|
||||
resource, (exchange, req) -> new ReadResourceResult(List.of()));
|
||||
resource, (exchange, req) -> ReadResourceResult.builder(List.of()).build());
|
||||
|
||||
assertThatCode(() -> mcpSyncServer.addResource(specification)).doesNotThrowAnyException();
|
||||
|
||||
|
|
@ -312,15 +292,13 @@ public abstract class AbstractMcpSyncServerTests {
|
|||
void testAddResourceWithoutCapability() {
|
||||
var serverWithoutResources = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0").build();
|
||||
|
||||
Resource resource = Resource.builder()
|
||||
.uri(TEST_RESOURCE_URI)
|
||||
.name("Test Resource")
|
||||
Resource resource = Resource.builder(TEST_RESOURCE_URI, "Test Resource")
|
||||
.title("Test Resource")
|
||||
.mimeType("text/plain")
|
||||
.description("Test resource description")
|
||||
.build();
|
||||
McpServerFeatures.SyncResourceSpecification specification = new McpServerFeatures.SyncResourceSpecification(
|
||||
resource, (exchange, req) -> new ReadResourceResult(List.of()));
|
||||
resource, (exchange, req) -> ReadResourceResult.builder(List.of()).build());
|
||||
|
||||
assertThatThrownBy(() -> serverWithoutResources.addResource(specification))
|
||||
.isInstanceOf(IllegalStateException.class)
|
||||
|
|
@ -342,15 +320,13 @@ public abstract class AbstractMcpSyncServerTests {
|
|||
.capabilities(ServerCapabilities.builder().resources(true, false).build())
|
||||
.build();
|
||||
|
||||
Resource resource = Resource.builder()
|
||||
.uri(TEST_RESOURCE_URI)
|
||||
.name("Test Resource")
|
||||
Resource resource = Resource.builder(TEST_RESOURCE_URI, "Test Resource")
|
||||
.title("Test Resource")
|
||||
.mimeType("text/plain")
|
||||
.description("Test resource description")
|
||||
.build();
|
||||
McpServerFeatures.SyncResourceSpecification specification = new McpServerFeatures.SyncResourceSpecification(
|
||||
resource, (exchange, req) -> new ReadResourceResult(List.of()));
|
||||
resource, (exchange, req) -> ReadResourceResult.builder(List.of()).build());
|
||||
|
||||
mcpSyncServer.addResource(specification);
|
||||
List<McpSchema.Resource> resources = mcpSyncServer.listResources();
|
||||
|
|
@ -367,15 +343,13 @@ public abstract class AbstractMcpSyncServerTests {
|
|||
.capabilities(ServerCapabilities.builder().resources(true, false).build())
|
||||
.build();
|
||||
|
||||
Resource resource = Resource.builder()
|
||||
.uri(TEST_RESOURCE_URI)
|
||||
.name("Test Resource")
|
||||
Resource resource = Resource.builder(TEST_RESOURCE_URI, "Test Resource")
|
||||
.title("Test Resource")
|
||||
.mimeType("text/plain")
|
||||
.description("Test resource description")
|
||||
.build();
|
||||
McpServerFeatures.SyncResourceSpecification specification = new McpServerFeatures.SyncResourceSpecification(
|
||||
resource, (exchange, req) -> new ReadResourceResult(List.of()));
|
||||
resource, (exchange, req) -> ReadResourceResult.builder(List.of()).build());
|
||||
|
||||
mcpSyncServer.addResource(specification);
|
||||
assertThatCode(() -> mcpSyncServer.removeResource(TEST_RESOURCE_URI)).doesNotThrowAnyException();
|
||||
|
|
@ -406,15 +380,14 @@ public abstract class AbstractMcpSyncServerTests {
|
|||
.capabilities(ServerCapabilities.builder().resources(true, false).build())
|
||||
.build();
|
||||
|
||||
McpSchema.ResourceTemplate template = McpSchema.ResourceTemplate.builder()
|
||||
.uriTemplate("test://template/{id}")
|
||||
.name("test-template")
|
||||
McpSchema.ResourceTemplate template = McpSchema.ResourceTemplate
|
||||
.builder("test://template/{id}", "test-template")
|
||||
.description("Test resource template")
|
||||
.mimeType("text/plain")
|
||||
.build();
|
||||
|
||||
McpServerFeatures.SyncResourceTemplateSpecification specification = new McpServerFeatures.SyncResourceTemplateSpecification(
|
||||
template, (exchange, req) -> new ReadResourceResult(List.of()));
|
||||
template, (exchange, req) -> ReadResourceResult.builder(List.of()).build());
|
||||
|
||||
assertThatCode(() -> mcpSyncServer.addResourceTemplate(specification)).doesNotThrowAnyException();
|
||||
|
||||
|
|
@ -426,15 +399,14 @@ public abstract class AbstractMcpSyncServerTests {
|
|||
// Create a server without resource capabilities
|
||||
var serverWithoutResources = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0").build();
|
||||
|
||||
McpSchema.ResourceTemplate template = McpSchema.ResourceTemplate.builder()
|
||||
.uriTemplate("test://template/{id}")
|
||||
.name("test-template")
|
||||
McpSchema.ResourceTemplate template = McpSchema.ResourceTemplate
|
||||
.builder("test://template/{id}", "test-template")
|
||||
.description("Test resource template")
|
||||
.mimeType("text/plain")
|
||||
.build();
|
||||
|
||||
McpServerFeatures.SyncResourceTemplateSpecification specification = new McpServerFeatures.SyncResourceTemplateSpecification(
|
||||
template, (exchange, req) -> new ReadResourceResult(List.of()));
|
||||
template, (exchange, req) -> ReadResourceResult.builder(List.of()).build());
|
||||
|
||||
assertThatThrownBy(() -> serverWithoutResources.addResourceTemplate(specification))
|
||||
.isInstanceOf(IllegalStateException.class)
|
||||
|
|
@ -443,15 +415,14 @@ public abstract class AbstractMcpSyncServerTests {
|
|||
|
||||
@Test
|
||||
void testRemoveResourceTemplate() {
|
||||
McpSchema.ResourceTemplate template = McpSchema.ResourceTemplate.builder()
|
||||
.uriTemplate("test://template/{id}")
|
||||
.name("test-template")
|
||||
McpSchema.ResourceTemplate template = McpSchema.ResourceTemplate
|
||||
.builder("test://template/{id}", "test-template")
|
||||
.description("Test resource template")
|
||||
.mimeType("text/plain")
|
||||
.build();
|
||||
|
||||
McpServerFeatures.SyncResourceTemplateSpecification specification = new McpServerFeatures.SyncResourceTemplateSpecification(
|
||||
template, (exchange, req) -> new ReadResourceResult(List.of()));
|
||||
template, (exchange, req) -> ReadResourceResult.builder(List.of()).build());
|
||||
|
||||
var mcpSyncServer = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0")
|
||||
.capabilities(ServerCapabilities.builder().resources(true, false).build())
|
||||
|
|
@ -487,15 +458,14 @@ public abstract class AbstractMcpSyncServerTests {
|
|||
|
||||
@Test
|
||||
void testListResourceTemplates() {
|
||||
McpSchema.ResourceTemplate template = McpSchema.ResourceTemplate.builder()
|
||||
.uriTemplate("test://template/{id}")
|
||||
.name("test-template")
|
||||
McpSchema.ResourceTemplate template = McpSchema.ResourceTemplate
|
||||
.builder("test://template/{id}", "test-template")
|
||||
.description("Test resource template")
|
||||
.mimeType("text/plain")
|
||||
.build();
|
||||
|
||||
McpServerFeatures.SyncResourceTemplateSpecification specification = new McpServerFeatures.SyncResourceTemplateSpecification(
|
||||
template, (exchange, req) -> new ReadResourceResult(List.of()));
|
||||
template, (exchange, req) -> ReadResourceResult.builder(List.of()).build());
|
||||
|
||||
var mcpSyncServer = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0")
|
||||
.capabilities(ServerCapabilities.builder().resources(true, false).build())
|
||||
|
|
@ -537,10 +507,21 @@ public abstract class AbstractMcpSyncServerTests {
|
|||
void testAddPromptWithoutCapability() {
|
||||
var serverWithoutPrompts = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0").build();
|
||||
|
||||
Prompt prompt = new Prompt(TEST_PROMPT_NAME, "Test Prompt", "Test Prompt", List.of());
|
||||
Prompt prompt = Prompt.builder(TEST_PROMPT_NAME)
|
||||
.title("Test Prompt")
|
||||
.description("Test Prompt")
|
||||
.arguments(List.of())
|
||||
.build();
|
||||
McpServerFeatures.SyncPromptSpecification specification = new McpServerFeatures.SyncPromptSpecification(prompt,
|
||||
(exchange, req) -> new GetPromptResult("Test prompt description", List
|
||||
.of(new PromptMessage(McpSchema.Role.ASSISTANT, new McpSchema.TextContent("Test content")))));
|
||||
(exchange,
|
||||
req) -> GetPromptResult
|
||||
.builder(
|
||||
List.of(PromptMessage
|
||||
.builder(McpSchema.Role.ASSISTANT,
|
||||
McpSchema.TextContent.builder("Test content").build())
|
||||
.build()))
|
||||
.description("Test prompt description")
|
||||
.build());
|
||||
|
||||
assertThatThrownBy(() -> serverWithoutPrompts.addPrompt(specification))
|
||||
.isInstanceOf(IllegalStateException.class)
|
||||
|
|
@ -558,10 +539,21 @@ public abstract class AbstractMcpSyncServerTests {
|
|||
|
||||
@Test
|
||||
void testRemovePrompt() {
|
||||
Prompt prompt = new Prompt(TEST_PROMPT_NAME, "Test Prompt", "Test Prompt", List.of());
|
||||
Prompt prompt = Prompt.builder(TEST_PROMPT_NAME)
|
||||
.title("Test Prompt")
|
||||
.description("Test Prompt")
|
||||
.arguments(List.of())
|
||||
.build();
|
||||
McpServerFeatures.SyncPromptSpecification specification = new McpServerFeatures.SyncPromptSpecification(prompt,
|
||||
(exchange, req) -> new GetPromptResult("Test prompt description", List
|
||||
.of(new PromptMessage(McpSchema.Role.ASSISTANT, new McpSchema.TextContent("Test content")))));
|
||||
(exchange,
|
||||
req) -> GetPromptResult
|
||||
.builder(
|
||||
List.of(PromptMessage
|
||||
.builder(McpSchema.Role.ASSISTANT,
|
||||
McpSchema.TextContent.builder("Test content").build())
|
||||
.build()))
|
||||
.description("Test prompt description")
|
||||
.build());
|
||||
|
||||
var mcpSyncServer = prepareSyncServerBuilder().serverInfo("test-server", "1.0.0")
|
||||
.capabilities(ServerCapabilities.builder().prompts(true).build())
|
||||
|
|
|
|||
|
|
@ -30,7 +30,8 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
|||
|
||||
class McpAsyncClientResponseHandlerTests {
|
||||
|
||||
private static final McpSchema.Implementation SERVER_INFO = new McpSchema.Implementation("test-server", "1.0.0");
|
||||
private static final McpSchema.Implementation SERVER_INFO = McpSchema.Implementation.builder("test-server", "1.0.0")
|
||||
.build();
|
||||
|
||||
private static final McpSchema.ServerCapabilities SERVER_CAPABILITIES = McpSchema.ServerCapabilities.builder()
|
||||
.tools(true)
|
||||
|
|
@ -43,13 +44,14 @@ class McpAsyncClientResponseHandlerTests {
|
|||
|
||||
private static MockMcpClientTransport initializationEnabledTransport(
|
||||
McpSchema.ServerCapabilities mockServerCapabilities, McpSchema.Implementation mockServerInfo) {
|
||||
McpSchema.InitializeResult mockInitResult = new McpSchema.InitializeResult(ProtocolVersions.MCP_2025_11_25,
|
||||
mockServerCapabilities, mockServerInfo, "Test instructions");
|
||||
McpSchema.InitializeResult mockInitResult = McpSchema.InitializeResult
|
||||
.builder(ProtocolVersions.MCP_2025_11_25, mockServerCapabilities, mockServerInfo)
|
||||
.instructions("Test instructions")
|
||||
.build();
|
||||
|
||||
return new MockMcpClientTransport((t, message) -> {
|
||||
if (message instanceof McpSchema.JSONRPCRequest r && METHOD_INITIALIZE.equals(r.method())) {
|
||||
McpSchema.JSONRPCResponse initResponse = new McpSchema.JSONRPCResponse(McpSchema.JSONRPC_VERSION,
|
||||
r.id(), mockInitResult, null);
|
||||
McpSchema.JSONRPCResponse initResponse = McpSchema.JSONRPCResponse.result(r.id(), mockInitResult);
|
||||
t.simulateIncomingMessage(initResponse);
|
||||
}
|
||||
}).withProtocolVersion(ProtocolVersions.MCP_2025_11_25);
|
||||
|
|
@ -57,7 +59,7 @@ class McpAsyncClientResponseHandlerTests {
|
|||
|
||||
@Test
|
||||
void testSuccessfulInitialization() {
|
||||
McpSchema.Implementation serverInfo = new McpSchema.Implementation("mcp-test-server", "0.0.1");
|
||||
McpSchema.Implementation serverInfo = McpSchema.Implementation.builder("mcp-test-server", "0.0.1").build();
|
||||
McpSchema.ServerCapabilities serverCapabilities = McpSchema.ServerCapabilities.builder()
|
||||
.tools(false)
|
||||
.resources(true, true) // Enable both resources and resource templates
|
||||
|
|
@ -111,37 +113,37 @@ class McpAsyncClientResponseHandlerTests {
|
|||
|
||||
// Create a mock tools list that the server will return
|
||||
Map<String, Object> inputSchema = Map.of("type", "object", "properties", Map.of(), "required", List.of());
|
||||
McpSchema.Tool mockTool = McpSchema.Tool.builder()
|
||||
.name("test-tool-1")
|
||||
McpSchema.Tool mockTool = McpSchema.Tool
|
||||
.builder("test-tool-1", JSON_MAPPER, JSON_MAPPER.writeValueAsString(inputSchema))
|
||||
.description("Test Tool 1 Description")
|
||||
.inputSchema(JSON_MAPPER, JSON_MAPPER.writeValueAsString(inputSchema))
|
||||
.build();
|
||||
|
||||
// Create page 1 response with nextPageToken
|
||||
String nextPageToken = "page2Token";
|
||||
McpSchema.ListToolsResult mockToolsResult1 = new McpSchema.ListToolsResult(List.of(mockTool), nextPageToken);
|
||||
McpSchema.ListToolsResult mockToolsResult1 = McpSchema.ListToolsResult.builder(List.of(mockTool))
|
||||
.nextCursor(nextPageToken)
|
||||
.build();
|
||||
|
||||
// Simulate server sending tools/list_changed notification
|
||||
McpSchema.JSONRPCNotification notification = new McpSchema.JSONRPCNotification(McpSchema.JSONRPC_VERSION,
|
||||
McpSchema.METHOD_NOTIFICATION_TOOLS_LIST_CHANGED, null);
|
||||
McpSchema.JSONRPCNotification notification = new McpSchema.JSONRPCNotification(
|
||||
McpSchema.METHOD_NOTIFICATION_TOOLS_LIST_CHANGED);
|
||||
transport.simulateIncomingMessage(notification);
|
||||
|
||||
// Simulate server response to first tools/list request
|
||||
McpSchema.JSONRPCRequest toolsListRequest1 = transport.getLastSentMessageAsRequest();
|
||||
assertThat(toolsListRequest1.method()).isEqualTo(McpSchema.METHOD_TOOLS_LIST);
|
||||
|
||||
McpSchema.JSONRPCResponse toolsListResponse1 = new McpSchema.JSONRPCResponse(McpSchema.JSONRPC_VERSION,
|
||||
toolsListRequest1.id(), mockToolsResult1, null);
|
||||
McpSchema.JSONRPCResponse toolsListResponse1 = McpSchema.JSONRPCResponse.result(toolsListRequest1.id(),
|
||||
mockToolsResult1);
|
||||
transport.simulateIncomingMessage(toolsListResponse1);
|
||||
|
||||
// Create mock tools for page 2
|
||||
McpSchema.Tool mockTool2 = McpSchema.Tool.builder()
|
||||
.name("test-tool-2")
|
||||
McpSchema.Tool mockTool2 = McpSchema.Tool
|
||||
.builder("test-tool-2", JSON_MAPPER, JSON_MAPPER.writeValueAsString(inputSchema))
|
||||
.description("Test Tool 2 Description")
|
||||
.inputSchema(JSON_MAPPER, JSON_MAPPER.writeValueAsString(inputSchema))
|
||||
.build();
|
||||
// Create page 2 response with no nextPageToken (last page)
|
||||
McpSchema.ListToolsResult mockToolsResult2 = new McpSchema.ListToolsResult(List.of(mockTool2), null);
|
||||
McpSchema.ListToolsResult mockToolsResult2 = McpSchema.ListToolsResult.builder(List.of(mockTool2)).build();
|
||||
|
||||
// Simulate server response to second tools/list request with page token
|
||||
McpSchema.JSONRPCRequest toolsListRequest2 = transport.getLastSentMessageAsRequest();
|
||||
|
|
@ -152,8 +154,8 @@ class McpAsyncClientResponseHandlerTests {
|
|||
assertThat(params).isNotNull();
|
||||
assertThat(params.cursor()).isEqualTo(nextPageToken);
|
||||
|
||||
McpSchema.JSONRPCResponse toolsListResponse2 = new McpSchema.JSONRPCResponse(McpSchema.JSONRPC_VERSION,
|
||||
toolsListRequest2.id(), mockToolsResult2, null);
|
||||
McpSchema.JSONRPCResponse toolsListResponse2 = McpSchema.JSONRPCResponse.result(toolsListRequest2.id(),
|
||||
mockToolsResult2);
|
||||
transport.simulateIncomingMessage(toolsListResponse2);
|
||||
|
||||
// Verify the consumer received all expected tools from both pages
|
||||
|
|
@ -171,14 +173,13 @@ class McpAsyncClientResponseHandlerTests {
|
|||
MockMcpClientTransport transport = initializationEnabledTransport();
|
||||
|
||||
McpAsyncClient asyncMcpClient = McpClient.async(transport)
|
||||
.roots(new Root("file:///test/path", "test-root"))
|
||||
.roots(Root.builder("file:///test/path").name("test-root").build())
|
||||
.build();
|
||||
|
||||
assertThat(asyncMcpClient.initialize().block()).isNotNull();
|
||||
|
||||
// Simulate incoming request
|
||||
McpSchema.JSONRPCRequest request = new McpSchema.JSONRPCRequest(McpSchema.JSONRPC_VERSION,
|
||||
McpSchema.METHOD_ROOTS_LIST, "test-id", null);
|
||||
McpSchema.JSONRPCRequest request = new McpSchema.JSONRPCRequest(McpSchema.METHOD_ROOTS_LIST, "test-id");
|
||||
transport.simulateIncomingMessage(request);
|
||||
|
||||
// Verify response
|
||||
|
|
@ -187,8 +188,9 @@ class McpAsyncClientResponseHandlerTests {
|
|||
|
||||
McpSchema.JSONRPCResponse response = (McpSchema.JSONRPCResponse) sentMessage;
|
||||
assertThat(response.id()).isEqualTo("test-id");
|
||||
assertThat(response.result())
|
||||
.isEqualTo(new McpSchema.ListRootsResult(List.of(new Root("file:///test/path", "test-root"))));
|
||||
assertThat(response.result()).isEqualTo(McpSchema.ListRootsResult
|
||||
.builder(List.of(McpSchema.Root.builder("file:///test/path").name("test-root").build()))
|
||||
.build());
|
||||
assertThat(response.error()).isNull();
|
||||
|
||||
asyncMcpClient.closeGracefully();
|
||||
|
|
@ -213,26 +215,24 @@ class McpAsyncClientResponseHandlerTests {
|
|||
assertThat(asyncMcpClient.initialize().block()).isNotNull();
|
||||
|
||||
// Create a mock resources list that the server will return
|
||||
McpSchema.Resource mockResource = McpSchema.Resource.builder()
|
||||
.uri("test://resource")
|
||||
.name("Test Resource")
|
||||
McpSchema.Resource mockResource = McpSchema.Resource.builder("test://resource", "Test Resource")
|
||||
.description("A test resource")
|
||||
.mimeType("text/plain")
|
||||
.build();
|
||||
McpSchema.ListResourcesResult mockResourcesResult = new McpSchema.ListResourcesResult(List.of(mockResource),
|
||||
null);
|
||||
McpSchema.ListResourcesResult mockResourcesResult = McpSchema.ListResourcesResult.builder(List.of(mockResource))
|
||||
.build();
|
||||
|
||||
// Simulate server sending resources/list_changed notification
|
||||
McpSchema.JSONRPCNotification notification = new McpSchema.JSONRPCNotification(McpSchema.JSONRPC_VERSION,
|
||||
McpSchema.METHOD_NOTIFICATION_RESOURCES_LIST_CHANGED, null);
|
||||
McpSchema.JSONRPCNotification notification = new McpSchema.JSONRPCNotification(
|
||||
McpSchema.METHOD_NOTIFICATION_RESOURCES_LIST_CHANGED);
|
||||
transport.simulateIncomingMessage(notification);
|
||||
|
||||
// Simulate server response to resources/list request
|
||||
McpSchema.JSONRPCRequest resourcesListRequest = transport.getLastSentMessageAsRequest();
|
||||
assertThat(resourcesListRequest.method()).isEqualTo(McpSchema.METHOD_RESOURCES_LIST);
|
||||
|
||||
McpSchema.JSONRPCResponse resourcesListResponse = new McpSchema.JSONRPCResponse(McpSchema.JSONRPC_VERSION,
|
||||
resourcesListRequest.id(), mockResourcesResult, null);
|
||||
McpSchema.JSONRPCResponse resourcesListResponse = McpSchema.JSONRPCResponse.result(resourcesListRequest.id(),
|
||||
mockResourcesResult);
|
||||
transport.simulateIncomingMessage(resourcesListResponse);
|
||||
|
||||
// Verify the consumer received the expected resources
|
||||
|
|
@ -261,21 +261,29 @@ class McpAsyncClientResponseHandlerTests {
|
|||
assertThat(asyncMcpClient.initialize().block()).isNotNull();
|
||||
|
||||
// Create a mock prompts list that the server will return
|
||||
McpSchema.Prompt mockPrompt = new McpSchema.Prompt("test-prompt", "Test Prompt", "Test Prompt Description",
|
||||
List.of(new McpSchema.PromptArgument("arg1", "Test argument", "Test argument", true)));
|
||||
McpSchema.ListPromptsResult mockPromptsResult = new McpSchema.ListPromptsResult(List.of(mockPrompt), null);
|
||||
McpSchema.Prompt mockPrompt = McpSchema.Prompt.builder("test-prompt")
|
||||
.title("Test Prompt")
|
||||
.description("Test Prompt Description")
|
||||
.arguments(List.of(McpSchema.PromptArgument.builder("arg1")
|
||||
.title("Test argument")
|
||||
.description("Test argument")
|
||||
.required(true)
|
||||
.build()))
|
||||
.build();
|
||||
McpSchema.ListPromptsResult mockPromptsResult = McpSchema.ListPromptsResult.builder(List.of(mockPrompt))
|
||||
.build();
|
||||
|
||||
// Simulate server sending prompts/list_changed notification
|
||||
McpSchema.JSONRPCNotification notification = new McpSchema.JSONRPCNotification(McpSchema.JSONRPC_VERSION,
|
||||
McpSchema.METHOD_NOTIFICATION_PROMPTS_LIST_CHANGED, null);
|
||||
McpSchema.JSONRPCNotification notification = new McpSchema.JSONRPCNotification(
|
||||
McpSchema.METHOD_NOTIFICATION_PROMPTS_LIST_CHANGED);
|
||||
transport.simulateIncomingMessage(notification);
|
||||
|
||||
// Simulate server response to prompts/list request
|
||||
McpSchema.JSONRPCRequest promptsListRequest = transport.getLastSentMessageAsRequest();
|
||||
assertThat(promptsListRequest.method()).isEqualTo(McpSchema.METHOD_PROMPT_LIST);
|
||||
|
||||
McpSchema.JSONRPCResponse promptsListResponse = new McpSchema.JSONRPCResponse(McpSchema.JSONRPC_VERSION,
|
||||
promptsListRequest.id(), mockPromptsResult, null);
|
||||
McpSchema.JSONRPCResponse promptsListResponse = McpSchema.JSONRPCResponse.result(promptsListRequest.id(),
|
||||
mockPromptsResult);
|
||||
transport.simulateIncomingMessage(promptsListResponse);
|
||||
|
||||
// Verify the consumer received the expected prompts
|
||||
|
|
@ -295,8 +303,9 @@ class McpAsyncClientResponseHandlerTests {
|
|||
// Create a test sampling handler that echoes back the input
|
||||
Function<McpSchema.CreateMessageRequest, Mono<McpSchema.CreateMessageResult>> samplingHandler = request -> {
|
||||
var content = request.messages().get(0).content();
|
||||
return Mono.just(new McpSchema.CreateMessageResult(McpSchema.Role.ASSISTANT, content, "test-model",
|
||||
McpSchema.CreateMessageResult.StopReason.END_TURN));
|
||||
return Mono.just(McpSchema.CreateMessageResult.builder(McpSchema.Role.ASSISTANT, content, "test-model")
|
||||
.stopReason(McpSchema.CreateMessageResult.StopReason.END_TURN)
|
||||
.build());
|
||||
};
|
||||
|
||||
// Create client with sampling capability and handler
|
||||
|
|
@ -308,18 +317,18 @@ class McpAsyncClientResponseHandlerTests {
|
|||
assertThat(asyncMcpClient.initialize().block()).isNotNull();
|
||||
|
||||
// Create a mock create message request
|
||||
var messageRequest = new McpSchema.CreateMessageRequest(
|
||||
List.of(new McpSchema.SamplingMessage(McpSchema.Role.USER, new McpSchema.TextContent("Test message"))),
|
||||
null, // modelPreferences
|
||||
"Test system prompt", McpSchema.CreateMessageRequest.ContextInclusionStrategy.NONE, 0.7, // temperature
|
||||
100, // maxTokens
|
||||
null, // stopSequences
|
||||
null // metadata
|
||||
);
|
||||
var messageRequest = McpSchema.CreateMessageRequest
|
||||
.builder(List.of(McpSchema.SamplingMessage
|
||||
.builder(McpSchema.Role.USER, McpSchema.TextContent.builder("Test message").build())
|
||||
.build()), 100)
|
||||
.systemPrompt("Test system prompt")
|
||||
.includeContext(McpSchema.CreateMessageRequest.ContextInclusionStrategy.NONE)
|
||||
.temperature(0.7)
|
||||
.build();
|
||||
|
||||
// Simulate incoming request
|
||||
McpSchema.JSONRPCRequest request = new McpSchema.JSONRPCRequest(McpSchema.JSONRPC_VERSION,
|
||||
McpSchema.METHOD_SAMPLING_CREATE_MESSAGE, "test-id", messageRequest);
|
||||
McpSchema.JSONRPCRequest request = new McpSchema.JSONRPCRequest(McpSchema.METHOD_SAMPLING_CREATE_MESSAGE,
|
||||
"test-id", messageRequest);
|
||||
transport.simulateIncomingMessage(request);
|
||||
|
||||
// Verify response
|
||||
|
|
@ -354,13 +363,13 @@ class McpAsyncClientResponseHandlerTests {
|
|||
assertThat(asyncMcpClient.initialize().block()).isNotNull();
|
||||
|
||||
// Create a mock create message request
|
||||
var messageRequest = new McpSchema.CreateMessageRequest(
|
||||
List.of(new McpSchema.SamplingMessage(McpSchema.Role.USER, new McpSchema.TextContent("Test message"))),
|
||||
null, null, null, null, 0, null, null);
|
||||
var messageRequest = McpSchema.CreateMessageRequest.builder(List.of(McpSchema.SamplingMessage
|
||||
.builder(McpSchema.Role.USER, McpSchema.TextContent.builder("Test message").build())
|
||||
.build()), 0).build();
|
||||
|
||||
// Simulate incoming request
|
||||
McpSchema.JSONRPCRequest request = new McpSchema.JSONRPCRequest(McpSchema.JSONRPC_VERSION,
|
||||
McpSchema.METHOD_SAMPLING_CREATE_MESSAGE, "test-id", messageRequest);
|
||||
McpSchema.JSONRPCRequest request = new McpSchema.JSONRPCRequest(McpSchema.METHOD_SAMPLING_CREATE_MESSAGE,
|
||||
"test-id", messageRequest);
|
||||
transport.simulateIncomingMessage(request);
|
||||
|
||||
// Verify error response
|
||||
|
|
@ -402,8 +411,7 @@ class McpAsyncClientResponseHandlerTests {
|
|||
assertThat(properties).isNotNull();
|
||||
assertThat(((Map<String, Object>) properties).get("message")).isInstanceOf(Map.class);
|
||||
|
||||
return Mono.just(McpSchema.ElicitResult.builder()
|
||||
.message(McpSchema.ElicitResult.Action.ACCEPT)
|
||||
return Mono.just(McpSchema.ElicitResult.builder(McpSchema.ElicitResult.Action.ACCEPT)
|
||||
.content(Map.of("message", request.message()))
|
||||
.build());
|
||||
};
|
||||
|
|
@ -417,14 +425,14 @@ class McpAsyncClientResponseHandlerTests {
|
|||
assertThat(asyncMcpClient.initialize().block()).isNotNull();
|
||||
|
||||
// Create a mock elicitation
|
||||
var elicitRequest = McpSchema.ElicitRequest.builder()
|
||||
.message("Test message")
|
||||
.requestedSchema(Map.of("type", "object", "properties", Map.of("message", Map.of("type", "string"))))
|
||||
var elicitRequest = McpSchema.ElicitRequest
|
||||
.builder("Test message",
|
||||
Map.of("type", "object", "properties", Map.of("message", Map.of("type", "string"))))
|
||||
.build();
|
||||
|
||||
// Simulate incoming request
|
||||
McpSchema.JSONRPCRequest request = new McpSchema.JSONRPCRequest(McpSchema.JSONRPC_VERSION,
|
||||
McpSchema.METHOD_ELICITATION_CREATE, "test-id", elicitRequest);
|
||||
McpSchema.JSONRPCRequest request = new McpSchema.JSONRPCRequest(McpSchema.METHOD_ELICITATION_CREATE, "test-id",
|
||||
elicitRequest);
|
||||
transport.simulateIncomingMessage(request);
|
||||
|
||||
// Verify response
|
||||
|
|
@ -451,7 +459,7 @@ class McpAsyncClientResponseHandlerTests {
|
|||
|
||||
// Create a test elicitation handler to decline the request
|
||||
Function<McpSchema.ElicitRequest, Mono<McpSchema.ElicitResult>> elicitationHandler = request -> Mono
|
||||
.just(McpSchema.ElicitResult.builder().message(action).build());
|
||||
.just(McpSchema.ElicitResult.builder(action).build());
|
||||
|
||||
// Create client with elicitation capability and handler
|
||||
McpAsyncClient asyncMcpClient = McpClient.async(transport)
|
||||
|
|
@ -462,14 +470,14 @@ class McpAsyncClientResponseHandlerTests {
|
|||
assertThat(asyncMcpClient.initialize().block()).isNotNull();
|
||||
|
||||
// Create a mock elicitation
|
||||
var elicitRequest = McpSchema.ElicitRequest.builder()
|
||||
.message("Test message")
|
||||
.requestedSchema(Map.of("type", "object", "properties", Map.of("message", Map.of("type", "string"))))
|
||||
var elicitRequest = McpSchema.ElicitRequest
|
||||
.builder("Test message",
|
||||
Map.of("type", "object", "properties", Map.of("message", Map.of("type", "string"))))
|
||||
.build();
|
||||
|
||||
// Simulate incoming request
|
||||
McpSchema.JSONRPCRequest request = new McpSchema.JSONRPCRequest(McpSchema.JSONRPC_VERSION,
|
||||
McpSchema.METHOD_ELICITATION_CREATE, "test-id", elicitRequest);
|
||||
McpSchema.JSONRPCRequest request = new McpSchema.JSONRPCRequest(McpSchema.METHOD_ELICITATION_CREATE, "test-id",
|
||||
elicitRequest);
|
||||
transport.simulateIncomingMessage(request);
|
||||
|
||||
// Verify response
|
||||
|
|
@ -502,13 +510,15 @@ class McpAsyncClientResponseHandlerTests {
|
|||
assertThat(asyncMcpClient.initialize().block()).isNotNull();
|
||||
|
||||
// Create a mock elicitation
|
||||
var elicitRequest = new McpSchema.ElicitRequest("test",
|
||||
Map.of("type", "object", "properties", Map.of("test", Map.of("type", "boolean", "defaultValue", true,
|
||||
"description", "test-description", "title", "test-title"))));
|
||||
var elicitRequest = McpSchema.ElicitRequest
|
||||
.builder("test",
|
||||
Map.of("type", "object", "properties", Map.of("test", Map.of("type", "boolean", "defaultValue",
|
||||
true, "description", "test-description", "title", "test-title"))))
|
||||
.build();
|
||||
|
||||
// Simulate incoming request
|
||||
McpSchema.JSONRPCRequest request = new McpSchema.JSONRPCRequest(McpSchema.JSONRPC_VERSION,
|
||||
McpSchema.METHOD_ELICITATION_CREATE, "test-id", elicitRequest);
|
||||
McpSchema.JSONRPCRequest request = new McpSchema.JSONRPCRequest(McpSchema.METHOD_ELICITATION_CREATE, "test-id",
|
||||
elicitRequest);
|
||||
transport.simulateIncomingMessage(request);
|
||||
|
||||
// Verify error response
|
||||
|
|
@ -544,8 +554,7 @@ class McpAsyncClientResponseHandlerTests {
|
|||
assertThat(asyncMcpClient.initialize().block()).isNotNull();
|
||||
|
||||
// Simulate incoming ping request from server
|
||||
McpSchema.JSONRPCRequest pingRequest = new McpSchema.JSONRPCRequest(McpSchema.JSONRPC_VERSION,
|
||||
McpSchema.METHOD_PING, "ping-id", null);
|
||||
McpSchema.JSONRPCRequest pingRequest = new McpSchema.JSONRPCRequest(McpSchema.METHOD_PING, "ping-id");
|
||||
transport.simulateIncomingMessage(pingRequest);
|
||||
|
||||
// Verify response
|
||||
|
|
|
|||
|
|
@ -26,15 +26,18 @@ import static org.assertj.core.api.Assertions.assertThatCode;
|
|||
|
||||
class McpAsyncClientTests {
|
||||
|
||||
public static final McpSchema.Implementation MOCK_SERVER_INFO = new McpSchema.Implementation("test-server",
|
||||
"1.0.0");
|
||||
public static final McpSchema.Implementation MOCK_SERVER_INFO = McpSchema.Implementation
|
||||
.builder("test-server", "1.0.0")
|
||||
.build();
|
||||
|
||||
public static final McpSchema.ServerCapabilities MOCK_SERVER_CAPABILITIES = McpSchema.ServerCapabilities.builder()
|
||||
.tools(true)
|
||||
.build();
|
||||
|
||||
public static final McpSchema.InitializeResult MOCK_INIT_RESULT = new McpSchema.InitializeResult(
|
||||
ProtocolVersions.MCP_2024_11_05, MOCK_SERVER_CAPABILITIES, MOCK_SERVER_INFO, "Test instructions");
|
||||
public static final McpSchema.InitializeResult MOCK_INIT_RESULT = McpSchema.InitializeResult
|
||||
.builder(ProtocolVersions.MCP_2024_11_05, MOCK_SERVER_CAPABILITIES, MOCK_SERVER_INFO)
|
||||
.instructions("Test instructions")
|
||||
.build();
|
||||
|
||||
private static final String CONTEXT_KEY = "context.key";
|
||||
|
||||
|
|
@ -44,10 +47,8 @@ class McpAsyncClientTests {
|
|||
Map<String, Object> inputSchemaMap = Map.of("type", "object", "properties",
|
||||
Map.of("expression", Map.of("type", "string")), "required", List.of("expression"));
|
||||
|
||||
McpSchema.Tool.Builder toolBuilder = McpSchema.Tool.builder()
|
||||
.name("calculator")
|
||||
.description("Performs mathematical calculations")
|
||||
.inputSchema(inputSchemaMap);
|
||||
McpSchema.Tool.Builder toolBuilder = McpSchema.Tool.builder("calculator", inputSchemaMap)
|
||||
.description("Performs mathematical calculations");
|
||||
|
||||
if (hasOutputSchema) {
|
||||
Map<String, Object> outputSchema = Map.of("type", "object", "properties",
|
||||
|
|
@ -57,7 +58,7 @@ class McpAsyncClientTests {
|
|||
}
|
||||
|
||||
McpSchema.Tool calculatorTool = toolBuilder.build();
|
||||
McpSchema.ListToolsResult mockToolsResult = new McpSchema.ListToolsResult(List.of(calculatorTool), null);
|
||||
McpSchema.ListToolsResult mockToolsResult = McpSchema.ListToolsResult.builder(List.of(calculatorTool)).build();
|
||||
|
||||
// Create call tool result - valid or invalid based on parameter
|
||||
Map<String, Object> structuredContent = invalidOutput ? Map.of("result", "5", "operation", "add")
|
||||
|
|
@ -91,16 +92,13 @@ class McpAsyncClientTests {
|
|||
|
||||
McpSchema.JSONRPCResponse response;
|
||||
if (McpSchema.METHOD_INITIALIZE.equals(request.method())) {
|
||||
response = new McpSchema.JSONRPCResponse(McpSchema.JSONRPC_VERSION, request.id(), MOCK_INIT_RESULT,
|
||||
null);
|
||||
response = McpSchema.JSONRPCResponse.result(request.id(), MOCK_INIT_RESULT);
|
||||
}
|
||||
else if (McpSchema.METHOD_TOOLS_LIST.equals(request.method())) {
|
||||
response = new McpSchema.JSONRPCResponse(McpSchema.JSONRPC_VERSION, request.id(), mockToolsResult,
|
||||
null);
|
||||
response = McpSchema.JSONRPCResponse.result(request.id(), mockToolsResult);
|
||||
}
|
||||
else if (McpSchema.METHOD_TOOLS_CALL.equals(request.method())) {
|
||||
response = new McpSchema.JSONRPCResponse(McpSchema.JSONRPC_VERSION, request.id(),
|
||||
mockCallToolResult, null);
|
||||
response = McpSchema.JSONRPCResponse.result(request.id(), mockCallToolResult);
|
||||
}
|
||||
else {
|
||||
return Mono.empty();
|
||||
|
|
@ -155,8 +153,8 @@ class McpAsyncClientTests {
|
|||
if (!(message instanceof McpSchema.JSONRPCRequest)) {
|
||||
return Mono.empty();
|
||||
}
|
||||
McpSchema.JSONRPCResponse initResponse = new McpSchema.JSONRPCResponse(McpSchema.JSONRPC_VERSION,
|
||||
((McpSchema.JSONRPCRequest) message).id(), MOCK_INIT_RESULT, null);
|
||||
McpSchema.JSONRPCResponse initResponse = McpSchema.JSONRPCResponse
|
||||
.result(((McpSchema.JSONRPCRequest) message).id(), MOCK_INIT_RESULT);
|
||||
return handler.apply(Mono.just(initResponse)).then();
|
||||
}
|
||||
|
||||
|
|
@ -185,7 +183,9 @@ class McpAsyncClientTests {
|
|||
|
||||
StepVerifier.create(client.initialize()).expectNextMatches(Objects::nonNull).verifyComplete();
|
||||
|
||||
StepVerifier.create(client.callTool(new McpSchema.CallToolRequest("calculator", Map.of("expression", "2 + 3"))))
|
||||
StepVerifier
|
||||
.create(client.callTool(
|
||||
McpSchema.CallToolRequest.builder("calculator").arguments(Map.of("expression", "2 + 3")).build()))
|
||||
.expectNextMatches(response -> {
|
||||
assertThat(response).isNotNull();
|
||||
assertThat(response.isError()).isFalse();
|
||||
|
|
@ -207,7 +207,9 @@ class McpAsyncClientTests {
|
|||
|
||||
StepVerifier.create(client.initialize()).expectNextMatches(Objects::nonNull).verifyComplete();
|
||||
|
||||
StepVerifier.create(client.callTool(new McpSchema.CallToolRequest("calculator", Map.of("expression", "2 + 3"))))
|
||||
StepVerifier
|
||||
.create(client.callTool(
|
||||
McpSchema.CallToolRequest.builder("calculator").arguments(Map.of("expression", "2 + 3")).build()))
|
||||
.expectNextMatches(response -> {
|
||||
assertThat(response).isNotNull();
|
||||
assertThat(response.isError()).isFalse();
|
||||
|
|
@ -229,7 +231,9 @@ class McpAsyncClientTests {
|
|||
|
||||
StepVerifier.create(client.initialize()).expectNextMatches(Objects::nonNull).verifyComplete();
|
||||
|
||||
StepVerifier.create(client.callTool(new McpSchema.CallToolRequest("calculator", Map.of("expression", "2 + 3"))))
|
||||
StepVerifier
|
||||
.create(client.callTool(
|
||||
McpSchema.CallToolRequest.builder("calculator").arguments(Map.of("expression", "2 + 3")).build()))
|
||||
.expectErrorMatches(ex -> ex instanceof IllegalArgumentException
|
||||
&& ex.getMessage().contains("Tool call result validation failed"))
|
||||
.verify();
|
||||
|
|
@ -326,50 +330,50 @@ class McpAsyncClientTests {
|
|||
.tools(false)
|
||||
.build();
|
||||
|
||||
McpSchema.InitializeResult initResult = new McpSchema.InitializeResult(ProtocolVersions.MCP_2024_11_05,
|
||||
caps, MOCK_SERVER_INFO, null);
|
||||
McpSchema.InitializeResult initResult = McpSchema.InitializeResult
|
||||
.builder(ProtocolVersions.MCP_2024_11_05, caps, MOCK_SERVER_INFO)
|
||||
.build();
|
||||
|
||||
response = new McpSchema.JSONRPCResponse(McpSchema.JSONRPC_VERSION, request.id(), initResult, null);
|
||||
response = McpSchema.JSONRPCResponse.result(request.id(), initResult);
|
||||
}
|
||||
else if (McpSchema.METHOD_PROMPT_LIST.equals(request.method())) {
|
||||
capturedRequest = JSON_MAPPER.convertValue(request.params(), McpSchema.PaginatedRequest.class);
|
||||
|
||||
McpSchema.Prompt mockPrompt = new McpSchema.Prompt("test-prompt", "A test prompt", List.of());
|
||||
McpSchema.ListPromptsResult mockPromptResult = new McpSchema.ListPromptsResult(List.of(mockPrompt),
|
||||
null);
|
||||
response = new McpSchema.JSONRPCResponse(McpSchema.JSONRPC_VERSION, request.id(), mockPromptResult,
|
||||
null);
|
||||
McpSchema.Prompt mockPrompt = McpSchema.Prompt.builder("test-prompt")
|
||||
.description("A test prompt")
|
||||
.arguments(List.of())
|
||||
.build();
|
||||
McpSchema.ListPromptsResult mockPromptResult = McpSchema.ListPromptsResult.builder(List.of(mockPrompt))
|
||||
.build();
|
||||
response = McpSchema.JSONRPCResponse.result(request.id(), mockPromptResult);
|
||||
}
|
||||
else if (McpSchema.METHOD_RESOURCES_TEMPLATES_LIST.equals(request.method())) {
|
||||
capturedRequest = JSON_MAPPER.convertValue(request.params(), McpSchema.PaginatedRequest.class);
|
||||
|
||||
McpSchema.ResourceTemplate mockTemplate = new McpSchema.ResourceTemplate("file:///{name}", "template",
|
||||
null, null, null);
|
||||
McpSchema.ListResourceTemplatesResult mockResourceTemplateResult = new McpSchema.ListResourceTemplatesResult(
|
||||
List.of(mockTemplate), null);
|
||||
response = new McpSchema.JSONRPCResponse(McpSchema.JSONRPC_VERSION, request.id(),
|
||||
mockResourceTemplateResult, null);
|
||||
McpSchema.ResourceTemplate mockTemplate = McpSchema.ResourceTemplate
|
||||
.builder("file:///{name}", "template")
|
||||
.build();
|
||||
McpSchema.ListResourceTemplatesResult mockResourceTemplateResult = McpSchema.ListResourceTemplatesResult
|
||||
.builder(List.of(mockTemplate))
|
||||
.build();
|
||||
response = McpSchema.JSONRPCResponse.result(request.id(), mockResourceTemplateResult);
|
||||
}
|
||||
else if (McpSchema.METHOD_RESOURCES_LIST.equals(request.method())) {
|
||||
capturedRequest = JSON_MAPPER.convertValue(request.params(), McpSchema.PaginatedRequest.class);
|
||||
|
||||
McpSchema.Resource mockResource = McpSchema.Resource.builder()
|
||||
.uri("file:///test.txt")
|
||||
.name("test.txt")
|
||||
McpSchema.Resource mockResource = McpSchema.Resource.builder("file:///test.txt", "test.txt").build();
|
||||
McpSchema.ListResourcesResult mockResourceResult = McpSchema.ListResourcesResult
|
||||
.builder(List.of(mockResource))
|
||||
.build();
|
||||
McpSchema.ListResourcesResult mockResourceResult = new McpSchema.ListResourcesResult(
|
||||
List.of(mockResource), null);
|
||||
|
||||
response = new McpSchema.JSONRPCResponse(McpSchema.JSONRPC_VERSION, request.id(), mockResourceResult,
|
||||
null);
|
||||
response = McpSchema.JSONRPCResponse.result(request.id(), mockResourceResult);
|
||||
}
|
||||
else if (McpSchema.METHOD_TOOLS_LIST.equals(request.method())) {
|
||||
capturedRequest = JSON_MAPPER.convertValue(request.params(), McpSchema.PaginatedRequest.class);
|
||||
|
||||
McpSchema.Tool addTool = McpSchema.Tool.builder().name("add").description("calculate add").build();
|
||||
McpSchema.ListToolsResult mockToolsResult = new McpSchema.ListToolsResult(List.of(addTool), null);
|
||||
response = new McpSchema.JSONRPCResponse(McpSchema.JSONRPC_VERSION, request.id(), mockToolsResult,
|
||||
null);
|
||||
McpSchema.Tool addTool = McpSchema.Tool.builder("add").description("calculate add").build();
|
||||
McpSchema.ListToolsResult mockToolsResult = McpSchema.ListToolsResult.builder(List.of(addTool)).build();
|
||||
response = McpSchema.JSONRPCResponse.result(request.id(), mockToolsResult);
|
||||
}
|
||||
else {
|
||||
return Mono.empty();
|
||||
|
|
|
|||
|
|
@ -25,7 +25,8 @@ class McpClientProtocolVersionTests {
|
|||
|
||||
private static final Duration REQUEST_TIMEOUT = Duration.ofSeconds(300);
|
||||
|
||||
private static final McpSchema.Implementation CLIENT_INFO = new McpSchema.Implementation("test-client", "1.0.0");
|
||||
private static final McpSchema.Implementation CLIENT_INFO = McpSchema.Implementation.builder("test-client", "1.0.0")
|
||||
.build();
|
||||
|
||||
@Test
|
||||
void shouldUseLatestVersionByDefault() {
|
||||
|
|
@ -46,10 +47,11 @@ class McpClientProtocolVersionTests {
|
|||
McpSchema.InitializeRequest initRequest = (McpSchema.InitializeRequest) request.params();
|
||||
assertThat(initRequest.protocolVersion()).isEqualTo(transport.protocolVersions().get(0));
|
||||
|
||||
transport.simulateIncomingMessage(new McpSchema.JSONRPCResponse(McpSchema.JSONRPC_VERSION, request.id(),
|
||||
new McpSchema.InitializeResult(protocolVersion, ServerCapabilities.builder().build(),
|
||||
new McpSchema.Implementation("test-server", "1.0.0"), null),
|
||||
null));
|
||||
transport.simulateIncomingMessage(McpSchema.JSONRPCResponse.result(request.id(),
|
||||
McpSchema.InitializeResult
|
||||
.builder(protocolVersion, ServerCapabilities.builder().build(),
|
||||
McpSchema.Implementation.builder("test-server", "1.0.0").build())
|
||||
.build()));
|
||||
}).assertNext(result -> {
|
||||
assertThat(result.protocolVersion()).isEqualTo(protocolVersion);
|
||||
}).verifyComplete();
|
||||
|
|
@ -80,10 +82,11 @@ class McpClientProtocolVersionTests {
|
|||
McpSchema.InitializeRequest initRequest = (McpSchema.InitializeRequest) request.params();
|
||||
assertThat(initRequest.protocolVersion()).isIn(List.of(oldVersion, ProtocolVersions.MCP_2025_11_25));
|
||||
|
||||
transport.simulateIncomingMessage(new McpSchema.JSONRPCResponse(McpSchema.JSONRPC_VERSION, request.id(),
|
||||
new McpSchema.InitializeResult(oldVersion, ServerCapabilities.builder().build(),
|
||||
new McpSchema.Implementation("test-server", "1.0.0"), null),
|
||||
null));
|
||||
transport.simulateIncomingMessage(McpSchema.JSONRPCResponse.result(request.id(),
|
||||
McpSchema.InitializeResult
|
||||
.builder(oldVersion, ServerCapabilities.builder().build(),
|
||||
McpSchema.Implementation.builder("test-server", "1.0.0").build())
|
||||
.build()));
|
||||
}).assertNext(result -> {
|
||||
assertThat(result.protocolVersion()).isEqualTo(oldVersion);
|
||||
}).verifyComplete();
|
||||
|
|
@ -109,10 +112,11 @@ class McpClientProtocolVersionTests {
|
|||
McpSchema.JSONRPCRequest request = transport.getLastSentMessageAsRequest();
|
||||
assertThat(request.params()).isInstanceOf(McpSchema.InitializeRequest.class);
|
||||
|
||||
transport.simulateIncomingMessage(new McpSchema.JSONRPCResponse(McpSchema.JSONRPC_VERSION, request.id(),
|
||||
new McpSchema.InitializeResult(unsupportedVersion, ServerCapabilities.builder().build(),
|
||||
new McpSchema.Implementation("test-server", "1.0.0"), null),
|
||||
null));
|
||||
transport.simulateIncomingMessage(McpSchema.JSONRPCResponse.result(request.id(),
|
||||
McpSchema.InitializeResult
|
||||
.builder(unsupportedVersion, ServerCapabilities.builder().build(),
|
||||
McpSchema.Implementation.builder("test-server", "1.0.0").build())
|
||||
.build()));
|
||||
}).expectError(RuntimeException.class).verify();
|
||||
}
|
||||
finally {
|
||||
|
|
@ -142,10 +146,11 @@ class McpClientProtocolVersionTests {
|
|||
McpSchema.InitializeRequest initRequest = (McpSchema.InitializeRequest) request.params();
|
||||
assertThat(initRequest.protocolVersion()).isEqualTo(latestVersion);
|
||||
|
||||
transport.simulateIncomingMessage(new McpSchema.JSONRPCResponse(McpSchema.JSONRPC_VERSION, request.id(),
|
||||
new McpSchema.InitializeResult(latestVersion, ServerCapabilities.builder().build(),
|
||||
new McpSchema.Implementation("test-server", "1.0.0"), null),
|
||||
null));
|
||||
transport.simulateIncomingMessage(McpSchema.JSONRPCResponse.result(request.id(),
|
||||
McpSchema.InitializeResult
|
||||
.builder(latestVersion, ServerCapabilities.builder().build(),
|
||||
McpSchema.Implementation.builder("test-server", "1.0.0").build())
|
||||
.build()));
|
||||
}).assertNext(result -> {
|
||||
assertThat(result.protocolVersion()).isEqualTo(latestVersion);
|
||||
}).verifyComplete();
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import io.modelcontextprotocol.client.transport.customizer.McpAsyncHttpClientRequestCustomizer;
|
||||
import io.modelcontextprotocol.client.transport.customizer.McpSyncHttpClientRequestCustomizer;
|
||||
import io.modelcontextprotocol.common.McpTransportContext;
|
||||
|
|
@ -126,8 +128,7 @@ class HttpClientSseClientTransportTests {
|
|||
|
||||
@Test
|
||||
void testErrorOnBogusMessage() {
|
||||
// bogus message
|
||||
JSONRPCRequest bogusMessage = new JSONRPCRequest(null, null, "test-id", Map.of("key", "value"));
|
||||
var bogusMessage = new BogusJsonRpcMessage("test-id", Map.of("key", "value"));
|
||||
|
||||
StepVerifier.create(transport.sendMessage(bogusMessage))
|
||||
.verifyErrorMessage(
|
||||
|
|
@ -137,8 +138,7 @@ class HttpClientSseClientTransportTests {
|
|||
@Test
|
||||
void testMessageProcessing() {
|
||||
// Create a test message
|
||||
JSONRPCRequest testMessage = new JSONRPCRequest(McpSchema.JSONRPC_VERSION, "test-method", "test-id",
|
||||
Map.of("key", "value"));
|
||||
JSONRPCRequest testMessage = new McpSchema.JSONRPCRequest("test-method", "test-id", Map.of("key", "value"));
|
||||
|
||||
// Simulate receiving the message
|
||||
transport.simulateMessageEvent("""
|
||||
|
|
@ -168,8 +168,7 @@ class HttpClientSseClientTransportTests {
|
|||
""");
|
||||
|
||||
// Create and send a request message
|
||||
JSONRPCRequest testMessage = new JSONRPCRequest(McpSchema.JSONRPC_VERSION, "test-method", "test-id",
|
||||
Map.of("key", "value"));
|
||||
JSONRPCRequest testMessage = new McpSchema.JSONRPCRequest("test-method", "test-id", Map.of("key", "value"));
|
||||
|
||||
// Verify message handling
|
||||
StepVerifier.create(transport.sendMessage(testMessage)).verifyComplete();
|
||||
|
|
@ -192,8 +191,7 @@ class HttpClientSseClientTransportTests {
|
|||
""");
|
||||
|
||||
// Create and send a request message
|
||||
JSONRPCRequest testMessage = new JSONRPCRequest(McpSchema.JSONRPC_VERSION, "test-method", "test-id",
|
||||
Map.of("key", "value"));
|
||||
JSONRPCRequest testMessage = new McpSchema.JSONRPCRequest("test-method", "test-id", Map.of("key", "value"));
|
||||
|
||||
// Verify message handling
|
||||
StepVerifier.create(transport.sendMessage(testMessage)).verifyComplete();
|
||||
|
|
@ -222,8 +220,7 @@ class HttpClientSseClientTransportTests {
|
|||
StepVerifier.create(transport.closeGracefully()).verifyComplete();
|
||||
|
||||
// Create a test message
|
||||
JSONRPCRequest testMessage = new JSONRPCRequest(McpSchema.JSONRPC_VERSION, "test-method", "test-id",
|
||||
Map.of("key", "value"));
|
||||
JSONRPCRequest testMessage = new McpSchema.JSONRPCRequest("test-method", "test-id", Map.of("key", "value"));
|
||||
|
||||
// Verify message is not processed after shutdown
|
||||
StepVerifier.create(transport.sendMessage(testMessage)).verifyComplete();
|
||||
|
|
@ -267,11 +264,9 @@ class HttpClientSseClientTransportTests {
|
|||
""");
|
||||
|
||||
// Create and send corresponding messages
|
||||
JSONRPCRequest message1 = new JSONRPCRequest(McpSchema.JSONRPC_VERSION, "method1", "id1",
|
||||
Map.of("key", "value1"));
|
||||
JSONRPCRequest message1 = new McpSchema.JSONRPCRequest("method1", "id1", Map.of("key", "value1"));
|
||||
|
||||
JSONRPCRequest message2 = new JSONRPCRequest(McpSchema.JSONRPC_VERSION, "method2", "id2",
|
||||
Map.of("key", "value2"));
|
||||
JSONRPCRequest message2 = new McpSchema.JSONRPCRequest("method2", "id2", Map.of("key", "value2"));
|
||||
|
||||
// Verify both messages are processed
|
||||
StepVerifier.create(transport.sendMessage(message1).then(transport.sendMessage(message2))).verifyComplete();
|
||||
|
|
@ -355,8 +350,7 @@ class HttpClientSseClientTransportTests {
|
|||
clearInvocations(mockCustomizer);
|
||||
|
||||
// Send test message
|
||||
var testMessage = new JSONRPCRequest(McpSchema.JSONRPC_VERSION, "test-method", "test-id",
|
||||
Map.of("key", "value"));
|
||||
var testMessage = new McpSchema.JSONRPCRequest("test-method", "test-id", Map.of("key", "value"));
|
||||
|
||||
// Subscribe to messages and verify
|
||||
StepVerifier
|
||||
|
|
@ -398,8 +392,7 @@ class HttpClientSseClientTransportTests {
|
|||
clearInvocations(mockCustomizer);
|
||||
|
||||
// Send test message
|
||||
var testMessage = new JSONRPCRequest(McpSchema.JSONRPC_VERSION, "test-method", "test-id",
|
||||
Map.of("key", "value"));
|
||||
var testMessage = new McpSchema.JSONRPCRequest("test-method", "test-id", Map.of("key", "value"));
|
||||
|
||||
// Subscribe to messages and verify
|
||||
StepVerifier
|
||||
|
|
@ -458,4 +451,30 @@ class HttpClientSseClientTransportTests {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* A minimal {@link McpSchema.JSONRPCMessage} that serializes only the supplied
|
||||
* fields, intentionally omitting {@code jsonrpc} and {@code method} to produce a
|
||||
* bogus wire payload for error-handling tests.
|
||||
*/
|
||||
private static class BogusJsonRpcMessage implements McpSchema.JSONRPCMessage {
|
||||
|
||||
@JsonProperty("id")
|
||||
private final String id;
|
||||
|
||||
@JsonProperty("params")
|
||||
private final Map<String, Object> params;
|
||||
|
||||
BogusJsonRpcMessage(String id, Map<String, Object> params) {
|
||||
this.id = id;
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public String jsonrpc() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,11 +76,11 @@ public class HttpClientStreamableHttpTransportEmptyJsonResponseTest {
|
|||
.httpRequestCustomizer(mockRequestCustomizer)
|
||||
.build();
|
||||
|
||||
var initializeRequest = new McpSchema.InitializeRequest(ProtocolVersions.MCP_2025_03_26,
|
||||
McpSchema.ClientCapabilities.builder().roots(true).build(),
|
||||
new McpSchema.Implementation("MCP Client", "0.3.1"));
|
||||
var testMessage = new McpSchema.JSONRPCRequest(McpSchema.JSONRPC_VERSION, McpSchema.METHOD_INITIALIZE,
|
||||
"test-id", initializeRequest);
|
||||
var initializeRequest = McpSchema.InitializeRequest
|
||||
.builder(ProtocolVersions.MCP_2025_03_26, McpSchema.ClientCapabilities.builder().roots(true).build(),
|
||||
McpSchema.Implementation.builder("MCP Client", "0.3.1").build())
|
||||
.build();
|
||||
var testMessage = new McpSchema.JSONRPCRequest(McpSchema.METHOD_INITIALIZE, "test-id", initializeRequest);
|
||||
|
||||
StepVerifier.create(transport.sendMessage(testMessage)).verifyComplete();
|
||||
|
||||
|
|
|
|||
|
|
@ -770,11 +770,11 @@ public class HttpClientStreamableHttpTransportErrorHandlingTest {
|
|||
}
|
||||
|
||||
private McpSchema.JSONRPCRequest createTestRequestMessage() {
|
||||
var initializeRequest = new McpSchema.InitializeRequest(ProtocolVersions.MCP_2025_03_26,
|
||||
McpSchema.ClientCapabilities.builder().roots(true).build(),
|
||||
new McpSchema.Implementation("Test Client", "1.0.0"));
|
||||
return new McpSchema.JSONRPCRequest(McpSchema.JSONRPC_VERSION, McpSchema.METHOD_INITIALIZE, "test-id",
|
||||
initializeRequest);
|
||||
var initializeRequest = McpSchema.InitializeRequest
|
||||
.builder(ProtocolVersions.MCP_2025_03_26, McpSchema.ClientCapabilities.builder().roots(true).build(),
|
||||
McpSchema.Implementation.builder("Test Client", "1.0.0").build())
|
||||
.build();
|
||||
return new McpSchema.JSONRPCRequest(McpSchema.METHOD_INITIALIZE, "test-id", initializeRequest);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,11 +79,11 @@ class HttpClientStreamableHttpTransportTest {
|
|||
|
||||
withTransport(transport, (t) -> {
|
||||
// Send test message
|
||||
var initializeRequest = new McpSchema.InitializeRequest(ProtocolVersions.MCP_2025_11_25,
|
||||
McpSchema.ClientCapabilities.builder().roots(true).build(),
|
||||
new McpSchema.Implementation("MCP Client", "0.3.1"));
|
||||
var testMessage = new McpSchema.JSONRPCRequest(McpSchema.JSONRPC_VERSION, McpSchema.METHOD_INITIALIZE,
|
||||
"test-id", initializeRequest);
|
||||
var initializeRequest = McpSchema.InitializeRequest
|
||||
.builder(ProtocolVersions.MCP_2025_11_25, McpSchema.ClientCapabilities.builder().roots(true).build(),
|
||||
McpSchema.Implementation.builder("MCP Client", "0.3.1").build())
|
||||
.build();
|
||||
var testMessage = new McpSchema.JSONRPCRequest(McpSchema.METHOD_INITIALIZE, "test-id", initializeRequest);
|
||||
|
||||
StepVerifier
|
||||
.create(t.sendMessage(testMessage).contextWrite(ctx -> ctx.put(McpTransportContext.KEY, context)))
|
||||
|
|
@ -109,11 +109,11 @@ class HttpClientStreamableHttpTransportTest {
|
|||
|
||||
withTransport(transport, (t) -> {
|
||||
// Send test message
|
||||
var initializeRequest = new McpSchema.InitializeRequest(ProtocolVersions.MCP_2025_11_25,
|
||||
McpSchema.ClientCapabilities.builder().roots(true).build(),
|
||||
new McpSchema.Implementation("MCP Client", "0.3.1"));
|
||||
var testMessage = new McpSchema.JSONRPCRequest(McpSchema.JSONRPC_VERSION, McpSchema.METHOD_INITIALIZE,
|
||||
"test-id", initializeRequest);
|
||||
var initializeRequest = McpSchema.InitializeRequest
|
||||
.builder(ProtocolVersions.MCP_2025_11_25, McpSchema.ClientCapabilities.builder().roots(true).build(),
|
||||
McpSchema.Implementation.builder("MCP Client", "0.3.1").build())
|
||||
.build();
|
||||
var testMessage = new McpSchema.JSONRPCRequest(McpSchema.METHOD_INITIALIZE, "test-id", initializeRequest);
|
||||
|
||||
StepVerifier
|
||||
.create(t.sendMessage(testMessage).contextWrite(ctx -> ctx.put(McpTransportContext.KEY, context)))
|
||||
|
|
@ -132,11 +132,11 @@ class HttpClientStreamableHttpTransportTest {
|
|||
|
||||
StepVerifier.create(transport.closeGracefully()).verifyComplete();
|
||||
|
||||
var initializeRequest = new McpSchema.InitializeRequest(ProtocolVersions.MCP_2025_11_25,
|
||||
McpSchema.ClientCapabilities.builder().roots(true).build(),
|
||||
new McpSchema.Implementation("MCP Client", "0.3.1"));
|
||||
var testMessage = new McpSchema.JSONRPCRequest(McpSchema.JSONRPC_VERSION, McpSchema.METHOD_INITIALIZE,
|
||||
"test-id", initializeRequest);
|
||||
var initializeRequest = McpSchema.InitializeRequest
|
||||
.builder(ProtocolVersions.MCP_2025_11_25, McpSchema.ClientCapabilities.builder().roots(true).build(),
|
||||
McpSchema.Implementation.builder("MCP Client", "0.3.1").build())
|
||||
.build();
|
||||
var testMessage = new McpSchema.JSONRPCRequest(McpSchema.METHOD_INITIALIZE, "test-id", initializeRequest);
|
||||
|
||||
StepVerifier.create(transport.sendMessage(testMessage))
|
||||
.expectErrorMessage("MCP session has been closed")
|
||||
|
|
@ -147,11 +147,11 @@ class HttpClientStreamableHttpTransportTest {
|
|||
void testCloseInitialized() {
|
||||
var transport = HttpClientStreamableHttpTransport.builder(host).build();
|
||||
|
||||
var initializeRequest = new McpSchema.InitializeRequest(ProtocolVersions.MCP_2025_11_25,
|
||||
McpSchema.ClientCapabilities.builder().roots(true).build(),
|
||||
new McpSchema.Implementation("MCP Client", "0.3.1"));
|
||||
var testMessage = new McpSchema.JSONRPCRequest(McpSchema.JSONRPC_VERSION, McpSchema.METHOD_INITIALIZE,
|
||||
"test-id", initializeRequest);
|
||||
var initializeRequest = McpSchema.InitializeRequest
|
||||
.builder(ProtocolVersions.MCP_2025_11_25, McpSchema.ClientCapabilities.builder().roots(true).build(),
|
||||
McpSchema.Implementation.builder("MCP Client", "0.3.1").build())
|
||||
.build();
|
||||
var testMessage = new McpSchema.JSONRPCRequest(McpSchema.METHOD_INITIALIZE, "test-id", initializeRequest);
|
||||
|
||||
StepVerifier.create(transport.sendMessage(testMessage)).verifyComplete();
|
||||
StepVerifier.create(transport.closeGracefully()).verifyComplete();
|
||||
|
|
|
|||
|
|
@ -125,8 +125,7 @@ public class AsyncServerMcpTransportContextIntegrationTests {
|
|||
.build())
|
||||
.build();
|
||||
|
||||
private final McpSchema.Tool tool = McpSchema.Tool.builder()
|
||||
.name("test-tool")
|
||||
private final McpSchema.Tool tool = McpSchema.Tool.builder("test-tool")
|
||||
.description("return the value of the x-test header from call tool request")
|
||||
.build();
|
||||
|
||||
|
|
@ -178,7 +177,8 @@ public class AsyncServerMcpTransportContextIntegrationTests {
|
|||
|
||||
// Test tool call with context
|
||||
StepVerifier
|
||||
.create(asyncStreamableClient.callTool(new McpSchema.CallToolRequest("test-tool", Map.of()))
|
||||
.create(asyncStreamableClient
|
||||
.callTool(McpSchema.CallToolRequest.builder("test-tool").arguments(Map.of()).build())
|
||||
.contextWrite(ctx -> ctx.put(McpTransportContext.KEY,
|
||||
McpTransportContext.create(Map.of("client-side-header-value", "some important value")))))
|
||||
.assertNext(response -> {
|
||||
|
|
@ -212,7 +212,8 @@ public class AsyncServerMcpTransportContextIntegrationTests {
|
|||
|
||||
// Test tool call with context
|
||||
StepVerifier
|
||||
.create(asyncStreamableClient.callTool(new McpSchema.CallToolRequest("test-tool", Map.of()))
|
||||
.create(asyncStreamableClient
|
||||
.callTool(McpSchema.CallToolRequest.builder("test-tool").arguments(Map.of()).build())
|
||||
.contextWrite(ctx -> ctx.put(McpTransportContext.KEY,
|
||||
McpTransportContext.create(Map.of("client-side-header-value", "some important value")))))
|
||||
.assertNext(response -> {
|
||||
|
|
@ -246,7 +247,7 @@ public class AsyncServerMcpTransportContextIntegrationTests {
|
|||
|
||||
// Test tool call with context
|
||||
StepVerifier
|
||||
.create(asyncSseClient.callTool(new McpSchema.CallToolRequest("test-tool", Map.of()))
|
||||
.create(asyncSseClient.callTool(McpSchema.CallToolRequest.builder("test-tool").arguments(Map.of()).build())
|
||||
.contextWrite(ctx -> ctx.put(McpTransportContext.KEY,
|
||||
McpTransportContext.create(Map.of("client-side-header-value", "some important value")))))
|
||||
.assertNext(response -> {
|
||||
|
|
|
|||
|
|
@ -41,8 +41,7 @@ class HttpClientStreamableHttpVersionNegotiationIntegrationTests {
|
|||
req -> McpTransportContext.create(Map.of("protocol-version", req.getHeader("MCP-protocol-version"))))
|
||||
.build();
|
||||
|
||||
private final McpSchema.Tool toolSpec = McpSchema.Tool.builder()
|
||||
.name("test-tool")
|
||||
private final McpSchema.Tool toolSpec = McpSchema.Tool.builder("test-tool")
|
||||
.description("return the protocol version used")
|
||||
.build();
|
||||
|
||||
|
|
@ -70,7 +69,8 @@ class HttpClientStreamableHttpVersionNegotiationIntegrationTests {
|
|||
.build();
|
||||
|
||||
client.initialize();
|
||||
McpSchema.CallToolResult response = client.callTool(new McpSchema.CallToolRequest("test-tool", Map.of()));
|
||||
McpSchema.CallToolResult response = client
|
||||
.callTool(McpSchema.CallToolRequest.builder("test-tool").arguments(Map.of()).build());
|
||||
|
||||
var calls = requestRecordingFilter.getCalls();
|
||||
|
||||
|
|
@ -100,7 +100,8 @@ class HttpClientStreamableHttpVersionNegotiationIntegrationTests {
|
|||
var client = McpClient.sync(transport).build();
|
||||
|
||||
client.initialize();
|
||||
McpSchema.CallToolResult response = client.callTool(new McpSchema.CallToolRequest("test-tool", Map.of()));
|
||||
McpSchema.CallToolResult response = client
|
||||
.callTool(McpSchema.CallToolRequest.builder("test-tool").arguments(Map.of()).build());
|
||||
|
||||
var calls = requestRecordingFilter.getCalls();
|
||||
// Initialize tells the server the Client's latest supported version
|
||||
|
|
|
|||
|
|
@ -116,8 +116,7 @@ public class SyncServerMcpTransportContextIntegrationTests {
|
|||
.transportContextProvider(clientContextProvider)
|
||||
.build();
|
||||
|
||||
private final McpSchema.Tool tool = McpSchema.Tool.builder()
|
||||
.name("test-tool")
|
||||
private final McpSchema.Tool tool = McpSchema.Tool.builder("test-tool")
|
||||
.description("return the value of the x-test header from call tool request")
|
||||
.build();
|
||||
|
||||
|
|
@ -156,7 +155,7 @@ public class SyncServerMcpTransportContextIntegrationTests {
|
|||
|
||||
CLIENT_SIDE_HEADER_VALUE_HOLDER.set("some important value");
|
||||
McpSchema.CallToolResult response = streamableClient
|
||||
.callTool(new McpSchema.CallToolRequest("test-tool", Map.of()));
|
||||
.callTool(McpSchema.CallToolRequest.builder("test-tool").arguments(Map.of()).build());
|
||||
|
||||
assertThat(response).isNotNull();
|
||||
assertThat(response.content()).hasSize(1)
|
||||
|
|
@ -182,7 +181,7 @@ public class SyncServerMcpTransportContextIntegrationTests {
|
|||
|
||||
CLIENT_SIDE_HEADER_VALUE_HOLDER.set("some important value");
|
||||
McpSchema.CallToolResult response = streamableClient
|
||||
.callTool(new McpSchema.CallToolRequest("test-tool", Map.of()));
|
||||
.callTool(McpSchema.CallToolRequest.builder("test-tool").arguments(Map.of()).build());
|
||||
|
||||
assertThat(response).isNotNull();
|
||||
assertThat(response.content()).hasSize(1)
|
||||
|
|
@ -207,7 +206,8 @@ public class SyncServerMcpTransportContextIntegrationTests {
|
|||
assertThat(initResult).isNotNull();
|
||||
|
||||
CLIENT_SIDE_HEADER_VALUE_HOLDER.set("some important value");
|
||||
McpSchema.CallToolResult response = sseClient.callTool(new McpSchema.CallToolRequest("test-tool", Map.of()));
|
||||
McpSchema.CallToolResult response = sseClient
|
||||
.callTool(McpSchema.CallToolRequest.builder("test-tool").arguments(Map.of()).build());
|
||||
|
||||
assertThat(response).isNotNull();
|
||||
assertThat(response.content()).hasSize(1)
|
||||
|
|
|
|||
|
|
@ -116,11 +116,11 @@ class HttpServletStatelessIntegrationTests {
|
|||
var clientBuilder = clientBuilders.get(clientType);
|
||||
|
||||
var callResponse = CallToolResult.builder()
|
||||
.content(List.of(new McpSchema.TextContent("CALL RESPONSE")))
|
||||
.content(List.of(McpSchema.TextContent.builder("CALL RESPONSE").build()))
|
||||
.isError(false)
|
||||
.build();
|
||||
McpStatelessServerFeatures.SyncToolSpecification tool1 = new McpStatelessServerFeatures.SyncToolSpecification(
|
||||
Tool.builder().name("tool1").title("tool1 description").inputSchema(EMPTY_JSON_SCHEMA).build(),
|
||||
Tool.builder("tool1", EMPTY_JSON_SCHEMA).title("tool1 description").build(),
|
||||
(transportContext, request) -> {
|
||||
// perform a blocking call to a remote service
|
||||
String response = RestClient.create()
|
||||
|
|
@ -144,7 +144,8 @@ class HttpServletStatelessIntegrationTests {
|
|||
|
||||
assertThat(mcpClient.listTools().tools()).contains(tool1.tool());
|
||||
|
||||
CallToolResult response = mcpClient.callTool(new McpSchema.CallToolRequest("tool1", Map.of()));
|
||||
CallToolResult response = mcpClient
|
||||
.callTool(McpSchema.CallToolRequest.builder("tool1").arguments(Map.of()).build());
|
||||
|
||||
assertThat(response).isNotNull();
|
||||
assertThat(response).isEqualTo(callResponse);
|
||||
|
|
@ -193,12 +194,17 @@ class HttpServletStatelessIntegrationTests {
|
|||
|
||||
var mcpServer = McpServer.sync(mcpStatelessServerTransport)
|
||||
.capabilities(ServerCapabilities.builder().completions().build())
|
||||
.prompts(new McpStatelessServerFeatures.SyncPromptSpecification(
|
||||
new Prompt("code_review", "Code review", "this is code review prompt",
|
||||
List.of(new PromptArgument("language", "Language", "string", false))),
|
||||
(transportContext, getPromptRequest) -> null))
|
||||
.prompts(new McpStatelessServerFeatures.SyncPromptSpecification(Prompt.builder("code_review")
|
||||
.title("Code review")
|
||||
.description("this is code review prompt")
|
||||
.arguments(List.of(PromptArgument.builder("language")
|
||||
.title("Language")
|
||||
.description("string")
|
||||
.required(false)
|
||||
.build()))
|
||||
.build(), (transportContext, getPromptRequest) -> null))
|
||||
.completions(new McpStatelessServerFeatures.SyncCompletionSpecification(
|
||||
new PromptReference(PromptReference.TYPE, "code_review", "Code review"), completionHandler))
|
||||
PromptReference.builder("code_review").title("Code review").build(), completionHandler))
|
||||
.build();
|
||||
|
||||
try (var mcpClient = clientBuilder.build()) {
|
||||
|
|
@ -206,9 +212,10 @@ class HttpServletStatelessIntegrationTests {
|
|||
InitializeResult initResult = mcpClient.initialize();
|
||||
assertThat(initResult).isNotNull();
|
||||
|
||||
CompleteRequest request = new CompleteRequest(
|
||||
new PromptReference(PromptReference.TYPE, "code_review", "Code review"),
|
||||
new CompleteRequest.CompleteArgument("language", "py"));
|
||||
CompleteRequest request = CompleteRequest
|
||||
.builder(PromptReference.builder("code_review").title("Code review").build(),
|
||||
new CompleteRequest.CompleteArgument("language", "py"))
|
||||
.build();
|
||||
|
||||
CompleteResult result = mcpClient.completeCompletion(request);
|
||||
|
||||
|
|
@ -237,8 +244,7 @@ class HttpServletStatelessIntegrationTests {
|
|||
Map.of("type", "string"), "timestamp", Map.of("type", "string")),
|
||||
"required", List.of("result", "operation"));
|
||||
|
||||
Tool calculatorTool = Tool.builder()
|
||||
.name("calculator")
|
||||
Tool calculatorTool = Tool.builder("calculator")
|
||||
.description("Performs mathematical calculations")
|
||||
.outputSchema(outputSchema)
|
||||
.build();
|
||||
|
|
@ -270,8 +276,8 @@ class HttpServletStatelessIntegrationTests {
|
|||
// Note: outputSchema might be null in sync server, but validation still works
|
||||
|
||||
// Call tool with valid structured output
|
||||
CallToolResult response = mcpClient
|
||||
.callTool(new McpSchema.CallToolRequest("calculator", Map.of("expression", "2 + 3")));
|
||||
CallToolResult response = mcpClient.callTool(
|
||||
McpSchema.CallToolRequest.builder("calculator").arguments(Map.of("expression", "2 + 3")).build());
|
||||
|
||||
assertThat(response).isNotNull();
|
||||
assertThat(response.isError()).isFalse();
|
||||
|
|
@ -312,8 +318,7 @@ class HttpServletStatelessIntegrationTests {
|
|||
"age", Map.of("type", "number")),
|
||||
"required", List.of("name", "age"))); // @formatter:on
|
||||
|
||||
Tool calculatorTool = Tool.builder()
|
||||
.name("getMembers")
|
||||
Tool calculatorTool = Tool.builder("getMembers")
|
||||
.description("Returns a list of members")
|
||||
.outputSchema(outputSchema)
|
||||
.build();
|
||||
|
|
@ -338,7 +343,8 @@ class HttpServletStatelessIntegrationTests {
|
|||
assertThat(mcpClient.initialize()).isNotNull();
|
||||
|
||||
// Call tool with valid structured output of type array
|
||||
CallToolResult response = mcpClient.callTool(new McpSchema.CallToolRequest("getMembers", Map.of()));
|
||||
CallToolResult response = mcpClient
|
||||
.callTool(McpSchema.CallToolRequest.builder("getMembers").arguments(Map.of()).build());
|
||||
|
||||
assertThat(response).isNotNull();
|
||||
assertThat(response.isError()).isFalse();
|
||||
|
|
@ -368,8 +374,7 @@ class HttpServletStatelessIntegrationTests {
|
|||
Map.of("type", "string"), "timestamp", Map.of("type", "string")),
|
||||
"required", List.of("result", "operation"));
|
||||
|
||||
Tool calculatorTool = Tool.builder()
|
||||
.name("calculator")
|
||||
Tool calculatorTool = Tool.builder("calculator")
|
||||
.description("Performs mathematical calculations")
|
||||
.outputSchema(outputSchema)
|
||||
.build();
|
||||
|
|
@ -380,7 +385,7 @@ class HttpServletStatelessIntegrationTests {
|
|||
.tool(calculatorTool)
|
||||
.callHandler((exchange, request) -> CallToolResult.builder()
|
||||
.isError(true)
|
||||
.content(List.of(new TextContent("Error calling tool: Simulated in-handler error")))
|
||||
.content(List.of(TextContent.builder("Error calling tool: Simulated in-handler error").build()))
|
||||
.build())
|
||||
.build();
|
||||
|
||||
|
|
@ -401,14 +406,14 @@ class HttpServletStatelessIntegrationTests {
|
|||
// Note: outputSchema might be null in sync server, but validation still works
|
||||
|
||||
// Call tool with valid structured output
|
||||
CallToolResult response = mcpClient
|
||||
.callTool(new McpSchema.CallToolRequest("calculator", Map.of("expression", "2 + 3")));
|
||||
CallToolResult response = mcpClient.callTool(
|
||||
McpSchema.CallToolRequest.builder("calculator").arguments(Map.of("expression", "2 + 3")).build());
|
||||
|
||||
assertThat(response).isNotNull();
|
||||
assertThat(response.isError()).isTrue();
|
||||
assertThat(response.content()).isNotEmpty();
|
||||
assertThat(response.content())
|
||||
.containsExactly(new McpSchema.TextContent("Error calling tool: Simulated in-handler error"));
|
||||
assertThat(response.content()).containsExactly(
|
||||
McpSchema.TextContent.builder("Error calling tool: Simulated in-handler error").build());
|
||||
assertThat(response.structuredContent()).isNull();
|
||||
}
|
||||
finally {
|
||||
|
|
@ -426,8 +431,7 @@ class HttpServletStatelessIntegrationTests {
|
|||
Map.of("result", Map.of("type", "number"), "operation", Map.of("type", "string")), "required",
|
||||
List.of("result", "operation"));
|
||||
|
||||
Tool calculatorTool = Tool.builder()
|
||||
.name("calculator")
|
||||
Tool calculatorTool = Tool.builder("calculator")
|
||||
.description("Performs mathematical calculations")
|
||||
.outputSchema(outputSchema)
|
||||
.build();
|
||||
|
|
@ -453,8 +457,8 @@ class HttpServletStatelessIntegrationTests {
|
|||
assertThat(initResult).isNotNull();
|
||||
|
||||
// Call tool with invalid structured output
|
||||
CallToolResult response = mcpClient
|
||||
.callTool(new McpSchema.CallToolRequest("calculator", Map.of("expression", "2 + 3")));
|
||||
CallToolResult response = mcpClient.callTool(
|
||||
McpSchema.CallToolRequest.builder("calculator").arguments(Map.of("expression", "2 + 3")).build());
|
||||
|
||||
assertThat(response).isNotNull();
|
||||
assertThat(response.isError()).isTrue();
|
||||
|
|
@ -478,8 +482,7 @@ class HttpServletStatelessIntegrationTests {
|
|||
Map<String, Object> outputSchema = Map.of("type", "object", "properties",
|
||||
Map.of("result", Map.of("type", "number")), "required", List.of("result"));
|
||||
|
||||
Tool calculatorTool = Tool.builder()
|
||||
.name("calculator")
|
||||
Tool calculatorTool = Tool.builder("calculator")
|
||||
.description("Performs mathematical calculations")
|
||||
.outputSchema(outputSchema)
|
||||
.build();
|
||||
|
|
@ -502,8 +505,8 @@ class HttpServletStatelessIntegrationTests {
|
|||
assertThat(initResult).isNotNull();
|
||||
|
||||
// Call tool that should return structured content but doesn't
|
||||
CallToolResult response = mcpClient
|
||||
.callTool(new McpSchema.CallToolRequest("calculator", Map.of("expression", "2 + 3")));
|
||||
CallToolResult response = mcpClient.callTool(
|
||||
McpSchema.CallToolRequest.builder("calculator").arguments(Map.of("expression", "2 + 3")).build());
|
||||
|
||||
assertThat(response).isNotNull();
|
||||
assertThat(response.isError()).isTrue();
|
||||
|
|
@ -542,8 +545,7 @@ class HttpServletStatelessIntegrationTests {
|
|||
Map.of("message", Map.of("type", "string"), "count", Map.of("type", "integer")), "required",
|
||||
List.of("message", "count"));
|
||||
|
||||
Tool dynamicTool = Tool.builder()
|
||||
.name("dynamic-tool")
|
||||
Tool dynamicTool = Tool.builder("dynamic-tool")
|
||||
.description("Dynamically added tool")
|
||||
.outputSchema(outputSchema)
|
||||
.build();
|
||||
|
|
@ -573,7 +575,7 @@ class HttpServletStatelessIntegrationTests {
|
|||
|
||||
// Call dynamically added tool
|
||||
CallToolResult response = mcpClient
|
||||
.callTool(new McpSchema.CallToolRequest("dynamic-tool", Map.of("count", 3)));
|
||||
.callTool(McpSchema.CallToolRequest.builder("dynamic-tool").arguments(Map.of("count", 3)).build());
|
||||
|
||||
assertThat(response).isNotNull();
|
||||
assertThat(response.isError()).isFalse();
|
||||
|
|
@ -601,7 +603,7 @@ class HttpServletStatelessIntegrationTests {
|
|||
.capabilities(ServerCapabilities.builder().tools(true).build())
|
||||
.build();
|
||||
|
||||
Tool testTool = Tool.builder().name("test").description("test").build();
|
||||
Tool testTool = Tool.builder("test").description("test").build();
|
||||
|
||||
McpStatelessServerFeatures.SyncToolSpecification toolSpec = new McpStatelessServerFeatures.SyncToolSpecification(
|
||||
testTool, (transportContext, request) -> {
|
||||
|
|
@ -610,9 +612,11 @@ class HttpServletStatelessIntegrationTests {
|
|||
|
||||
mcpServer.addTool(toolSpec);
|
||||
|
||||
McpSchema.CallToolRequest callToolRequest = new McpSchema.CallToolRequest("test", Map.of());
|
||||
McpSchema.JSONRPCRequest jsonrpcRequest = new McpSchema.JSONRPCRequest(McpSchema.JSONRPC_VERSION,
|
||||
McpSchema.METHOD_TOOLS_CALL, "test", callToolRequest);
|
||||
McpSchema.CallToolRequest callToolRequest = McpSchema.CallToolRequest.builder("test")
|
||||
.arguments(Map.of())
|
||||
.build();
|
||||
McpSchema.JSONRPCRequest jsonrpcRequest = new McpSchema.JSONRPCRequest(McpSchema.METHOD_TOOLS_CALL, "test",
|
||||
callToolRequest);
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("POST", CUSTOM_MESSAGE_ENDPOINT);
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
|
|
|||
|
|
@ -98,11 +98,9 @@ class McpCompletionTests {
|
|||
return new CompleteResult(new CompleteResult.CompleteCompletion(List.of("test-completion"), 1, false));
|
||||
};
|
||||
|
||||
ResourceReference resourceRef = new ResourceReference(ResourceReference.TYPE, "test://resource/{param}");
|
||||
ResourceReference resourceRef = new ResourceReference("test://resource/{param}");
|
||||
|
||||
var resource = Resource.builder()
|
||||
.uri("test://resource/{param}")
|
||||
.name("Test Resource")
|
||||
var resource = Resource.builder("test://resource/{param}", "Test Resource")
|
||||
.description("A resource for testing")
|
||||
.mimeType("text/plain")
|
||||
.size(123L)
|
||||
|
|
@ -111,19 +109,21 @@ class McpCompletionTests {
|
|||
var mcpServer = McpServer.sync(mcpServerTransportProvider)
|
||||
.capabilities(ServerCapabilities.builder().completions().build())
|
||||
.resources(new McpServerFeatures.SyncResourceSpecification(resource,
|
||||
(exchange, req) -> new ReadResourceResult(List.of())))
|
||||
(exchange, req) -> ReadResourceResult.builder(List.of()).build()))
|
||||
.completions(new McpServerFeatures.SyncCompletionSpecification(resourceRef, completionHandler))
|
||||
.build();
|
||||
|
||||
try (var mcpClient = clientBuilder.clientInfo(new McpSchema.Implementation("Sample " + "client", "0.0.0"))
|
||||
try (var mcpClient = clientBuilder
|
||||
.clientInfo(McpSchema.Implementation.builder("Sample " + "client", "0.0.0").build())
|
||||
.build();) {
|
||||
InitializeResult initResult = mcpClient.initialize();
|
||||
assertThat(initResult).isNotNull();
|
||||
|
||||
// Test with context
|
||||
CompleteRequest request = new CompleteRequest(resourceRef,
|
||||
new CompleteRequest.CompleteArgument("param", "test"), null,
|
||||
new CompleteRequest.CompleteContext(Map.of("previous", "value")));
|
||||
CompleteRequest request = CompleteRequest
|
||||
.builder(resourceRef, new CompleteRequest.CompleteArgument("param", "test"))
|
||||
.context(new CompleteRequest.CompleteContext(Map.of("previous", "value")))
|
||||
.build();
|
||||
|
||||
CompleteResult result = mcpClient.completeCompletion(request);
|
||||
|
||||
|
|
@ -145,25 +145,29 @@ class McpCompletionTests {
|
|||
new CompleteResult.CompleteCompletion(List.of("no-context-completion"), 1, false));
|
||||
};
|
||||
|
||||
McpSchema.Prompt prompt = new Prompt("test-prompt", "this is a test prompt",
|
||||
List.of(new PromptArgument("arg", "string", false)));
|
||||
McpSchema.Prompt prompt = Prompt.builder("test-prompt")
|
||||
.description("this is a test prompt")
|
||||
.arguments(List.of(PromptArgument.builder("arg").description("string").required(false).build()))
|
||||
.build();
|
||||
|
||||
var mcpServer = McpServer.sync(mcpServerTransportProvider)
|
||||
.capabilities(ServerCapabilities.builder().completions().build())
|
||||
.prompts(new McpServerFeatures.SyncPromptSpecification(prompt,
|
||||
(mcpSyncServerExchange, getPromptRequest) -> null))
|
||||
.completions(new McpServerFeatures.SyncCompletionSpecification(
|
||||
new PromptReference(PromptReference.TYPE, "test-prompt"), completionHandler))
|
||||
.completions(new McpServerFeatures.SyncCompletionSpecification(new PromptReference("test-prompt"),
|
||||
completionHandler))
|
||||
.build();
|
||||
|
||||
try (var mcpClient = clientBuilder.clientInfo(new McpSchema.Implementation("Sample " + "client", "0.0.0"))
|
||||
try (var mcpClient = clientBuilder
|
||||
.clientInfo(McpSchema.Implementation.builder("Sample " + "client", "0.0.0").build())
|
||||
.build();) {
|
||||
InitializeResult initResult = mcpClient.initialize();
|
||||
assertThat(initResult).isNotNull();
|
||||
|
||||
// Test without context
|
||||
CompleteRequest request = new CompleteRequest(new PromptReference(PromptReference.TYPE, "test-prompt"),
|
||||
new CompleteRequest.CompleteArgument("arg", "val"));
|
||||
CompleteRequest request = CompleteRequest
|
||||
.builder(new PromptReference("test-prompt"), new CompleteRequest.CompleteArgument("arg", "val"))
|
||||
.build();
|
||||
|
||||
CompleteResult result = mcpClient.completeCompletion(request);
|
||||
|
||||
|
|
@ -205,9 +209,7 @@ class McpCompletionTests {
|
|||
return new CompleteResult(new CompleteResult.CompleteCompletion(List.of(), 0, false));
|
||||
};
|
||||
|
||||
McpSchema.Resource resource = Resource.builder()
|
||||
.uri("db://{database}/{table}")
|
||||
.name("Database Table")
|
||||
McpSchema.Resource resource = Resource.builder("db://{database}/{table}", "Database Table")
|
||||
.description("Resource representing a table in a database")
|
||||
.mimeType("application/json")
|
||||
.size(456L)
|
||||
|
|
@ -216,38 +218,42 @@ class McpCompletionTests {
|
|||
var mcpServer = McpServer.sync(mcpServerTransportProvider)
|
||||
.capabilities(ServerCapabilities.builder().completions().build())
|
||||
.resources(new McpServerFeatures.SyncResourceSpecification(resource,
|
||||
(exchange, req) -> new ReadResourceResult(List.of())))
|
||||
(exchange, req) -> ReadResourceResult.builder(List.of()).build()))
|
||||
.completions(new McpServerFeatures.SyncCompletionSpecification(
|
||||
new ResourceReference(ResourceReference.TYPE, "db://{database}/{table}"), completionHandler))
|
||||
new ResourceReference("db://{database}/{table}"), completionHandler))
|
||||
.build();
|
||||
|
||||
try (var mcpClient = clientBuilder.clientInfo(new McpSchema.Implementation("Sample " + "client", "0.0.0"))
|
||||
try (var mcpClient = clientBuilder
|
||||
.clientInfo(McpSchema.Implementation.builder("Sample " + "client", "0.0.0").build())
|
||||
.build();) {
|
||||
InitializeResult initResult = mcpClient.initialize();
|
||||
assertThat(initResult).isNotNull();
|
||||
|
||||
// First, complete database
|
||||
CompleteRequest dbRequest = new CompleteRequest(
|
||||
new ResourceReference(ResourceReference.TYPE, "db://{database}/{table}"),
|
||||
new CompleteRequest.CompleteArgument("database", ""));
|
||||
CompleteRequest dbRequest = CompleteRequest
|
||||
.builder(new ResourceReference("db://{database}/{table}"),
|
||||
new CompleteRequest.CompleteArgument("database", ""))
|
||||
.build();
|
||||
|
||||
CompleteResult dbResult = mcpClient.completeCompletion(dbRequest);
|
||||
assertThat(dbResult.completion().values()).contains("users_db", "products_db");
|
||||
|
||||
// Then complete table with database context
|
||||
CompleteRequest tableRequest = new CompleteRequest(
|
||||
new ResourceReference(ResourceReference.TYPE, "db://{database}/{table}"),
|
||||
new CompleteRequest.CompleteArgument("table", ""),
|
||||
new CompleteRequest.CompleteContext(Map.of("database", "users_db")));
|
||||
CompleteRequest tableRequest = CompleteRequest
|
||||
.builder(new ResourceReference("db://{database}/{table}"),
|
||||
new CompleteRequest.CompleteArgument("table", ""))
|
||||
.context(new CompleteRequest.CompleteContext(Map.of("database", "users_db")))
|
||||
.build();
|
||||
|
||||
CompleteResult tableResult = mcpClient.completeCompletion(tableRequest);
|
||||
assertThat(tableResult.completion().values()).containsExactly("users", "sessions", "permissions");
|
||||
|
||||
// Different database gives different tables
|
||||
CompleteRequest tableRequest2 = new CompleteRequest(
|
||||
new ResourceReference(ResourceReference.TYPE, "db://{database}/{table}"),
|
||||
new CompleteRequest.CompleteArgument("table", ""),
|
||||
new CompleteRequest.CompleteContext(Map.of("database", "products_db")));
|
||||
CompleteRequest tableRequest2 = CompleteRequest
|
||||
.builder(new ResourceReference("db://{database}/{table}"),
|
||||
new CompleteRequest.CompleteArgument("table", ""))
|
||||
.context(new CompleteRequest.CompleteContext(Map.of("database", "products_db")))
|
||||
.build();
|
||||
|
||||
CompleteResult tableResult2 = mcpClient.completeCompletion(tableRequest2);
|
||||
assertThat(tableResult2.completion().values()).containsExactly("products", "categories", "inventory");
|
||||
|
|
@ -282,9 +288,7 @@ class McpCompletionTests {
|
|||
return new CompleteResult(new CompleteResult.CompleteCompletion(List.of(), 0, false));
|
||||
};
|
||||
|
||||
McpSchema.Resource resource = Resource.builder()
|
||||
.uri("db://{database}/{table}")
|
||||
.name("Database Table")
|
||||
McpSchema.Resource resource = Resource.builder("db://{database}/{table}", "Database Table")
|
||||
.description("Resource representing a table in a database")
|
||||
.mimeType("application/json")
|
||||
.size(456L)
|
||||
|
|
@ -293,30 +297,33 @@ class McpCompletionTests {
|
|||
var mcpServer = McpServer.sync(mcpServerTransportProvider)
|
||||
.capabilities(ServerCapabilities.builder().completions().build())
|
||||
.resources(new McpServerFeatures.SyncResourceSpecification(resource,
|
||||
(exchange, req) -> new ReadResourceResult(List.of())))
|
||||
(exchange, req) -> ReadResourceResult.builder(List.of()).build()))
|
||||
.completions(new McpServerFeatures.SyncCompletionSpecification(
|
||||
new ResourceReference(ResourceReference.TYPE, "db://{database}/{table}"), completionHandler))
|
||||
new ResourceReference("db://{database}/{table}"), completionHandler))
|
||||
.build();
|
||||
|
||||
try (var mcpClient = clientBuilder.clientInfo(new McpSchema.Implementation("Sample" + "client", "0.0.0"))
|
||||
try (var mcpClient = clientBuilder
|
||||
.clientInfo(McpSchema.Implementation.builder("Sample" + "client", "0.0.0").build())
|
||||
.build();) {
|
||||
InitializeResult initResult = mcpClient.initialize();
|
||||
assertThat(initResult).isNotNull();
|
||||
|
||||
// Try to complete table without database context - should raise error
|
||||
CompleteRequest requestWithoutContext = new CompleteRequest(
|
||||
new ResourceReference(ResourceReference.TYPE, "db://{database}/{table}"),
|
||||
new CompleteRequest.CompleteArgument("table", ""));
|
||||
CompleteRequest requestWithoutContext = CompleteRequest
|
||||
.builder(new ResourceReference("db://{database}/{table}"),
|
||||
new CompleteRequest.CompleteArgument("table", ""))
|
||||
.build();
|
||||
|
||||
assertThatExceptionOfType(McpError.class)
|
||||
.isThrownBy(() -> mcpClient.completeCompletion(requestWithoutContext))
|
||||
.withMessageContaining("Please select a database first");
|
||||
|
||||
// Now complete with proper context - should work normally
|
||||
CompleteRequest requestWithContext = new CompleteRequest(
|
||||
new ResourceReference(ResourceReference.TYPE, "db://{database}/{table}"),
|
||||
new CompleteRequest.CompleteArgument("table", ""),
|
||||
new CompleteRequest.CompleteContext(Map.of("database", "test_db")));
|
||||
CompleteRequest requestWithContext = CompleteRequest
|
||||
.builder(new ResourceReference("db://{database}/{table}"),
|
||||
new CompleteRequest.CompleteArgument("table", ""))
|
||||
.context(new CompleteRequest.CompleteContext(Map.of("database", "test_db")))
|
||||
.build();
|
||||
|
||||
CompleteResult resultWithContext = mcpClient.completeCompletion(requestWithContext);
|
||||
assertThat(resultWithContext.completion().values()).containsExactly("users", "orders", "products");
|
||||
|
|
@ -330,24 +337,26 @@ class McpCompletionTests {
|
|||
BiFunction<McpSyncServerExchange, CompleteRequest, CompleteResult> completionHandler = (exchange,
|
||||
request) -> new CompleteResult(new CompleteResult.CompleteCompletion(List.of("test"), 1, false));
|
||||
|
||||
McpSchema.Prompt prompt = new Prompt("test-prompt", "this is a test prompt", null);
|
||||
McpSchema.Prompt prompt = Prompt.builder("test-prompt").description("this is a test prompt").build();
|
||||
|
||||
var mcpServer = McpServer.sync(mcpServerTransportProvider)
|
||||
.capabilities(ServerCapabilities.builder().completions().build())
|
||||
.prompts(new McpServerFeatures.SyncPromptSpecification(prompt,
|
||||
(mcpSyncServerExchange, getPromptRequest) -> null))
|
||||
.completions(new McpServerFeatures.SyncCompletionSpecification(
|
||||
new PromptReference(PromptReference.TYPE, "test-prompt"), completionHandler))
|
||||
.completions(new McpServerFeatures.SyncCompletionSpecification(new PromptReference("test-prompt"),
|
||||
completionHandler))
|
||||
.build();
|
||||
|
||||
try (var mcpClient = clientBuilder.clientInfo(new McpSchema.Implementation("Sample " + "client", "0.0.0"))
|
||||
try (var mcpClient = clientBuilder
|
||||
.clientInfo(McpSchema.Implementation.builder("Sample " + "client", "0.0.0").build())
|
||||
.build()) {
|
||||
InitializeResult initResult = mcpClient.initialize();
|
||||
assertThat(initResult).isNotNull();
|
||||
|
||||
// try completing an argument knowing that the prompt is not parameterized
|
||||
CompleteRequest request = new CompleteRequest(new PromptReference(PromptReference.TYPE, "test-prompt"),
|
||||
new CompleteRequest.CompleteArgument("arg", "val"));
|
||||
CompleteRequest request = CompleteRequest
|
||||
.builder(new PromptReference("test-prompt"), new CompleteRequest.CompleteArgument("arg", "val"))
|
||||
.build();
|
||||
|
||||
CompleteResult completeResult = mcpClient.completeCompletion(request);
|
||||
assertThat(completeResult.completion().values()).isEmpty();
|
||||
|
|
|
|||
|
|
@ -20,13 +20,17 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||
*/
|
||||
class McpServerProtocolVersionTests {
|
||||
|
||||
private static final McpSchema.Implementation SERVER_INFO = new McpSchema.Implementation("test-server", "1.0.0");
|
||||
private static final McpSchema.Implementation SERVER_INFO = McpSchema.Implementation.builder("test-server", "1.0.0")
|
||||
.build();
|
||||
|
||||
private static final McpSchema.Implementation CLIENT_INFO = new McpSchema.Implementation("test-client", "1.0.0");
|
||||
private static final McpSchema.Implementation CLIENT_INFO = McpSchema.Implementation.builder("test-client", "1.0.0")
|
||||
.build();
|
||||
|
||||
private McpSchema.JSONRPCRequest jsonRpcInitializeRequest(String requestId, String protocolVersion) {
|
||||
return new McpSchema.JSONRPCRequest(McpSchema.JSONRPC_VERSION, McpSchema.METHOD_INITIALIZE, requestId,
|
||||
new McpSchema.InitializeRequest(protocolVersion, null, CLIENT_INFO));
|
||||
return new McpSchema.JSONRPCRequest(McpSchema.METHOD_INITIALIZE, requestId,
|
||||
McpSchema.InitializeRequest
|
||||
.builder(protocolVersion, McpSchema.ClientCapabilities.builder().build(), CLIENT_INFO)
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue