1717package org .springframework .ai .model .tool .autoconfigure ;
1818
1919import java .util .ArrayList ;
20- import java .util .Arrays ;
2120import java .util .List ;
2221
2322import io .micrometer .observation .ObservationRegistry ;
3635import org .springframework .ai .tool .resolution .SpringBeanToolCallbackResolver ;
3736import org .springframework .ai .tool .resolution .StaticToolCallbackResolver ;
3837import org .springframework .ai .tool .resolution .ToolCallbackResolver ;
39- import org .springframework .beans .BeansException ;
4038import org .springframework .beans .factory .ObjectProvider ;
41- import org .springframework .beans .factory .annotation .Qualifier ;
42- import org .springframework .beans .factory .config .BeanDefinition ;
43- import org .springframework .beans .factory .support .BeanDefinitionBuilder ;
44- import org .springframework .beans .factory .support .BeanDefinitionRegistry ;
45- import org .springframework .beans .factory .support .BeanDefinitionRegistryPostProcessor ;
46- import org .springframework .beans .factory .support .DefaultListableBeanFactory ;
4739import org .springframework .boot .autoconfigure .AutoConfiguration ;
4840import org .springframework .boot .autoconfigure .condition .ConditionalOnClass ;
4941import org .springframework .boot .autoconfigure .condition .ConditionalOnMissingBean ;
6052 * @author Thomas Vitale
6153 * @author Christian Tzolov
6254 * @author Daniel Garnier-Moiroux
55+ * @author Yanming Zhou
6356 * @since 1.0.0
6457 */
6558@ AutoConfiguration
6659@ ConditionalOnClass (ChatModel .class )
6760@ EnableConfigurationProperties (ToolCallingProperties .class )
68- public class ToolCallingAutoConfiguration implements BeanDefinitionRegistryPostProcessor {
61+ public class ToolCallingAutoConfiguration {
6962
7063 private static final Logger logger = LoggerFactory .getLogger (ToolCallingAutoConfiguration .class );
7164
72- // Marker qualifier to exclude MCP-related ToolCallbackProviders
73- private static final String EXCLUDE_MCP_TOOL_CALLBACK_PROVIDER = "org.springframework.ai.model.tool.autoconfigure.ToolCallingAutoConfiguration.toolcallbackprovider.mcp-excluded" ;
74-
7565 /**
7666 * The default {@link ToolCallbackResolver} resolves tools by name for methods,
7767 * functions, and {@link ToolCallbackProvider} beans.
@@ -83,11 +73,10 @@ public class ToolCallingAutoConfiguration implements BeanDefinitionRegistryPostP
8373 @ Bean
8474 @ ConditionalOnMissingBean
8575 ToolCallbackResolver toolCallbackResolver (GenericApplicationContext applicationContext ,
86- List <ToolCallback > toolCallbacks ,
87- @ Qualifier ( EXCLUDE_MCP_TOOL_CALLBACK_PROVIDER ) List < ToolCallbackProvider > tcbProviders ) {
76+ List <ToolCallback > toolCallbacks , ObjectProvider < ToolCallbackProvider > tcbProviders ) {
77+
8878 List <ToolCallback > allFunctionAndToolCallbacks = new ArrayList <>(toolCallbacks );
89- tcbProviders .stream ()
90- .filter (pr -> !isMcpToolCallbackProvider (ResolvableType .forInstance (pr )))
79+ tcbProviders .stream (clazz -> !isMcpToolCallbackProvider (ResolvableType .forClass (clazz )))
9180 .map (pr -> List .of (pr .getToolCallbacks ()))
9281 .forEach (allFunctionAndToolCallbacks ::addAll );
9382
@@ -100,41 +89,6 @@ ToolCallbackResolver toolCallbackResolver(GenericApplicationContext applicationC
10089 return new DelegatingToolCallbackResolver (List .of (staticToolCallbackResolver , springBeanToolCallbackResolver ));
10190 }
10291
103- /**
104- * Wrap {@link ToolCallbackProvider} beans that are not MCP-related into a named bean,
105- * which will be picked up by the
106- * {@link ToolCallingAutoConfiguration#toolCallbackResolver}.
107- * <p>
108- * MCP providers must be excluded, because they may depend on a {@code ChatClient} to
109- * do sampling. The chat client, in turn, depends on a {@link ToolCallbackResolver}.
110- * To do the detection, we depend on the exposed bean type. If a bean uses a factory
111- * method which returns a {@link ToolCallbackProvider}, which is an MCP provider under
112- * the hood, it will be included in the list.
113- */
114- @ Override
115- public void postProcessBeanDefinitionRegistry (BeanDefinitionRegistry registry ) throws BeansException {
116- if (!(registry instanceof DefaultListableBeanFactory beanFactory )) {
117- return ;
118- }
119-
120- var excludeMcpToolCallbackProviderBeanDefinition = BeanDefinitionBuilder
121- .genericBeanDefinition (List .class , () -> {
122- var providerNames = beanFactory .getBeanNamesForType (ToolCallbackProvider .class );
123- return Arrays .stream (providerNames )
124- .filter (name -> !isMcpToolCallbackProvider (beanFactory .getBeanDefinition (name ).getResolvableType ()))
125- .map (beanFactory ::getBean )
126- .filter (ToolCallbackProvider .class ::isInstance )
127- .map (ToolCallbackProvider .class ::cast )
128- .toList ();
129- })
130- .setScope (BeanDefinition .SCOPE_SINGLETON )
131- .setLazyInit (true )
132- .getBeanDefinition ();
133-
134- registry .registerBeanDefinition (EXCLUDE_MCP_TOOL_CALLBACK_PROVIDER ,
135- excludeMcpToolCallbackProviderBeanDefinition );
136- }
137-
13892 private static boolean isMcpToolCallbackProvider (ResolvableType type ) {
13993 if (type .getType ().getTypeName ().equals ("org.springframework.ai.mcp.SyncMcpToolCallbackProvider" )
14094 || type .getType ().getTypeName ().equals ("org.springframework.ai.mcp.AsyncMcpToolCallbackProvider" )) {
0 commit comments