Compare commits

...
Author SHA1 Message Date
Christian Tzolov
e9e1a2f34d Release version 1.1.2
Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
2026-04-24 16:29:58 +03:00
Daniel Garnier-Moiroux
141063c99c Polish gh-906 2026-04-09 11:12:29 +02:00
smohite04
92bb47b67c feat: add support for meta parameter in client paginated list queries (#906)
* feat: add support for meta parameter in client paginated list queries#

- resources/list
- resources/templates/list
- prompts/list
- tools/list

paginated list operations extended in this review:
- listResources(String cursor, Map<String, Object> meta)
- listResourceTemplates(String cursor, Map<String, Object> meta)
- listPrompts(String cursor, Map<String, Object> meta)

Closes #907

Co-authored-by: SHEETAL MOHITE <mohishee@amazon.com>
Signed-off-by: Daniel Garnier-Moiroux <git@garnier.wf>
2026-04-09 11:12:29 +02:00
RameshReddy Adutla
9ead4d154e Fix UTF-8 encoding for non-ASCII tool names in HTTP client transports
Both HttpClientSseClientTransport and HttpClientStreamableHttpTransport
set Content-Type to 'application/json' without specifying the charset.
While Java's BodyPublishers.ofString() uses UTF-8 by default, the
missing charset in the header can cause the server to interpret the
request body using a different encoding (e.g., ISO-8859-1), corrupting
non-ASCII characters such as Chinese tool names.

Explicitly set Content-Type to 'application/json; charset=utf-8' in
POST requests on both client transports.

Fixes #260
Backport of #850

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Daniel Garnier-Moiroux <git@garnier.wf>
Signed-off-by: Daniel Garnier-Moiroux <git@garnier.wf>
2026-04-08 15:05:52 +02:00
Daniel Garnier-Moiroux
8e1c5d0cd4 HttpClientStreamableHttpTransport: handle HTTP 405
- Fixes #877

Signed-off-by: Daniel Garnier-Moiroux <git@garnier.wf>
2026-04-02 17:26:27 +02:00
300:29:1
7e4c179b77 Deprecate Builder.customizeRequest() in favor of httpRequestCustomizer() (#791)
Deprecate Builder.customizeRequest() in HttpClientSseClientTransport and HttpClientStreamableHttpTransport

customizeRequest() executes its consumer once at build time, freezing
headers into the shared requestBuilder. This silently breaks OAuth
token refresh scenarios where the Authorization header needs to be
updated after the transport is built.

Add @Deprecated and update Javadoc to clarify the build-time-only
semantics and guide users toward httpRequestCustomizer() or
asyncHttpRequestCustomizer() which run on every request.

Closes #788

Signed-off-by: Daniel Garnier-Moiroux <git@garnier.wf>
2026-04-02 11:39:17 +02:00
Daniel Garnier-Moiroux
3c27d8e3f8 Next development version
Signed-off-by: Daniel Garnier-Moiroux <git@garnier.wf>
2026-03-27 20:54:05 +01:00
Daniel Garnier-Moiroux
5968078106 Release version 1.1.1
Signed-off-by: Daniel Garnier-Moiroux <git@garnier.wf>
2026-03-27 20:53:25 +01:00
Daniel Garnier-Moiroux
d69501fd28
Merge commit from fork 2026-03-27 18:19:49 +00:00
Christian Tzolov
c9b936835f Next development version
Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
2026-03-13 13:28:37 +01:00
Christian Tzolov
d4d8072693 Release version 1.1.0
Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
2026-03-13 12:55:15 +01:00
27 changed files with 455 additions and 113 deletions

View file

@ -27,7 +27,7 @@ Once we catch up on the most recent MCP specification revision we aim to fully s
### v1.x Development ### v1.x Development
The Java SDK is currently in active development as v1.x, following a recent stable 1.0.0 release. The SDK provides: The Java SDK is currently in active development as v1.x, following a recent stable 1.1.0 release. The SDK provides:
- MCP protocol implementation - MCP protocol implementation
- Synchronous and asynchronous programming models - Synchronous and asynchronous programming models

View file

@ -87,7 +87,7 @@ cd conformance-tests/client-jdk-http-client
# Run all scenarios # Run all scenarios
for scenario in initialize tools_call elicitation-sep1034-client-defaults sse-retry; do for scenario in initialize tools_call elicitation-sep1034-client-defaults sse-retry; do
npx @modelcontextprotocol/conformance client \ npx @modelcontextprotocol/conformance client \
--command "java -jar target/client-jdk-http-client-1.1.0-SNAPSHOT.jar" \ --command "java -jar target/client-jdk-http-client-1.1.1-SNAPSHOT.jar" \
--scenario $scenario --scenario $scenario
done done
``` ```
@ -104,7 +104,7 @@ cd conformance-tests/client-spring-http-client
# Run auth suite # Run auth suite
npx @modelcontextprotocol/conformance@0.1.15 client \ npx @modelcontextprotocol/conformance@0.1.15 client \
--spec-version 2025-11-25 \ --spec-version 2025-11-25 \
--command "java -jar target/client-spring-http-client-1.1.0-SNAPSHOT.jar" \ --command "java -jar target/client-spring-http-client-1.1.1-SNAPSHOT.jar" \
--suite auth --suite auth
``` ```

View file

@ -54,7 +54,7 @@ cd conformance-tests/client-jdk-http-client
This creates an executable JAR at: This creates an executable JAR at:
``` ```
target/client-jdk-http-client-1.1.0-SNAPSHOT.jar target/client-jdk-http-client-1.1.1-SNAPSHOT.jar
``` ```
## Running Tests ## Running Tests
@ -65,19 +65,19 @@ Run a single scenario:
```bash ```bash
npx @modelcontextprotocol/conformance client \ npx @modelcontextprotocol/conformance client \
--command "java -jar conformance-tests/client-jdk-http-client/target/client-jdk-http-client-1.1.0-SNAPSHOT.jar" \ --command "java -jar conformance-tests/client-jdk-http-client/target/client-jdk-http-client-1.1.1-SNAPSHOT.jar" \
--scenario initialize --scenario initialize
npx @modelcontextprotocol/conformance client \ npx @modelcontextprotocol/conformance client \
--command "java -jar conformance-tests/client-jdk-http-client/target/client-jdk-http-client-1.1.0-SNAPSHOT.jar" \ --command "java -jar conformance-tests/client-jdk-http-client/target/client-jdk-http-client-1.1.1-SNAPSHOT.jar" \
--scenario tools_call --scenario tools_call
npx @modelcontextprotocol/conformance client \ npx @modelcontextprotocol/conformance client \
--command "java -jar conformance-tests/client-jdk-http-client/target/client-jdk-http-client-1.1.0-SNAPSHOT.jar" \ --command "java -jar conformance-tests/client-jdk-http-client/target/client-jdk-http-client-1.1.1-SNAPSHOT.jar" \
--scenario elicitation-sep1034-client-defaults --scenario elicitation-sep1034-client-defaults
npx @modelcontextprotocol/conformance client \ npx @modelcontextprotocol/conformance client \
--command "java -jar conformance-tests/client-jdk-http-client/target/client-jdk-http-client-1.1.0-SNAPSHOT.jar" \ --command "java -jar conformance-tests/client-jdk-http-client/target/client-jdk-http-client-1.1.1-SNAPSHOT.jar" \
--scenario sse-retry --scenario sse-retry
``` ```
@ -85,7 +85,7 @@ Run with verbose output:
```bash ```bash
npx @modelcontextprotocol/conformance client \ npx @modelcontextprotocol/conformance client \
--command "java -jar conformance-tests/client-jdk-http-client/target/client-jdk-http-client-1.1.0-SNAPSHOT.jar" \ --command "java -jar conformance-tests/client-jdk-http-client/target/client-jdk-http-client-1.1.1-SNAPSHOT.jar" \
--scenario initialize \ --scenario initialize \
--verbose --verbose
``` ```
@ -96,7 +96,7 @@ You can also run the client manually if you have a test server:
```bash ```bash
export MCP_CONFORMANCE_SCENARIO=initialize export MCP_CONFORMANCE_SCENARIO=initialize
java -jar conformance-tests/client-jdk-http-client/target/client-jdk-http-client-1.1.0-SNAPSHOT.jar http://localhost:3000/mcp java -jar conformance-tests/client-jdk-http-client/target/client-jdk-http-client-1.1.1-SNAPSHOT.jar http://localhost:3000/mcp
``` ```
## Test Results ## Test Results

View file

@ -6,7 +6,7 @@
<parent> <parent>
<groupId>io.modelcontextprotocol.sdk</groupId> <groupId>io.modelcontextprotocol.sdk</groupId>
<artifactId>conformance-tests</artifactId> <artifactId>conformance-tests</artifactId>
<version>1.1.0-SNAPSHOT</version> <version>1.1.2</version>
</parent> </parent>
<artifactId>client-jdk-http-client</artifactId> <artifactId>client-jdk-http-client</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
@ -28,7 +28,7 @@
<dependency> <dependency>
<groupId>io.modelcontextprotocol.sdk</groupId> <groupId>io.modelcontextprotocol.sdk</groupId>
<artifactId>mcp</artifactId> <artifactId>mcp</artifactId>
<version>1.1.0-SNAPSHOT</version> <version>1.1.2</version>
</dependency> </dependency>
<!-- Logging --> <!-- Logging -->

View file

@ -67,7 +67,7 @@ cd conformance-tests/client-spring-http-client
This creates an executable JAR at: This creates an executable JAR at:
``` ```
target/client-spring-http-client-1.1.0-SNAPSHOT.jar target/client-spring-http-client-1.1.1-SNAPSHOT.jar
``` ```
## Running Tests ## Running Tests
@ -79,7 +79,7 @@ Run the full auth suite:
```bash ```bash
npx @modelcontextprotocol/conformance@0.1.15 client \ npx @modelcontextprotocol/conformance@0.1.15 client \
--spec-version 2025-11-25 \ --spec-version 2025-11-25 \
--command "java -jar conformance-tests/client-spring-http-client/target/client-spring-http-client-1.1.0-SNAPSHOT.jar" \ --command "java -jar conformance-tests/client-spring-http-client/target/client-spring-http-client-1.1.1-SNAPSHOT.jar" \
--suite auth --suite auth
``` ```
@ -88,7 +88,7 @@ Run a single scenario:
```bash ```bash
npx @modelcontextprotocol/conformance@0.1.15 client \ npx @modelcontextprotocol/conformance@0.1.15 client \
--spec-version 2025-11-25 \ --spec-version 2025-11-25 \
--command "java -jar conformance-tests/client-spring-http-client/target/client-spring-http-client-1.1.0-SNAPSHOT.jar" \ --command "java -jar conformance-tests/client-spring-http-client/target/client-spring-http-client-1.1.1-SNAPSHOT.jar" \
--scenario auth/metadata-default --scenario auth/metadata-default
``` ```
@ -97,7 +97,7 @@ Run with verbose output:
```bash ```bash
npx @modelcontextprotocol/conformance@0.1.15 client \ npx @modelcontextprotocol/conformance@0.1.15 client \
--spec-version 2025-11-25 \ --spec-version 2025-11-25 \
--command "java -jar conformance-tests/client-spring-http-client/target/client-spring-http-client-1.1.0-SNAPSHOT.jar" \ --command "java -jar conformance-tests/client-spring-http-client/target/client-spring-http-client-1.1.1-SNAPSHOT.jar" \
--scenario auth/metadata-default \ --scenario auth/metadata-default \
--verbose --verbose
``` ```
@ -108,7 +108,7 @@ You can also run the client manually if you have a test server:
```bash ```bash
export MCP_CONFORMANCE_SCENARIO=auth/metadata-default export MCP_CONFORMANCE_SCENARIO=auth/metadata-default
java -jar conformance-tests/client-spring-http-client/target/client-spring-http-client-1.1.0-SNAPSHOT.jar http://localhost:3000/mcp java -jar conformance-tests/client-spring-http-client/target/client-spring-http-client-1.1.1-SNAPSHOT.jar http://localhost:3000/mcp
``` ```
## Known Issues ## Known Issues

View file

@ -6,7 +6,7 @@
<parent> <parent>
<groupId>io.modelcontextprotocol.sdk</groupId> <groupId>io.modelcontextprotocol.sdk</groupId>
<artifactId>conformance-tests</artifactId> <artifactId>conformance-tests</artifactId>
<version>1.1.0-SNAPSHOT</version> <version>1.1.2</version>
</parent> </parent>
<artifactId>client-spring-http-client</artifactId> <artifactId>client-spring-http-client</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>

View file

@ -6,7 +6,7 @@
<parent> <parent>
<groupId>io.modelcontextprotocol.sdk</groupId> <groupId>io.modelcontextprotocol.sdk</groupId>
<artifactId>mcp-parent</artifactId> <artifactId>mcp-parent</artifactId>
<version>1.1.0-SNAPSHOT</version> <version>1.1.2</version>
</parent> </parent>
<artifactId>conformance-tests</artifactId> <artifactId>conformance-tests</artifactId>
<packaging>pom</packaging> <packaging>pom</packaging>

View file

@ -6,7 +6,7 @@
<parent> <parent>
<groupId>io.modelcontextprotocol.sdk</groupId> <groupId>io.modelcontextprotocol.sdk</groupId>
<artifactId>conformance-tests</artifactId> <artifactId>conformance-tests</artifactId>
<version>1.1.0-SNAPSHOT</version> <version>1.1.2</version>
</parent> </parent>
<artifactId>server-servlet</artifactId> <artifactId>server-servlet</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
@ -28,7 +28,7 @@
<dependency> <dependency>
<groupId>io.modelcontextprotocol.sdk</groupId> <groupId>io.modelcontextprotocol.sdk</groupId>
<artifactId>mcp</artifactId> <artifactId>mcp</artifactId>
<version>1.1.0-SNAPSHOT</version> <version>1.1.2</version>
</dependency> </dependency>
<dependency> <dependency>

View file

@ -123,7 +123,7 @@ Add the BOM to your project:
<dependency> <dependency>
<groupId>io.modelcontextprotocol.sdk</groupId> <groupId>io.modelcontextprotocol.sdk</groupId>
<artifactId>mcp-bom</artifactId> <artifactId>mcp-bom</artifactId>
<version>1.0.0</version> <version>1.1.0</version>
<type>pom</type> <type>pom</type>
<scope>import</scope> <scope>import</scope>
</dependency> </dependency>
@ -135,7 +135,7 @@ Add the BOM to your project:
```groovy ```groovy
dependencies { dependencies {
implementation platform("io.modelcontextprotocol.sdk:mcp-bom:1.0.0") implementation platform("io.modelcontextprotocol.sdk:mcp-bom:1.1.0")
//... //...
} }
``` ```

View file

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>io.modelcontextprotocol.sdk</groupId> <groupId>io.modelcontextprotocol.sdk</groupId>
<artifactId>mcp-parent</artifactId> <artifactId>mcp-parent</artifactId>
<version>1.1.0-SNAPSHOT</version> <version>1.1.2</version>
</parent> </parent>
<artifactId>mcp-bom</artifactId> <artifactId>mcp-bom</artifactId>

View file

@ -6,7 +6,7 @@
<parent> <parent>
<groupId>io.modelcontextprotocol.sdk</groupId> <groupId>io.modelcontextprotocol.sdk</groupId>
<artifactId>mcp-parent</artifactId> <artifactId>mcp-parent</artifactId>
<version>1.1.0-SNAPSHOT</version> <version>1.1.2</version>
</parent> </parent>
<artifactId>mcp-core</artifactId> <artifactId>mcp-core</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>

View file

@ -303,7 +303,7 @@ public class McpAsyncClient {
return Mono.empty(); return Mono.empty();
} }
return this.listToolsInternal(init, McpSchema.FIRST_PAGE).doOnNext(listToolsResult -> { return this.listToolsInternal(init, McpSchema.FIRST_PAGE, null).doOnNext(listToolsResult -> {
listToolsResult.tools() listToolsResult.tools()
.forEach(tool -> logger.debug("Tool {} schema: {}", tool.name(), tool.outputSchema())); .forEach(tool -> logger.debug("Tool {} schema: {}", tool.name(), tool.outputSchema()));
if (enableCallToolSchemaCaching && listToolsResult.tools() != null) { if (enableCallToolSchemaCaching && listToolsResult.tools() != null) {
@ -645,16 +645,27 @@ public class McpAsyncClient {
* @return A Mono that emits the list of tools result * @return A Mono that emits the list of tools result
*/ */
public Mono<McpSchema.ListToolsResult> listTools(String cursor) { public Mono<McpSchema.ListToolsResult> listTools(String cursor) {
return this.initializer.withInitialization("listing tools", init -> this.listToolsInternal(init, cursor)); return this.initializer.withInitialization("listing tools", init -> this.listToolsInternal(init, cursor, null));
} }
private Mono<McpSchema.ListToolsResult> listToolsInternal(Initialization init, String cursor) { /**
* Retrieves a paginated list of tools with optional metadata.
* @param cursor Optional pagination cursor from a previous list request
* @param meta Optional metadata to include in the request (_meta field)
* @return A Mono that emits the list of tools result
*/
public Mono<McpSchema.ListToolsResult> listTools(String cursor, Map<String, Object> meta) {
return this.initializer.withInitialization("listing tools", init -> this.listToolsInternal(init, cursor, meta));
}
private Mono<McpSchema.ListToolsResult> listToolsInternal(Initialization init, String cursor,
Map<String, Object> meta) {
if (init.initializeResult().capabilities().tools() == null) { if (init.initializeResult().capabilities().tools() == null) {
return Mono.error(new IllegalStateException("Server does not provide tools capability")); return Mono.error(new IllegalStateException("Server does not provide tools capability"));
} }
return init.mcpSession() return init.mcpSession()
.sendRequest(McpSchema.METHOD_TOOLS_LIST, new McpSchema.PaginatedRequest(cursor), .sendRequest(McpSchema.METHOD_TOOLS_LIST, new McpSchema.PaginatedRequest(cursor, meta),
LIST_TOOLS_RESULT_TYPE_REF) LIST_TOOLS_RESULT_TYPE_REF)
.doOnNext(result -> { .doOnNext(result -> {
// Validate tool names (warn only) // Validate tool names (warn only)
@ -725,12 +736,30 @@ public class McpAsyncClient {
* @see #readResource(McpSchema.Resource) * @see #readResource(McpSchema.Resource)
*/ */
public Mono<McpSchema.ListResourcesResult> listResources(String cursor) { public Mono<McpSchema.ListResourcesResult> listResources(String cursor) {
return this.listResourcesInternal(cursor, null);
}
/**
* Retrieves a paginated list of resources provided by the server. Resources represent
* any kind of UTF-8 encoded data that an MCP server makes available to clients, such
* as database records, API responses, log files, and more.
* @param cursor Optional pagination cursor from a previous list request
* @param meta Optional metadata to include in the request (_meta field)
* @return A Mono that completes with the list of resources result.
* @see McpSchema.ListResourcesResult
* @see #readResource(McpSchema.Resource)
*/
public Mono<McpSchema.ListResourcesResult> listResources(String cursor, Map<String, Object> meta) {
return this.listResourcesInternal(cursor, meta);
}
private Mono<McpSchema.ListResourcesResult> listResourcesInternal(String cursor, Map<String, Object> meta) {
return this.initializer.withInitialization("listing resources", init -> { return this.initializer.withInitialization("listing resources", init -> {
if (init.initializeResult().capabilities().resources() == null) { if (init.initializeResult().capabilities().resources() == null) {
return Mono.error(new IllegalStateException("Server does not provide the resources capability")); return Mono.error(new IllegalStateException("Server does not provide the resources capability"));
} }
return init.mcpSession() return init.mcpSession()
.sendRequest(McpSchema.METHOD_RESOURCES_LIST, new McpSchema.PaginatedRequest(cursor), .sendRequest(McpSchema.METHOD_RESOURCES_LIST, new McpSchema.PaginatedRequest(cursor, meta),
LIST_RESOURCES_RESULT_TYPE_REF); LIST_RESOURCES_RESULT_TYPE_REF);
}); });
} }
@ -795,12 +824,30 @@ public class McpAsyncClient {
* @see McpSchema.ListResourceTemplatesResult * @see McpSchema.ListResourceTemplatesResult
*/ */
public Mono<McpSchema.ListResourceTemplatesResult> listResourceTemplates(String cursor) { public Mono<McpSchema.ListResourceTemplatesResult> listResourceTemplates(String cursor) {
return this.listResourceTemplatesInternal(cursor, null);
}
/**
* Retrieves a paginated list of resource templates provided by the server. Resource
* templates allow servers to expose parameterized resources using URI templates,
* enabling dynamic resource access based on variable parameters.
* @param cursor Optional pagination cursor from a previous list request
* @param meta Optional metadata to include in the request (_meta field)
* @return A Mono that completes with the list of resource templates result.
* @see McpSchema.ListResourceTemplatesResult
*/
public Mono<McpSchema.ListResourceTemplatesResult> listResourceTemplates(String cursor, Map<String, Object> meta) {
return this.listResourceTemplatesInternal(cursor, meta);
}
private Mono<McpSchema.ListResourceTemplatesResult> listResourceTemplatesInternal(String cursor,
Map<String, Object> meta) {
return this.initializer.withInitialization("listing resource templates", init -> { return this.initializer.withInitialization("listing resource templates", init -> {
if (init.initializeResult().capabilities().resources() == null) { if (init.initializeResult().capabilities().resources() == null) {
return Mono.error(new IllegalStateException("Server does not provide the resources capability")); return Mono.error(new IllegalStateException("Server does not provide the resources capability"));
} }
return init.mcpSession() return init.mcpSession()
.sendRequest(McpSchema.METHOD_RESOURCES_TEMPLATES_LIST, new McpSchema.PaginatedRequest(cursor), .sendRequest(McpSchema.METHOD_RESOURCES_TEMPLATES_LIST, new McpSchema.PaginatedRequest(cursor, meta),
LIST_RESOURCE_TEMPLATES_RESULT_TYPE_REF); LIST_RESOURCE_TEMPLATES_RESULT_TYPE_REF);
}); });
} }
@ -895,8 +942,26 @@ public class McpAsyncClient {
* @see #getPrompt(GetPromptRequest) * @see #getPrompt(GetPromptRequest)
*/ */
public Mono<ListPromptsResult> listPrompts(String cursor) { public Mono<ListPromptsResult> listPrompts(String cursor) {
return this.initializer.withInitialization("listing prompts", init -> init.mcpSession() return this.listPromptsInternal(cursor, null);
.sendRequest(McpSchema.METHOD_PROMPT_LIST, new PaginatedRequest(cursor), LIST_PROMPTS_RESULT_TYPE_REF)); }
/**
* Retrieves a paginated list of prompts with optional metadata.
* @param cursor Optional pagination cursor from a previous list request
* @param meta Optional metadata to include in the request (_meta field)
* @return A Mono that completes with the list of prompts result.
* @see McpSchema.ListPromptsResult
* @see #getPrompt(GetPromptRequest)
*/
public Mono<ListPromptsResult> listPrompts(String cursor, Map<String, Object> meta) {
return this.listPromptsInternal(cursor, meta);
}
private Mono<ListPromptsResult> listPromptsInternal(String cursor, Map<String, Object> meta) {
return this.initializer.withInitialization("listing prompts",
init -> init.mcpSession()
.sendRequest(McpSchema.METHOD_PROMPT_LIST, new PaginatedRequest(cursor, meta),
LIST_PROMPTS_RESULT_TYPE_REF));
} }
/** /**

View file

@ -5,6 +5,7 @@
package io.modelcontextprotocol.client; package io.modelcontextprotocol.client;
import java.time.Duration; import java.time.Duration;
import java.util.Map;
import java.util.function.Supplier; import java.util.function.Supplier;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -259,6 +260,18 @@ public class McpSyncClient implements AutoCloseable {
} }
/**
* Retrieves a paginated list of tools provided by the server.
* @param cursor Optional pagination cursor from a previous list request
* @param meta Optional metadata to include in the request (_meta field)
* @return The list of tools result containing: - tools: List of available tools, each
* with a name, description, and input schema - nextCursor: Optional cursor for
* pagination if more tools are available
*/
public McpSchema.ListToolsResult listTools(String cursor, Map<String, Object> meta) {
return withProvidedContext(this.delegate.listTools(cursor, meta)).block();
}
// -------------------------- // --------------------------
// Resources // Resources
// -------------------------- // --------------------------
@ -282,6 +295,17 @@ public class McpSyncClient implements AutoCloseable {
} }
/**
* Retrieves a paginated list of resources with optional metadata.
* @param cursor Optional pagination cursor from a previous list request
* @param meta Optional metadata to include in the request (_meta field)
* @return The list of resources result
*/
public McpSchema.ListResourcesResult listResources(String cursor, Map<String, Object> meta) {
return withProvidedContext(this.delegate.listResources(cursor, meta)).block();
}
/** /**
* Send a resources/read request. * Send a resources/read request.
* @param resource the resource to read * @param resource the resource to read
@ -324,6 +348,20 @@ public class McpSyncClient implements AutoCloseable {
} }
/**
* Resource templates allow servers to expose parameterized resources using URI
* templates. Arguments may be auto-completed through the completion API.
*
* Retrieves a paginated list of resource templates provided by the server.
* @param cursor Optional pagination cursor from a previous list request
* @param meta Optional metadata to include in the request (_meta field)
* @return The list of resource templates result.
*/
public McpSchema.ListResourceTemplatesResult listResourceTemplates(String cursor, Map<String, Object> meta) {
return withProvidedContext(this.delegate.listResourceTemplates(cursor, meta)).block();
}
/** /**
* Subscriptions. The protocol supports optional subscriptions to resource changes. * Subscriptions. The protocol supports optional subscriptions to resource changes.
* Clients can subscribe to specific resources and receive notifications when they * Clients can subscribe to specific resources and receive notifications when they
@ -370,6 +408,17 @@ public class McpSyncClient implements AutoCloseable {
} }
/**
* Retrieves a paginated list of prompts provided by the server.
* @param cursor Optional pagination cursor from a previous list request
* @param meta Optional metadata to include in the request (_meta field)
* @return The list of prompts result.
*/
public ListPromptsResult listPrompts(String cursor, Map<String, Object> meta) {
return withProvidedContext(this.delegate.listPrompts(cursor, meta)).block();
}
public GetPromptResult getPrompt(GetPromptRequest getPromptRequest) { public GetPromptResult getPrompt(GetPromptRequest getPromptRequest) {
return withProvidedContext(this.delegate.getPrompt(getPromptRequest)).block(); return withProvidedContext(this.delegate.getPrompt(getPromptRequest)).block();
} }

View file

@ -241,10 +241,17 @@ public class HttpClientSseClientTransport implements McpClientTransport {
} }
/** /**
* Customizes the HTTP client builder. * Applies the given consumer to the shared {@link HttpRequest.Builder} <b>once,
* at build time</b>. Any headers set here are frozen into the template and
* <b>cannot be updated</b> after the transport is built.
* @param requestCustomizer the consumer to customize the HTTP request builder * @param requestCustomizer the consumer to customize the HTTP request builder
* @return this builder * @return this builder
* @deprecated Use {@link #requestBuilder(HttpRequest.Builder)} for stable
* headers, or {@link #httpRequestCustomizer(McpSyncHttpClientRequestCustomizer)}
* / {@link #asyncHttpRequestCustomizer(McpAsyncHttpClientRequestCustomizer)} for
* dynamic per-request customization.
*/ */
@Deprecated
public Builder customizeRequest(final Consumer<HttpRequest.Builder> requestCustomizer) { public Builder customizeRequest(final Consumer<HttpRequest.Builder> requestCustomizer) {
Assert.notNull(requestCustomizer, "requestCustomizer must not be null"); Assert.notNull(requestCustomizer, "requestCustomizer must not be null");
requestCustomizer.accept(requestBuilder); requestCustomizer.accept(requestBuilder);
@ -456,7 +463,7 @@ public class HttpClientSseClientTransport implements McpClientTransport {
return Mono.deferContextual(ctx -> { return Mono.deferContextual(ctx -> {
var builder = this.requestBuilder.copy() var builder = this.requestBuilder.copy()
.uri(requestUri) .uri(requestUri)
.header(HttpHeaders.CONTENT_TYPE, "application/json") .header(HttpHeaders.CONTENT_TYPE, "application/json; charset=utf-8")
.header(MCP_PROTOCOL_VERSION_HEADER_NAME, MCP_PROTOCOL_VERSION) .header(MCP_PROTOCOL_VERSION_HEADER_NAME, MCP_PROTOCOL_VERSION)
.POST(HttpRequest.BodyPublishers.ofString(body)); .POST(HttpRequest.BodyPublishers.ofString(body));
var transportContext = ctx.getOrDefault(McpTransportContext.KEY, McpTransportContext.EMPTY); var transportContext = ctx.getOrDefault(McpTransportContext.KEY, McpTransportContext.EMPTY);

View file

@ -102,6 +102,8 @@ public class HttpClientStreamableHttpTransport implements McpClientTransport {
private static final String APPLICATION_JSON = "application/json"; private static final String APPLICATION_JSON = "application/json";
private static final String APPLICATION_JSON_UTF8 = "application/json; charset=utf-8";
private static final String TEXT_EVENT_STREAM = "text/event-stream"; private static final String TEXT_EVENT_STREAM = "text/event-stream";
public static int NOT_FOUND = 404; public static int NOT_FOUND = 404;
@ -298,6 +300,10 @@ public class HttpClientStreamableHttpTransport implements McpClientTransport {
"Authorization error connecting to SSE stream", "Authorization error connecting to SSE stream",
responseEvent.responseInfo())); responseEvent.responseInfo()));
} }
else if (statusCode == METHOD_NOT_ALLOWED) {
logger.debug("The server does not support SSE streams, using request-response mode.");
return Flux.empty();
}
if (!(responseEvent instanceof ResponseSubscribers.SseResponseEvent sseResponseEvent)) { if (!(responseEvent instanceof ResponseSubscribers.SseResponseEvent sseResponseEvent)) {
return Flux.<McpSchema.JSONRPCMessage>error(new McpTransportException( return Flux.<McpSchema.JSONRPCMessage>error(new McpTransportException(
@ -344,10 +350,6 @@ public class HttpClientStreamableHttpTransport implements McpClientTransport {
return Flux.empty(); return Flux.empty();
} }
} }
else if (statusCode == METHOD_NOT_ALLOWED) { // NotAllowed
logger.debug("The server does not support SSE streams, using request-response mode.");
return Flux.empty();
}
else if (statusCode == NOT_FOUND) { else if (statusCode == NOT_FOUND) {
if (transportSession != null && transportSession.sessionId().isPresent()) { if (transportSession != null && transportSession.sessionId().isPresent()) {
@ -477,7 +479,7 @@ public class HttpClientStreamableHttpTransport implements McpClientTransport {
var builder = requestBuilder.uri(uri) var builder = requestBuilder.uri(uri)
.header(HttpHeaders.ACCEPT, APPLICATION_JSON + ", " + TEXT_EVENT_STREAM) .header(HttpHeaders.ACCEPT, APPLICATION_JSON + ", " + TEXT_EVENT_STREAM)
.header(HttpHeaders.CONTENT_TYPE, APPLICATION_JSON) .header(HttpHeaders.CONTENT_TYPE, APPLICATION_JSON_UTF8)
.header(HttpHeaders.CACHE_CONTROL, "no-cache") .header(HttpHeaders.CACHE_CONTROL, "no-cache")
.header(HttpHeaders.PROTOCOL_VERSION, .header(HttpHeaders.PROTOCOL_VERSION,
ctx.getOrDefault(McpAsyncClient.NEGOTIATED_PROTOCOL_VERSION, ctx.getOrDefault(McpAsyncClient.NEGOTIATED_PROTOCOL_VERSION,
@ -738,10 +740,17 @@ public class HttpClientStreamableHttpTransport implements McpClientTransport {
} }
/** /**
* Customizes the HTTP client builder. * Applies the given consumer to the shared {@link HttpRequest.Builder} <b>once,
* at build time</b>. Any headers set here are frozen into the template and
* <b>cannot be updated</b> after the transport is built.
* @param requestCustomizer the consumer to customize the HTTP request builder * @param requestCustomizer the consumer to customize the HTTP request builder
* @return this builder * @return this builder
* @deprecated Use {@link #requestBuilder(HttpRequest.Builder)} for stable
* headers, or {@link #httpRequestCustomizer(McpSyncHttpClientRequestCustomizer)}
* / {@link #asyncHttpRequestCustomizer(McpAsyncHttpClientRequestCustomizer)} for
* dynamic per-request customization.
*/ */
@Deprecated
public Builder customizeRequest(final Consumer<HttpRequest.Builder> requestCustomizer) { public Builder customizeRequest(final Consumer<HttpRequest.Builder> requestCustomizer) {
Assert.notNull(requestCustomizer, "requestCustomizer must not be null"); Assert.notNull(requestCustomizer, "requestCustomizer must not be null");
requestCustomizer.accept(requestBuilder); requestCustomizer.accept(requestBuilder);

View file

@ -286,7 +286,6 @@ public class HttpServletSseServerTransportProvider extends HttpServlet implement
response.setCharacterEncoding(UTF_8); response.setCharacterEncoding(UTF_8);
response.setHeader("Cache-Control", "no-cache"); response.setHeader("Cache-Control", "no-cache");
response.setHeader("Connection", "keep-alive"); response.setHeader("Connection", "keep-alive");
response.setHeader("Access-Control-Allow-Origin", "*");
String sessionId = UUID.randomUUID().toString(); String sessionId = UUID.randomUUID().toString();
AsyncContext asyncContext = request.startAsync(); AsyncContext asyncContext = request.startAsync();

View file

@ -315,7 +315,6 @@ public class HttpServletStreamableServerTransportProvider extends HttpServlet
response.setCharacterEncoding(UTF_8); response.setCharacterEncoding(UTF_8);
response.setHeader("Cache-Control", "no-cache"); response.setHeader("Cache-Control", "no-cache");
response.setHeader("Connection", "keep-alive"); response.setHeader("Connection", "keep-alive");
response.setHeader("Access-Control-Allow-Origin", "*");
AsyncContext asyncContext = request.startAsync(); AsyncContext asyncContext = request.startAsync();
asyncContext.setTimeout(0); asyncContext.setTimeout(0);
@ -522,7 +521,6 @@ public class HttpServletStreamableServerTransportProvider extends HttpServlet
response.setCharacterEncoding(UTF_8); response.setCharacterEncoding(UTF_8);
response.setHeader("Cache-Control", "no-cache"); response.setHeader("Cache-Control", "no-cache");
response.setHeader("Connection", "keep-alive"); response.setHeader("Connection", "keep-alive");
response.setHeader("Access-Control-Allow-Origin", "*");
AsyncContext asyncContext = request.startAsync(); AsyncContext asyncContext = request.startAsync();
asyncContext.setTimeout(0); asyncContext.setTimeout(0);

View file

@ -6,7 +6,7 @@
<parent> <parent>
<groupId>io.modelcontextprotocol.sdk</groupId> <groupId>io.modelcontextprotocol.sdk</groupId>
<artifactId>mcp-parent</artifactId> <artifactId>mcp-parent</artifactId>
<version>1.1.0-SNAPSHOT</version> <version>1.1.2</version>
</parent> </parent>
<artifactId>mcp-json-jackson2</artifactId> <artifactId>mcp-json-jackson2</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
@ -72,7 +72,7 @@
<dependency> <dependency>
<groupId>io.modelcontextprotocol.sdk</groupId> <groupId>io.modelcontextprotocol.sdk</groupId>
<artifactId>mcp-core</artifactId> <artifactId>mcp-core</artifactId>
<version>1.1.0-SNAPSHOT</version> <version>1.1.2</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.networknt</groupId> <groupId>com.networknt</groupId>

View file

@ -6,7 +6,7 @@
<parent> <parent>
<groupId>io.modelcontextprotocol.sdk</groupId> <groupId>io.modelcontextprotocol.sdk</groupId>
<artifactId>mcp-parent</artifactId> <artifactId>mcp-parent</artifactId>
<version>1.1.0-SNAPSHOT</version> <version>1.1.2</version>
</parent> </parent>
<artifactId>mcp-json-jackson3</artifactId> <artifactId>mcp-json-jackson3</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
@ -66,7 +66,7 @@
<dependency> <dependency>
<groupId>io.modelcontextprotocol.sdk</groupId> <groupId>io.modelcontextprotocol.sdk</groupId>
<artifactId>mcp-core</artifactId> <artifactId>mcp-core</artifactId>
<version>1.1.0-SNAPSHOT</version> <version>1.1.2</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>tools.jackson.core</groupId> <groupId>tools.jackson.core</groupId>

View file

@ -6,7 +6,7 @@
<parent> <parent>
<groupId>io.modelcontextprotocol.sdk</groupId> <groupId>io.modelcontextprotocol.sdk</groupId>
<artifactId>mcp-parent</artifactId> <artifactId>mcp-parent</artifactId>
<version>1.1.0-SNAPSHOT</version> <version>1.1.2</version>
</parent> </parent>
<artifactId>mcp-test</artifactId> <artifactId>mcp-test</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
@ -24,7 +24,7 @@
<dependency> <dependency>
<groupId>io.modelcontextprotocol.sdk</groupId> <groupId>io.modelcontextprotocol.sdk</groupId>
<artifactId>mcp-core</artifactId> <artifactId>mcp-core</artifactId>
<version>1.1.0-SNAPSHOT</version> <version>1.1.2</version>
</dependency> </dependency>
<dependency> <dependency>
@ -159,7 +159,7 @@
<dependency> <dependency>
<groupId>io.modelcontextprotocol.sdk</groupId> <groupId>io.modelcontextprotocol.sdk</groupId>
<artifactId>mcp-json-jackson3</artifactId> <artifactId>mcp-json-jackson3</artifactId>
<version>1.1.0-SNAPSHOT</version> <version>1.1.2</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
</dependencies> </dependencies>
@ -170,7 +170,7 @@
<dependency> <dependency>
<groupId>io.modelcontextprotocol.sdk</groupId> <groupId>io.modelcontextprotocol.sdk</groupId>
<artifactId>mcp-json-jackson2</artifactId> <artifactId>mcp-json-jackson2</artifactId>
<version>1.1.0-SNAPSHOT</version> <version>1.1.2</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
</dependencies> </dependencies>

Some files were not shown because too many files have changed in this diff Show more