Skip to content

Commit 664f86b

Browse files
committed
Address review comments and improve docs structure and content
Resolves: #127 Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
1 parent 2810776 commit 664f86b

File tree

9 files changed

+543
-216
lines changed

9 files changed

+543
-216
lines changed

README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ For comprehensive guides and SDK API documentation
2020
- [Java MCP Server](https://modelcontextprotocol.github.io/java-sdk/server/) - Learn how to implement and configure a MCP servers.
2121

2222
#### Spring AI MCP documentation
23-
[Spring AI MCP](https://docs.spring.io/spring-ai/reference/api/mcp/mcp-overview.html) extends the MCP Java SDK with Spring Boot integration, providing both [client](https://docs.spring.io/spring-ai/reference/api/mcp/mcp-client-boot-starter-docs.html) and [server](https://docs.spring.io/spring-ai/reference/api/mcp/mcp-server-boot-starter-docs.html) starters.
24-
The [MCP Annotations](https://docs.spring.io/spring-ai/reference/api/mcp/mcp-annotations-overview.html) - provides annotation-based method handling for MCP servers and clients in Java.
25-
The [MCP Security](https://docs.spring.io/spring-ai/reference/api/mcp/mcp-security.html) - provides comprehensive OAuth 2.0 and API key-based security support for Model Context Protocol implementations in Spring AI.
23+
[Spring AI MCP](https://docs.spring.io/spring-ai/reference/2.0-SNAPSHOT/api/mcp/mcp-overview.html) extends the MCP Java SDK with Spring Boot integration, providing both [client](https://docs.spring.io/spring-ai/reference/2.0-SNAPSHOT/api/mcp/mcp-client-boot-starter-docs.html) and [server](https://docs.spring.io/spring-ai/reference/2.0-SNAPSHOT/api/mcp/mcp-server-boot-starter-docs.html) starters.
24+
The [MCP Annotations](https://docs.spring.io/spring-ai/reference/2.0-SNAPSHOT/api/mcp/mcp-annotations-overview.html) - provides annotation-based method handling for MCP servers and clients in Java.
25+
The [MCP Security](https://docs.spring.io/spring-ai/reference/2.0-SNAPSHOT/api/mcp/mcp-security.html) - provides comprehensive OAuth 2.0 and API key-based security support for Model Context Protocol implementations in Spring AI.
2626
Bootstrap your AI applications with MCP support using [Spring Initializer](https://start.spring.io).
2727

2828
## Development
@@ -143,7 +143,7 @@ MCP supports both clients (applications consuming MCP servers) and servers (appl
143143

144144
* **Why**: The JDK HttpClient is built-in, portable, and supports streaming responses. This keeps the default lightweight with no extra dependencies.
145145

146-
* **How we expose it**: MCP Client APIs are transport-agnostic. The core module ships with JDK HttpClient transport. Spring WebClient-based transport is available in [Spring AI](https://docs.spring.io/spring-ai/reference/api/mcp/mcp-overview.html) 2.0+.
146+
* **How we expose it**: MCP Client APIs are transport-agnostic. The core module ships with JDK HttpClient transport. Spring WebClient-based transport is available in [Spring AI](https://docs.spring.io/spring-ai/reference/2.0-SNAPSHOT/api/mcp/mcp-overview.html) 2.0+.
147147

148148
* **How it fits the SDK**: This ensures all applications can talk to MCP servers out of the box, while allowing richer integration in Spring and other environments.
149149

@@ -153,7 +153,7 @@ MCP supports both clients (applications consuming MCP servers) and servers (appl
153153

154154
* **Why**: Servlet is the most widely deployed Java server API, providing broad reach across blocking and non-blocking models without additional dependencies.
155155

156-
* **How we expose it**: Server APIs are transport-agnostic. Core includes Servlet support. Spring WebFlux and WebMVC server transports are available in [Spring AI](https://docs.spring.io/spring-ai/reference/api/mcp/mcp-overview.html) 2.0+.
156+
* **How we expose it**: Server APIs are transport-agnostic. Core includes Servlet support. Spring WebFlux and WebMVC server transports are available in [Spring AI](https://docs.spring.io/spring-ai/reference/2.0-SNAPSHOT/api/mcp/mcp-overview.html) 2.0+.
157157

158158
* **How it fits the SDK**: This allows developers to expose MCP servers in the most common Java environments today, while enabling other transport implementations such as Netty, Vert.x, or Helidon.
159159

@@ -177,7 +177,7 @@ The SDK is organized into modules to separate concerns and allow adopters to bri
177177
* `mcp` – Convenience bundle (core + Jackson 3)
178178
* `mcp-test` – Shared testing utilities
179179

180-
Spring integrations (WebClient, WebFlux, WebMVC) are now part of [Spring AI](https://docs.spring.io/spring-ai/reference/api/mcp/mcp-overview.html) 2.0+ (group `org.springframework.ai`).
180+
Spring integrations (WebClient, WebFlux, WebMVC) are now part of [Spring AI](https://docs.spring.io/spring-ai/reference/2.0-SNAPSHOT/api/mcp/mcp-overview.html) 2.0+ (group `org.springframework.ai`).
181181

182182
For example, a minimal adopter may depend only on `mcp` (core + Jackson), while a Spring-based application can use the Spring AI `mcp-spring-webflux` or `mcp-spring-webmvc` artifacts for deeper framework integration.
183183

docs/blog/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
# Blog
1+
# News

docs/blog/posts/spring-transport-migration.md

Lines changed: 0 additions & 69 deletions
This file was deleted.

docs/client.md

Lines changed: 191 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ The MCP Client is a key component in the Model Context Protocol (MCP) architectu
1919
!!! tip
2020
The core `io.modelcontextprotocol.sdk:mcp` module provides STDIO, SSE, and Streamable HTTP client transport implementations without requiring external web frameworks.
2121

22-
The Spring-specific WebFlux transport (`mcp-spring-webflux`) is now part of [Spring AI](https://docs.spring.io/spring-ai/reference/api/mcp/mcp-overview.html) 2.0+ (group `org.springframework.ai`) and is no longer shipped by this SDK.
23-
See the [MCP Client Boot Starter](https://docs.spring.io/spring-ai/reference/api/mcp/mcp-client-boot-starter-docs.html) documentation for Spring-based client setup.
22+
The Spring-specific WebFlux transport (`mcp-spring-webflux`) is now part of [Spring AI](https://docs.spring.io/spring-ai/reference/2.0-SNAPSHOT/api/mcp/mcp-overview.html) 2.0+ (group `org.springframework.ai`) and is no longer shipped by this SDK.
23+
See the [MCP Client Boot Starter](https://docs.spring.io/spring-ai/reference/2.0-SNAPSHOT/api/mcp/mcp-client-boot-starter-docs.html) documentation for Spring-based client setup.
2424

2525
The client provides both synchronous and asynchronous APIs for flexibility in different application contexts.
2626

@@ -136,26 +136,20 @@ The client provides both synchronous and asynchronous APIs for flexibility in di
136136

137137
The transport layer handles the communication between MCP clients and servers, providing different implementations for various use cases. The client transport manages message serialization, connection establishment, and protocol-specific communication patterns.
138138

139-
=== "STDIO"
139+
### STDIO
140140

141-
Creates transport for process-based communication using stdin/stdout:
141+
Creates transport for process-based communication using stdin/stdout:
142142

143-
```java
144-
ServerParameters params = ServerParameters.builder("npx")
145-
.args("-y", "@modelcontextprotocol/server-everything", "dir")
146-
.build();
147-
McpTransport transport = new StdioClientTransport(params);
148-
```
149-
150-
=== "SSE (HttpClient)"
151-
152-
Creates a framework-agnostic (pure Java API) SSE client transport. Included in the core `mcp` module:
143+
```java
144+
ServerParameters params = ServerParameters.builder("npx")
145+
.args("-y", "@modelcontextprotocol/server-everything", "dir")
146+
.build();
147+
McpTransport transport = new StdioClientTransport(params);
148+
```
153149

154-
```java
155-
McpTransport transport = new HttpClientSseClientTransport("http://your-mcp-server");
156-
```
150+
### Streamable HTTP
157151

158-
=== "Streamable HTTP"
152+
=== "Streamable HttpClient"
159153

160154
Creates a Streamable HTTP client transport for efficient bidirectional communication. Included in the core `mcp` module:
161155

@@ -173,16 +167,36 @@ The transport layer handles the communication between MCP clients and servers, p
173167
- Custom HTTP request customization
174168
- Multiple protocol version negotiation
175169

176-
=== "SSE (WebFlux)"
170+
=== "Streamable WebClient (external)"
171+
172+
Creates Streamable HTTP WebClient-based client transport. Requires the `mcp-spring-webflux` dependency from [Spring AI](https://docs.spring.io/spring-ai/reference/2.0-SNAPSHOT/api/mcp/mcp-overview.html) 2.0+ (group `org.springframework.ai`):
173+
174+
```java
175+
McpTransport transport = WebFluxSseClientTransport
176+
.builder(WebClient.builder().baseUrl("http://your-mcp-server"))
177+
.build();
178+
```
179+
180+
### SSE HTTP (Legacy)
177181

178-
Creates WebFlux-based SSE client transport. Requires the `mcp-spring-webflux` dependency from [Spring AI](https://docs.spring.io/spring-ai/reference/api/mcp/mcp-overview.html) 2.0+ (group `org.springframework.ai`):
182+
=== "SSE HttpClient"
183+
184+
Creates a framework-agnostic (pure Java API) SSE client transport. Included in the core `mcp` module:
185+
186+
```java
187+
McpTransport transport = new HttpClientSseClientTransport("http://your-mcp-server");
188+
```
189+
=== "SSE WebClient (external)"
190+
191+
Creates WebFlux-based SSE client transport. Requires the `mcp-spring-webflux` dependency from [Spring AI](https://docs.spring.io/spring-ai/reference/2.0-SNAPSHOT/api/mcp/mcp-overview.html) 2.0+ (group `org.springframework.ai`):
179192

180193
```java
181194
WebClient.Builder webClientBuilder = WebClient.builder()
182195
.baseUrl("http://your-mcp-server");
183196
McpTransport transport = new WebFluxSseClientTransport(webClientBuilder);
184197
```
185198

199+
186200
## Client Capabilities
187201

188202
The client can be configured with various capabilities:
@@ -423,3 +437,160 @@ The prompt system enables interaction with server-side prompt templates. These t
423437
client.getPrompt(new GetPromptRequest("greeting", Map.of("name", "World")))
424438
.subscribe();
425439
```
440+
441+
## MCP Security
442+
443+
The [MCP Security](https://github.com/spring-ai-community/mcp-security) community library provides OAuth 2.0 authorization support for Spring AI MCP clients. It supports both `HttpClient`-based and `WebClient`-based (WebFlux) MCP clients used with the [Spring AI MCP Client Boot Starter](https://docs.spring.io/spring-ai/reference/2.0-SNAPSHOT/api/mcp/mcp-client-boot-starter-docs.html).
444+
445+
!!! note
446+
This is a community project (`org.springaicommunity`), not officially part of the MCP Java SDK. It requires Spring AI 2.0.x (`mcp-client-security` version 0.1.x). For Spring AI 1.1.x, use version 0.0.6.
447+
448+
### Add Dependency
449+
450+
=== "Maven"
451+
452+
```xml
453+
<dependency>
454+
<groupId>org.springaicommunity</groupId>
455+
<artifactId>mcp-client-security</artifactId>
456+
<version>0.1.1</version>
457+
</dependency>
458+
```
459+
460+
=== "Gradle"
461+
462+
```groovy
463+
implementation("org.springaicommunity:mcp-client-security:0.1.1")
464+
```
465+
466+
### Authorization Flows
467+
468+
Three OAuth 2.0 flows are available:
469+
470+
- **Authorization Code** — For user-present scenarios. The client sends requests with a bearer token on behalf of the user. Use `OAuth2AuthorizationCodeSyncHttpRequestCustomizer` (HttpClient) or `McpOAuth2AuthorizationCodeExchangeFilterFunction` (WebClient).
471+
- **Client Credentials** — For machine-to-machine communication without a user in the loop. Use `OAuth2ClientCredentialsSyncHttpRequestCustomizer` (HttpClient) or `McpOAuth2ClientCredentialsExchangeFilterFunction` (WebClient).
472+
- **Hybrid** — For mixed scenarios where some calls (e.g., `tools/list` on startup) use client credentials, while user-specific calls (e.g., `tools/call`) use authorization code tokens. Use `OAuth2HybridSyncHttpRequestCustomizer` (HttpClient) or `McpOAuth2HybridExchangeFilterFunction` (WebClient).
473+
474+
!!! tip
475+
Use the **Hybrid** flow when Spring AI's autoconfiguration initializes MCP clients on startup (listing tools before a user is present), but tool calls are user-authenticated.
476+
477+
### Setup
478+
479+
Add the following to `application.properties`:
480+
481+
```properties
482+
# Ensure MCP clients are sync
483+
spring.ai.mcp.client.type=SYNC
484+
# Disable auto-initialization (most MCP servers require authentication on every request)
485+
spring.ai.mcp.client.initialized=false
486+
487+
# Authorization Code client registration (for user-present flows)
488+
spring.security.oauth2.client.registration.authserver.client-id=<CLIENT_ID>
489+
spring.security.oauth2.client.registration.authserver.client-secret=<CLIENT_SECRET>
490+
spring.security.oauth2.client.registration.authserver.authorization-grant-type=authorization_code
491+
spring.security.oauth2.client.registration.authserver.provider=authserver
492+
493+
# Client Credentials registration (for machine-to-machine or hybrid flows)
494+
spring.security.oauth2.client.registration.authserver-client-credentials.client-id=<CLIENT_ID>
495+
spring.security.oauth2.client.registration.authserver-client-credentials.client-secret=<CLIENT_SECRET>
496+
spring.security.oauth2.client.registration.authserver-client-credentials.authorization-grant-type=client_credentials
497+
spring.security.oauth2.client.registration.authserver-client-credentials.provider=authserver
498+
499+
# Authorization server issuer URI
500+
spring.security.oauth2.client.provider.authserver.issuer-uri=<ISSUER_URI>
501+
```
502+
503+
Then activate OAuth2 client support in a security configuration class:
504+
505+
```java
506+
@Configuration
507+
@EnableWebSecurity
508+
class SecurityConfiguration {
509+
510+
@Bean
511+
SecurityFilterChain securityFilterChain(HttpSecurity http) {
512+
return http
513+
.authorizeHttpRequests(auth -> auth.anyRequest().permitAll())
514+
.oauth2Client(Customizer.withDefaults())
515+
.build();
516+
}
517+
}
518+
```
519+
520+
### HttpClient-Based Client
521+
522+
When using `spring-ai-starter-mcp-client`, the transport is backed by the JDK's `HttpClient`. Expose a `McpSyncHttpClientRequestCustomizer` bean and an `AuthenticationMcpTransportContextProvider` on the client:
523+
524+
```java
525+
@Configuration
526+
class McpConfiguration {
527+
528+
@Bean
529+
McpSyncClientCustomizer syncClientCustomizer() {
530+
return (name, syncSpec) ->
531+
syncSpec.transportContextProvider(
532+
new AuthenticationMcpTransportContextProvider()
533+
);
534+
}
535+
536+
@Bean
537+
McpSyncHttpClientRequestCustomizer requestCustomizer(
538+
OAuth2AuthorizedClientManager clientManager
539+
) {
540+
// "authserver" must match the registration name in application.properties
541+
return new OAuth2AuthorizationCodeSyncHttpRequestCustomizer(
542+
clientManager,
543+
"authserver"
544+
);
545+
}
546+
}
547+
```
548+
549+
Replace `OAuth2AuthorizationCodeSyncHttpRequestCustomizer` with `OAuth2ClientCredentialsSyncHttpRequestCustomizer` or `OAuth2HybridSyncHttpRequestCustomizer` for the corresponding flow.
550+
551+
### WebClient-Based Client
552+
553+
When using `spring-ai-starter-mcp-client-webflux`, the transport is backed by Spring's reactive `WebClient`. Expose a `WebClient.Builder` bean configured with an `ExchangeFilterFunction`:
554+
555+
```java
556+
@Configuration
557+
class McpConfiguration {
558+
559+
@Bean
560+
McpSyncClientCustomizer syncClientCustomizer() {
561+
return (name, syncSpec) ->
562+
syncSpec.transportContextProvider(
563+
new AuthenticationMcpTransportContextProvider()
564+
);
565+
}
566+
567+
@Bean
568+
WebClient.Builder mcpWebClientBuilder(OAuth2AuthorizedClientManager clientManager) {
569+
// "authserver" must match the registration name in application.properties
570+
return WebClient.builder().filter(
571+
new McpOAuth2AuthorizationCodeExchangeFilterFunction(
572+
clientManager,
573+
"authserver"
574+
)
575+
);
576+
}
577+
}
578+
```
579+
580+
Replace `McpOAuth2AuthorizationCodeExchangeFilterFunction` with `McpOAuth2ClientCredentialsExchangeFilterFunction` or `McpOAuth2HybridExchangeFilterFunction` for the corresponding flow.
581+
582+
When using the chat client's `.stream()` method, Reactor does not preserve thread-locals. Inject the authentication into the Reactor context manually:
583+
584+
```java
585+
chatClient
586+
.prompt("<your prompt>")
587+
.stream()
588+
.content()
589+
.contextWrite(AuthenticationMcpTransportContextProvider.writeToReactorContext());
590+
```
591+
592+
### Known Limitations
593+
594+
- Only `McpSyncClient` is supported; async clients are not.
595+
- Set `spring.ai.mcp.client.initialized=false` when servers require authentication on every request, as Spring AI autoconfiguration will otherwise attempt to list tools on startup without a token.
596+
- The SSE transport is supported by the client module (unlike the server module).

0 commit comments

Comments
 (0)