Skip to content

Commit 24d9009

Browse files
committed
README: more documentation
Signed-off-by: Daniel Garnier-Moiroux <[email protected]>
1 parent a8bde5c commit 24d9009

File tree

1 file changed

+98
-11
lines changed

1 file changed

+98
-11
lines changed

README.md

Lines changed: 98 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,14 @@ To configure, import the dependency in your project.
3838

3939
// TODO: add import instructions for both maven and gradle
4040

41+
Ensure that MCP server is enabled in your `application.properties`:
42+
43+
```properties
44+
spring.ai.mcp.server.name=my-cool-mcp-server
45+
# Supported protocols: STREAMABLE, STATELESS
46+
spring.ai.mcp.server.protocol=STREAMABLE
47+
```
48+
4149
Then, configure the security for your project in the usual Spring-Security way, adding the provided configurer.
4250
Create a configuration class, and reference the authorization server's URI.
4351
In this example, we have set the authz server's issuer URI in the well known Spring property
@@ -148,8 +156,8 @@ public String greet(ToolContext toolContext) {
148156

149157
- The deprecated SSE transport is not supported.
150158
Use [Streamable HTTP](https://modelcontextprotocol.io/specification/2025-06-18/basic/transports#streamable-http)
151-
or [stateless](https://modelcontextprotocol.io/sdk/java/mcp-server#stateless-streamable-http-webmvc). (the link for
152-
stateless does not work out of the box, reload the page if required)
159+
or [stateless transport](https://modelcontextprotocol.io/sdk/java/mcp-server#stateless-streamable-http-webmvc). (the
160+
link for stateless does not work out of the box, reload the page if required)
153161
- WebFlux-based servers are not supported.
154162
- Opaque tokens are not supported. Please use JWT.
155163

@@ -182,37 +190,116 @@ For our MCP clients, there are three flows available for obtaining tokens:
182190

183191
🤔 Which flow should I use?
184192

193+
- If there are user-level permission, AND you know every MCP request will be made within the context of a user request
194+
(such as: adding tools manually in the GUI), then use the `authorization_code` flow, with either
195+
`OAuth2AuthorizationCodeSyncHttpRequestCustomizer` or `McpOAuth2AuthorizationCodeExchangeFilterFunction`.
185196
- If there are no user-level permissions, and you want to secure "client-to-server" communication with an access token,
186197
use the `client_credentials` flow, either with `OAuth2ClientCredentialsSyncHttpRequestCustomizer` or
187198
`McpOAuth2ClientCredentialsExchangeFilterFunction`.
188199
- If there are user-level permission, AND you configure your MCP clients using Spring Boot properties (such as
189200
`spring.ai.mcp.client.streamable-http.connections.<server-name>.url=<server-url>`), then, on application startup,
190201
Spring AI will try to list the tools. And startup happens without a user present. In that specific case, use a hybrid
191202
flow, with either `OAuth2HybridSyncHttpRequestCustomizer` or `McpOAuth2HybridExchangeFilterFunction`.
192-
- If there are user-level permission, AND you know every MCP request will be made within the context of a user request
193-
(such as: adding tools manually in the GUI), then use the `authorization_code` flow, with either
194-
`OAuth2AuthorizationCodeSyncHttpRequestCustomizer` or `McpOAuth2AuthorizationCodeExchangeFilterFunction`.
195-
- If, in your server, only the tool calls are secured, and all tool calls
196203

197204
### Setup for all use-cases
198205

199206
In very case, you need to activate Spring Security's OAuth2 client support.
207+
Add the following properties to your `application.properties` file.
208+
Depending on the flow you chose (see above), you may need one or both client registrations:
200209

201210
```properties
202-
# TODO
211+
# Ensure MCP clients are sync
212+
spring.ai.mcp.client.type=SYNC
213+
#
214+
#
215+
# For obtaining tokens for calling the tool
216+
# When using the hybrid flow or authorization_code flow, this registers a client
217+
# called "authserver". If using client_credentials, do not include this:
218+
spring.security.oauth2.client.registration.authserver.client-id=<THE CLIENT ID>
219+
spring.security.oauth2.client.registration.authserver.client-secret=<THE CLIENT SECRET>
220+
spring.security.oauth2.client.registration.authserver.authorization-grant-type=authorization_code
221+
spring.security.oauth2.client.registration.authserver.provider=authserver
222+
#
223+
# When using the hybrid flow or client_credentials flow, this registers a client
224+
# called "authserver-client-credentials". If using authorization_code, do not include this:
225+
spring.security.oauth2.client.registration.authserver-client-credentials.client-id=<THE CLIENT ID>
226+
spring.security.oauth2.client.registration.authserver-client-credentials.client-secret=<THE CLIENT SECRET>
227+
spring.security.oauth2.client.registration.authserver-client-credentials.authorization-grant-type=client_credentials
228+
spring.security.oauth2.client.registration.authserver-client-credentials.provider=authserver
229+
#
230+
# Both clients above rely on the authorization server, specified by its issuer URI:
231+
spring.security.oauth2.client.provider.authserver.issuer-uri=<THE ISSUER URI OF YOUR AUTH SERVER>
203232
```
204233

234+
Then, create a configuration class, activating the OAuth2 client capabilities with a `SecurityFilterChain`.
235+
236+
```java
237+
238+
@Configuration
239+
@EnableWebSecurity
240+
class SecurityConfiguration {
241+
242+
@Bean
243+
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
244+
return http
245+
// in this example, the client app has no security on its endpoints
246+
.authorizeHttpRequests(auth -> auth.anyRequest().permitAll())
247+
// turn on OAuth2 support
248+
.oauth2Client(Customizer.withDefaults())
249+
.build();
250+
}
251+
252+
}
253+
```
254+
255+
If you already have a filter chain configured, ensure that `.oauth2Client(...)` is on.
256+
205257
### Use with `spring-ai-starter-mcp-client`
206258

207-
Then, configure the security for your project in the usual Spring-Security way, adding the provided configurer.
208-
Create a configuration class, and reference the authorization server's URI.
209-
In this example, we have set the authz server's issuer URI in the well known Spring property
210-
`spring.security.oauth2.resourceserver.jwt.issuer-uri`. This property is not a requirement.
259+
When using `spring-ai-starter-mcp-client`, the underlying MCP client transport will be based on the Java SDK's
260+
`HttpClient`.
261+
In that case, you can expose a bean of type `McpSyncHttpClientRequestCustomizer`.
262+
Depending on your [authorization flow](#authorization-flows) of choice, you may use one of the following
263+
implementations:
264+
265+
- `OAuth2AuthorizationCodeSyncHttpRequestCustomizer` (preferred)
266+
- `OAuth2ClientCredentialsSyncHttpRequestCustomizer` (machine-to-machine)
267+
- `OAuth2HybridSyncHttpRequestCustomizer` (last resort)
268+
269+
All these request customizers rely on request and authentication data.
270+
That data is passed through
271+
`McpTransportContext` ([MCP docs](https://modelcontextprotocol.io/sdk/java/mcp-client#adding-context-information)).
272+
To make that information available, you also need to add an `AuthenticationMcpTransportContextProvider` to your MCP Sync
273+
Client.
274+
Tying it all together:
275+
276+
```java
277+
278+
@Configuration
279+
class McpConfiguration {
280+
281+
@Bean
282+
McpSyncClientCustomizer syncClientCustomizer() {
283+
return (name, syncSpec) -> syncSpec.transportContextProvider(new AuthenticationMcpTransportContextProvider());
284+
}
285+
286+
@Bean
287+
McpSyncHttpClientRequestCustomizer requestCustomizer(
288+
OAuth2AuthorizedClientManager oAuth2AuthorizedClientManager,
289+
ClientRegistrationRepository clientRegistrationRepository) {
290+
// The clientRegistration name, "authserver", must match the name in application.properties
291+
return new OAuth2AuthorizationCodeSyncHttpRequestCustomizer(oAuth2AuthorizedClientManager, "authserver");
292+
}
293+
294+
}
295+
```
211296

212297
### Known limitations
213298

214299
TODO
215300

301+
- Mention Tool confusion on initialization
302+
216303
## Authorization Server
217304

218305
TODO

0 commit comments

Comments
 (0)