Skip to content

Commit de4a454

Browse files
committed
samples: remove hacks around client eager initialization
Signed-off-by: Daniel Garnier-Moiroux <[email protected]>
1 parent c786a6a commit de4a454

File tree

4 files changed

+6
-88
lines changed

4 files changed

+6
-88
lines changed

README.md

Lines changed: 5 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,8 @@ Depending on the flow you chose (see above), you may need one or both client reg
370370
```properties
371371
# Ensure MCP clients are sync
372372
spring.ai.mcp.client.type=SYNC
373+
# Ensure that you do not initialize the clients on startup
374+
spring.ai.mcp.client.initialized=false
373375
#
374376
#
375377
# For obtaining tokens for calling the tool
@@ -619,41 +621,9 @@ class McpConfiguration {
619621
}
620622
```
621623

622-
### Work around Spring AI autoconfiguration
624+
### Programmatically configure MCP clients
623625

624-
Spring AI integrates MCP tools as if they were regular "tools" (e.g. `@Tool` methods).
625-
As such, they are discovered when application starts up.
626-
This means that any MCP client that is configured through configuration properties, such
627-
as `spring.ai.mcp.client.streamable-http.connections.<SERVER-NAME>.url=...` will be initialized.
628-
In practice, there will be multiple calls issued to the MCP Server (`initialize` followed by `tools/list`).
629-
The server will require a token for these calls, and, without a user present, this is an issue in the general case.
630-
631-
To avoid this, you first need to ensure that the clients are not initialized on startup.
632-
You can do so by setting the property `spring.ai.mcp.client.initialized=false`.
633-
Then, you need to ensure tools are not listed. There are a few ways to avoid this:
634-
635-
**Disable the @Tool auto-configuration**
636-
637-
You can turn off Spring AI's `@Tool` autoconfiguration altogether.
638-
This will disable all method and function-based tool calling, and only MCP tools will be available.
639-
The easiest way to do so is to publish an empty `ToolCallbackResolver` bean:
640-
641-
```java
642-
643-
@Configuration
644-
public class McpConfiguration {
645-
646-
@Bean
647-
ToolCallbackResolver resolver() {
648-
return new StaticToolCallbackResolver(List.of());
649-
}
650-
651-
}
652-
```
653-
654-
**Programmatically configure MCP clients**
655-
656-
You may also forego Spring AI's autoconfiguration altogether, and create the MCP clients programmatically.
626+
If you'd like to use Spring AI's autoconfiguration altogether, you can create the MCP clients programmatically.
657627
The easiest way is to draw some inspiration on the transport
658628
auto-configurations ([HttpClient](https://github.com/spring-projects/spring-ai/blob/main/auto-configurations/mcp/spring-ai-autoconfigure-mcp-client-httpclient/src/main/java/org/springframework/ai/mcp/client/httpclient/autoconfigure/StreamableHttpHttpClientTransportAutoConfiguration.java), [WebClient](https://github.com/spring-projects/spring-ai/blob/main/auto-configurations/mcp/spring-ai-autoconfigure-mcp-client-webflux/src/main/java/org/springframework/ai/mcp/client/webflux/autoconfigure/StreamableHttpWebFluxTransportAutoConfiguration.java))
659629
as well as
@@ -723,7 +693,7 @@ var chatResponse = chatClient.prompt("Prompt the LLM to _do the thing_")
723693
- Spring WebFlux servers are not supported.
724694
- Spring AI autoconfiguration initializes the MCP client app start.
725695
Most MCP servers want calls to be authenticated with a token, so you
726-
need to work around the Spring AI auto-config ([see the workaround above](#work-around-spring-ai-autoconfiguration))
696+
need to turn initialization off with `spring.ai.mcp.client.initialized=false`.
727697

728698
Note:
729699

samples/sample-mcp-client-webflux/src/main/java/org/springaicommunity/mcp/security/sample/client/McpConfiguration.java

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,10 @@
1616

1717
package org.springaicommunity.mcp.security.sample.client;
1818

19-
import java.util.List;
20-
2119
import org.springaicommunity.mcp.security.client.sync.AuthenticationMcpTransportContextProvider;
2220
import org.springaicommunity.mcp.security.client.sync.oauth2.webclient.McpOAuth2AuthorizationCodeExchangeFilterFunction;
2321

2422
import org.springframework.ai.mcp.customizer.McpSyncClientCustomizer;
25-
import org.springframework.ai.model.anthropic.autoconfigure.AnthropicChatAutoConfiguration;
26-
import org.springframework.ai.model.tool.autoconfigure.ToolCallingAutoConfiguration;
27-
import org.springframework.ai.tool.resolution.StaticToolCallbackResolver;
28-
import org.springframework.ai.tool.resolution.ToolCallbackResolver;
2923
import org.springframework.context.annotation.Bean;
3024
import org.springframework.context.annotation.Configuration;
3125
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager;
@@ -39,26 +33,6 @@
3933
@Configuration
4034
class McpConfiguration {
4135

42-
/**
43-
* If the default {@link ToolCallbackResolver} from
44-
* {@link ToolCallingAutoConfiguration} is imported, then all MCP-based tools are
45-
* added to the resolver. In order to do so, the {@link ToolCallbackResolver} bean
46-
* lists all MCP tools, therefore initializing MCP clients and listing the tools.
47-
* <p>
48-
* This is an issue when the MCP server is secured with OAuth2, because to obtain a
49-
* token, a user must be involved in the flow, and there is no user present on app
50-
* startup.
51-
* <p>
52-
* To avoid this issue, we must exclude the default {@link ToolCallbackResolver}. We
53-
* can't easily disable the entire {@link ToolCallingAutoConfiguration} class, because
54-
* it is imported directly by the chat model configurations, such as
55-
* {@link AnthropicChatAutoConfiguration}. Instead, we provide a default, no-op bean.
56-
*/
57-
@Bean
58-
ToolCallbackResolver resolver() {
59-
return new StaticToolCallbackResolver(List.of());
60-
}
61-
6236
@Bean
6337
McpSyncClientCustomizer syncClientCustomizer() {
6438
return (name, syncSpec) -> syncSpec.transportContextProvider(new AuthenticationMcpTransportContextProvider());

samples/sample-mcp-client/src/main/java/org/springaicommunity/mcp/security/sample/client/McpConfiguration.java

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,11 @@
1616

1717
package org.springaicommunity.mcp.security.sample.client;
1818

19-
import java.util.List;
20-
2119
import io.modelcontextprotocol.client.transport.customizer.McpSyncHttpClientRequestCustomizer;
2220
import org.springaicommunity.mcp.security.client.sync.AuthenticationMcpTransportContextProvider;
2321
import org.springaicommunity.mcp.security.client.sync.oauth2.http.client.OAuth2AuthorizationCodeSyncHttpRequestCustomizer;
2422

2523
import org.springframework.ai.mcp.customizer.McpSyncClientCustomizer;
26-
import org.springframework.ai.model.anthropic.autoconfigure.AnthropicChatAutoConfiguration;
27-
import org.springframework.ai.model.tool.autoconfigure.ToolCallingAutoConfiguration;
28-
import org.springframework.ai.tool.resolution.StaticToolCallbackResolver;
29-
import org.springframework.ai.tool.resolution.ToolCallbackResolver;
3024
import org.springframework.context.annotation.Bean;
3125
import org.springframework.context.annotation.Configuration;
3226
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager;
@@ -39,26 +33,6 @@
3933
@Configuration
4034
class McpConfiguration {
4135

42-
/**
43-
* If the default {@link ToolCallbackResolver} from
44-
* {@link ToolCallingAutoConfiguration} is imported, then all MCP-based tools are
45-
* added to the resolver. In order to do so, the {@link ToolCallbackResolver} bean
46-
* lists all MCP tools, therefore initializing MCP clients and listing the tools.
47-
* <p>
48-
* This is an issue when the MCP server is secured with OAuth2, because to obtain a
49-
* token, a user must be involved in the flow, and there is no user present on app
50-
* startup.
51-
* <p>
52-
* To avoid this issue, we must exclude the default {@link ToolCallbackResolver}. We
53-
* can't easily disable the entire {@link ToolCallingAutoConfiguration} class, because
54-
* it is imported directly by the chat model configurations, such as
55-
* {@link AnthropicChatAutoConfiguration}. Instead, we provide a default, no-op bean.
56-
*/
57-
@Bean
58-
ToolCallbackResolver resolver() {
59-
return new StaticToolCallbackResolver(List.of());
60-
}
61-
6236
@Bean
6337
McpSyncHttpClientRequestCustomizer requestCustomizer(OAuth2AuthorizedClientManager oAuth2AuthorizedClientManager,
6438
ClientRegistrationRepository clientRegistrationRepository) {

samples/sample-mcp-client/src/main/resources/application.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ spring.ai.anthropic.api-key=${ANTHROPIC_API_KEY}
55

66
spring.ai.mcp.client.streamable-http.connections.current-weather.url=http://localhost:8091
77
spring.ai.mcp.client.streamable-http.connections.historical-weather.url=http://localhost:8090
8-
spring.ai.mcp.client.initialized=false
98
spring.ai.mcp.client.type=SYNC
9+
spring.ai.mcp.client.initialized=false
1010

1111
# For obtaining tokens for calling the tool
1212
spring.security.oauth2.client.registration.authserver.client-id=default-client

0 commit comments

Comments
 (0)