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
21 changed files with 4258 additions and 1688 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -24,9 +24,11 @@ class ResourceSubscriptionTests {
|
|||
|
||||
private static final String RESOURCE_URI = "test://resource/1";
|
||||
|
||||
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 static McpAsyncServer buildServer(MockMcpServerTransportProvider transportProvider) {
|
||||
return McpServer.async(transportProvider)
|
||||
|
|
@ -36,24 +38,25 @@ class ResourceSubscriptionTests {
|
|||
}
|
||||
|
||||
private static McpSchema.JSONRPCRequest initRequest() {
|
||||
return new McpSchema.JSONRPCRequest(McpSchema.JSONRPC_VERSION, McpSchema.METHOD_INITIALIZE,
|
||||
UUID.randomUUID().toString(),
|
||||
new McpSchema.InitializeRequest(ProtocolVersions.MCP_2025_11_25, null, CLIENT_INFO));
|
||||
return new McpSchema.JSONRPCRequest(McpSchema.METHOD_INITIALIZE, UUID.randomUUID().toString(),
|
||||
McpSchema.InitializeRequest
|
||||
.builder(ProtocolVersions.MCP_2025_11_25, McpSchema.ClientCapabilities.builder().build(),
|
||||
CLIENT_INFO)
|
||||
.build());
|
||||
}
|
||||
|
||||
private static McpSchema.JSONRPCNotification initializedNotification() {
|
||||
return new McpSchema.JSONRPCNotification(McpSchema.JSONRPC_VERSION, McpSchema.METHOD_NOTIFICATION_INITIALIZED,
|
||||
null);
|
||||
return new McpSchema.JSONRPCNotification(McpSchema.METHOD_NOTIFICATION_INITIALIZED);
|
||||
}
|
||||
|
||||
private static McpSchema.JSONRPCRequest subscribeRequest(String uri) {
|
||||
return new McpSchema.JSONRPCRequest(McpSchema.JSONRPC_VERSION, McpSchema.METHOD_RESOURCES_SUBSCRIBE,
|
||||
UUID.randomUUID().toString(), new McpSchema.SubscribeRequest(uri));
|
||||
return new McpSchema.JSONRPCRequest(McpSchema.METHOD_RESOURCES_SUBSCRIBE, UUID.randomUUID().toString(),
|
||||
McpSchema.SubscribeRequest.builder(uri).build());
|
||||
}
|
||||
|
||||
private static McpSchema.JSONRPCRequest unsubscribeRequest(String uri) {
|
||||
return new McpSchema.JSONRPCRequest(McpSchema.JSONRPC_VERSION, McpSchema.METHOD_RESOURCES_UNSUBSCRIBE,
|
||||
UUID.randomUUID().toString(), new McpSchema.UnsubscribeRequest(uri));
|
||||
return new McpSchema.JSONRPCRequest(McpSchema.METHOD_RESOURCES_UNSUBSCRIBE, UUID.randomUUID().toString(),
|
||||
McpSchema.UnsubscribeRequest.builder(uri).build());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
|||
|
|
@ -62,15 +62,13 @@ public class ResourceTemplateManagementTests {
|
|||
.capabilities(ServerCapabilities.builder().resources(true, false).build())
|
||||
.build();
|
||||
|
||||
ResourceTemplate template = ResourceTemplate.builder()
|
||||
.uriTemplate(TEST_TEMPLATE_URI)
|
||||
.name(TEST_TEMPLATE_NAME)
|
||||
ResourceTemplate template = ResourceTemplate.builder(TEST_TEMPLATE_URI, TEST_TEMPLATE_NAME)
|
||||
.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();
|
||||
}
|
||||
|
|
@ -82,15 +80,13 @@ public class ResourceTemplateManagementTests {
|
|||
.serverInfo("test-server", "1.0.0")
|
||||
.build();
|
||||
|
||||
ResourceTemplate template = ResourceTemplate.builder()
|
||||
.uriTemplate(TEST_TEMPLATE_URI)
|
||||
.name(TEST_TEMPLATE_NAME)
|
||||
ResourceTemplate template = ResourceTemplate.builder(TEST_TEMPLATE_URI, TEST_TEMPLATE_NAME)
|
||||
.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)
|
||||
|
|
@ -103,15 +99,13 @@ public class ResourceTemplateManagementTests {
|
|||
|
||||
@Test
|
||||
void testRemoveResourceTemplate() {
|
||||
ResourceTemplate template = ResourceTemplate.builder()
|
||||
.uriTemplate(TEST_TEMPLATE_URI)
|
||||
.name(TEST_TEMPLATE_NAME)
|
||||
ResourceTemplate template = ResourceTemplate.builder(TEST_TEMPLATE_URI, TEST_TEMPLATE_NAME)
|
||||
.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()));
|
||||
|
||||
mcpAsyncServer = McpServer.async(mockTransportProvider)
|
||||
.serverInfo("test-server", "1.0.0")
|
||||
|
|
@ -154,25 +148,21 @@ public class ResourceTemplateManagementTests {
|
|||
|
||||
@Test
|
||||
void testReplaceExistingResourceTemplate() {
|
||||
ResourceTemplate originalTemplate = ResourceTemplate.builder()
|
||||
.uriTemplate(TEST_TEMPLATE_URI)
|
||||
.name(TEST_TEMPLATE_NAME)
|
||||
ResourceTemplate originalTemplate = ResourceTemplate.builder(TEST_TEMPLATE_URI, TEST_TEMPLATE_NAME)
|
||||
.description("Original template")
|
||||
.mimeType("text/plain")
|
||||
.build();
|
||||
|
||||
ResourceTemplate updatedTemplate = ResourceTemplate.builder()
|
||||
.uriTemplate(TEST_TEMPLATE_URI)
|
||||
.name(TEST_TEMPLATE_NAME)
|
||||
ResourceTemplate updatedTemplate = ResourceTemplate.builder(TEST_TEMPLATE_URI, TEST_TEMPLATE_NAME)
|
||||
.description("Updated template")
|
||||
.mimeType("application/json")
|
||||
.build();
|
||||
|
||||
McpServerFeatures.AsyncResourceTemplateSpecification originalSpec = new McpServerFeatures.AsyncResourceTemplateSpecification(
|
||||
originalTemplate, (exchange, req) -> Mono.just(new ReadResourceResult(List.of())));
|
||||
originalTemplate, (exchange, req) -> Mono.just(ReadResourceResult.builder(List.of()).build()));
|
||||
|
||||
McpServerFeatures.AsyncResourceTemplateSpecification updatedSpec = new McpServerFeatures.AsyncResourceTemplateSpecification(
|
||||
updatedTemplate, (exchange, req) -> Mono.just(new ReadResourceResult(List.of())));
|
||||
updatedTemplate, (exchange, req) -> Mono.just(ReadResourceResult.builder(List.of()).build()));
|
||||
|
||||
mcpAsyncServer = McpServer.async(mockTransportProvider)
|
||||
.serverInfo("test-server", "1.0.0")
|
||||
|
|
@ -190,15 +180,13 @@ public class ResourceTemplateManagementTests {
|
|||
|
||||
@Test
|
||||
void testSyncAddResourceTemplate() {
|
||||
ResourceTemplate template = ResourceTemplate.builder()
|
||||
.uriTemplate(TEST_TEMPLATE_URI)
|
||||
.name(TEST_TEMPLATE_NAME)
|
||||
ResourceTemplate template = ResourceTemplate.builder(TEST_TEMPLATE_URI, TEST_TEMPLATE_NAME)
|
||||
.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 = McpServer.sync(mockTransportProvider)
|
||||
.serverInfo("test-server", "1.0.0")
|
||||
|
|
@ -212,15 +200,13 @@ public class ResourceTemplateManagementTests {
|
|||
|
||||
@Test
|
||||
void testSyncRemoveResourceTemplate() {
|
||||
ResourceTemplate template = ResourceTemplate.builder()
|
||||
.uriTemplate(TEST_TEMPLATE_URI)
|
||||
.name(TEST_TEMPLATE_NAME)
|
||||
ResourceTemplate template = ResourceTemplate.builder(TEST_TEMPLATE_URI, TEST_TEMPLATE_NAME)
|
||||
.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 = McpServer.sync(mockTransportProvider)
|
||||
.serverInfo("test-server", "1.0.0")
|
||||
|
|
@ -239,25 +225,21 @@ public class ResourceTemplateManagementTests {
|
|||
|
||||
@Test
|
||||
void testResourceTemplateMapBasedStorage() {
|
||||
ResourceTemplate template1 = ResourceTemplate.builder()
|
||||
.uriTemplate("test://template1/{id}")
|
||||
.name("template1")
|
||||
ResourceTemplate template1 = ResourceTemplate.builder("test://template1/{id}", "template1")
|
||||
.description("First template")
|
||||
.mimeType("text/plain")
|
||||
.build();
|
||||
|
||||
ResourceTemplate template2 = ResourceTemplate.builder()
|
||||
.uriTemplate("test://template2/{id}")
|
||||
.name("template2")
|
||||
ResourceTemplate template2 = ResourceTemplate.builder("test://template2/{id}", "template2")
|
||||
.description("Second template")
|
||||
.mimeType("application/json")
|
||||
.build();
|
||||
|
||||
McpServerFeatures.AsyncResourceTemplateSpecification spec1 = new McpServerFeatures.AsyncResourceTemplateSpecification(
|
||||
template1, (exchange, req) -> Mono.just(new ReadResourceResult(List.of())));
|
||||
template1, (exchange, req) -> Mono.just(ReadResourceResult.builder(List.of()).build()));
|
||||
|
||||
McpServerFeatures.AsyncResourceTemplateSpecification spec2 = new McpServerFeatures.AsyncResourceTemplateSpecification(
|
||||
template2, (exchange, req) -> Mono.just(new ReadResourceResult(List.of())));
|
||||
template2, (exchange, req) -> Mono.just(ReadResourceResult.builder(List.of()).build()));
|
||||
|
||||
mcpAsyncServer = McpServer.async(mockTransportProvider)
|
||||
.serverInfo("test-server", "1.0.0")
|
||||
|
|
@ -274,15 +256,13 @@ public class ResourceTemplateManagementTests {
|
|||
@Test
|
||||
void testResourceTemplateBuilderWithMap() {
|
||||
// Test that the new Map-based builder methods work correctly
|
||||
ResourceTemplate template = ResourceTemplate.builder()
|
||||
.uriTemplate(TEST_TEMPLATE_URI)
|
||||
.name(TEST_TEMPLATE_NAME)
|
||||
ResourceTemplate template = ResourceTemplate.builder(TEST_TEMPLATE_URI, TEST_TEMPLATE_NAME)
|
||||
.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()));
|
||||
|
||||
// Test varargs builder method
|
||||
assertThatCode(() -> {
|
||||
|
|
|
|||
|
|
@ -49,9 +49,11 @@ class ToolInputValidationIntegrationTests {
|
|||
|
||||
private static final String TOOL_NAME = "test-tool";
|
||||
|
||||
private static final McpSchema.JsonSchema INPUT_SCHEMA = new McpSchema.JsonSchema("object",
|
||||
Map.of("name", Map.of("type", "string"), "age", Map.of("type", "integer", "minimum", 0)),
|
||||
List.of("name", "age"), null, null, null);
|
||||
private static final McpSchema.JsonSchema INPUT_SCHEMA = McpSchema.JsonSchema.builder()
|
||||
.type("object")
|
||||
.properties(Map.of("name", Map.of("type", "string"), "age", Map.of("type", "integer", "minimum", 0)))
|
||||
.required(List.of("name", "age"))
|
||||
.build();
|
||||
|
||||
private static final McpTransportContextExtractor<HttpServletRequest> TEST_CONTEXT_EXTRACTOR = (
|
||||
r) -> McpTransportContext.create(Map.of("important", "value"));
|
||||
|
|
@ -123,34 +125,26 @@ class ToolInputValidationIntegrationTests {
|
|||
}
|
||||
|
||||
private McpServerFeatures.SyncToolSpecification createSyncTool() {
|
||||
Tool tool = Tool.builder()
|
||||
.name(TOOL_NAME)
|
||||
.description("Test tool with schema")
|
||||
.inputSchema(INPUT_SCHEMA)
|
||||
.build();
|
||||
Tool tool = Tool.builder(TOOL_NAME).inputSchema(INPUT_SCHEMA).description("Test tool with schema").build();
|
||||
|
||||
return McpServerFeatures.SyncToolSpecification.builder().tool(tool).callHandler((exchange, request) -> {
|
||||
String name = (String) request.arguments().get("name");
|
||||
Integer age = ((Number) request.arguments().get("age")).intValue();
|
||||
return CallToolResult.builder()
|
||||
.content(List.of(new TextContent("Hello " + name + ", age " + age)))
|
||||
.content(List.of(TextContent.builder("Hello " + name + ", age " + age).build()))
|
||||
.isError(false)
|
||||
.build();
|
||||
}).build();
|
||||
}
|
||||
|
||||
private McpServerFeatures.AsyncToolSpecification createAsyncTool() {
|
||||
Tool tool = Tool.builder()
|
||||
.name(TOOL_NAME)
|
||||
.description("Test tool with schema")
|
||||
.inputSchema(INPUT_SCHEMA)
|
||||
.build();
|
||||
Tool tool = Tool.builder(TOOL_NAME).inputSchema(INPUT_SCHEMA).description("Test tool with schema").build();
|
||||
|
||||
return McpServerFeatures.AsyncToolSpecification.builder().tool(tool).callHandler((exchange, request) -> {
|
||||
String name = (String) request.arguments().get("name");
|
||||
Integer age = ((Number) request.arguments().get("age")).intValue();
|
||||
return Mono.just(CallToolResult.builder()
|
||||
.content(List.of(new TextContent("Hello " + name + ", age " + age)))
|
||||
.content(List.of(TextContent.builder("Hello " + name + ", age " + age).build()))
|
||||
.isError(false)
|
||||
.build());
|
||||
}).build();
|
||||
|
|
@ -162,9 +156,10 @@ class ToolInputValidationIntegrationTests {
|
|||
String expectedOutput) {
|
||||
Object server = createServer(serverType, validationEnabled);
|
||||
|
||||
try (var client = clientBuilder.clientInfo(new McpSchema.Implementation("test-client", "1.0.0")).build()) {
|
||||
try (var client = clientBuilder.clientInfo(McpSchema.Implementation.builder("test-client", "1.0.0").build())
|
||||
.build()) {
|
||||
client.initialize();
|
||||
CallToolResult result = client.callTool(new CallToolRequest(TOOL_NAME, input));
|
||||
CallToolResult result = client.callTool(CallToolRequest.builder(TOOL_NAME).arguments(input).build());
|
||||
|
||||
assertThat(result.isError()).isFalse();
|
||||
assertThat(((TextContent) result.content().get(0)).text()).isEqualTo(expectedOutput);
|
||||
|
|
@ -180,9 +175,10 @@ class ToolInputValidationIntegrationTests {
|
|||
String expectedErrorSubstring) {
|
||||
Object server = createServerWithDefaultValidation(serverType);
|
||||
|
||||
try (var client = clientBuilder.clientInfo(new McpSchema.Implementation("test-client", "1.0.0")).build()) {
|
||||
try (var client = clientBuilder.clientInfo(McpSchema.Implementation.builder("test-client", "1.0.0").build())
|
||||
.build()) {
|
||||
client.initialize();
|
||||
CallToolResult result = client.callTool(new CallToolRequest(TOOL_NAME, input));
|
||||
CallToolResult result = client.callTool(CallToolRequest.builder(TOOL_NAME).arguments(input).build());
|
||||
|
||||
assertThat(result.isError()).isTrue();
|
||||
String errorMessage = ((TextContent) result.content().get(0)).text();
|
||||
|
|
@ -199,13 +195,14 @@ class ToolInputValidationIntegrationTests {
|
|||
String ignored) {
|
||||
Object server = createServer(serverType, false);
|
||||
|
||||
try (var client = clientBuilder.clientInfo(new McpSchema.Implementation("test-client", "1.0.0")).build()) {
|
||||
try (var client = clientBuilder.clientInfo(McpSchema.Implementation.builder("test-client", "1.0.0").build())
|
||||
.build()) {
|
||||
client.initialize();
|
||||
// Invalid input should pass through when validation is disabled
|
||||
// The tool handler will fail, but that's expected - we're testing validation
|
||||
// is skipped
|
||||
try {
|
||||
client.callTool(new CallToolRequest(TOOL_NAME, input));
|
||||
client.callTool(CallToolRequest.builder(TOOL_NAME).arguments(input).build());
|
||||
}
|
||||
catch (Exception e) {
|
||||
// Expected - tool handler fails on invalid input, but validation didn't
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ class HttpServletSseServerCustomContextPathTests {
|
|||
void testCustomContextPath() {
|
||||
var server = McpServer.async(mcpServerTransportProvider).serverInfo("test-server", "1.0.0").build();
|
||||
try (//@formatter:off
|
||||
var client = clientBuilder.clientInfo(new McpSchema.Implementation("Sample " + "client", "0.0.0")) .build()) { //@formatter:on
|
||||
var client = clientBuilder.clientInfo(McpSchema.Implementation.builder("Sample " + "client", "0.0.0").build()) .build()) { //@formatter:on
|
||||
|
||||
assertThat(client.initialize()).isNotNull();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ package io.modelcontextprotocol.spec;
|
|||
import static io.modelcontextprotocol.util.McpJsonMapperUtils.JSON_MAPPER;
|
||||
import static net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
|
@ -50,7 +51,7 @@ class CompleteReferenceJsonTests {
|
|||
McpSchema.CompleteRequest req = mapper.readValue(json, McpSchema.CompleteRequest.class);
|
||||
|
||||
assertThat(req.ref()).isInstanceOf(McpSchema.PromptReference.class);
|
||||
assertThat(req.ref().identifier()).isEqualTo("my-prompt");
|
||||
assertThat(((McpSchema.PromptReference) req.ref()).name()).isEqualTo("my-prompt");
|
||||
assertThat(req.argument().name()).isEqualTo("lang");
|
||||
assertThat(req.argument().value()).isEqualTo("java");
|
||||
}
|
||||
|
|
@ -64,7 +65,7 @@ class CompleteReferenceJsonTests {
|
|||
McpSchema.CompleteRequest req = mapper.readValue(json, McpSchema.CompleteRequest.class);
|
||||
|
||||
assertThat(req.ref()).isInstanceOf(McpSchema.ResourceReference.class);
|
||||
assertThat(req.ref().identifier()).isEqualTo("file:///src/Foo.java");
|
||||
assertThat(((McpSchema.ResourceReference) req.ref()).uri()).isEqualTo("file:///src/Foo.java");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -79,7 +80,21 @@ class CompleteReferenceJsonTests {
|
|||
});
|
||||
|
||||
assertThat(req.ref()).isInstanceOf(McpSchema.PromptReference.class);
|
||||
assertThat(req.ref().identifier()).isEqualTo("my-prompt");
|
||||
assertThat(((McpSchema.PromptReference) req.ref()).name()).isEqualTo("my-prompt");
|
||||
}
|
||||
|
||||
@Test
|
||||
void completeRequestMissingRefFailsToInstantiate() throws IOException {
|
||||
String json = """
|
||||
{"argument":{"name":"lang","value":"java"}}
|
||||
""";
|
||||
|
||||
// This is the real in-process path: params arrives as a Map from JSON-RPC
|
||||
Object paramsMap = mapper.readValue(json, Object.class);
|
||||
|
||||
assertThatThrownBy(() -> mapper.convertValue(paramsMap, new TypeRef<McpSchema.CompleteRequest>() {
|
||||
})).hasMessageContaining("ref must not be null");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ class ContentJsonTests {
|
|||
|
||||
@Test
|
||||
void textContentHasExactlyOneTypeProperty() throws IOException {
|
||||
McpSchema.TextContent content = new McpSchema.TextContent("hello");
|
||||
McpSchema.TextContent content = McpSchema.TextContent.builder("hello").build();
|
||||
String json = mapper.writeValueAsString(content);
|
||||
|
||||
assertExactlyOneTypeProperty(json);
|
||||
|
|
@ -34,7 +34,7 @@ class ContentJsonTests {
|
|||
|
||||
@Test
|
||||
void imageContentHasExactlyOneTypeProperty() throws IOException {
|
||||
McpSchema.ImageContent content = new McpSchema.ImageContent(null, "base64data", "image/png");
|
||||
McpSchema.ImageContent content = McpSchema.ImageContent.builder("base64data", "image/png").build();
|
||||
String json = mapper.writeValueAsString(content);
|
||||
|
||||
assertExactlyOneTypeProperty(json);
|
||||
|
|
@ -43,7 +43,7 @@ class ContentJsonTests {
|
|||
|
||||
@Test
|
||||
void audioContentHasExactlyOneTypeProperty() throws IOException {
|
||||
McpSchema.AudioContent content = new McpSchema.AudioContent(null, "base64data", "audio/mp3");
|
||||
McpSchema.AudioContent content = McpSchema.AudioContent.builder("base64data", "audio/mp3").build();
|
||||
String json = mapper.writeValueAsString(content);
|
||||
|
||||
assertExactlyOneTypeProperty(json);
|
||||
|
|
@ -52,7 +52,7 @@ class ContentJsonTests {
|
|||
|
||||
@Test
|
||||
void textContentRoundTrip() throws IOException {
|
||||
McpSchema.TextContent original = new McpSchema.TextContent("round-trip");
|
||||
McpSchema.TextContent original = McpSchema.TextContent.builder("round-trip").build();
|
||||
String json = mapper.writeValueAsString(original);
|
||||
|
||||
McpSchema.Content decoded = mapper.readValue(json, McpSchema.Content.class);
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ public class McpSchemaTests {
|
|||
|
||||
@Test
|
||||
void testTextContent() throws Exception {
|
||||
McpSchema.TextContent test = new McpSchema.TextContent("XXX");
|
||||
McpSchema.TextContent test = McpSchema.TextContent.builder("XXX").build();
|
||||
String value = JSON_MAPPER.writeValueAsString(test);
|
||||
|
||||
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
|
||||
|
|
@ -73,7 +73,7 @@ public class McpSchemaTests {
|
|||
|
||||
@Test
|
||||
void testImageContent() throws Exception {
|
||||
McpSchema.ImageContent test = new McpSchema.ImageContent(null, "base64encodeddata", "image/png");
|
||||
McpSchema.ImageContent test = McpSchema.ImageContent.builder("base64encodeddata", "image/png").build();
|
||||
String value = JSON_MAPPER.writeValueAsString(test);
|
||||
|
||||
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
|
||||
|
|
@ -97,7 +97,7 @@ public class McpSchemaTests {
|
|||
|
||||
@Test
|
||||
void testAudioContent() throws Exception {
|
||||
McpSchema.AudioContent audioContent = new McpSchema.AudioContent(null, "base64encodeddata", "audio/wav");
|
||||
McpSchema.AudioContent audioContent = McpSchema.AudioContent.builder("base64encodeddata", "audio/wav").build();
|
||||
String value = JSON_MAPPER.writeValueAsString(audioContent);
|
||||
|
||||
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
|
||||
|
|
@ -121,11 +121,15 @@ public class McpSchemaTests {
|
|||
|
||||
@Test
|
||||
void testCreateMessageRequestWithMeta() throws Exception {
|
||||
McpSchema.TextContent content = new McpSchema.TextContent("User message");
|
||||
McpSchema.SamplingMessage message = new McpSchema.SamplingMessage(McpSchema.Role.USER, content);
|
||||
McpSchema.ModelHint hint = new McpSchema.ModelHint("gpt-4");
|
||||
McpSchema.ModelPreferences preferences = new McpSchema.ModelPreferences(Collections.singletonList(hint), 0.3,
|
||||
0.7, 0.9);
|
||||
McpSchema.TextContent content = McpSchema.TextContent.builder("User message").build();
|
||||
McpSchema.SamplingMessage message = McpSchema.SamplingMessage.builder(McpSchema.Role.USER, content).build();
|
||||
McpSchema.ModelHint hint = McpSchema.ModelHint.of("gpt-4");
|
||||
McpSchema.ModelPreferences preferences = McpSchema.ModelPreferences.builder()
|
||||
.hints(Collections.singletonList(hint))
|
||||
.costPriority(0.3)
|
||||
.speedPriority(0.7)
|
||||
.intelligencePriority(0.9)
|
||||
.build();
|
||||
|
||||
Map<String, Object> metadata = new HashMap<>();
|
||||
metadata.put("session", "test-session");
|
||||
|
|
@ -133,13 +137,12 @@ public class McpSchemaTests {
|
|||
Map<String, Object> meta = new HashMap<>();
|
||||
meta.put("progressToken", "create-message-token-456");
|
||||
|
||||
McpSchema.CreateMessageRequest request = McpSchema.CreateMessageRequest.builder()
|
||||
.messages(Collections.singletonList(message))
|
||||
McpSchema.CreateMessageRequest request = McpSchema.CreateMessageRequest
|
||||
.builder(Collections.singletonList(message), 1000)
|
||||
.modelPreferences(preferences)
|
||||
.systemPrompt("You are a helpful assistant")
|
||||
.includeContext(McpSchema.CreateMessageRequest.ContextInclusionStrategy.THIS_SERVER)
|
||||
.temperature(0.7)
|
||||
.maxTokens(1000)
|
||||
.stopSequences(Arrays.asList("STOP", "END"))
|
||||
.metadata(metadata)
|
||||
.meta(meta)
|
||||
|
|
@ -158,10 +161,12 @@ public class McpSchemaTests {
|
|||
|
||||
@Test
|
||||
void testEmbeddedResource() throws Exception {
|
||||
McpSchema.TextResourceContents resourceContents = new McpSchema.TextResourceContents("resource://test",
|
||||
"text/plain", "Sample resource content");
|
||||
McpSchema.TextResourceContents resourceContents = McpSchema.TextResourceContents
|
||||
.builder("resource://test", "Sample resource content")
|
||||
.mimeType("text/plain")
|
||||
.build();
|
||||
|
||||
McpSchema.EmbeddedResource test = new McpSchema.EmbeddedResource(null, resourceContents);
|
||||
McpSchema.EmbeddedResource test = McpSchema.EmbeddedResource.builder(resourceContents).build();
|
||||
|
||||
String value = JSON_MAPPER.writeValueAsString(test);
|
||||
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
|
||||
|
|
@ -189,10 +194,12 @@ public class McpSchemaTests {
|
|||
|
||||
@Test
|
||||
void testEmbeddedResourceWithBlobContents() throws Exception {
|
||||
McpSchema.BlobResourceContents resourceContents = new McpSchema.BlobResourceContents("resource://test",
|
||||
"application/octet-stream", "base64encodedblob");
|
||||
McpSchema.BlobResourceContents resourceContents = McpSchema.BlobResourceContents
|
||||
.builder("resource://test", "base64encodedblob")
|
||||
.mimeType("application/octet-stream")
|
||||
.build();
|
||||
|
||||
McpSchema.EmbeddedResource test = new McpSchema.EmbeddedResource(null, resourceContents);
|
||||
McpSchema.EmbeddedResource test = McpSchema.EmbeddedResource.builder(resourceContents).build();
|
||||
|
||||
String value = JSON_MAPPER.writeValueAsString(test);
|
||||
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
|
||||
|
|
@ -221,9 +228,14 @@ public class McpSchemaTests {
|
|||
|
||||
@Test
|
||||
void testResourceLink() throws Exception {
|
||||
McpSchema.ResourceLink resourceLink = new McpSchema.ResourceLink("main.rs", "Main file",
|
||||
"file:///project/src/main.rs", "Primary application entry point", "text/x-rust", null, null,
|
||||
Map.of("metaKey", "metaValue"));
|
||||
McpSchema.ResourceLink resourceLink = McpSchema.ResourceLink.builder()
|
||||
.name("main.rs")
|
||||
.title("Main file")
|
||||
.uri("file:///project/src/main.rs")
|
||||
.description("Primary application entry point")
|
||||
.mimeType("text/x-rust")
|
||||
.meta(Map.of("metaKey", "metaValue"))
|
||||
.build();
|
||||
String value = JSON_MAPPER.writeValueAsString(resourceLink);
|
||||
|
||||
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
|
||||
|
|
@ -256,8 +268,7 @@ public class McpSchemaTests {
|
|||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("key", "value");
|
||||
|
||||
McpSchema.JSONRPCRequest request = new McpSchema.JSONRPCRequest(McpSchema.JSONRPC_VERSION, "method_name", 1,
|
||||
params);
|
||||
McpSchema.JSONRPCRequest request = new McpSchema.JSONRPCRequest("method_name", 1, params);
|
||||
|
||||
String value = JSON_MAPPER.writeValueAsString(request);
|
||||
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
|
||||
|
|
@ -272,8 +283,7 @@ public class McpSchemaTests {
|
|||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("key", "value");
|
||||
|
||||
McpSchema.JSONRPCNotification notification = new McpSchema.JSONRPCNotification(McpSchema.JSONRPC_VERSION,
|
||||
"notification_method", params);
|
||||
McpSchema.JSONRPCNotification notification = new McpSchema.JSONRPCNotification("notification_method", params);
|
||||
|
||||
String value = JSON_MAPPER.writeValueAsString(notification);
|
||||
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
|
||||
|
|
@ -288,7 +298,7 @@ public class McpSchemaTests {
|
|||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("result_key", "result_value");
|
||||
|
||||
McpSchema.JSONRPCResponse response = new McpSchema.JSONRPCResponse(McpSchema.JSONRPC_VERSION, 1, result, null);
|
||||
McpSchema.JSONRPCResponse response = McpSchema.JSONRPCResponse.result(1, result);
|
||||
|
||||
String value = JSON_MAPPER.writeValueAsString(response);
|
||||
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
|
||||
|
|
@ -301,9 +311,9 @@ public class McpSchemaTests {
|
|||
@Test
|
||||
void testJSONRPCResponseWithError() throws Exception {
|
||||
McpSchema.JSONRPCResponse.JSONRPCError error = new McpSchema.JSONRPCResponse.JSONRPCError(
|
||||
McpSchema.ErrorCodes.INVALID_REQUEST, "Invalid request", null);
|
||||
McpSchema.ErrorCodes.INVALID_REQUEST, "Invalid request");
|
||||
|
||||
McpSchema.JSONRPCResponse response = new McpSchema.JSONRPCResponse(McpSchema.JSONRPC_VERSION, 1, null, error);
|
||||
McpSchema.JSONRPCResponse response = McpSchema.JSONRPCResponse.error(1, error);
|
||||
|
||||
String value = JSON_MAPPER.writeValueAsString(response);
|
||||
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
|
||||
|
|
@ -322,11 +332,13 @@ public class McpSchemaTests {
|
|||
.sampling()
|
||||
.build();
|
||||
|
||||
McpSchema.Implementation clientInfo = new McpSchema.Implementation("test-client", "1.0.0");
|
||||
McpSchema.Implementation clientInfo = McpSchema.Implementation.builder("test-client", "1.0.0").build();
|
||||
Map<String, Object> meta = Map.of("metaKey", "metaValue");
|
||||
|
||||
McpSchema.InitializeRequest request = new McpSchema.InitializeRequest(ProtocolVersions.MCP_2024_11_05,
|
||||
capabilities, clientInfo, meta);
|
||||
McpSchema.InitializeRequest request = McpSchema.InitializeRequest
|
||||
.builder(ProtocolVersions.MCP_2024_11_05, capabilities, clientInfo)
|
||||
.meta(meta)
|
||||
.build();
|
||||
|
||||
String value = JSON_MAPPER.writeValueAsString(request);
|
||||
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
|
||||
|
|
@ -346,10 +358,12 @@ public class McpSchemaTests {
|
|||
.tools(true)
|
||||
.build();
|
||||
|
||||
McpSchema.Implementation serverInfo = new McpSchema.Implementation("test-server", "1.0.0");
|
||||
McpSchema.Implementation serverInfo = McpSchema.Implementation.builder("test-server", "1.0.0").build();
|
||||
|
||||
McpSchema.InitializeResult result = new McpSchema.InitializeResult(ProtocolVersions.MCP_2024_11_05,
|
||||
capabilities, serverInfo, "Server initialized successfully");
|
||||
McpSchema.InitializeResult result = McpSchema.InitializeResult
|
||||
.builder(ProtocolVersions.MCP_2024_11_05, capabilities, serverInfo)
|
||||
.instructions("Server initialized successfully")
|
||||
.build();
|
||||
|
||||
String value = JSON_MAPPER.writeValueAsString(result);
|
||||
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
|
||||
|
|
@ -364,12 +378,12 @@ public class McpSchemaTests {
|
|||
|
||||
@Test
|
||||
void testResource() throws Exception {
|
||||
McpSchema.Annotations annotations = new McpSchema.Annotations(
|
||||
Arrays.asList(McpSchema.Role.USER, McpSchema.Role.ASSISTANT), 0.8);
|
||||
McpSchema.Annotations annotations = McpSchema.Annotations.builder()
|
||||
.audience(Arrays.asList(McpSchema.Role.USER, McpSchema.Role.ASSISTANT))
|
||||
.priority(0.8)
|
||||
.build();
|
||||
|
||||
McpSchema.Resource resource = McpSchema.Resource.builder()
|
||||
.uri("resource://test")
|
||||
.name("Test Resource")
|
||||
McpSchema.Resource resource = McpSchema.Resource.builder("resource://test", "Test Resource")
|
||||
.description("A test resource")
|
||||
.mimeType("text/plain")
|
||||
.annotations(annotations)
|
||||
|
|
@ -386,12 +400,12 @@ public class McpSchemaTests {
|
|||
|
||||
@Test
|
||||
void testResourceBuilder() throws Exception {
|
||||
McpSchema.Annotations annotations = new McpSchema.Annotations(
|
||||
Arrays.asList(McpSchema.Role.USER, McpSchema.Role.ASSISTANT), 0.8);
|
||||
McpSchema.Annotations annotations = McpSchema.Annotations.builder()
|
||||
.audience(Arrays.asList(McpSchema.Role.USER, McpSchema.Role.ASSISTANT))
|
||||
.priority(0.8)
|
||||
.build();
|
||||
|
||||
McpSchema.Resource resource = McpSchema.Resource.builder()
|
||||
.uri("resource://test")
|
||||
.name("Test Resource")
|
||||
McpSchema.Resource resource = McpSchema.Resource.builder("resource://test", "Test Resource")
|
||||
.description("A test resource")
|
||||
.mimeType("text/plain")
|
||||
.size(256L)
|
||||
|
|
@ -410,41 +424,32 @@ public class McpSchemaTests {
|
|||
|
||||
@Test
|
||||
void testResourceBuilderUriRequired() {
|
||||
McpSchema.Annotations annotations = new McpSchema.Annotations(
|
||||
Arrays.asList(McpSchema.Role.USER, McpSchema.Role.ASSISTANT), 0.8);
|
||||
|
||||
McpSchema.Resource.Builder resourceBuilder = McpSchema.Resource.builder()
|
||||
.name("Test Resource")
|
||||
.description("A test resource")
|
||||
.mimeType("text/plain")
|
||||
.size(256L)
|
||||
.annotations(annotations);
|
||||
|
||||
assertThatThrownBy(resourceBuilder::build).isInstanceOf(java.lang.IllegalArgumentException.class);
|
||||
assertThatThrownBy(() -> McpSchema.Resource.builder(null, "Test Resource"))
|
||||
.isInstanceOf(java.lang.IllegalArgumentException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testResourceBuilderNameRequired() {
|
||||
McpSchema.Annotations annotations = new McpSchema.Annotations(
|
||||
Arrays.asList(McpSchema.Role.USER, McpSchema.Role.ASSISTANT), 0.8);
|
||||
|
||||
McpSchema.Resource.Builder resourceBuilder = McpSchema.Resource.builder()
|
||||
.uri("resource://test")
|
||||
.description("A test resource")
|
||||
.mimeType("text/plain")
|
||||
.size(256L)
|
||||
.annotations(annotations);
|
||||
|
||||
assertThatThrownBy(resourceBuilder::build).isInstanceOf(java.lang.IllegalArgumentException.class);
|
||||
assertThatThrownBy(() -> McpSchema.Resource.builder("resource://test", null))
|
||||
.isInstanceOf(java.lang.IllegalArgumentException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testResourceTemplate() throws Exception {
|
||||
McpSchema.Annotations annotations = new McpSchema.Annotations(Arrays.asList(McpSchema.Role.USER), 0.5);
|
||||
McpSchema.Annotations annotations = McpSchema.Annotations.builder()
|
||||
.audience(Arrays.asList(McpSchema.Role.USER))
|
||||
.priority(0.5)
|
||||
.build();
|
||||
Map<String, Object> meta = Map.of("metaKey", "metaValue");
|
||||
|
||||
McpSchema.ResourceTemplate template = new McpSchema.ResourceTemplate("resource://{param}/test", "Test Template",
|
||||
"Test Template", "A test resource template", "text/plain", annotations, meta);
|
||||
McpSchema.ResourceTemplate template = McpSchema.ResourceTemplate
|
||||
.builder("resource://{param}/test", "Test Template")
|
||||
.title("Test Template")
|
||||
.description("A test resource template")
|
||||
.mimeType("text/plain")
|
||||
.annotations(annotations)
|
||||
.meta(meta)
|
||||
.build();
|
||||
|
||||
String value = JSON_MAPPER.writeValueAsString(template);
|
||||
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
|
||||
|
|
@ -457,24 +462,23 @@ public class McpSchemaTests {
|
|||
|
||||
@Test
|
||||
void testListResourcesResult() throws Exception {
|
||||
McpSchema.Resource resource1 = McpSchema.Resource.builder()
|
||||
.uri("resource://test1")
|
||||
.name("Test Resource 1")
|
||||
McpSchema.Resource resource1 = McpSchema.Resource.builder("resource://test1", "Test Resource 1")
|
||||
.description("First test resource")
|
||||
.mimeType("text/plain")
|
||||
.build();
|
||||
|
||||
McpSchema.Resource resource2 = McpSchema.Resource.builder()
|
||||
.uri("resource://test2")
|
||||
.name("Test Resource 2")
|
||||
McpSchema.Resource resource2 = McpSchema.Resource.builder("resource://test2", "Test Resource 2")
|
||||
.description("Second test resource")
|
||||
.mimeType("application/json")
|
||||
.build();
|
||||
|
||||
Map<String, Object> meta = Map.of("metaKey", "metaValue");
|
||||
|
||||
McpSchema.ListResourcesResult result = new McpSchema.ListResourcesResult(Arrays.asList(resource1, resource2),
|
||||
"next-cursor", meta);
|
||||
McpSchema.ListResourcesResult result = McpSchema.ListResourcesResult
|
||||
.builder(Arrays.asList(resource1, resource2))
|
||||
.nextCursor("next-cursor")
|
||||
.meta(meta)
|
||||
.build();
|
||||
|
||||
String value = JSON_MAPPER.writeValueAsString(result);
|
||||
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
|
||||
|
|
@ -487,14 +491,24 @@ public class McpSchemaTests {
|
|||
|
||||
@Test
|
||||
void testListResourceTemplatesResult() throws Exception {
|
||||
McpSchema.ResourceTemplate template1 = new McpSchema.ResourceTemplate("resource://{param}/test1",
|
||||
"Test Template 1", "Test Template 1", "First test template", "text/plain", null);
|
||||
McpSchema.ResourceTemplate template1 = McpSchema.ResourceTemplate
|
||||
.builder("resource://{param}/test1", "Test Template 1")
|
||||
.title("Test Template 1")
|
||||
.description("First test template")
|
||||
.mimeType("text/plain")
|
||||
.build();
|
||||
|
||||
McpSchema.ResourceTemplate template2 = new McpSchema.ResourceTemplate("resource://{param}/test2",
|
||||
"Test Template 2", "Test Template 2", "Second test template", "application/json", null);
|
||||
McpSchema.ResourceTemplate template2 = McpSchema.ResourceTemplate
|
||||
.builder("resource://{param}/test2", "Test Template 2")
|
||||
.title("Test Template 2")
|
||||
.description("Second test template")
|
||||
.mimeType("application/json")
|
||||
.build();
|
||||
|
||||
McpSchema.ListResourceTemplatesResult result = new McpSchema.ListResourceTemplatesResult(
|
||||
Arrays.asList(template1, template2), "next-cursor");
|
||||
McpSchema.ListResourceTemplatesResult result = McpSchema.ListResourceTemplatesResult
|
||||
.builder(Arrays.asList(template1, template2))
|
||||
.nextCursor("next-cursor")
|
||||
.build();
|
||||
|
||||
String value = JSON_MAPPER.writeValueAsString(result);
|
||||
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
|
||||
|
|
@ -507,8 +521,9 @@ public class McpSchemaTests {
|
|||
|
||||
@Test
|
||||
void testReadResourceRequest() throws Exception {
|
||||
McpSchema.ReadResourceRequest request = new McpSchema.ReadResourceRequest("resource://test",
|
||||
Map.of("metaKey", "metaValue"));
|
||||
McpSchema.ReadResourceRequest request = McpSchema.ReadResourceRequest.builder("resource://test")
|
||||
.meta(Map.of("metaKey", "metaValue"))
|
||||
.build();
|
||||
|
||||
String value = JSON_MAPPER.writeValueAsString(request);
|
||||
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
|
||||
|
|
@ -523,7 +538,9 @@ public class McpSchemaTests {
|
|||
Map<String, Object> meta = new HashMap<>();
|
||||
meta.put("progressToken", "read-resource-token-123");
|
||||
|
||||
McpSchema.ReadResourceRequest request = new McpSchema.ReadResourceRequest("resource://test", meta);
|
||||
McpSchema.ReadResourceRequest request = McpSchema.ReadResourceRequest.builder("resource://test")
|
||||
.meta(meta)
|
||||
.build();
|
||||
|
||||
String value = JSON_MAPPER.writeValueAsString(request);
|
||||
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
|
||||
|
|
@ -550,14 +567,19 @@ public class McpSchemaTests {
|
|||
|
||||
@Test
|
||||
void testReadResourceResult() throws Exception {
|
||||
McpSchema.TextResourceContents contents1 = new McpSchema.TextResourceContents("resource://test1", "text/plain",
|
||||
"Sample text content");
|
||||
McpSchema.TextResourceContents contents1 = McpSchema.TextResourceContents
|
||||
.builder("resource://test1", "Sample text content")
|
||||
.mimeType("text/plain")
|
||||
.build();
|
||||
|
||||
McpSchema.BlobResourceContents contents2 = new McpSchema.BlobResourceContents("resource://test2",
|
||||
"application/octet-stream", "base64encodedblob");
|
||||
McpSchema.BlobResourceContents contents2 = McpSchema.BlobResourceContents
|
||||
.builder("resource://test2", "base64encodedblob")
|
||||
.mimeType("application/octet-stream")
|
||||
.build();
|
||||
|
||||
McpSchema.ReadResourceResult result = new McpSchema.ReadResourceResult(Arrays.asList(contents1, contents2),
|
||||
Map.of("metaKey", "metaValue"));
|
||||
McpSchema.ReadResourceResult result = McpSchema.ReadResourceResult.builder(Arrays.asList(contents1, contents2))
|
||||
.meta(Map.of("metaKey", "metaValue"))
|
||||
.build();
|
||||
|
||||
String value = JSON_MAPPER.writeValueAsString(result);
|
||||
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
|
||||
|
|
@ -572,13 +594,24 @@ public class McpSchemaTests {
|
|||
|
||||
@Test
|
||||
void testPrompt() throws Exception {
|
||||
McpSchema.PromptArgument arg1 = new McpSchema.PromptArgument("arg1", "First argument", "First argument", true);
|
||||
McpSchema.PromptArgument arg1 = McpSchema.PromptArgument.builder("arg1")
|
||||
.title("First argument")
|
||||
.description("First argument")
|
||||
.required(true)
|
||||
.build();
|
||||
|
||||
McpSchema.PromptArgument arg2 = new McpSchema.PromptArgument("arg2", "Second argument", "Second argument",
|
||||
false);
|
||||
McpSchema.PromptArgument arg2 = McpSchema.PromptArgument.builder("arg2")
|
||||
.title("Second argument")
|
||||
.description("Second argument")
|
||||
.required(false)
|
||||
.build();
|
||||
|
||||
McpSchema.Prompt prompt = new McpSchema.Prompt("test-prompt", "Test Prompt", "A test prompt",
|
||||
Arrays.asList(arg1, arg2), Map.of("metaKey", "metaValue"));
|
||||
McpSchema.Prompt prompt = McpSchema.Prompt.builder("test-prompt")
|
||||
.title("Test Prompt")
|
||||
.description("A test prompt")
|
||||
.arguments(Arrays.asList(arg1, arg2))
|
||||
.meta(Map.of("metaKey", "metaValue"))
|
||||
.build();
|
||||
|
||||
String value = JSON_MAPPER.writeValueAsString(prompt);
|
||||
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
|
||||
|
|
@ -591,9 +624,9 @@ public class McpSchemaTests {
|
|||
|
||||
@Test
|
||||
void testPromptMessage() throws Exception {
|
||||
McpSchema.TextContent content = new McpSchema.TextContent("Hello, world!");
|
||||
McpSchema.TextContent content = McpSchema.TextContent.builder("Hello, world!").build();
|
||||
|
||||
McpSchema.PromptMessage message = new McpSchema.PromptMessage(McpSchema.Role.USER, content);
|
||||
McpSchema.PromptMessage message = McpSchema.PromptMessage.builder(McpSchema.Role.USER, content).build();
|
||||
|
||||
String value = JSON_MAPPER.writeValueAsString(message);
|
||||
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
|
||||
|
|
@ -605,16 +638,27 @@ public class McpSchemaTests {
|
|||
|
||||
@Test
|
||||
void testListPromptsResult() throws Exception {
|
||||
McpSchema.PromptArgument arg = new McpSchema.PromptArgument("arg", "Argument", "An argument", true);
|
||||
McpSchema.PromptArgument arg = McpSchema.PromptArgument.builder("arg")
|
||||
.title("Argument")
|
||||
.description("An argument")
|
||||
.required(true)
|
||||
.build();
|
||||
|
||||
McpSchema.Prompt prompt1 = new McpSchema.Prompt("prompt1", "First prompt", "First prompt",
|
||||
Collections.singletonList(arg));
|
||||
McpSchema.Prompt prompt1 = McpSchema.Prompt.builder("prompt1")
|
||||
.title("First prompt")
|
||||
.description("First prompt")
|
||||
.arguments(Collections.singletonList(arg))
|
||||
.build();
|
||||
|
||||
McpSchema.Prompt prompt2 = new McpSchema.Prompt("prompt2", "Second prompt", "Second prompt",
|
||||
Collections.emptyList());
|
||||
McpSchema.Prompt prompt2 = McpSchema.Prompt.builder("prompt2")
|
||||
.title("Second prompt")
|
||||
.description("Second prompt")
|
||||
.arguments(Collections.emptyList())
|
||||
.build();
|
||||
|
||||
McpSchema.ListPromptsResult result = new McpSchema.ListPromptsResult(Arrays.asList(prompt1, prompt2),
|
||||
"next-cursor");
|
||||
McpSchema.ListPromptsResult result = McpSchema.ListPromptsResult.builder(Arrays.asList(prompt1, prompt2))
|
||||
.nextCursor("next-cursor")
|
||||
.build();
|
||||
|
||||
String value = JSON_MAPPER.writeValueAsString(result);
|
||||
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
|
||||
|
|
@ -631,7 +675,9 @@ public class McpSchemaTests {
|
|||
arguments.put("arg1", "value1");
|
||||
arguments.put("arg2", 42);
|
||||
|
||||
McpSchema.GetPromptRequest request = new McpSchema.GetPromptRequest("test-prompt", arguments);
|
||||
McpSchema.GetPromptRequest request = McpSchema.GetPromptRequest.builder("test-prompt")
|
||||
.arguments(arguments)
|
||||
.build();
|
||||
|
||||
assertThat(JSON_MAPPER.readValue("""
|
||||
{"name":"test-prompt","arguments":{"arg1":"value1","arg2":42}}""", McpSchema.GetPromptRequest.class))
|
||||
|
|
@ -647,7 +693,10 @@ public class McpSchemaTests {
|
|||
Map<String, Object> meta = new HashMap<>();
|
||||
meta.put("progressToken", "token123");
|
||||
|
||||
McpSchema.GetPromptRequest request = new McpSchema.GetPromptRequest("test-prompt", arguments, meta);
|
||||
McpSchema.GetPromptRequest request = McpSchema.GetPromptRequest.builder("test-prompt")
|
||||
.arguments(arguments)
|
||||
.meta(meta)
|
||||
.build();
|
||||
|
||||
String value = JSON_MAPPER.writeValueAsString(request);
|
||||
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
|
||||
|
|
@ -664,15 +713,16 @@ public class McpSchemaTests {
|
|||
|
||||
@Test
|
||||
void testGetPromptResult() throws Exception {
|
||||
McpSchema.TextContent content1 = new McpSchema.TextContent("System message");
|
||||
McpSchema.TextContent content2 = new McpSchema.TextContent("User message");
|
||||
McpSchema.TextContent content1 = McpSchema.TextContent.builder("System message").build();
|
||||
McpSchema.TextContent content2 = McpSchema.TextContent.builder("User message").build();
|
||||
|
||||
McpSchema.PromptMessage message1 = new McpSchema.PromptMessage(McpSchema.Role.ASSISTANT, content1);
|
||||
McpSchema.PromptMessage message1 = McpSchema.PromptMessage.builder(McpSchema.Role.ASSISTANT, content1).build();
|
||||
|
||||
McpSchema.PromptMessage message2 = new McpSchema.PromptMessage(McpSchema.Role.USER, content2);
|
||||
McpSchema.PromptMessage message2 = McpSchema.PromptMessage.builder(McpSchema.Role.USER, content2).build();
|
||||
|
||||
McpSchema.GetPromptResult result = new McpSchema.GetPromptResult("A test prompt result",
|
||||
Arrays.asList(message1, message2));
|
||||
McpSchema.GetPromptResult result = McpSchema.GetPromptResult.builder(Arrays.asList(message1, message2))
|
||||
.description("A test prompt result")
|
||||
.build();
|
||||
|
||||
String value = JSON_MAPPER.writeValueAsString(result);
|
||||
|
||||
|
|
@ -793,10 +843,8 @@ public class McpSchemaTests {
|
|||
}
|
||||
""";
|
||||
|
||||
McpSchema.Tool tool = McpSchema.Tool.builder()
|
||||
.name("test-tool")
|
||||
McpSchema.Tool tool = McpSchema.Tool.builder("test-tool", JSON_MAPPER, schemaJson)
|
||||
.description("A test tool")
|
||||
.inputSchema(JSON_MAPPER, schemaJson)
|
||||
.build();
|
||||
|
||||
String value = JSON_MAPPER.writeValueAsString(tool);
|
||||
|
|
@ -831,10 +879,8 @@ public class McpSchemaTests {
|
|||
}
|
||||
""";
|
||||
|
||||
McpSchema.Tool tool = McpSchema.Tool.builder()
|
||||
.name("addressTool")
|
||||
McpSchema.Tool tool = McpSchema.Tool.builder("addressTool", JSON_MAPPER, complexSchemaJson)
|
||||
.title("Handles addresses")
|
||||
.inputSchema(JSON_MAPPER, complexSchemaJson)
|
||||
.build();
|
||||
|
||||
// Serialize the tool to a string
|
||||
|
|
@ -877,11 +923,9 @@ public class McpSchemaTests {
|
|||
Map<String, Object> inputSchema = Map.of("inputSchema", schemaJson);
|
||||
Map<String, Object> meta = Map.of("metaKey", "metaValue");
|
||||
|
||||
McpSchema.Tool tool = McpSchema.Tool.builder()
|
||||
.name("addressTool")
|
||||
McpSchema.Tool tool = McpSchema.Tool.builder("addressTool", inputSchema)
|
||||
.title("addressTool")
|
||||
.description("Handles addresses")
|
||||
.inputSchema(inputSchema)
|
||||
.meta(meta)
|
||||
.build();
|
||||
|
||||
|
|
@ -906,13 +950,17 @@ public class McpSchemaTests {
|
|||
"required": ["name"]
|
||||
}
|
||||
""";
|
||||
McpSchema.ToolAnnotations annotations = new McpSchema.ToolAnnotations("A test tool", false, false, false, false,
|
||||
false);
|
||||
McpSchema.ToolAnnotations annotations = McpSchema.ToolAnnotations.builder()
|
||||
.title("A test tool")
|
||||
.readOnlyHint(false)
|
||||
.destructiveHint(false)
|
||||
.idempotentHint(false)
|
||||
.openWorldHint(false)
|
||||
.returnDirect(false)
|
||||
.build();
|
||||
|
||||
McpSchema.Tool tool = McpSchema.Tool.builder()
|
||||
.name("test-tool")
|
||||
McpSchema.Tool tool = McpSchema.Tool.builder("test-tool", JSON_MAPPER, schemaJson)
|
||||
.description("A test tool")
|
||||
.inputSchema(JSON_MAPPER, schemaJson)
|
||||
.annotations(annotations)
|
||||
.build();
|
||||
|
||||
|
|
@ -977,10 +1025,8 @@ public class McpSchemaTests {
|
|||
}
|
||||
""";
|
||||
|
||||
McpSchema.Tool tool = McpSchema.Tool.builder()
|
||||
.name("test-tool")
|
||||
McpSchema.Tool tool = McpSchema.Tool.builder("test-tool", JSON_MAPPER, inputSchemaJson)
|
||||
.description("A test tool")
|
||||
.inputSchema(JSON_MAPPER, inputSchemaJson)
|
||||
.outputSchema(JSON_MAPPER, outputSchemaJson)
|
||||
.build();
|
||||
|
||||
|
|
@ -1041,13 +1087,17 @@ public class McpSchemaTests {
|
|||
}
|
||||
""";
|
||||
|
||||
McpSchema.ToolAnnotations annotations = new McpSchema.ToolAnnotations("A test tool with output", true, false,
|
||||
true, false, true);
|
||||
McpSchema.ToolAnnotations annotations = McpSchema.ToolAnnotations.builder()
|
||||
.title("A test tool with output")
|
||||
.readOnlyHint(true)
|
||||
.destructiveHint(false)
|
||||
.idempotentHint(true)
|
||||
.openWorldHint(false)
|
||||
.returnDirect(true)
|
||||
.build();
|
||||
|
||||
McpSchema.Tool tool = McpSchema.Tool.builder()
|
||||
.name("test-tool")
|
||||
McpSchema.Tool tool = McpSchema.Tool.builder("test-tool", JSON_MAPPER, inputSchemaJson)
|
||||
.description("A test tool")
|
||||
.inputSchema(JSON_MAPPER, inputSchemaJson)
|
||||
.outputSchema(JSON_MAPPER, outputSchemaJson)
|
||||
.annotations(annotations)
|
||||
.build();
|
||||
|
|
@ -1166,7 +1216,7 @@ public class McpSchemaTests {
|
|||
arguments.put("name", "test");
|
||||
arguments.put("value", 42);
|
||||
|
||||
McpSchema.CallToolRequest request = new McpSchema.CallToolRequest("test-tool", arguments);
|
||||
McpSchema.CallToolRequest request = McpSchema.CallToolRequest.builder("test-tool").arguments(arguments).build();
|
||||
|
||||
String value = JSON_MAPPER.writeValueAsString(request);
|
||||
|
||||
|
|
@ -1180,12 +1230,12 @@ public class McpSchemaTests {
|
|||
@Test
|
||||
void testCallToolRequestJsonArguments() throws Exception {
|
||||
|
||||
McpSchema.CallToolRequest request = new McpSchema.CallToolRequest(JSON_MAPPER, "test-tool", """
|
||||
McpSchema.CallToolRequest request = McpSchema.CallToolRequest.builder("test-tool").arguments(JSON_MAPPER, """
|
||||
{
|
||||
"name": "test",
|
||||
"value": 42
|
||||
}
|
||||
""");
|
||||
""").build();
|
||||
|
||||
String value = JSON_MAPPER.writeValueAsString(request);
|
||||
|
||||
|
|
@ -1261,7 +1311,7 @@ public class McpSchemaTests {
|
|||
|
||||
@Test
|
||||
void testCallToolResult() throws Exception {
|
||||
McpSchema.TextContent content = new McpSchema.TextContent("Tool execution result");
|
||||
McpSchema.TextContent content = McpSchema.TextContent.builder("Tool execution result").build();
|
||||
|
||||
McpSchema.CallToolResult result = McpSchema.CallToolResult.builder()
|
||||
.content(Collections.singletonList(content))
|
||||
|
|
@ -1294,8 +1344,8 @@ public class McpSchemaTests {
|
|||
|
||||
@Test
|
||||
void testCallToolResultBuilderWithMultipleContents() throws Exception {
|
||||
McpSchema.TextContent textContent = new McpSchema.TextContent("Text result");
|
||||
McpSchema.ImageContent imageContent = new McpSchema.ImageContent(null, "base64data", "image/png");
|
||||
McpSchema.TextContent textContent = McpSchema.TextContent.builder("Text result").build();
|
||||
McpSchema.ImageContent imageContent = McpSchema.ImageContent.builder("base64data", "image/png").build();
|
||||
|
||||
McpSchema.CallToolResult result = McpSchema.CallToolResult.builder()
|
||||
.addContent(textContent)
|
||||
|
|
@ -1315,8 +1365,8 @@ public class McpSchemaTests {
|
|||
|
||||
@Test
|
||||
void testCallToolResultBuilderWithContentList() throws Exception {
|
||||
McpSchema.TextContent textContent = new McpSchema.TextContent("Text result");
|
||||
McpSchema.ImageContent imageContent = new McpSchema.ImageContent(null, "base64data", "image/png");
|
||||
McpSchema.TextContent textContent = McpSchema.TextContent.builder("Text result").build();
|
||||
McpSchema.ImageContent imageContent = McpSchema.ImageContent.builder("base64data", "image/png").build();
|
||||
List<McpSchema.Content> contents = Arrays.asList(textContent, imageContent);
|
||||
|
||||
McpSchema.CallToolResult result = McpSchema.CallToolResult.builder().content(contents).isError(true).build();
|
||||
|
|
@ -1347,29 +1397,42 @@ public class McpSchemaTests {
|
|||
{"content":[{"type":"text","text":"Error: Operation failed"}],"isError":true}"""));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCallToolResultDeserializationWithMissingContent() throws Exception {
|
||||
McpSchema.CallToolResult result = JSON_MAPPER.readValue("""
|
||||
{"isError":false}""", McpSchema.CallToolResult.class);
|
||||
|
||||
assertThat(result).isNotNull();
|
||||
assertThat(result.content()).isEmpty();
|
||||
assertThat(result.isError()).isFalse();
|
||||
}
|
||||
|
||||
// Sampling Tests
|
||||
|
||||
@Test
|
||||
void testCreateMessageRequest() throws Exception {
|
||||
McpSchema.TextContent content = new McpSchema.TextContent("User message");
|
||||
McpSchema.TextContent content = McpSchema.TextContent.builder("User message").build();
|
||||
|
||||
McpSchema.SamplingMessage message = new McpSchema.SamplingMessage(McpSchema.Role.USER, content);
|
||||
McpSchema.SamplingMessage message = McpSchema.SamplingMessage.builder(McpSchema.Role.USER, content).build();
|
||||
|
||||
McpSchema.ModelHint hint = new McpSchema.ModelHint("gpt-4");
|
||||
McpSchema.ModelHint hint = McpSchema.ModelHint.of("gpt-4");
|
||||
|
||||
McpSchema.ModelPreferences preferences = new McpSchema.ModelPreferences(Collections.singletonList(hint), 0.3,
|
||||
0.7, 0.9);
|
||||
McpSchema.ModelPreferences preferences = McpSchema.ModelPreferences.builder()
|
||||
.hints(Collections.singletonList(hint))
|
||||
.costPriority(0.3)
|
||||
.speedPriority(0.7)
|
||||
.intelligencePriority(0.9)
|
||||
.build();
|
||||
|
||||
Map<String, Object> metadata = new HashMap<>();
|
||||
metadata.put("session", "test-session");
|
||||
|
||||
McpSchema.CreateMessageRequest request = McpSchema.CreateMessageRequest.builder()
|
||||
.messages(Collections.singletonList(message))
|
||||
McpSchema.CreateMessageRequest request = McpSchema.CreateMessageRequest
|
||||
.builder(Collections.singletonList(message), 1000)
|
||||
.modelPreferences(preferences)
|
||||
.systemPrompt("You are a helpful assistant")
|
||||
.includeContext(McpSchema.CreateMessageRequest.ContextInclusionStrategy.THIS_SERVER)
|
||||
.temperature(0.7)
|
||||
.maxTokens(1000)
|
||||
.stopSequences(Arrays.asList("STOP", "END"))
|
||||
.metadata(metadata)
|
||||
.build();
|
||||
|
|
@ -1385,13 +1448,31 @@ public class McpSchemaTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
void testCreateMessageResult() throws Exception {
|
||||
McpSchema.TextContent content = new McpSchema.TextContent("Assistant response");
|
||||
void testSamplingMessageDeserializationWithMissingFields() throws Exception {
|
||||
McpSchema.SamplingMessage message = JSON_MAPPER.readValue("{}", McpSchema.SamplingMessage.class);
|
||||
|
||||
McpSchema.CreateMessageResult result = McpSchema.CreateMessageResult.builder()
|
||||
.role(McpSchema.Role.ASSISTANT)
|
||||
.content(content)
|
||||
.model("gpt-4")
|
||||
assertThat(message).isNotNull();
|
||||
assertThat(message.role()).isEqualTo(McpSchema.Role.USER);
|
||||
assertThat(message.content()).isInstanceOf(McpSchema.TextContent.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCreateMessageRequestDeserializationWithMissingRequiredFields() throws Exception {
|
||||
McpSchema.CreateMessageRequest request = JSON_MAPPER.readValue("""
|
||||
{"systemPrompt":"hello"}""", McpSchema.CreateMessageRequest.class);
|
||||
|
||||
assertThat(request).isNotNull();
|
||||
assertThat(request.messages()).isEmpty();
|
||||
assertThat(request.maxTokens()).isZero();
|
||||
assertThat(request.systemPrompt()).isEqualTo("hello");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCreateMessageResult() throws Exception {
|
||||
McpSchema.TextContent content = McpSchema.TextContent.builder("Assistant response").build();
|
||||
|
||||
McpSchema.CreateMessageResult result = McpSchema.CreateMessageResult
|
||||
.builder(McpSchema.Role.ASSISTANT, content, "gpt-4")
|
||||
.stopReason(McpSchema.CreateMessageResult.StopReason.END_TURN)
|
||||
.build();
|
||||
|
||||
|
|
@ -1412,11 +1493,9 @@ public class McpSchemaTests {
|
|||
|
||||
McpSchema.CreateMessageResult value = JSON_MAPPER.readValue(input, McpSchema.CreateMessageResult.class);
|
||||
|
||||
McpSchema.TextContent expectedContent = new McpSchema.TextContent("Assistant response");
|
||||
McpSchema.CreateMessageResult expected = McpSchema.CreateMessageResult.builder()
|
||||
.role(McpSchema.Role.ASSISTANT)
|
||||
.content(expectedContent)
|
||||
.model("gpt-4")
|
||||
McpSchema.TextContent expectedContent = McpSchema.TextContent.builder("Assistant response").build();
|
||||
McpSchema.CreateMessageResult expected = McpSchema.CreateMessageResult
|
||||
.builder(McpSchema.Role.ASSISTANT, expectedContent, "gpt-4")
|
||||
.stopReason(McpSchema.CreateMessageResult.StopReason.UNKNOWN)
|
||||
.build();
|
||||
assertThat(value).isEqualTo(expected);
|
||||
|
|
@ -1426,9 +1505,9 @@ public class McpSchemaTests {
|
|||
|
||||
@Test
|
||||
void testCreateElicitationRequest() throws Exception {
|
||||
McpSchema.ElicitRequest request = McpSchema.ElicitRequest.builder()
|
||||
.requestedSchema(Map.of("type", "object", "required", List.of("a"), "properties",
|
||||
Map.of("foo", Map.of("type", "string"))))
|
||||
McpSchema.ElicitRequest request = McpSchema.ElicitRequest
|
||||
.builder("Please provide additional information", Map.of("type", "object", "required", List.of("a"),
|
||||
"properties", Map.of("foo", Map.of("type", "string"))))
|
||||
.build();
|
||||
|
||||
String value = JSON_MAPPER.writeValueAsString(request);
|
||||
|
|
@ -1436,15 +1515,15 @@ public class McpSchemaTests {
|
|||
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
|
||||
.when(Option.IGNORING_EXTRA_ARRAY_ITEMS)
|
||||
.isObject()
|
||||
.isEqualTo(json("""
|
||||
{"requestedSchema":{"properties":{"foo":{"type":"string"}},"required":["a"],"type":"object"}}"""));
|
||||
.isEqualTo(
|
||||
json("""
|
||||
{"message":"Please provide additional information","requestedSchema":{"properties":{"foo":{"type":"string"}},"required":["a"],"type":"object"}}"""));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCreateElicitationResult() throws Exception {
|
||||
McpSchema.ElicitResult result = McpSchema.ElicitResult.builder()
|
||||
McpSchema.ElicitResult result = McpSchema.ElicitResult.builder(McpSchema.ElicitResult.Action.ACCEPT)
|
||||
.content(Map.of("foo", "bar"))
|
||||
.message(McpSchema.ElicitResult.Action.ACCEPT)
|
||||
.build();
|
||||
|
||||
String value = JSON_MAPPER.writeValueAsString(result);
|
||||
|
|
@ -1456,6 +1535,15 @@ public class McpSchemaTests {
|
|||
{"action":"accept","content":{"foo":"bar"}}"""));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testElicitRequestDeserializationWithMissingRequiredFields() throws Exception {
|
||||
McpSchema.ElicitRequest request = JSON_MAPPER.readValue("{}", McpSchema.ElicitRequest.class);
|
||||
|
||||
assertThat(request).isNotNull();
|
||||
assertThat(request.message()).isEmpty();
|
||||
assertThat(request.requestedSchema()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testElicitRequestWithMeta() throws Exception {
|
||||
Map<String, Object> requestedSchema = Map.of("type", "object", "required", List.of("name"), "properties",
|
||||
|
|
@ -1464,9 +1552,7 @@ public class McpSchemaTests {
|
|||
Map<String, Object> meta = new HashMap<>();
|
||||
meta.put("progressToken", "elicit-token-789");
|
||||
|
||||
McpSchema.ElicitRequest request = McpSchema.ElicitRequest.builder()
|
||||
.message("Please provide your name")
|
||||
.requestedSchema(requestedSchema)
|
||||
McpSchema.ElicitRequest request = McpSchema.ElicitRequest.builder("Please provide your name", requestedSchema)
|
||||
.meta(meta)
|
||||
.build();
|
||||
|
||||
|
|
@ -1552,7 +1638,7 @@ public class McpSchemaTests {
|
|||
McpSchema.CompleteRequest.CompleteArgument argument = new McpSchema.CompleteRequest.CompleteArgument("arg1",
|
||||
"partial-value");
|
||||
|
||||
McpSchema.CompleteRequest request = new McpSchema.CompleteRequest(promptRef, argument);
|
||||
McpSchema.CompleteRequest request = McpSchema.CompleteRequest.builder(promptRef, argument).build();
|
||||
|
||||
String value = JSON_MAPPER.writeValueAsString(request);
|
||||
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
|
||||
|
|
@ -1576,7 +1662,7 @@ public class McpSchemaTests {
|
|||
Map<String, Object> meta = new HashMap<>();
|
||||
meta.put("progressToken", "complete-progress-789");
|
||||
|
||||
McpSchema.CompleteRequest request = new McpSchema.CompleteRequest(resourceRef, argument, meta, null);
|
||||
McpSchema.CompleteRequest request = McpSchema.CompleteRequest.builder(resourceRef, argument).meta(meta).build();
|
||||
|
||||
String value = JSON_MAPPER.writeValueAsString(request);
|
||||
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
|
||||
|
|
@ -1595,7 +1681,10 @@ public class McpSchemaTests {
|
|||
|
||||
@Test
|
||||
void testRoot() throws Exception {
|
||||
McpSchema.Root root = new McpSchema.Root("file:///path/to/root", "Test Root", Map.of("metaKey", "metaValue"));
|
||||
McpSchema.Root root = McpSchema.Root.builder("file:///path/to/root")
|
||||
.name("Test Root")
|
||||
.meta(Map.of("metaKey", "metaValue"))
|
||||
.build();
|
||||
|
||||
String value = JSON_MAPPER.writeValueAsString(root);
|
||||
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
|
||||
|
|
@ -1607,11 +1696,13 @@ public class McpSchemaTests {
|
|||
|
||||
@Test
|
||||
void testListRootsResult() throws Exception {
|
||||
McpSchema.Root root1 = new McpSchema.Root("file:///path/to/root1", "First Root");
|
||||
McpSchema.Root root1 = McpSchema.Root.builder("file:///path/to/root1").name("First Root").build();
|
||||
|
||||
McpSchema.Root root2 = new McpSchema.Root("file:///path/to/root2", "Second Root");
|
||||
McpSchema.Root root2 = McpSchema.Root.builder("file:///path/to/root2").name("Second Root").build();
|
||||
|
||||
McpSchema.ListRootsResult result = new McpSchema.ListRootsResult(Arrays.asList(root1, root2), "next-cursor");
|
||||
McpSchema.ListRootsResult result = McpSchema.ListRootsResult.builder(Arrays.asList(root1, root2))
|
||||
.nextCursor("next-cursor")
|
||||
.build();
|
||||
|
||||
String value = JSON_MAPPER.writeValueAsString(result);
|
||||
|
||||
|
|
@ -1729,8 +1820,11 @@ public class McpSchemaTests {
|
|||
|
||||
@Test
|
||||
void testProgressNotificationWithMessage() throws Exception {
|
||||
McpSchema.ProgressNotification notification = new McpSchema.ProgressNotification("progress-token-123", 0.5, 1.0,
|
||||
"Processing file 1 of 2", Map.of("key", "value"));
|
||||
McpSchema.ProgressNotification notification = McpSchema.ProgressNotification.builder("progress-token-123", 0.5)
|
||||
.total(1.0)
|
||||
.message("Processing file 1 of 2")
|
||||
.meta(Map.of("key", "value"))
|
||||
.build();
|
||||
|
||||
String value = JSON_MAPPER.writeValueAsString(notification);
|
||||
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
|
||||
|
|
@ -1755,10 +1849,21 @@ public class McpSchemaTests {
|
|||
assertThat(notification.meta()).containsEntry("key", "value");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testProgressNotificationDeserializationWithMissingRequiredFields() throws Exception {
|
||||
McpSchema.ProgressNotification notification = JSON_MAPPER.readValue("""
|
||||
{"total":1.0}""", McpSchema.ProgressNotification.class);
|
||||
|
||||
assertThat(notification).isNotNull();
|
||||
assertThat(notification.progressToken()).isEqualTo("");
|
||||
assertThat(notification.progress()).isZero();
|
||||
assertThat(notification.total()).isEqualTo(1.0);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testProgressNotificationWithoutMessage() throws Exception {
|
||||
McpSchema.ProgressNotification notification = new McpSchema.ProgressNotification("progress-token-789", 0.25,
|
||||
null, null);
|
||||
McpSchema.ProgressNotification notification = McpSchema.ProgressNotification.builder("progress-token-789", 0.25)
|
||||
.build();
|
||||
|
||||
String value = JSON_MAPPER.writeValueAsString(notification);
|
||||
assertThatJson(value).when(Option.IGNORING_ARRAY_ORDER)
|
||||
|
|
@ -1768,4 +1873,15 @@ public class McpSchemaTests {
|
|||
{"progressToken":"progress-token-789","progress":0.25}"""));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLoggingMessageNotificationDeserializationWithMissingRequiredFields() throws Exception {
|
||||
McpSchema.LoggingMessageNotification notification = JSON_MAPPER.readValue("""
|
||||
{"logger":"my-logger"}""", McpSchema.LoggingMessageNotification.class);
|
||||
|
||||
assertThat(notification).isNotNull();
|
||||
assertThat(notification.level()).isEqualTo(McpSchema.LoggingLevel.INFO);
|
||||
assertThat(notification.logger()).isEqualTo("my-logger");
|
||||
assertThat(notification.data()).isEmpty();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue