This is an automated email from the ASF dual-hosted git repository.

fmariani pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git

commit ec4b2f6acbb91dbcca096805887a341b2a375376
Author: Croway <[email protected]>
AuthorDate: Wed Mar 11 14:53:40 2026 +0100

    CAMEL-23175: MCP support, Tool bean discovery, Tool context, 
StructuredOutputValidation, Tool selection by Name
---
 .../camel-spring-ai/camel-spring-ai-chat/pom.xml   |  14 ++
 .../chat/SpringAiChatEndpointConfigurer.java       |  50 ++++-
 .../chat/SpringAiChatEndpointUriFactory.java       |  13 +-
 .../component/springai/chat/spring-ai-chat.json    |  57 +++---
 .../src/main/docs/spring-ai-chat-component.adoc    | 228 +++++++++++++++++++++
 .../springai/chat/SpringAiChatConfiguration.java   | 128 ++++++++++++
 .../springai/chat/SpringAiChatConstants.java       |   8 +
 .../springai/chat/SpringAiChatProducer.java        |  89 ++++++++
 .../springai/chat/mcp/SpringAiChatMcpManager.java  | 186 +++++++++++++++++
 .../component/springai/chat/SpringAiChatMcpIT.java |  88 ++++++++
 .../springai/chat/SpringAiChatMcpSseIT.java        |  74 +++++++
 .../SpringAiChatStructuredOutputValidationIT.java  | 129 ++++++++++++
 .../chat/SpringAiChatToolBeanDiscoveryIT.java      | 119 +++++++++++
 .../springai/chat/SpringAiChatToolContextIT.java   | 105 ++++++++++
 .../src/main/docs/spring-ai-image-component.adoc   |   2 +-
 .../services/McpEverythingSseService.java          |  26 +++
 16 files changed, 1288 insertions(+), 28 deletions(-)

diff --git 
a/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-chat/pom.xml 
b/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-chat/pom.xml
index 4e8d6bd38885..f222fe2ce036 100644
--- 
a/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-chat/pom.xml
+++ 
b/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-chat/pom.xml
@@ -75,6 +75,13 @@
             <artifactId>spring-ai-advisors-vector-store</artifactId>
         </dependency>
 
+        <!-- Spring AI MCP integration for Model Context Protocol client 
support.
+             The MCP SDK is included transitively via spring-ai-mcp. -->
+        <dependency>
+            <groupId>org.springframework.ai</groupId>
+            <artifactId>spring-ai-mcp</artifactId>
+        </dependency>
+
         <!-- Test dependencies -->
         <dependency>
             <groupId>org.apache.camel</groupId>
@@ -110,6 +117,13 @@
             <version>${project.version}</version>
             <scope>test</scope>
         </dependency>
+        <!-- MCP Everything Server test infrastructure -->
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-test-infra-mcp-everything</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
 </project>
diff --git 
a/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-chat/src/generated/java/org/apache/camel/component/springai/chat/SpringAiChatEndpointConfigurer.java
 
b/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-chat/src/generated/java/org/apache/camel/component/springai/chat/SpringAiChatEndpointConfigurer.java
index 03254f1979bb..f73ad56a2006 100644
--- 
a/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-chat/src/generated/java/org/apache/camel/component/springai/chat/SpringAiChatEndpointConfigurer.java
+++ 
b/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-chat/src/generated/java/org/apache/camel/component/springai/chat/SpringAiChatEndpointConfigurer.java
@@ -42,6 +42,10 @@ public class SpringAiChatEndpointConfigurer extends 
PropertyConfigurerSupport im
         case "maxFileSize": 
target.getConfiguration().setMaxFileSize(property(camelContext, long.class, 
value)); return true;
         case "maxtokens":
         case "maxTokens": 
target.getConfiguration().setMaxTokens(property(camelContext, 
java.lang.Integer.class, value)); return true;
+        case "mcpserver":
+        case "mcpServer": 
target.getConfiguration().setMcpServer(property(camelContext, 
java.util.Map.class, value)); return true;
+        case "mcptimeout":
+        case "mcpTimeout": 
target.getConfiguration().setMcpTimeout(property(camelContext, int.class, 
value)); return true;
         case "outputclass":
         case "outputClass": 
target.getConfiguration().setOutputClass(property(camelContext, 
java.lang.Class.class, value)); return true;
         case "outputformat":
@@ -58,12 +62,22 @@ public class SpringAiChatEndpointConfigurer extends 
PropertyConfigurerSupport im
         case "similarityThreshold": 
target.getConfiguration().setSimilarityThreshold(property(camelContext, 
double.class, value)); return true;
         case "structuredoutputconverter":
         case "structuredOutputConverter": 
target.getConfiguration().setStructuredOutputConverter(property(camelContext, 
org.springframework.ai.converter.StructuredOutputConverter.class, value)); 
return true;
+        case "structuredoutputvalidation":
+        case "structuredOutputValidation": 
target.getConfiguration().setStructuredOutputValidation(property(camelContext, 
boolean.class, value)); return true;
+        case "structuredoutputvalidationmaxattempts":
+        case "structuredOutputValidationMaxAttempts": 
target.getConfiguration().setStructuredOutputValidationMaxAttempts(property(camelContext,
 int.class, value)); return true;
         case "systemmessage":
         case "systemMessage": 
target.getConfiguration().setSystemMessage(property(camelContext, 
java.lang.String.class, value)); return true;
         case "systemmetadata":
         case "systemMetadata": 
target.getConfiguration().setSystemMetadata(property(camelContext, 
java.util.Map.class, value)); return true;
         case "tags": target.getConfiguration().setTags(property(camelContext, 
java.lang.String.class, value)); return true;
         case "temperature": 
target.getConfiguration().setTemperature(property(camelContext, 
java.lang.Double.class, value)); return true;
+        case "toolcallbacks":
+        case "toolCallbacks": 
target.getConfiguration().setToolCallbacks(property(camelContext, 
java.util.List.class, value)); return true;
+        case "toolcontext":
+        case "toolContext": 
target.getConfiguration().setToolContext(property(camelContext, 
java.util.Map.class, value)); return true;
+        case "toolnames":
+        case "toolNames": 
target.getConfiguration().setToolNames(property(camelContext, 
java.lang.String.class, value)); return true;
         case "topk":
         case "topK": target.getConfiguration().setTopK(property(camelContext, 
int.class, value)); return true;
         case "topksampling":
@@ -82,7 +96,7 @@ public class SpringAiChatEndpointConfigurer extends 
PropertyConfigurerSupport im
 
     @Override
     public String[] getAutowiredNames() {
-        return new String[]{"chatClient", "chatMemory", "chatModel", 
"structuredOutputConverter", "vectorStore"};
+        return new String[]{"chatClient", "chatMemory", "chatModel", 
"structuredOutputConverter", "toolCallbacks", "vectorStore"};
     }
 
     @Override
@@ -107,6 +121,10 @@ public class SpringAiChatEndpointConfigurer extends 
PropertyConfigurerSupport im
         case "maxFileSize": return long.class;
         case "maxtokens":
         case "maxTokens": return java.lang.Integer.class;
+        case "mcpserver":
+        case "mcpServer": return java.util.Map.class;
+        case "mcptimeout":
+        case "mcpTimeout": return int.class;
         case "outputclass":
         case "outputClass": return java.lang.Class.class;
         case "outputformat":
@@ -123,12 +141,22 @@ public class SpringAiChatEndpointConfigurer extends 
PropertyConfigurerSupport im
         case "similarityThreshold": return double.class;
         case "structuredoutputconverter":
         case "structuredOutputConverter": return 
org.springframework.ai.converter.StructuredOutputConverter.class;
+        case "structuredoutputvalidation":
+        case "structuredOutputValidation": return boolean.class;
+        case "structuredoutputvalidationmaxattempts":
+        case "structuredOutputValidationMaxAttempts": return int.class;
         case "systemmessage":
         case "systemMessage": return java.lang.String.class;
         case "systemmetadata":
         case "systemMetadata": return java.util.Map.class;
         case "tags": return java.lang.String.class;
         case "temperature": return java.lang.Double.class;
+        case "toolcallbacks":
+        case "toolCallbacks": return java.util.List.class;
+        case "toolcontext":
+        case "toolContext": return java.util.Map.class;
+        case "toolnames":
+        case "toolNames": return java.lang.String.class;
         case "topk":
         case "topK": return int.class;
         case "topksampling":
@@ -168,6 +196,10 @@ public class SpringAiChatEndpointConfigurer extends 
PropertyConfigurerSupport im
         case "maxFileSize": return target.getConfiguration().getMaxFileSize();
         case "maxtokens":
         case "maxTokens": return target.getConfiguration().getMaxTokens();
+        case "mcpserver":
+        case "mcpServer": return target.getConfiguration().getMcpServer();
+        case "mcptimeout":
+        case "mcpTimeout": return target.getConfiguration().getMcpTimeout();
         case "outputclass":
         case "outputClass": return target.getConfiguration().getOutputClass();
         case "outputformat":
@@ -184,12 +216,22 @@ public class SpringAiChatEndpointConfigurer extends 
PropertyConfigurerSupport im
         case "similarityThreshold": return 
target.getConfiguration().getSimilarityThreshold();
         case "structuredoutputconverter":
         case "structuredOutputConverter": return 
target.getConfiguration().getStructuredOutputConverter();
+        case "structuredoutputvalidation":
+        case "structuredOutputValidation": return 
target.getConfiguration().isStructuredOutputValidation();
+        case "structuredoutputvalidationmaxattempts":
+        case "structuredOutputValidationMaxAttempts": return 
target.getConfiguration().getStructuredOutputValidationMaxAttempts();
         case "systemmessage":
         case "systemMessage": return 
target.getConfiguration().getSystemMessage();
         case "systemmetadata":
         case "systemMetadata": return 
target.getConfiguration().getSystemMetadata();
         case "tags": return target.getConfiguration().getTags();
         case "temperature": return target.getConfiguration().getTemperature();
+        case "toolcallbacks":
+        case "toolCallbacks": return 
target.getConfiguration().getToolCallbacks();
+        case "toolcontext":
+        case "toolContext": return target.getConfiguration().getToolContext();
+        case "toolnames":
+        case "toolNames": return target.getConfiguration().getToolNames();
         case "topk":
         case "topK": return target.getConfiguration().getTopK();
         case "topksampling":
@@ -212,12 +254,18 @@ public class SpringAiChatEndpointConfigurer extends 
PropertyConfigurerSupport im
         case "advisors": return 
org.springframework.ai.chat.client.advisor.api.Advisor.class;
         case "entityclass":
         case "entityClass": return java.lang.Object.class;
+        case "mcpserver":
+        case "mcpServer": return java.lang.Object.class;
         case "outputclass":
         case "outputClass": return java.lang.Object.class;
         case "structuredoutputconverter":
         case "structuredOutputConverter": return java.lang.Object.class;
         case "systemmetadata":
         case "systemMetadata": return java.lang.Object.class;
+        case "toolcallbacks":
+        case "toolCallbacks": return 
org.springframework.ai.tool.ToolCallback.class;
+        case "toolcontext":
+        case "toolContext": return java.lang.Object.class;
         case "usermetadata":
         case "userMetadata": return java.lang.Object.class;
         default: return null;
diff --git 
a/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-chat/src/generated/java/org/apache/camel/component/springai/chat/SpringAiChatEndpointUriFactory.java
 
b/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-chat/src/generated/java/org/apache/camel/component/springai/chat/SpringAiChatEndpointUriFactory.java
index 32ad0c2615d4..149cec1daf61 100644
--- 
a/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-chat/src/generated/java/org/apache/camel/component/springai/chat/SpringAiChatEndpointUriFactory.java
+++ 
b/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-chat/src/generated/java/org/apache/camel/component/springai/chat/SpringAiChatEndpointUriFactory.java
@@ -23,7 +23,7 @@ public class SpringAiChatEndpointUriFactory extends 
org.apache.camel.support.com
     private static final Set<String> SECRET_PROPERTY_NAMES;
     private static final Map<String, String> MULTI_VALUE_PREFIXES;
     static {
-        Set<String> props = new HashSet<>(29);
+        Set<String> props = new HashSet<>(36);
         props.add("advisors");
         props.add("chatClient");
         props.add("chatId");
@@ -35,6 +35,8 @@ public class SpringAiChatEndpointUriFactory extends 
org.apache.camel.support.com
         props.add("lazyStartProducer");
         props.add("maxFileSize");
         props.add("maxTokens");
+        props.add("mcpServer");
+        props.add("mcpTimeout");
         props.add("outputClass");
         props.add("outputFormat");
         props.add("ragTemplate");
@@ -43,10 +45,15 @@ public class SpringAiChatEndpointUriFactory extends 
org.apache.camel.support.com
         props.add("safeguardSensitiveWords");
         props.add("similarityThreshold");
         props.add("structuredOutputConverter");
+        props.add("structuredOutputValidation");
+        props.add("structuredOutputValidationMaxAttempts");
         props.add("systemMessage");
         props.add("systemMetadata");
         props.add("tags");
         props.add("temperature");
+        props.add("toolCallbacks");
+        props.add("toolContext");
+        props.add("toolNames");
         props.add("topK");
         props.add("topKSampling");
         props.add("topP");
@@ -55,7 +62,9 @@ public class SpringAiChatEndpointUriFactory extends 
org.apache.camel.support.com
         props.add("vectorStore");
         PROPERTY_NAMES = Collections.unmodifiableSet(props);
         SECRET_PROPERTY_NAMES = Collections.emptySet();
-        MULTI_VALUE_PREFIXES = Collections.emptyMap();
+        Map<String, String> prefixes = new HashMap<>(1);
+        prefixes.put("mcpServer", "mcpServer.");
+        MULTI_VALUE_PREFIXES = Collections.unmodifiableMap(prefixes);
     }
 
     @Override
diff --git 
a/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-chat/src/generated/resources/META-INF/org/apache/camel/component/springai/chat/spring-ai-chat.json
 
b/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-chat/src/generated/resources/META-INF/org/apache/camel/component/springai/chat/spring-ai-chat.json
index 590077c9cdf5..0608321cf737 100644
--- 
a/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-chat/src/generated/resources/META-INF/org/apache/camel/component/springai/chat/spring-ai-chat.json
+++ 
b/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-chat/src/generated/resources/META-INF/org/apache/camel/component/springai/chat/spring-ai-chat.json
@@ -58,7 +58,9 @@
     "CamelSpringAiChatFinishReason": { "index": 26, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "The reason why the chat response 
generation stopped (e.g., STOP, LENGTH, TOOL_CALLS)", "constantName": 
"org.apache.camel.component.springai.chat.SpringAiChatConstants#FINISH_REASON" 
},
     "CamelSpringAiChatModelName": { "index": 27, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "The name of the AI model used to 
generate the response", "constantName": 
"org.apache.camel.component.springai.chat.SpringAiChatConstants#MODEL_NAME" },
     "CamelSpringAiChatResponseId": { "index": 28, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "The unique ID of the chat response", 
"constantName": 
"org.apache.camel.component.springai.chat.SpringAiChatConstants#RESPONSE_ID" },
-    "CamelSpringAiChatResponseMetadata": { "index": 29, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "java.util.Map<String, Object>", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Full response metadata as a Map containing all available metadata fields", 
"constantName": 
"org.apache.camel.component.springai.chat.SpringAiChatConstants#RESPONSE_METADATA"
 }
+    "CamelSpringAiChatResponseMetadata": { "index": 29, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "java.util.Map<String, Object>", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Full response metadata as a Map containing all available metadata fields", 
"constantName": 
"org.apache.camel.component.springai.chat.SpringAiChatConstants#RESPONSE_METADATA"
 },
+    "CamelSpringAiChatToolNames": { "index": 30, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "Comma-separated tool names for 
selecting tools by name via ToolCallbackResolver", "constantName": 
"org.apache.camel.component.springai.chat.SpringAiChatConstants#TOOL_NAMES" },
+    "CamelSpringAiChatToolContext": { "index": 31, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "java.util.Map<String, Object>", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Context map to pass to tools during execution", "constantName": 
"org.apache.camel.component.springai.chat.SpringAiChatConstants#TOOL_CONTEXT" }
   },
   "properties": {
     "chatId": { "index": 0, "kind": "path", "displayName": "Chat Id", "group": 
"producer", "label": "", "required": false, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "autowired": false, "secret": false, 
"description": "The ID of the chat endpoint" },
@@ -67,28 +69,35 @@
     "chatOperation": { "index": 3, "kind": "parameter", "displayName": "Chat 
Operation", "group": "producer", "label": "", "required": true, "type": "enum", 
"javaType": "org.apache.camel.component.springai.chat.SpringAiChatOperations", 
"enum": [ "CHAT_SINGLE_MESSAGE", "CHAT_SINGLE_MESSAGE_WITH_PROMPT", 
"CHAT_MULTIPLE_MESSAGES" ], "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "defaultValue": "CHAT_SINGLE_MESSAGE", 
"configurationClass": "org.apache.camel. [...]
     "systemMessage": { "index": 4, "kind": "parameter", "displayName": "System 
Message", "group": "producer", "label": "", "required": false, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, "autowired": 
false, "secret": false, "configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "Default system message 
to set context for the conversation. Can be overridden by the CamelSprin [...]
     "tags": { "index": 5, "kind": "parameter", "displayName": "Tags", "group": 
"producer", "label": "", "required": false, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "autowired": false, "secret": false, 
"configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "Tags for discovering and 
calling Camel route tools" },
-    "userMessage": { "index": 6, "kind": "parameter", "displayName": "User 
Message", "group": "producer", "label": "", "required": false, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, "autowired": 
false, "secret": false, "configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "Default user message 
text for multimodal requests. Can be combined with media data in the message b 
[...]
-    "lazyStartProducer": { "index": 7, "kind": "parameter", "displayName": 
"Lazy Start Producer", "group": "producer (advanced)", "label": 
"producer,advanced", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": false, "description": "Whether the producer should be started 
lazy (on the first message). By starting lazy you can use this to allow 
CamelContext and routes to startup in situations where a produc [...]
-    "advisors": { "index": 8, "kind": "parameter", "displayName": "Advisors", 
"group": "advanced", "label": "advanced", "required": false, "type": "array", 
"javaType": 
"java.util.List<org.springframework.ai.chat.client.advisor.api.Advisor>", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "List of custom advisor 
[...]
-    "chatMemory": { "index": 9, "kind": "parameter", "displayName": "Chat 
Memory", "group": "advanced", "label": "advanced", "required": false, "type": 
"object", "javaType": "org.springframework.ai.chat.memory.ChatMemory", 
"deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, 
"configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "ChatMemory instance for 
maintaining conver [...]
-    "chatMemoryVectorStore": { "index": 10, "kind": "parameter", 
"displayName": "Chat Memory Vector Store", "group": "advanced", "label": 
"advanced", "required": false, "type": "object", "javaType": 
"org.springframework.ai.vectorstore.VectorStore", "deprecated": false, 
"autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "VectorStore instance for 
maintaining c [...]
-    "entityClass": { "index": 11, "kind": "parameter", "displayName": "Entity 
Class", "group": "advanced", "label": "advanced", "required": false, "type": 
"string", "javaType": "java.lang.Class<java.lang.Object>", "deprecated": false, 
"autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "The Java class to use 
for entity response conversion using ChatClient.ent [...]
-    "maxFileSize": { "index": 12, "kind": "parameter", "displayName": "Max 
File Size", "group": "advanced", "label": "advanced", "required": false, 
"type": "integer", "javaType": "long", "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": 1048576, "configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "Maximum file size in 
bytes for multimodal content (images, audio, PDFs, etc [...]
-    "maxTokens": { "index": 13, "kind": "parameter", "displayName": "Max 
Tokens", "group": "advanced", "label": "advanced", "required": false, "type": 
"integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired": 
false, "secret": false, "configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "Maximum tokens in the 
response." },
-    "outputClass": { "index": 14, "kind": "parameter", "displayName": "Output 
Class", "group": "advanced", "label": "advanced", "required": false, "type": 
"string", "javaType": "java.lang.Class<java.lang.Object>", "deprecated": false, 
"autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "The Java class to use 
for BEAN output format conversion. Required when ou [...]
-    "outputFormat": { "index": 15, "kind": "parameter", "displayName": "Output 
Format", "group": "advanced", "label": "advanced", "required": false, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, "autowired": 
false, "secret": false, "configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "The output format for 
structured output conversion (BEAN, MAP, LIST). Used in conjunctio [...]
-    "structuredOutputConverter": { "index": 16, "kind": "parameter", 
"displayName": "Structured Output Converter", "group": "advanced", "label": 
"advanced", "required": false, "type": "object", "javaType": 
"org.springframework.ai.converter.StructuredOutputConverter<java.lang.Object>", 
"deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, 
"configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configurati [...]
-    "systemMetadata": { "index": 17, "kind": "parameter", "displayName": 
"System Metadata", "group": "advanced", "label": "advanced", "required": false, 
"type": "object", "javaType": "java.util.Map<java.lang.String, 
java.lang.Object>", "deprecated": false, "autowired": false, "secret": false, 
"configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "Metadata to attach to 
system messages. This metadat [...]
-    "temperature": { "index": 18, "kind": "parameter", "displayName": 
"Temperature", "group": "advanced", "label": "advanced", "required": false, 
"type": "number", "javaType": "java.lang.Double", "deprecated": false, 
"autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "Temperature parameter 
for response randomness (0.0-2.0)." },
-    "topKSampling": { "index": 19, "kind": "parameter", "displayName": "Top 
KSampling", "group": "advanced", "label": "advanced", "required": false, 
"type": "integer", "javaType": "java.lang.Integer", "deprecated": false, 
"autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "Top K parameter for 
sampling." },
-    "topP": { "index": 20, "kind": "parameter", "displayName": "Top P", 
"group": "advanced", "label": "advanced", "required": false, "type": "number", 
"javaType": "java.lang.Double", "deprecated": false, "autowired": false, 
"secret": false, "configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "Top P parameter for 
nucleus sampling." },
-    "userMetadata": { "index": 21, "kind": "parameter", "displayName": "User 
Metadata", "group": "advanced", "label": "advanced", "required": false, "type": 
"object", "javaType": "java.util.Map<java.lang.String, java.lang.Object>", 
"deprecated": false, "autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "Metadata to attach to 
user messages. This metadata can  [...]
-    "ragTemplate": { "index": 22, "kind": "parameter", "displayName": "Rag 
Template", "group": "rag", "label": "rag", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": "Context:\\n\\{context}\\n\\nQuestion: 
\\{question}", "configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "Template for formatting 
RAG (R [...]
-    "similarityThreshold": { "index": 23, "kind": "parameter", "displayName": 
"Similarity Threshold", "group": "rag", "label": "rag", "required": false, 
"type": "number", "javaType": "double", "deprecated": false, "autowired": 
false, "secret": false, "defaultValue": 0.7, "configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "Similarity threshold for 
RAG retrieval (default: 0.7)." },
-    "topK": { "index": 24, "kind": "parameter", "displayName": "Top K", 
"group": "rag", "label": "rag", "required": false, "type": "integer", 
"javaType": "int", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": 5, "configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "Number of top documents 
to retrieve for RAG (default: 5)." },
-    "vectorStore": { "index": 25, "kind": "parameter", "displayName": "Vector 
Store", "group": "rag", "label": "rag", "required": false, "type": "object", 
"javaType": "org.springframework.ai.vectorstore.VectorStore", "deprecated": 
false, "deprecationNote": "", "autowired": true, "secret": false, 
"configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "VectorStore for 
automatic RAG retrieval." },
-    "safeguardFailureResponse": { "index": 26, "kind": "parameter", 
"displayName": "Safeguard Failure Response", "group": "security", "label": 
"security", "required": false, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "autowired": false, "secret": false, 
"configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "Failure response message 
for SafeGuard advisor when sensitive c [...]
-    "safeguardSensitiveWords": { "index": 27, "kind": "parameter", 
"displayName": "Safeguard Sensitive Words", "group": "security", "label": 
"security", "required": false, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "autowired": false, "secret": false, 
"configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "Comma-separated list of 
sensitive words for SafeGuard advisor. Wh [...]
-    "safeguardOrder": { "index": 28, "kind": "parameter", "displayName": 
"Safeguard Order", "group": "security (advanced)", "label": 
"security,advanced", "required": false, "type": "integer", "javaType": 
"java.lang.Integer", "deprecated": false, "autowired": false, "secret": false, 
"configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "Order of execution for 
SafeGuard advisor. Lower numbers execut [...]
+    "toolNames": { "index": 6, "kind": "parameter", "displayName": "Tool 
Names", "group": "producer", "label": "", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": false, "configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "Comma-separated tool 
names for selecting tools by name via Spring AI's ToolCallbackResolver. This 
enabl [...]
+    "userMessage": { "index": 7, "kind": "parameter", "displayName": "User 
Message", "group": "producer", "label": "", "required": false, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, "autowired": 
false, "secret": false, "configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "Default user message 
text for multimodal requests. Can be combined with media data in the message b 
[...]
+    "lazyStartProducer": { "index": 8, "kind": "parameter", "displayName": 
"Lazy Start Producer", "group": "producer (advanced)", "label": 
"producer,advanced", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": false, "description": "Whether the producer should be started 
lazy (on the first message). By starting lazy you can use this to allow 
CamelContext and routes to startup in situations where a produc [...]
+    "advisors": { "index": 9, "kind": "parameter", "displayName": "Advisors", 
"group": "advanced", "label": "advanced", "required": false, "type": "array", 
"javaType": 
"java.util.List<org.springframework.ai.chat.client.advisor.api.Advisor>", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "List of custom advisor 
[...]
+    "chatMemory": { "index": 10, "kind": "parameter", "displayName": "Chat 
Memory", "group": "advanced", "label": "advanced", "required": false, "type": 
"object", "javaType": "org.springframework.ai.chat.memory.ChatMemory", 
"deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, 
"configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "ChatMemory instance for 
maintaining conve [...]
+    "chatMemoryVectorStore": { "index": 11, "kind": "parameter", 
"displayName": "Chat Memory Vector Store", "group": "advanced", "label": 
"advanced", "required": false, "type": "object", "javaType": 
"org.springframework.ai.vectorstore.VectorStore", "deprecated": false, 
"autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "VectorStore instance for 
maintaining c [...]
+    "entityClass": { "index": 12, "kind": "parameter", "displayName": "Entity 
Class", "group": "advanced", "label": "advanced", "required": false, "type": 
"string", "javaType": "java.lang.Class<java.lang.Object>", "deprecated": false, 
"autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "The Java class to use 
for entity response conversion using ChatClient.ent [...]
+    "maxFileSize": { "index": 13, "kind": "parameter", "displayName": "Max 
File Size", "group": "advanced", "label": "advanced", "required": false, 
"type": "integer", "javaType": "long", "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": 1048576, "configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "Maximum file size in 
bytes for multimodal content (images, audio, PDFs, etc [...]
+    "maxTokens": { "index": 14, "kind": "parameter", "displayName": "Max 
Tokens", "group": "advanced", "label": "advanced", "required": false, "type": 
"integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired": 
false, "secret": false, "configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "Maximum tokens in the 
response." },
+    "mcpServer": { "index": 15, "kind": "parameter", "displayName": "Mcp 
Server", "group": "advanced", "label": "advanced", "required": false, "type": 
"object", "javaType": "java.util.Map<java.lang.String, java.lang.Object>", 
"prefix": "mcpServer.", "multiValue": true, "deprecated": false, "autowired": 
false, "secret": false, "configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "MCP server config [...]
+    "mcpTimeout": { "index": 16, "kind": "parameter", "displayName": "Mcp 
Timeout", "group": "advanced", "label": "advanced", "required": false, "type": 
"integer", "javaType": "int", "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": 20, "configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "Timeout in seconds for 
MCP operations including tool execution and initialization" },
+    "outputClass": { "index": 17, "kind": "parameter", "displayName": "Output 
Class", "group": "advanced", "label": "advanced", "required": false, "type": 
"string", "javaType": "java.lang.Class<java.lang.Object>", "deprecated": false, 
"autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "The Java class to use 
for BEAN output format conversion. Required when ou [...]
+    "outputFormat": { "index": 18, "kind": "parameter", "displayName": "Output 
Format", "group": "advanced", "label": "advanced", "required": false, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, "autowired": 
false, "secret": false, "configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "The output format for 
structured output conversion (BEAN, MAP, LIST). Used in conjunctio [...]
+    "structuredOutputConverter": { "index": 19, "kind": "parameter", 
"displayName": "Structured Output Converter", "group": "advanced", "label": 
"advanced", "required": false, "type": "object", "javaType": 
"org.springframework.ai.converter.StructuredOutputConverter<java.lang.Object>", 
"deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, 
"configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configurati [...]
+    "structuredOutputValidation": { "index": 20, "kind": "parameter", 
"displayName": "Structured Output Validation", "group": "advanced", "label": 
"advanced", "required": false, "type": "boolean", "javaType": "boolean", 
"deprecated": false, "autowired": false, "secret": false, "defaultValue": 
false, "configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "Enable structured output 
validation with aut [...]
+    "structuredOutputValidationMaxAttempts": { "index": 21, "kind": 
"parameter", "displayName": "Structured Output Validation Max Attempts", 
"group": "advanced", "label": "advanced", "required": false, "type": "integer", 
"javaType": "int", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": 3, "configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "Maximum number of retry 
atte [...]
+    "systemMetadata": { "index": 22, "kind": "parameter", "displayName": 
"System Metadata", "group": "advanced", "label": "advanced", "required": false, 
"type": "object", "javaType": "java.util.Map<java.lang.String, 
java.lang.Object>", "deprecated": false, "autowired": false, "secret": false, 
"configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "Metadata to attach to 
system messages. This metadat [...]
+    "temperature": { "index": 23, "kind": "parameter", "displayName": 
"Temperature", "group": "advanced", "label": "advanced", "required": false, 
"type": "number", "javaType": "java.lang.Double", "deprecated": false, 
"autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "Temperature parameter 
for response randomness (0.0-2.0)." },
+    "toolCallbacks": { "index": 24, "kind": "parameter", "displayName": "Tool 
Callbacks", "group": "advanced", "label": "advanced", "required": false, 
"type": "array", "javaType": 
"java.util.List<org.springframework.ai.tool.ToolCallback>", "deprecated": 
false, "deprecationNote": "", "autowired": true, "secret": false, 
"configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "List of ToolCallback 
inst [...]
+    "toolContext": { "index": 25, "kind": "parameter", "displayName": "Tool 
Context", "group": "advanced", "label": "advanced", "required": false, "type": 
"object", "javaType": "java.util.Map<java.lang.String, java.lang.Object>", 
"deprecated": false, "autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "Context map to pass to 
tools during execution. Tool metho [...]
+    "topKSampling": { "index": 26, "kind": "parameter", "displayName": "Top 
KSampling", "group": "advanced", "label": "advanced", "required": false, 
"type": "integer", "javaType": "java.lang.Integer", "deprecated": false, 
"autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "Top K parameter for 
sampling." },
+    "topP": { "index": 27, "kind": "parameter", "displayName": "Top P", 
"group": "advanced", "label": "advanced", "required": false, "type": "number", 
"javaType": "java.lang.Double", "deprecated": false, "autowired": false, 
"secret": false, "configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "Top P parameter for 
nucleus sampling." },
+    "userMetadata": { "index": 28, "kind": "parameter", "displayName": "User 
Metadata", "group": "advanced", "label": "advanced", "required": false, "type": 
"object", "javaType": "java.util.Map<java.lang.String, java.lang.Object>", 
"deprecated": false, "autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "Metadata to attach to 
user messages. This metadata can  [...]
+    "ragTemplate": { "index": 29, "kind": "parameter", "displayName": "Rag 
Template", "group": "rag", "label": "rag", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": "Context:\\n\\{context}\\n\\nQuestion: 
\\{question}", "configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "Template for formatting 
RAG (R [...]
+    "similarityThreshold": { "index": 30, "kind": "parameter", "displayName": 
"Similarity Threshold", "group": "rag", "label": "rag", "required": false, 
"type": "number", "javaType": "double", "deprecated": false, "autowired": 
false, "secret": false, "defaultValue": 0.7, "configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "Similarity threshold for 
RAG retrieval (default: 0.7)." },
+    "topK": { "index": 31, "kind": "parameter", "displayName": "Top K", 
"group": "rag", "label": "rag", "required": false, "type": "integer", 
"javaType": "int", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": 5, "configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "Number of top documents 
to retrieve for RAG (default: 5)." },
+    "vectorStore": { "index": 32, "kind": "parameter", "displayName": "Vector 
Store", "group": "rag", "label": "rag", "required": false, "type": "object", 
"javaType": "org.springframework.ai.vectorstore.VectorStore", "deprecated": 
false, "deprecationNote": "", "autowired": true, "secret": false, 
"configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "VectorStore for 
automatic RAG retrieval." },
+    "safeguardFailureResponse": { "index": 33, "kind": "parameter", 
"displayName": "Safeguard Failure Response", "group": "security", "label": 
"security", "required": false, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "autowired": false, "secret": false, 
"configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "Failure response message 
for SafeGuard advisor when sensitive c [...]
+    "safeguardSensitiveWords": { "index": 34, "kind": "parameter", 
"displayName": "Safeguard Sensitive Words", "group": "security", "label": 
"security", "required": false, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "autowired": false, "secret": false, 
"configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "Comma-separated list of 
sensitive words for SafeGuard advisor. Wh [...]
+    "safeguardOrder": { "index": 35, "kind": "parameter", "displayName": 
"Safeguard Order", "group": "security (advanced)", "label": 
"security,advanced", "required": false, "type": "integer", "javaType": 
"java.lang.Integer", "deprecated": false, "autowired": false, "secret": false, 
"configurationClass": 
"org.apache.camel.component.springai.chat.SpringAiChatConfiguration", 
"configurationField": "configuration", "description": "Order of execution for 
SafeGuard advisor. Lower numbers execut [...]
   }
 }
diff --git 
a/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-chat/src/main/docs/spring-ai-chat-component.adoc
 
b/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-chat/src/main/docs/spring-ai-chat-component.adoc
index 2b15fd4cc9ee..6b3054cc229e 100644
--- 
a/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-chat/src/main/docs/spring-ai-chat-component.adoc
+++ 
b/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-chat/src/main/docs/spring-ai-chat-component.adoc
@@ -577,6 +577,233 @@ from("direct:chat")
 
 NOTE: Most users should use `ChatModel` and let the component handle 
`ChatClient` creation automatically. Only use this approach if you have 
specific requirements that cannot be met with standard configuration options.
 
+=== Spring @Tool Bean Discovery
+
+In addition to Camel route tools (via `tags`), you can use Spring AI 
`@Tool`-annotated beans directly.
+
+==== Camel Spring Boot (Recommended)
+
+When using Camel Spring Boot, Spring AI's auto-configuration automatically 
discovers `@Tool`-annotated
+methods from Spring beans via `ToolCallbackResolver`. Simply define your tool 
as a Spring bean and
+reference it by name using `toolNames`:
+
+[source,java]
+----
+@Component
+public class MyTools {
+
+    @Tool(description = "Get the capital city of a country", name = 
"getCapital")
+    public String getCapital(String country) {
+        return switch (country.toLowerCase()) {
+            case "france" -> "Paris";
+            case "germany" -> "Berlin";
+            case "italy" -> "Rome";
+            default -> "Unknown";
+        };
+    }
+}
+
+// In your route — no manual callback registration needed
+from("direct:chat")
+    .to("spring-ai-chat:chat?chatModel=#chatModel&toolNames=getCapital");
+----
+
+==== Without Spring Boot
+
+Outside Spring Boot (e.g., in plain Camel or tests), there is no 
`ToolCallbackResolver`.
+You need to resolve the callbacks manually and bind them in the registry:
+
+[source,java]
+----
+ToolCallbackProvider provider = MethodToolCallbackProvider.builder()
+    .toolObjects(new MyTools())
+    .build();
+context.getRegistry().bind("myTools", 
Arrays.asList(provider.getToolCallbacks()));
+
+from("direct:chat")
+    .to("spring-ai-chat:chat?chatModel=#chatModel&toolCallbacks=#myTools");
+----
+
+==== Tool Selection by Name
+
+Select specific tools by name using the `toolNames` parameter, instead of (or 
in addition to) tag-based discovery.
+This is useful for selecting individual `@Tool` methods or controlling which 
tools are available per endpoint:
+
+[source,java]
+----
+// Select only the getCapital tool by name
+from("direct:chat")
+    .to("spring-ai-chat:chat?chatModel=#chatModel&toolNames=getCapital");
+
+// Select tools dynamically at runtime via header
+template.requestBodyAndHeader("direct:chat", "What is the capital of France?",
+    SpringAiChatConstants.TOOL_NAMES, "getCapital", String.class);
+----
+
+Tool names are resolved via Spring AI's `ToolCallbackResolver`. You can 
combine `toolNames` with `tags` —
+both tool sources are additive.
+
+=== Tool Context
+
+Pass contextual data (user ID, session info, tenant ID, etc.) to tools during 
execution.
+Tools with a `ToolContext` parameter receive these values automatically:
+
+[source,java]
+----
+// Tool that uses context
+@Tool(description = "Get user profile")
+public String getUserProfile(@ToolParam(description = "detail level") String 
detail,
+                              ToolContext toolContext) {
+    String userId = (String) toolContext.getContext().get("userId");
+    return "Profile for user: " + userId;
+}
+
+// Via endpoint configuration
+from("direct:chat")
+    .to("spring-ai-chat:chat?chatModel=#chatModel&toolCallbacks=#myTools"
+        + "&toolContext.userId=user-42"
+        + "&toolContext.role=admin");
+
+// Via header (overrides endpoint config)
+template.request("direct:chat", e -> {
+    e.getIn().setBody("Get my profile");
+    e.getIn().setHeader(SpringAiChatConstants.TOOL_CONTEXT,
+        Map.of("userId", "user-99", "role", "admin"));
+});
+----
+
+NOTE: Tool context works with Spring AI `@Tool` methods and MCP tools.
+Camel route tools (defined via `spring-ai-tools` consumer) do not receive the 
`ToolContext`.
+
+=== Structured Output Validation
+
+Enable automatic validation of structured output with retry on failure.
+When the LLM produces invalid output (doesn't match the expected JSON Schema),
+the advisor re-prompts the LLM with validation errors:
+
+[source,java]
+----
+from("direct:chat")
+    .to("spring-ai-chat:chat?chatModel=#chatModel"
+        + "&outputFormat=BEAN"
+        + "&outputClass=com.example.ActorFilms"
+        + "&structuredOutputValidation=true"
+        + "&structuredOutputValidationMaxAttempts=3");
+----
+
+If all retry attempts fail, the exception propagates to Camel's error handler:
+
+[source,java]
+----
+from("direct:chat")
+    .doTry()
+        .to("spring-ai-chat:chat?chatModel=#chatModel"
+            + "&outputFormat=BEAN&outputClass=com.example.ActorFilms"
+            + 
"&structuredOutputValidation=true&structuredOutputValidationMaxAttempts=2")
+    .doCatch(Exception.class)
+        .log("Structured output validation failed: ${exception.message}")
+        .to("direct:fallback")
+    .end();
+----
+
+The advisor requires `outputClass` or `entityClass` to be set so it can 
generate a JSON Schema
+for validation. A warning is logged if neither is configured.
+
+=== MCP Client (Model Context Protocol)
+
+The component supports connecting to MCP servers, enabling the LLM to use 
tools provided by
+external MCP-compatible services. This follows the same pattern as the
+xref:openai-component.adoc[OpenAI component]'s MCP support.
+
+Configure MCP servers using the `mcpServer.<name>.<property>` prefix notation:
+
+==== Stdio Transport
+
+[source,java]
+----
+// Connect to MCP filesystem server via stdio
+from("direct:chat")
+    .to("spring-ai-chat:chat?chatModel=#chatModel"
+        + "&mcpServer.fs.transportType=stdio"
+        + "&mcpServer.fs.command=npx"
+        + 
"&mcpServer.fs.args=-y,@modelcontextprotocol/server-filesystem,/tmp");
+----
+
+==== SSE Transport
+
+[source,java]
+----
+// Connect to MCP server via SSE
+from("direct:chat")
+    .to("spring-ai-chat:chat?chatModel=#chatModel"
+        + "&mcpServer.weather.transportType=sse"
+        + "&mcpServer.weather.url=http://mcp-server:3001/sse";);
+----
+
+==== Multiple MCP Servers
+
+[source,java]
+----
+from("direct:chat")
+    .to("spring-ai-chat:chat?chatModel=#chatModel"
+        + "&mcpServer.fs.transportType=stdio"
+        + "&mcpServer.fs.command=npx"
+        + "&mcpServer.fs.args=-y,@modelcontextprotocol/server-filesystem,/tmp"
+        + "&mcpServer.weather.transportType=sse"
+        + "&mcpServer.weather.url=http://weather-mcp:3001/sse";);
+----
+
+==== OAuth Authentication for MCP Servers
+
+For MCP servers requiring authentication, configure an OAuth profile per 
server.
+This requires `camel-oauth` on the classpath:
+
+[source,java]
+----
+from("direct:chat")
+    .to("spring-ai-chat:chat?chatModel=#chatModel"
+        + "&mcpServer.api.transportType=sse"
+        + "&mcpServer.api.url=http://secure-mcp:3001/sse";
+        + "&mcpServer.api.oauthProfile=keycloak");
+----
+
+With corresponding properties:
+
+[source,properties]
+----
+camel.oauth.keycloak.client-id=my-client
+camel.oauth.keycloak.client-secret=my-secret
+camel.oauth.keycloak.token-endpoint=https://keycloak/realms/myrealm/protocol/openid-connect/token
+----
+
+IMPORTANT: The Spring AI chat component uses the MCP SDK version managed by 
the Spring AI BOM.
+Using this component's MCP support alongside `camel-openai` MCP support in the 
same application
+may cause version conflicts. Choose one approach per application.
+
+=== Observability
+
+When using Camel Spring Boot with `spring-boot-starter-actuator`, Spring AI's 
built-in
+observability support is automatically enabled. No additional Camel-side 
configuration is needed —
+the `ChatModel` and `ChatClient` calls are instrumented by Spring AI through 
Micrometer.
+
+Add the actuator dependency to your Spring Boot application:
+
+[source,xml]
+----
+<dependency>
+    <groupId>org.springframework.boot</groupId>
+    <artifactId>spring-boot-starter-actuator</artifactId>
+</dependency>
+----
+
+This works automatically because the Camel component delegates to Spring AI's
+`ChatClient` and `ChatModel`, which are already instrumented. The component 
itself does not need
+to add any observation code — Spring AI's auto-configuration handles 
everything when actuator
+is on the classpath.
+
+Refer to the 
https://docs.spring.io/spring-ai/reference/observability/index.html[Spring AI 
Observability documentation]
+for details on available metrics, tracing, and prompt/completion logging 
configuration.
+
 === Request/Response Logging
 
 The component automatically adds Spring AI's `SimpleLoggerAdvisor` to log 
requests and responses for debugging. Enable it by setting the logger 
`org.springframework.ai.chat.client.advisor` to DEBUG level:
@@ -593,5 +820,6 @@ 
logging.level.org.springframework.ai.chat.client.advisor=DEBUG
 * xref:spring-ai-tools-component.adoc[Spring AI Tools Component]
 * xref:spring-ai-embeddings-component.adoc[Spring AI Embeddings Component]
 * xref:spring-ai-vector-store-component.adoc[Spring AI VectorStore Component]
+* xref:spring-ai-image-component.adoc[Spring AI Image Component]
 
 include::spring-boot:partial$starter.adoc[]
diff --git 
a/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-chat/src/main/java/org/apache/camel/component/springai/chat/SpringAiChatConfiguration.java
 
b/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-chat/src/main/java/org/apache/camel/component/springai/chat/SpringAiChatConfiguration.java
index a9dd2341bc14..52e4324c8542 100644
--- 
a/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-chat/src/main/java/org/apache/camel/component/springai/chat/SpringAiChatConfiguration.java
+++ 
b/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-chat/src/main/java/org/apache/camel/component/springai/chat/SpringAiChatConfiguration.java
@@ -27,6 +27,7 @@ import org.springframework.ai.chat.client.advisor.api.Advisor;
 import org.springframework.ai.chat.memory.ChatMemory;
 import org.springframework.ai.chat.model.ChatModel;
 import org.springframework.ai.converter.StructuredOutputConverter;
+import org.springframework.ai.tool.ToolCallback;
 import org.springframework.ai.vectorstore.VectorStore;
 
 @UriParams
@@ -120,6 +121,43 @@ public class SpringAiChatConfiguration implements 
Cloneable {
     @UriParam(label = "advanced", defaultValue = "1048576")
     private long maxFileSize = 1024 * 1024; // 1MB default
 
+    @UriParam(description = "Comma-separated tool names for selecting tools by 
name via Spring AI's ToolCallbackResolver. "
+                            + "This enables selecting Spring @Tool annotated 
beans or any registered ToolCallback by name.")
+    private String toolNames;
+
+    @UriParam(label = "advanced",
+              description = "List of ToolCallback instances to register 
alongside Camel route tools. "
+                            + "Use 
MethodToolCallbackProvider.builder().toolObjects(bean).build().getToolCallbacks()
 "
+                            + "to resolve callbacks from @Tool-annotated 
beans.")
+    @Metadata(autowired = true)
+    private List<ToolCallback> toolCallbacks;
+
+    @UriParam(label = "advanced",
+              description = "Context map to pass to tools during execution. 
Tool methods accepting a ToolContext parameter will receive these values.")
+    private Map<String, Object> toolContext;
+
+    @UriParam(label = "advanced", defaultValue = "false",
+              description = "Enable structured output validation with 
automatic retry on validation failure. "
+                            + "When enabled, the 
StructuredOutputValidationAdvisor validates the response against a JSON Schema "
+                            + "and re-prompts the LLM with validation errors 
if the output is invalid.")
+    private boolean structuredOutputValidation;
+
+    @UriParam(label = "advanced", defaultValue = "3",
+              description = "Maximum number of retry attempts for structured 
output validation")
+    private int structuredOutputValidationMaxAttempts = 3;
+
+    @UriParam(prefix = "mcpServer.", multiValue = true, label = "advanced",
+              description = "MCP server configurations. Define servers using 
prefix notation: "
+                            + "mcpServer.<name>.transportType=stdio|sse, "
+                            + "mcpServer.<name>.command=<cmd> (stdio), 
mcpServer.<name>.args=<comma-separated> (stdio), "
+                            + "mcpServer.<name>.url=<url> (sse), "
+                            + "mcpServer.<name>.oauthProfile=<profile> (OAuth 
profile for HTTP auth, requires camel-oauth)")
+    private Map<String, Object> mcpServer;
+
+    @UriParam(label = "advanced", defaultValue = "20",
+              description = "Timeout in seconds for MCP operations including 
tool execution and initialization")
+    private int mcpTimeout = 20;
+
     public ChatClient getChatClient() {
         return chatClient;
     }
@@ -436,6 +474,96 @@ public class SpringAiChatConfiguration implements 
Cloneable {
         this.maxFileSize = maxFileSize;
     }
 
+    public String getToolNames() {
+        return toolNames;
+    }
+
+    /**
+     * Comma-separated tool names for selecting tools by name via Spring AI's 
ToolCallbackResolver. This enables
+     * selecting Spring @Tool annotated beans or any registered ToolCallback 
by name, in addition to tag-based
+     * discovery.
+     */
+    public void setToolNames(String toolNames) {
+        this.toolNames = toolNames;
+    }
+
+    public List<ToolCallback> getToolCallbacks() {
+        return toolCallbacks;
+    }
+
+    /**
+     * List of additional ToolCallback instances to register alongside Camel 
route tools. These callbacks are added
+     * directly without requiring a ToolCallbackProvider.
+     */
+    public void setToolCallbacks(List<ToolCallback> toolCallbacks) {
+        this.toolCallbacks = toolCallbacks;
+    }
+
+    public Map<String, Object> getToolContext() {
+        return toolContext;
+    }
+
+    /**
+     * Context map to pass to tools during execution. Tool methods accepting a 
ToolContext parameter will receive these
+     * values. Can be overridden per-request via the 
CamelSpringAiChatToolContext header.
+     */
+    public void setToolContext(Map<String, Object> toolContext) {
+        this.toolContext = toolContext;
+    }
+
+    public Map<String, Object> getMcpServer() {
+        return mcpServer;
+    }
+
+    /**
+     * MCP server configurations for Model Context Protocol integration. 
Define servers using prefix notation:
+     * mcpServer.&lt;name&gt;.transportType=stdio|sse, 
mcpServer.&lt;name&gt;.command=&lt;cmd&gt; (stdio),
+     * mcpServer.&lt;name&gt;.args=&lt;comma-separated&gt; (stdio), 
mcpServer.&lt;name&gt;.url=&lt;url&gt; (sse).
+     * <p>
+     * <strong>Note:</strong> Using this component with MCP alongside the 
camel-openai component with MCP may lead to
+     * MCP SDK version conflicts. The spring-ai-chat component uses MCP SDK 
version managed by Spring AI BOM while
+     * camel-openai uses the version defined in camel-parent. Avoid using both 
in the same application.
+     * </p>
+     */
+    public void setMcpServer(Map<String, Object> mcpServer) {
+        this.mcpServer = mcpServer;
+    }
+
+    public int getMcpTimeout() {
+        return mcpTimeout;
+    }
+
+    /**
+     * Timeout in seconds for MCP operations including tool execution and 
initialization. Default is 20.
+     */
+    public void setMcpTimeout(int mcpTimeout) {
+        this.mcpTimeout = mcpTimeout;
+    }
+
+    public boolean isStructuredOutputValidation() {
+        return structuredOutputValidation;
+    }
+
+    /**
+     * Enable structured output validation with automatic retry on validation 
failure. When enabled, the
+     * StructuredOutputValidationAdvisor validates the response against a JSON 
Schema derived from the outputClass or
+     * entityClass, and re-prompts the LLM with validation errors if the 
output is invalid.
+     */
+    public void setStructuredOutputValidation(boolean 
structuredOutputValidation) {
+        this.structuredOutputValidation = structuredOutputValidation;
+    }
+
+    public int getStructuredOutputValidationMaxAttempts() {
+        return structuredOutputValidationMaxAttempts;
+    }
+
+    /**
+     * Maximum number of retry attempts for structured output validation. 
Default is 3.
+     */
+    public void setStructuredOutputValidationMaxAttempts(int 
structuredOutputValidationMaxAttempts) {
+        this.structuredOutputValidationMaxAttempts = 
structuredOutputValidationMaxAttempts;
+    }
+
     public SpringAiChatConfiguration copy() {
         try {
             return (SpringAiChatConfiguration) clone();
diff --git 
a/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-chat/src/main/java/org/apache/camel/component/springai/chat/SpringAiChatConstants.java
 
b/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-chat/src/main/java/org/apache/camel/component/springai/chat/SpringAiChatConstants.java
index dd43ea80fa17..bd7090974bc6 100644
--- 
a/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-chat/src/main/java/org/apache/camel/component/springai/chat/SpringAiChatConstants.java
+++ 
b/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-chat/src/main/java/org/apache/camel/component/springai/chat/SpringAiChatConstants.java
@@ -119,6 +119,14 @@ public final class SpringAiChatConstants {
               javaType = "java.util.Map<String, Object>")
     public static final String RESPONSE_METADATA = 
"CamelSpringAiChatResponseMetadata";
 
+    @Metadata(description = "Comma-separated tool names for selecting tools by 
name via ToolCallbackResolver",
+              javaType = "String")
+    public static final String TOOL_NAMES = "CamelSpringAiChatToolNames";
+
+    @Metadata(description = "Context map to pass to tools during execution",
+              javaType = "java.util.Map<String, Object>")
+    public static final String TOOL_CONTEXT = "CamelSpringAiChatToolContext";
+
     private SpringAiChatConstants() {
     }
 }
diff --git 
a/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-chat/src/main/java/org/apache/camel/component/springai/chat/SpringAiChatProducer.java
 
b/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-chat/src/main/java/org/apache/camel/component/springai/chat/SpringAiChatProducer.java
index e39a23392827..322f1cd427c7 100644
--- 
a/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-chat/src/main/java/org/apache/camel/component/springai/chat/SpringAiChatProducer.java
+++ 
b/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-chat/src/main/java/org/apache/camel/component/springai/chat/SpringAiChatProducer.java
@@ -21,6 +21,7 @@ import java.io.IOException;
 import java.nio.file.Files;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -30,6 +31,7 @@ import org.apache.camel.Exchange;
 import org.apache.camel.InvalidPayloadException;
 import org.apache.camel.NoSuchHeaderException;
 import org.apache.camel.WrappedFile;
+import org.apache.camel.component.springai.chat.mcp.SpringAiChatMcpManager;
 import org.apache.camel.component.springai.tools.TagsHelper;
 import org.apache.camel.component.springai.tools.spec.CamelToolExecutorCache;
 import org.apache.camel.component.springai.tools.spec.CamelToolSpecification;
@@ -40,6 +42,7 @@ import org.springframework.ai.chat.client.ChatClient;
 import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
 import org.springframework.ai.chat.client.advisor.SafeGuardAdvisor;
 import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
+import 
org.springframework.ai.chat.client.advisor.StructuredOutputValidationAdvisor;
 import org.springframework.ai.chat.client.advisor.api.Advisor;
 import 
org.springframework.ai.chat.client.advisor.vectorstore.QuestionAnswerAdvisor;
 import 
org.springframework.ai.chat.client.advisor.vectorstore.VectorStoreChatMemoryAdvisor;
@@ -72,6 +75,7 @@ public class SpringAiChatProducer extends DefaultProducer {
     private static final Logger LOG = 
LoggerFactory.getLogger(SpringAiChatProducer.class);
 
     private ChatClient chatClient;
+    private SpringAiChatMcpManager mcpManager;
 
     public SpringAiChatProducer(SpringAiChatEndpoint endpoint) {
         super(endpoint);
@@ -115,6 +119,23 @@ public class SpringAiChatProducer extends DefaultProducer {
 
             this.chatClient = builder.build();
         }
+
+        // Initialize MCP clients if configured
+        Map<String, Object> mcpConfig = 
getEndpoint().getConfiguration().getMcpServer();
+        if (mcpConfig != null && !mcpConfig.isEmpty()) {
+            mcpManager = new SpringAiChatMcpManager();
+            mcpManager.initialize(mcpConfig, 
getEndpoint().getConfiguration().getMcpTimeout(),
+                    getEndpoint().getCamelContext());
+        }
+    }
+
+    @Override
+    protected void doStop() throws Exception {
+        if (mcpManager != null) {
+            mcpManager.close();
+            mcpManager = null;
+        }
+        super.doStop();
     }
 
     @Override
@@ -553,6 +574,40 @@ public class SpringAiChatProducer extends DefaultProducer {
         ToolCallingChatOptions options = optionsBuilder.build();
         request.options(options);
 
+        // Add direct ToolCallbacks if configured
+        List<ToolCallback> configuredCallbacks = 
getEndpoint().getConfiguration().getToolCallbacks();
+        if (configuredCallbacks != null && !configuredCallbacks.isEmpty()) {
+            request.toolCallbacks(configuredCallbacks);
+            LOG.debug("Added {} configured ToolCallbacks", 
configuredCallbacks.size());
+        }
+
+        // Add MCP tool callbacks if MCP servers are configured
+        if (mcpManager != null && mcpManager.getToolCallbackProvider() != 
null) {
+            request.toolCallbacks(mcpManager.getToolCallbackProvider());
+            LOG.debug("Added MCP tool callback provider");
+        }
+
+        // Apply tool names for resolution via ToolCallbackResolver
+        String toolNames = 
exchange.getIn().getHeader(SpringAiChatConstants.TOOL_NAMES, String.class);
+        if (toolNames == null) {
+            toolNames = getEndpoint().getConfiguration().getToolNames();
+        }
+        if (toolNames != null && !toolNames.trim().isEmpty()) {
+            String[] names = Arrays.stream(toolNames.split(","))
+                    .map(String::trim)
+                    .filter(s -> !s.isEmpty())
+                    .toArray(String[]::new);
+            request.toolNames(names);
+            LOG.debug("Added {} tool names for resolution: {}", names.length, 
Arrays.toString(names));
+        }
+
+        // Apply tool context if configured
+        Map<String, Object> toolContext = getToolContext(exchange);
+        if (toolContext != null && !toolContext.isEmpty()) {
+            request.toolContext(toolContext);
+            LOG.debug("Added tool context with {} entries", 
toolContext.size());
+        }
+
         // Apply conversation ID for chat memory if provided
         String conversationId = 
exchange.getIn().getHeader(SpringAiChatConstants.CONVERSATION_ID, String.class);
         if (conversationId != null) {
@@ -719,6 +774,20 @@ public class SpringAiChatProducer extends DefaultProducer {
         return getEndpoint().getConfiguration().getSystemMetadata();
     }
 
+    @SuppressWarnings("unchecked")
+    private Map<String, Object> getToolContext(Exchange exchange) {
+        Map<String, Object> headerContext = 
exchange.getIn().getHeader(SpringAiChatConstants.TOOL_CONTEXT, Map.class);
+        Map<String, Object> configContext = 
getEndpoint().getConfiguration().getToolContext();
+
+        if (headerContext != null && configContext != null) {
+            // Merge: header overrides config
+            Map<String, Object> merged = new HashMap<>(configContext);
+            merged.putAll(headerContext);
+            return merged;
+        }
+        return headerContext != null ? headerContext : configContext;
+    }
+
     private Class<?> getEntityClass(Exchange exchange) {
         // Check if entity class is provided via header (takes highest 
priority)
         Class<?> entityClass = 
exchange.getIn().getHeader(SpringAiChatConstants.ENTITY_CLASS, Class.class);
@@ -1142,6 +1211,26 @@ public class SpringAiChatProducer extends 
DefaultProducer {
                     getEndpoint().getConfiguration().getSimilarityThreshold());
         }
 
+        // Add StructuredOutputValidationAdvisor if configured
+        if (getEndpoint().getConfiguration().isStructuredOutputValidation()) {
+            Class<?> outputType = 
getEndpoint().getConfiguration().getOutputClass();
+            if (outputType == null) {
+                outputType = getEndpoint().getConfiguration().getEntityClass();
+            }
+            if (outputType != null) {
+                advisors.add(StructuredOutputValidationAdvisor.builder()
+                        .outputType(outputType)
+                        
.maxRepeatAttempts(getEndpoint().getConfiguration().getStructuredOutputValidationMaxAttempts())
+                        .build());
+                LOG.debug("StructuredOutputValidationAdvisor enabled with 
maxRepeatAttempts={} for type={}",
+                        
getEndpoint().getConfiguration().getStructuredOutputValidationMaxAttempts(),
+                        outputType.getName());
+            } else {
+                LOG.warn("structuredOutputValidation is enabled but no 
outputClass or entityClass is configured. "
+                         + "The advisor requires a type to validate against.");
+            }
+        }
+
         // Add custom advisors if configured
         List<Advisor> customAdvisors = 
getEndpoint().getConfiguration().getAdvisors();
         if (customAdvisors != null && !customAdvisors.isEmpty()) {
diff --git 
a/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-chat/src/main/java/org/apache/camel/component/springai/chat/mcp/SpringAiChatMcpManager.java
 
b/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-chat/src/main/java/org/apache/camel/component/springai/chat/mcp/SpringAiChatMcpManager.java
new file mode 100644
index 000000000000..d778d541478f
--- /dev/null
+++ 
b/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-chat/src/main/java/org/apache/camel/component/springai/chat/mcp/SpringAiChatMcpManager.java
@@ -0,0 +1,186 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.springai.chat.mcp;
+
+import java.net.http.HttpRequest;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.modelcontextprotocol.client.McpClient;
+import io.modelcontextprotocol.client.McpSyncClient;
+import io.modelcontextprotocol.client.transport.HttpClientSseClientTransport;
+import io.modelcontextprotocol.client.transport.ServerParameters;
+import io.modelcontextprotocol.client.transport.StdioClientTransport;
+import io.modelcontextprotocol.json.jackson.JacksonMcpJsonMapper;
+import io.modelcontextprotocol.spec.McpClientTransport;
+import org.apache.camel.CamelContext;
+import org.apache.camel.support.OAuthHelper;
+import org.apache.camel.util.ObjectHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.ai.mcp.SyncMcpToolCallbackProvider;
+import org.springframework.ai.tool.ToolCallbackProvider;
+
+/**
+ * Manages MCP (Model Context Protocol) client lifecycle for the Spring AI 
Chat component.
+ * <p>
+ * Handles initialization, tool discovery via {@link 
SyncMcpToolCallbackProvider}, and graceful shutdown of MCP clients.
+ * Supports stdio, sse, and sse transport types.
+ * </p>
+ */
+public class SpringAiChatMcpManager {
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(SpringAiChatMcpManager.class);
+
+    private final List<McpSyncClient> mcpClients = new ArrayList<>();
+    private SyncMcpToolCallbackProvider toolCallbackProvider;
+
+    /**
+     * Initialize MCP clients from flat configuration map.
+     * <p>
+     * Configuration keys follow the pattern: {@code <serverName>.<property>}. 
Supported properties:
+     * <ul>
+     * <li>{@code transportType} - Required. One of: stdio, sse</li>
+     * <li>{@code command} - Required for stdio. The command to execute</li>
+     * <li>{@code args} - Optional for stdio. Comma-separated arguments</li>
+     * <li>{@code url} - Required for sse. The server URL</li>
+     * <li>{@code oauthProfile} - Optional for sse. OAuth profile name for 
obtaining a Bearer token (requires
+     * camel-oauth)</li>
+     * </ul>
+     *
+     * @param  mcpServerConfig flat configuration map with dotted keys
+     * @param  mcpTimeout      timeout in seconds for MCP operations
+     * @param  camelContext    the CamelContext for OAuth token resolution
+     * @throws Exception       if initialization fails
+     */
+    public void initialize(Map<String, Object> mcpServerConfig, int 
mcpTimeout, CamelContext camelContext)
+            throws Exception {
+        // Group flat keys by server name: "fs.transportType" -> {"fs": 
{"transportType": ...}}
+        Map<String, Map<String, String>> serverConfigs = new HashMap<>();
+        for (Map.Entry<String, Object> entry : mcpServerConfig.entrySet()) {
+            String key = entry.getKey();
+            int dot = key.indexOf('.');
+            if (dot < 0) {
+                continue;
+            }
+            String serverName = key.substring(0, dot);
+            String property = key.substring(dot + 1);
+            serverConfigs.computeIfAbsent(serverName, k -> new 
HashMap<>()).put(property, String.valueOf(entry.getValue()));
+        }
+
+        Duration timeout = Duration.ofSeconds(mcpTimeout);
+
+        for (Map.Entry<String, Map<String, String>> entry : 
serverConfigs.entrySet()) {
+            String serverName = entry.getKey();
+            Map<String, String> props = entry.getValue();
+
+            String transportType = props.get("transportType");
+            if (transportType == null) {
+                throw new IllegalArgumentException("mcpServer." + serverName + 
".transportType is required");
+            }
+
+            LOG.debug("Creating MCP transport for server '{}' with type '{}'", 
serverName, transportType);
+            McpClientTransport transport = createTransport(serverName, 
transportType, props, camelContext);
+            McpSyncClient mcpClient = McpClient.sync(transport)
+                    .requestTimeout(timeout)
+                    .initializationTimeout(timeout)
+                    .build();
+            mcpClient.initialize();
+            mcpClients.add(mcpClient);
+            LOG.info("Initialized MCP server '{}'", serverName);
+        }
+
+        if (!mcpClients.isEmpty()) {
+            toolCallbackProvider = SyncMcpToolCallbackProvider.builder()
+                    .mcpClients(mcpClients)
+                    .build();
+            LOG.info("MCP tool callback provider created with {} tool 
callbacks from {} servers",
+                    toolCallbackProvider.getToolCallbacks().length, 
mcpClients.size());
+        }
+    }
+
+    /**
+     * Returns the tool callback provider that provides MCP tools as Spring AI 
ToolCallbacks.
+     */
+    public ToolCallbackProvider getToolCallbackProvider() {
+        return toolCallbackProvider;
+    }
+
+    /**
+     * Close all MCP clients gracefully.
+     */
+    public void close() {
+        for (McpSyncClient client : mcpClients) {
+            try {
+                client.close();
+            } catch (Exception e) {
+                LOG.debug("Error closing MCP client: {}", e.getMessage());
+            }
+        }
+        mcpClients.clear();
+        toolCallbackProvider = null;
+        LOG.debug("All MCP clients closed");
+    }
+
+    private McpClientTransport createTransport(
+            String serverName, String transportType, Map<String, String> 
props, CamelContext camelContext)
+            throws Exception {
+
+        // Resolve per-server OAuth token if configured
+        String oauthProfile = props.get("oauthProfile");
+        HttpRequest.Builder authRequestBuilder = null;
+        if (ObjectHelper.isNotEmpty(oauthProfile)) {
+            String token = OAuthHelper.resolveOAuthToken(camelContext, 
oauthProfile);
+            authRequestBuilder = HttpRequest.newBuilder()
+                    .header("Authorization", "Bearer " + token);
+            LOG.debug("OAuth token resolved for MCP server '{}' using profile 
'{}'", serverName, oauthProfile);
+        }
+
+        return switch (transportType) {
+            case "stdio" -> {
+                String command = props.get("command");
+                if (command == null) {
+                    throw new IllegalArgumentException("mcpServer." + 
serverName + ".command is required for stdio transport");
+                }
+                ServerParameters.Builder paramsBuilder = 
ServerParameters.builder(command);
+                String args = props.get("args");
+                if (args != null) {
+                    paramsBuilder.args(List.of(args.split(",")));
+                }
+                yield new StdioClientTransport(paramsBuilder.build(), new 
JacksonMcpJsonMapper(new ObjectMapper()));
+            }
+            case "sse" -> {
+                String url = props.get("url");
+                if (url == null) {
+                    throw new IllegalArgumentException("mcpServer." + 
serverName + ".url is required for sse transport");
+                }
+                HttpClientSseClientTransport.Builder sseBuilder = 
HttpClientSseClientTransport.builder(url);
+                if (authRequestBuilder != null) {
+                    sseBuilder.requestBuilder(authRequestBuilder);
+                }
+                yield sseBuilder.build();
+            }
+            default -> throw new IllegalArgumentException(
+                    "Unknown transport type '" + transportType + "' for 
mcpServer." + serverName
+                                                          + ". Supported: 
stdio, sse");
+        };
+    }
+}
diff --git 
a/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-chat/src/test/java/org/apache/camel/component/springai/chat/SpringAiChatMcpIT.java
 
b/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-chat/src/test/java/org/apache/camel/component/springai/chat/SpringAiChatMcpIT.java
new file mode 100644
index 000000000000..6d943678c5fe
--- /dev/null
+++ 
b/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-chat/src/test/java/org/apache/camel/component/springai/chat/SpringAiChatMcpIT.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.springai.chat;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.DisabledIfSystemProperty;
+import org.junit.jupiter.api.io.TempDir;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Integration test for MCP (Model Context Protocol) client support.
+ *
+ * Uses the MCP filesystem server via stdio transport. Requires Node.js and 
npx to be available on the system path.
+ *
+ * The test creates temporary files and verifies that the LLM can use MCP 
tools to read and list them.
+ */
+@DisabledIfSystemProperty(named = "ci.env.name", matches = ".*", 
disabledReason = "Disabled unless running in CI")
+public class SpringAiChatMcpIT extends OllamaTestSupport {
+
+    @TempDir
+    static Path tempDir;
+
+    @BeforeAll
+    static void setupTestFiles() throws IOException {
+        // Create test files for the MCP filesystem server to read
+        Files.writeString(tempDir.resolve("hello.txt"), "Hello from Camel 
Spring AI MCP test!");
+        Files.writeString(tempDir.resolve("data.csv"), 
"name,age\nAlice,30\nBob,25");
+    }
+
+    @Test
+    public void testMcpListFiles() {
+        String response = template().requestBody("direct:mcpChat",
+                "List the files in the allowed directory", String.class);
+
+        assertThat(response).isNotNull();
+        assertThat(response.toLowerCase()).containsAnyOf("hello", "data", 
"txt", "csv", "file");
+    }
+
+    @Test
+    public void testMcpReadFile() {
+        String response = template().requestBody("direct:mcpChat",
+                "Read the contents of hello.txt", String.class);
+
+        assertThat(response).isNotNull();
+        assertThat(response.toLowerCase()).containsAnyOf("hello", "camel", 
"mcp");
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        String tempDirPath = tempDir.toAbsolutePath().toString();
+
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                bindChatModel(getCamelContext());
+
+                // Chat endpoint with MCP filesystem server via stdio transport
+                from("direct:mcpChat")
+                        .toF("spring-ai-chat:mcpChat?chatModel=#chatModel"
+                             + "&mcpServer.fs.transportType=stdio"
+                             + "&mcpServer.fs.command=npx"
+                             + 
"&mcpServer.fs.args=-y,@modelcontextprotocol/server-filesystem,%s",
+                                tempDirPath);
+            }
+        };
+    }
+}
diff --git 
a/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-chat/src/test/java/org/apache/camel/component/springai/chat/SpringAiChatMcpSseIT.java
 
b/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-chat/src/test/java/org/apache/camel/component/springai/chat/SpringAiChatMcpSseIT.java
new file mode 100644
index 000000000000..decd9ff56efd
--- /dev/null
+++ 
b/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-chat/src/test/java/org/apache/camel/component/springai/chat/SpringAiChatMcpSseIT.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.springai.chat;
+
+import org.apache.camel.builder.RouteBuilder;
+import 
org.apache.camel.test.infra.mcp.everything.services.McpEverythingSseService;
+import 
org.apache.camel.test.infra.mcp.everything.services.McpEverythingSseServiceFactory;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.DisabledIfSystemProperty;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Integration test for MCP client support using SSE transport with the MCP 
Everything Server.
+ *
+ * Uses the tzolov/mcp-everything-server:v3 Docker container in SSE mode, 
which provides echo and add tools.
+ */
+@DisabledIfSystemProperty(named = "ci.env.name", matches = ".*", 
disabledReason = "Disabled unless running in CI")
+public class SpringAiChatMcpSseIT extends OllamaTestSupport {
+
+    @RegisterExtension
+    static McpEverythingSseService MCP_EVERYTHING = 
McpEverythingSseServiceFactory.createService();
+
+    @Test
+    public void testMcpEchoTool() {
+        String response = template().requestBody("direct:mcpSseChat",
+                "Use the echo tool to echo the message 'Hello from Camel'.", 
String.class);
+
+        assertThat(response).isNotNull();
+        assertThat(response.toLowerCase()).containsAnyOf("hello", "camel");
+    }
+
+    @Test
+    public void testMcpAddTool() {
+        String response = template().requestBody("direct:mcpSseChat",
+                "Use the add tool to add 17 and 25.", String.class);
+
+        assertThat(response).isNotNull();
+        assertThat(response).containsAnyOf("42", "forty-two", "forty two");
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        String sseUrl = MCP_EVERYTHING.sseUrl();
+
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                bindChatModel(getCamelContext());
+
+                from("direct:mcpSseChat")
+                        .toF("spring-ai-chat:mcpSseChat?chatModel=#chatModel"
+                             + "&mcpServer.everything.transportType=sse"
+                             + "&mcpServer.everything.url=%s",
+                                sseUrl);
+            }
+        };
+    }
+}
diff --git 
a/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-chat/src/test/java/org/apache/camel/component/springai/chat/SpringAiChatStructuredOutputValidationIT.java
 
b/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-chat/src/test/java/org/apache/camel/component/springai/chat/SpringAiChatStructuredOutputValidationIT.java
new file mode 100644
index 000000000000..13d537c69a99
--- /dev/null
+++ 
b/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-chat/src/test/java/org/apache/camel/component/springai/chat/SpringAiChatStructuredOutputValidationIT.java
@@ -0,0 +1,129 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.springai.chat;
+
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import org.apache.camel.builder.RouteBuilder;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.DisabledIfSystemProperty;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Integration test for StructuredOutputValidationAdvisor.
+ *
+ * Tests that the advisor validates structured output against JSON Schema and 
retries on validation failure. If all
+ * retries fail, the exception propagates to Camel's error handler.
+ */
+@DisabledIfSystemProperty(named = "ci.env.name", matches = ".*", 
disabledReason = "Disabled unless running in CI")
+public class SpringAiChatStructuredOutputValidationIT extends 
OllamaTestSupport {
+
+    @Test
+    public void testValidationWithBeanOutput() {
+        var exchange = template().request("direct:validatedChat", e -> {
+            e.getIn().setBody("Generate filmography for Tom Hanks. Include at 
least 3 movies.");
+        });
+
+        assertThat(exchange).isNotNull();
+        assertThat(exchange.getException()).isNull();
+
+        Object body = exchange.getMessage().getBody();
+        assertThat(body).isInstanceOf(ActorFilms.class);
+
+        ActorFilms actorFilms = (ActorFilms) body;
+        assertThat(actorFilms.actor()).isNotNull();
+        assertThat(actorFilms.movies()).isNotNull().isNotEmpty();
+    }
+
+    @Test
+    public void testValidationWithEntityClass() {
+        var exchange = template().request("direct:entityValidatedChat", e -> {
+            e.getIn().setBody("Generate filmography for Meryl Streep. Include 
at least 3 movies.");
+        });
+
+        assertThat(exchange).isNotNull();
+        assertThat(exchange.getException()).isNull();
+
+        Object body = exchange.getMessage().getBody();
+        assertThat(body).isInstanceOf(ActorFilms.class);
+
+        ActorFilms actorFilms = (ActorFilms) body;
+        assertThat(actorFilms.actor()).isNotNull();
+        assertThat(actorFilms.movies()).isNotNull().isNotEmpty();
+    }
+
+    @Test
+    public void testValidationFailurePropagesToErrorHandler() {
+        // Use an unreasonable request that may produce invalid output
+        // The error handler should catch the exception after max retries
+        var exchange = template().request("direct:errorHandledChat", e -> {
+            e.getIn().setBody("Generate filmography for Tom Hanks");
+        });
+
+        assertThat(exchange).isNotNull();
+        // Either success or error handled — exchange should complete
+        if (exchange.getException() == null) {
+            // Validation succeeded — body should be ActorFilms
+            
assertThat(exchange.getMessage().getBody()).isInstanceOf(ActorFilms.class);
+        }
+        // If exception, it was propagated correctly to Camel error handling
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                bindChatModel(getCamelContext());
+
+                // Chat with structured output validation using 
outputFormat/outputClass
+                from("direct:validatedChat")
+                        .to("spring-ai-chat:validatedChat?chatModel=#chatModel"
+                            + "&outputFormat=BEAN"
+                            + 
"&outputClass=org.apache.camel.component.springai.chat.SpringAiChatStructuredOutputValidationIT$ActorFilms"
+                            + "&structuredOutputValidation=true"
+                            + "&structuredOutputValidationMaxAttempts=3");
+
+                // Chat with structured output validation using entityClass
+                from("direct:entityValidatedChat")
+                        
.to("spring-ai-chat:entityValidatedChat?chatModel=#chatModel"
+                            + 
"&entityClass=org.apache.camel.component.springai.chat.SpringAiChatStructuredOutputValidationIT$ActorFilms"
+                            + "&structuredOutputValidation=true"
+                            + "&structuredOutputValidationMaxAttempts=3");
+
+                // Chat with error handling
+                from("direct:errorHandledChat")
+                        .doTry()
+                            
.to("spring-ai-chat:errorHandledChat?chatModel=#chatModel"
+                                + "&outputFormat=BEAN"
+                                + 
"&outputClass=org.apache.camel.component.springai.chat.SpringAiChatStructuredOutputValidationIT$ActorFilms"
+                                + "&structuredOutputValidation=true"
+                                + "&structuredOutputValidationMaxAttempts=1")
+                        .doCatch(Exception.class)
+                            .log("Validation failed after retries: 
${exception.message}")
+                            .setBody(simple("Validation failed: 
${exception.message}"))
+                        .end();
+            }
+        };
+    }
+
+    @JsonPropertyOrder({ "actor", "movies" })
+    public record ActorFilms(String actor, List<String> movies) {
+    }
+}
diff --git 
a/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-chat/src/test/java/org/apache/camel/component/springai/chat/SpringAiChatToolBeanDiscoveryIT.java
 
b/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-chat/src/test/java/org/apache/camel/component/springai/chat/SpringAiChatToolBeanDiscoveryIT.java
new file mode 100644
index 000000000000..24eeb350f180
--- /dev/null
+++ 
b/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-chat/src/test/java/org/apache/camel/component/springai/chat/SpringAiChatToolBeanDiscoveryIT.java
@@ -0,0 +1,119 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.springai.chat;
+
+import java.util.Arrays;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.DisabledIfSystemProperty;
+import org.springframework.ai.tool.ToolCallbackProvider;
+import org.springframework.ai.tool.annotation.Tool;
+import org.springframework.ai.tool.method.MethodToolCallbackProvider;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Integration test for @Tool bean discovery and toolNames-based tool 
selection.
+ *
+ * Tests that Spring @Tool annotated beans can be discovered via 
ToolCallbackProvider and selected by name using the
+ * toolNames parameter.
+ */
+@DisabledIfSystemProperty(named = "ci.env.name", matches = ".*", 
disabledReason = "Disabled unless running in CI")
+public class SpringAiChatToolBeanDiscoveryIT extends OllamaTestSupport {
+
+    @Test
+    public void testToolCallbackProviderDiscovery() {
+        String response = template().requestBody("direct:providerChat",
+                "What is the current date and time?", String.class);
+
+        assertThat(response).isNotNull();
+        // The LLM should use the tool and include date/time info
+        assertThat(response).isNotEmpty();
+    }
+
+    @Test
+    public void testToolSelectionByName() {
+        String response = template().requestBody("direct:namedChat",
+                "What is the capital of France?", String.class);
+
+        assertThat(response).isNotNull();
+        assertThat(response.toLowerCase()).containsAnyOf("paris", "capital", 
"france");
+    }
+
+    @Test
+    public void testToolNamesViaHeader() {
+        var exchange = template().request("direct:headerChat", e -> {
+            e.getIn().setBody("What is the capital of Germany?");
+            e.getIn().setHeader(SpringAiChatConstants.TOOL_NAMES, 
"getCapital");
+        });
+
+        assertThat(exchange).isNotNull();
+        String response = exchange.getMessage().getBody(String.class);
+        assertThat(response).isNotNull();
+        assertThat(response.toLowerCase()).containsAnyOf("berlin", "capital", 
"germany");
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                bindChatModel(getCamelContext());
+
+                // Resolve ToolCallbacks from @Tool-annotated bean
+                ToolCallbackProvider provider = 
MethodToolCallbackProvider.builder()
+                        .toolObjects(new MyTools())
+                        .build();
+                getCamelContext().getRegistry().bind("myTools", 
Arrays.asList(provider.getToolCallbacks()));
+
+                // Chat with ToolCallbacks resolved from @Tool bean
+                from("direct:providerChat")
+                        
.to("spring-ai-chat:providerChat?chatModel=#chatModel&toolCallbacks=#myTools");
+
+                // Chat with toolNames selection
+                from("direct:namedChat")
+                        
.to("spring-ai-chat:namedChat?chatModel=#chatModel&toolCallbacks=#myTools&toolNames=getCapital");
+
+                // Chat without toolNames - selected via header at runtime
+                from("direct:headerChat")
+                        
.to("spring-ai-chat:headerChat?chatModel=#chatModel&toolCallbacks=#myTools");
+            }
+        };
+    }
+
+    /**
+     * Spring AI @Tool annotated bean for testing.
+     */
+    public static class MyTools {
+
+        @Tool(description = "Get the current date and time")
+        public String getCurrentDateTime() {
+            return "The current date and time is 2026-03-11T10:30:00Z";
+        }
+
+        @Tool(description = "Get the capital city of a country")
+        public String getCapital(String country) {
+            return switch (country.toLowerCase()) {
+                case "france" -> "The capital of France is Paris";
+                case "germany" -> "The capital of Germany is Berlin";
+                case "italy" -> "The capital of Italy is Rome";
+                default -> "Capital not found for " + country;
+            };
+        }
+    }
+}
diff --git 
a/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-chat/src/test/java/org/apache/camel/component/springai/chat/SpringAiChatToolContextIT.java
 
b/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-chat/src/test/java/org/apache/camel/component/springai/chat/SpringAiChatToolContextIT.java
new file mode 100644
index 000000000000..fbfffefcc834
--- /dev/null
+++ 
b/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-chat/src/test/java/org/apache/camel/component/springai/chat/SpringAiChatToolContextIT.java
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.springai.chat;
+
+import java.util.Arrays;
+import java.util.Map;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.DisabledIfSystemProperty;
+import org.springframework.ai.chat.model.ToolContext;
+import org.springframework.ai.tool.annotation.Tool;
+import org.springframework.ai.tool.annotation.ToolParam;
+import org.springframework.ai.tool.method.MethodToolCallbackProvider;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Integration test for ToolContext support.
+ *
+ * Tests that contextual data (e.g., user ID, session info) is passed to @Tool 
methods that accept a ToolContext
+ * parameter.
+ */
+@DisabledIfSystemProperty(named = "ci.env.name", matches = ".*", 
disabledReason = "Disabled unless running in CI")
+public class SpringAiChatToolContextIT extends OllamaTestSupport {
+
+    @Test
+    public void testToolContextFromConfig() {
+        // The route has toolContext configured with userId=user-42
+        String response = template().requestBody("direct:contextChat",
+                "Get my user profile", String.class);
+
+        assertThat(response).isNotNull();
+        // The tool should receive the context and include user-42 in its 
response
+        assertThat(response.toLowerCase()).containsAnyOf("user-42", "user", 
"profile");
+    }
+
+    @Test
+    public void testToolContextFromHeader() {
+        var exchange = template().request("direct:headerContextChat", e -> {
+            e.getIn().setBody("Get my user profile");
+            e.getIn().setHeader(SpringAiChatConstants.TOOL_CONTEXT, 
Map.of("userId", "user-99", "role", "admin"));
+        });
+
+        assertThat(exchange).isNotNull();
+        String response = exchange.getMessage().getBody(String.class);
+        assertThat(response).isNotNull();
+        assertThat(response.toLowerCase()).containsAnyOf("user-99", "admin", 
"user", "profile");
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                bindChatModel(getCamelContext());
+
+                // Resolve ToolCallbacks from @Tool-annotated bean
+                var provider = MethodToolCallbackProvider.builder()
+                        .toolObjects(new ContextAwareTools())
+                        .build();
+                getCamelContext().getRegistry().bind("contextTools",
+                        Arrays.asList(provider.getToolCallbacks()));
+
+                // Chat with tool context configured on endpoint
+                from("direct:contextChat")
+                        .to("spring-ai-chat:contextChat?chatModel=#chatModel"
+                            + "&toolCallbacks=#contextTools"
+                            + "&toolContext.userId=user-42"
+                            + "&toolContext.role=viewer");
+
+                // Chat with tool context from header (no endpoint config)
+                from("direct:headerContextChat")
+                        
.to("spring-ai-chat:headerContextChat?chatModel=#chatModel"
+                            + "&toolCallbacks=#contextTools");
+            }
+        };
+    }
+
+    public static class ContextAwareTools {
+
+        @Tool(description = "Get user profile information for the current 
user")
+        public String getUserProfile(
+                @ToolParam(description = "optional detail level") String 
detail,
+                ToolContext toolContext) {
+            String userId = (String) 
toolContext.getContext().getOrDefault("userId", "unknown");
+            String role = (String) 
toolContext.getContext().getOrDefault("role", "guest");
+            return String.format("User profile: userId=%s, role=%s", userId, 
role);
+        }
+    }
+}
diff --git 
a/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-image/src/main/docs/spring-ai-image-component.adoc
 
b/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-image/src/main/docs/spring-ai-image-component.adoc
index 13d151476efc..f371c09e15a5 100644
--- 
a/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-image/src/main/docs/spring-ai-image-component.adoc
+++ 
b/components/camel-spring-parent/camel-spring-ai/camel-spring-ai-image/src/main/docs/spring-ai-image-component.adoc
@@ -2,7 +2,7 @@
 :doctitle: Spring AI Image
 :shortname: spring-ai-image
 :artifactid: camel-spring-ai-image
-:description: Generate images using Spring AI.
+:description: Spring AI Image Generation
 :since: 4.19
 :supportlevel: Preview
 :tabs-sync-option:
diff --git 
a/test-infra/camel-test-infra-mcp-everything/src/main/java/org/apache/camel/test/infra/mcp/everything/services/McpEverythingSseService.java
 
b/test-infra/camel-test-infra-mcp-everything/src/main/java/org/apache/camel/test/infra/mcp/everything/services/McpEverythingSseService.java
new file mode 100644
index 000000000000..00d380bace6d
--- /dev/null
+++ 
b/test-infra/camel-test-infra-mcp-everything/src/main/java/org/apache/camel/test/infra/mcp/everything/services/McpEverythingSseService.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.test.infra.mcp.everything.services;
+
+import org.apache.camel.test.infra.common.services.ContainerTestService;
+import org.apache.camel.test.infra.common.services.TestService;
+
+/**
+ * Test infra service for the MCP Everything Server running in SSE transport 
mode.
+ */
+public interface McpEverythingSseService extends TestService, 
McpEverythingSseInfraService, ContainerTestService {
+}

Reply via email to