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

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


The following commit(s) were added to refs/heads/main by this push:
     new 5ef1539bacbb CAMEL-22851: Implement native tool-search-tool for 
langchain4j-tools component (#20996)
5ef1539bacbb is described below

commit 5ef1539bacbb4732ed2610db95896715a98e916b
Author: Guillaume Nodet <[email protected]>
AuthorDate: Thu Feb 5 15:46:16 2026 +0100

    CAMEL-22851: Implement native tool-search-tool for langchain4j-tools 
component (#20996)
    
    This commit implements a native tool-search-tool feature for the 
camel-langchain4j-tools component that allows LLMs to discover and access tools 
dynamically without consuming the entire context window.
---
 .../catalog/components/langchain4j-tools.json      |  17 +-
 .../tools/LangChain4jToolsEndpointConfigurer.java  |   3 +
 .../tools/LangChain4jToolsEndpointUriFactory.java  |   3 +-
 .../langchain4j/tools/langchain4j-tools.json       |  17 +-
 .../src/main/docs/langchain4j-tools-component.adoc |  79 +++++++++
 .../tools/LangChain4jToolsEndpoint.java            |  54 ++++++-
 .../tools/LangChain4jToolsProducer.java            |  89 +++++++++++
 .../langchain4j/tools/ToolSearchTool.java          | 135 ++++++++++++++++
 .../tools/spec/CamelToolExecutorCache.java         |  54 ++++++-
 .../tools/spec/CamelToolSpecification.java         |  21 ++-
 .../langchain4j/tools/LangChain4jToolTest.java     |  85 ++++++++++
 .../tools/ToolSearchToolFormatTest.java            | 121 ++++++++++++++
 .../langchain4j/tools/ToolSearchToolTest.java      | 177 +++++++++++++++++++++
 .../tools/spec/CamelToolExecutorCacheTest.java     | 160 +++++++++++++++++++
 .../LangChain4jToolsEndpointBuilderFactory.java    |  34 ++++
 15 files changed, 1024 insertions(+), 25 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/langchain4j-tools.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/langchain4j-tools.json
index ab847741672e..d108c3e84d72 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/langchain4j-tools.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/langchain4j-tools.json
@@ -34,13 +34,14 @@
     "toolId": { "index": 0, "kind": "path", "displayName": "Tool Id", "group": 
"common", "label": "", "required": true, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "The tool id" },
     "tags": { "index": 1, "kind": "parameter", "displayName": "Tags", "group": 
"common", "label": "", "required": true, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "The tags for the tools" },
     "description": { "index": 2, "kind": "parameter", "displayName": 
"Description", "group": "consumer", "label": "consumer", "required": false, 
"type": "string", "javaType": "java.lang.String", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Tool description" },
-    "name": { "index": 3, "kind": "parameter", "displayName": "Name", "group": 
"consumer", "label": "consumer", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Tool name" },
-    "parameters": { "index": 4, "kind": "parameter", "displayName": 
"Parameters", "group": "consumer", "label": "consumer", "required": false, 
"type": "object", "javaType": "java.util.Map<java.lang.String, 
java.lang.String>", "prefix": "parameter.", "multiValue": true, "deprecated": 
false, "deprecationNote": "", "autowired": false, "secret": false, 
"description": "List of Tool parameters in the form of parameter.=. This is a 
multi-value option with prefix: parameter." },
-    "bridgeErrorHandler": { "index": 5, "kind": "parameter", "displayName": 
"Bridge Error Handler", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": false, "description": "Allows for bridging the consumer to the 
Camel routing Error Handler, which mean any exceptions (if possible) occurred 
while the Camel consumer is trying to pickup incoming  [...]
-    "camelToolParameter": { "index": 6, "kind": "parameter", "displayName": 
"Camel Tool Parameter", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "object", "javaType": 
"org.apache.camel.component.langchain4j.tools.spec.CamelSimpleToolParameter", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "Tool's Camel Parameters, programmatically define Tool 
description and parameters" },
-    "exceptionHandler": { "index": 7, "kind": "parameter", "displayName": 
"Exception Handler", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "object", "javaType": 
"org.apache.camel.spi.ExceptionHandler", "optionalPrefix": "consumer.", 
"deprecated": false, "autowired": false, "secret": false, "description": "To 
let the consumer use a custom ExceptionHandler. Notice if the option 
bridgeErrorHandler is enabled then this option is not in use. By def [...]
-    "exchangePattern": { "index": 8, "kind": "parameter", "displayName": 
"Exchange Pattern", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "enum", "javaType": 
"org.apache.camel.ExchangePattern", "enum": [ "InOnly", "InOut" ], 
"deprecated": false, "autowired": false, "secret": false, "description": "Sets 
the exchange pattern when the consumer creates an exchange." },
-    "lazyStartProducer": { "index": 9, "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 [...]
-    "chatModel": { "index": 10, "kind": "parameter", "displayName": "Chat 
Model", "group": "advanced", "label": "advanced", "required": false, "type": 
"object", "javaType": "dev.langchain4j.model.chat.ChatModel", "deprecated": 
false, "deprecationNote": "", "autowired": true, "secret": false, 
"configurationClass": 
"org.apache.camel.component.langchain4j.tools.LangChain4jToolsConfiguration", 
"configurationField": "configuration", "description": "Chat Model of type 
dev.langchain4j.model.cha [...]
+    "exposed": { "index": 3, "kind": "parameter", "displayName": "Exposed", 
"group": "consumer", "label": "consumer", "required": false, "type": "boolean", 
"javaType": "boolean", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "defaultValue": true, "description": "Whether the tool 
is automatically exposed to the LLM. When false, the tool is added to a 
searchable list and can be discovered via the tool-search-tool" },
+    "name": { "index": 4, "kind": "parameter", "displayName": "Name", "group": 
"consumer", "label": "consumer", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Tool name" },
+    "parameters": { "index": 5, "kind": "parameter", "displayName": 
"Parameters", "group": "consumer", "label": "consumer", "required": false, 
"type": "object", "javaType": "java.util.Map<java.lang.String, 
java.lang.String>", "prefix": "parameter.", "multiValue": true, "deprecated": 
false, "deprecationNote": "", "autowired": false, "secret": false, 
"description": "List of Tool parameters in the form of parameter.=. This is a 
multi-value option with prefix: parameter." },
+    "bridgeErrorHandler": { "index": 6, "kind": "parameter", "displayName": 
"Bridge Error Handler", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": false, "description": "Allows for bridging the consumer to the 
Camel routing Error Handler, which mean any exceptions (if possible) occurred 
while the Camel consumer is trying to pickup incoming  [...]
+    "camelToolParameter": { "index": 7, "kind": "parameter", "displayName": 
"Camel Tool Parameter", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "object", "javaType": 
"org.apache.camel.component.langchain4j.tools.spec.CamelSimpleToolParameter", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "Tool's Camel Parameters, programmatically define Tool 
description and parameters" },
+    "exceptionHandler": { "index": 8, "kind": "parameter", "displayName": 
"Exception Handler", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "object", "javaType": 
"org.apache.camel.spi.ExceptionHandler", "optionalPrefix": "consumer.", 
"deprecated": false, "autowired": false, "secret": false, "description": "To 
let the consumer use a custom ExceptionHandler. Notice if the option 
bridgeErrorHandler is enabled then this option is not in use. By def [...]
+    "exchangePattern": { "index": 9, "kind": "parameter", "displayName": 
"Exchange Pattern", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "enum", "javaType": 
"org.apache.camel.ExchangePattern", "enum": [ "InOnly", "InOut" ], 
"deprecated": false, "autowired": false, "secret": false, "description": "Sets 
the exchange pattern when the consumer creates an exchange." },
+    "lazyStartProducer": { "index": 10, "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 produ [...]
+    "chatModel": { "index": 11, "kind": "parameter", "displayName": "Chat 
Model", "group": "advanced", "label": "advanced", "required": false, "type": 
"object", "javaType": "dev.langchain4j.model.chat.ChatModel", "deprecated": 
false, "deprecationNote": "", "autowired": true, "secret": false, 
"configurationClass": 
"org.apache.camel.component.langchain4j.tools.LangChain4jToolsConfiguration", 
"configurationField": "configuration", "description": "Chat Model of type 
dev.langchain4j.model.cha [...]
   }
 }
diff --git 
a/components/camel-ai/camel-langchain4j-tools/src/generated/java/org/apache/camel/component/langchain4j/tools/LangChain4jToolsEndpointConfigurer.java
 
b/components/camel-ai/camel-langchain4j-tools/src/generated/java/org/apache/camel/component/langchain4j/tools/LangChain4jToolsEndpointConfigurer.java
index 1eb3697ccef6..65185ab644f1 100644
--- 
a/components/camel-ai/camel-langchain4j-tools/src/generated/java/org/apache/camel/component/langchain4j/tools/LangChain4jToolsEndpointConfigurer.java
+++ 
b/components/camel-ai/camel-langchain4j-tools/src/generated/java/org/apache/camel/component/langchain4j/tools/LangChain4jToolsEndpointConfigurer.java
@@ -34,6 +34,7 @@ public class LangChain4jToolsEndpointConfigurer extends 
PropertyConfigurerSuppor
         case "exceptionHandler": 
target.setExceptionHandler(property(camelContext, 
org.apache.camel.spi.ExceptionHandler.class, value)); return true;
         case "exchangepattern":
         case "exchangePattern": 
target.setExchangePattern(property(camelContext, 
org.apache.camel.ExchangePattern.class, value)); return true;
+        case "exposed": target.setExposed(property(camelContext, 
boolean.class, value)); return true;
         case "lazystartproducer":
         case "lazyStartProducer": 
target.setLazyStartProducer(property(camelContext, boolean.class, value)); 
return true;
         case "name": target.setName(property(camelContext, 
java.lang.String.class, value)); return true;
@@ -62,6 +63,7 @@ public class LangChain4jToolsEndpointConfigurer extends 
PropertyConfigurerSuppor
         case "exceptionHandler": return 
org.apache.camel.spi.ExceptionHandler.class;
         case "exchangepattern":
         case "exchangePattern": return org.apache.camel.ExchangePattern.class;
+        case "exposed": return boolean.class;
         case "lazystartproducer":
         case "lazyStartProducer": return boolean.class;
         case "name": return java.lang.String.class;
@@ -86,6 +88,7 @@ public class LangChain4jToolsEndpointConfigurer extends 
PropertyConfigurerSuppor
         case "exceptionHandler": return target.getExceptionHandler();
         case "exchangepattern":
         case "exchangePattern": return target.getExchangePattern();
+        case "exposed": return target.isExposed();
         case "lazystartproducer":
         case "lazyStartProducer": return target.isLazyStartProducer();
         case "name": return target.getName();
diff --git 
a/components/camel-ai/camel-langchain4j-tools/src/generated/java/org/apache/camel/component/langchain4j/tools/LangChain4jToolsEndpointUriFactory.java
 
b/components/camel-ai/camel-langchain4j-tools/src/generated/java/org/apache/camel/component/langchain4j/tools/LangChain4jToolsEndpointUriFactory.java
index f67e9c5fe8ce..ef88f458975f 100644
--- 
a/components/camel-ai/camel-langchain4j-tools/src/generated/java/org/apache/camel/component/langchain4j/tools/LangChain4jToolsEndpointUriFactory.java
+++ 
b/components/camel-ai/camel-langchain4j-tools/src/generated/java/org/apache/camel/component/langchain4j/tools/LangChain4jToolsEndpointUriFactory.java
@@ -23,13 +23,14 @@ public class LangChain4jToolsEndpointUriFactory extends 
org.apache.camel.support
     private static final Set<String> SECRET_PROPERTY_NAMES;
     private static final Map<String, String> MULTI_VALUE_PREFIXES;
     static {
-        Set<String> props = new HashSet<>(11);
+        Set<String> props = new HashSet<>(12);
         props.add("bridgeErrorHandler");
         props.add("camelToolParameter");
         props.add("chatModel");
         props.add("description");
         props.add("exceptionHandler");
         props.add("exchangePattern");
+        props.add("exposed");
         props.add("lazyStartProducer");
         props.add("name");
         props.add("parameters");
diff --git 
a/components/camel-ai/camel-langchain4j-tools/src/generated/resources/META-INF/org/apache/camel/component/langchain4j/tools/langchain4j-tools.json
 
b/components/camel-ai/camel-langchain4j-tools/src/generated/resources/META-INF/org/apache/camel/component/langchain4j/tools/langchain4j-tools.json
index ab847741672e..d108c3e84d72 100644
--- 
a/components/camel-ai/camel-langchain4j-tools/src/generated/resources/META-INF/org/apache/camel/component/langchain4j/tools/langchain4j-tools.json
+++ 
b/components/camel-ai/camel-langchain4j-tools/src/generated/resources/META-INF/org/apache/camel/component/langchain4j/tools/langchain4j-tools.json
@@ -34,13 +34,14 @@
     "toolId": { "index": 0, "kind": "path", "displayName": "Tool Id", "group": 
"common", "label": "", "required": true, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "The tool id" },
     "tags": { "index": 1, "kind": "parameter", "displayName": "Tags", "group": 
"common", "label": "", "required": true, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "The tags for the tools" },
     "description": { "index": 2, "kind": "parameter", "displayName": 
"Description", "group": "consumer", "label": "consumer", "required": false, 
"type": "string", "javaType": "java.lang.String", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Tool description" },
-    "name": { "index": 3, "kind": "parameter", "displayName": "Name", "group": 
"consumer", "label": "consumer", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Tool name" },
-    "parameters": { "index": 4, "kind": "parameter", "displayName": 
"Parameters", "group": "consumer", "label": "consumer", "required": false, 
"type": "object", "javaType": "java.util.Map<java.lang.String, 
java.lang.String>", "prefix": "parameter.", "multiValue": true, "deprecated": 
false, "deprecationNote": "", "autowired": false, "secret": false, 
"description": "List of Tool parameters in the form of parameter.=. This is a 
multi-value option with prefix: parameter." },
-    "bridgeErrorHandler": { "index": 5, "kind": "parameter", "displayName": 
"Bridge Error Handler", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": false, "description": "Allows for bridging the consumer to the 
Camel routing Error Handler, which mean any exceptions (if possible) occurred 
while the Camel consumer is trying to pickup incoming  [...]
-    "camelToolParameter": { "index": 6, "kind": "parameter", "displayName": 
"Camel Tool Parameter", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "object", "javaType": 
"org.apache.camel.component.langchain4j.tools.spec.CamelSimpleToolParameter", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "Tool's Camel Parameters, programmatically define Tool 
description and parameters" },
-    "exceptionHandler": { "index": 7, "kind": "parameter", "displayName": 
"Exception Handler", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "object", "javaType": 
"org.apache.camel.spi.ExceptionHandler", "optionalPrefix": "consumer.", 
"deprecated": false, "autowired": false, "secret": false, "description": "To 
let the consumer use a custom ExceptionHandler. Notice if the option 
bridgeErrorHandler is enabled then this option is not in use. By def [...]
-    "exchangePattern": { "index": 8, "kind": "parameter", "displayName": 
"Exchange Pattern", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "enum", "javaType": 
"org.apache.camel.ExchangePattern", "enum": [ "InOnly", "InOut" ], 
"deprecated": false, "autowired": false, "secret": false, "description": "Sets 
the exchange pattern when the consumer creates an exchange." },
-    "lazyStartProducer": { "index": 9, "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 [...]
-    "chatModel": { "index": 10, "kind": "parameter", "displayName": "Chat 
Model", "group": "advanced", "label": "advanced", "required": false, "type": 
"object", "javaType": "dev.langchain4j.model.chat.ChatModel", "deprecated": 
false, "deprecationNote": "", "autowired": true, "secret": false, 
"configurationClass": 
"org.apache.camel.component.langchain4j.tools.LangChain4jToolsConfiguration", 
"configurationField": "configuration", "description": "Chat Model of type 
dev.langchain4j.model.cha [...]
+    "exposed": { "index": 3, "kind": "parameter", "displayName": "Exposed", 
"group": "consumer", "label": "consumer", "required": false, "type": "boolean", 
"javaType": "boolean", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "defaultValue": true, "description": "Whether the tool 
is automatically exposed to the LLM. When false, the tool is added to a 
searchable list and can be discovered via the tool-search-tool" },
+    "name": { "index": 4, "kind": "parameter", "displayName": "Name", "group": 
"consumer", "label": "consumer", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Tool name" },
+    "parameters": { "index": 5, "kind": "parameter", "displayName": 
"Parameters", "group": "consumer", "label": "consumer", "required": false, 
"type": "object", "javaType": "java.util.Map<java.lang.String, 
java.lang.String>", "prefix": "parameter.", "multiValue": true, "deprecated": 
false, "deprecationNote": "", "autowired": false, "secret": false, 
"description": "List of Tool parameters in the form of parameter.=. This is a 
multi-value option with prefix: parameter." },
+    "bridgeErrorHandler": { "index": 6, "kind": "parameter", "displayName": 
"Bridge Error Handler", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": false, "description": "Allows for bridging the consumer to the 
Camel routing Error Handler, which mean any exceptions (if possible) occurred 
while the Camel consumer is trying to pickup incoming  [...]
+    "camelToolParameter": { "index": 7, "kind": "parameter", "displayName": 
"Camel Tool Parameter", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "object", "javaType": 
"org.apache.camel.component.langchain4j.tools.spec.CamelSimpleToolParameter", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "Tool's Camel Parameters, programmatically define Tool 
description and parameters" },
+    "exceptionHandler": { "index": 8, "kind": "parameter", "displayName": 
"Exception Handler", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "object", "javaType": 
"org.apache.camel.spi.ExceptionHandler", "optionalPrefix": "consumer.", 
"deprecated": false, "autowired": false, "secret": false, "description": "To 
let the consumer use a custom ExceptionHandler. Notice if the option 
bridgeErrorHandler is enabled then this option is not in use. By def [...]
+    "exchangePattern": { "index": 9, "kind": "parameter", "displayName": 
"Exchange Pattern", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "enum", "javaType": 
"org.apache.camel.ExchangePattern", "enum": [ "InOnly", "InOut" ], 
"deprecated": false, "autowired": false, "secret": false, "description": "Sets 
the exchange pattern when the consumer creates an exchange." },
+    "lazyStartProducer": { "index": 10, "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 produ [...]
+    "chatModel": { "index": 11, "kind": "parameter", "displayName": "Chat 
Model", "group": "advanced", "label": "advanced", "required": false, "type": 
"object", "javaType": "dev.langchain4j.model.chat.ChatModel", "deprecated": 
false, "deprecationNote": "", "autowired": true, "secret": false, 
"configurationClass": 
"org.apache.camel.component.langchain4j.tools.LangChain4jToolsConfiguration", 
"configurationField": "configuration", "description": "Chat Model of type 
dev.langchain4j.model.cha [...]
   }
 }
diff --git 
a/components/camel-ai/camel-langchain4j-tools/src/main/docs/langchain4j-tools-component.adoc
 
b/components/camel-ai/camel-langchain4j-tools/src/main/docs/langchain4j-tools-component.adoc
index 517b96194389..093e376d1edc 100644
--- 
a/components/camel-ai/camel-langchain4j-tools/src/main/docs/langchain4j-tools-component.adoc
+++ 
b/components/camel-ai/camel-langchain4j-tools/src/main/docs/langchain4j-tools-component.adoc
@@ -181,3 +181,82 @@ To switch to another Large Language Model and its 
corresponding dependency, repl
 In some circumstances, the LLM may decide not to call a tool.
 This is a valid scenario that needs to be handled by application developers.
 To do so, developers can get the `LangChain4jTools.NO_TOOLS_CALLED_HEADER` 
from the exchange.
+
+=== Tool Search Tool
+
+The Tool Search Tool is a native feature that allows LLMs to discover and 
access tools dynamically without consuming the entire context window with tool 
definitions.
+
+==== Overview
+
+When you have many tools available, exposing all of them to the LLM in every 
request can:
+
+* Consume significant context window space
+* Reduce the space available for actual conversation
+* Potentially confuse the LLM with too many options
+
+The Tool Search Tool solves this by allowing you to mark certain tools as 
"searchable" (non-exposed). These tools are not automatically sent to the LLM 
but can be discovered when needed.
+
+==== Using the `exposed` Parameter
+
+By default, all tools are exposed to the LLM (`exposed=true`). To make a tool 
searchable instead:
+
+[source, java]
+----
+from("langchain4j-tools:queryBySSN?tags=users&description=Query user database 
by social security number&parameter.ssn=string&exposed=false")
+    .to("sql:SELECT name FROM users WHERE ssn = :#ssn");
+----
+
+==== How It Works
+
+1. When you define tools with `exposed=false`, they are added to a searchable 
tool registry
+2. A native `toolSearchTool` is automatically exposed to the LLM when 
searchable tools exist
+3. The LLM can invoke `toolSearchTool` with tags to discover available tools
+4. The search results are returned to the LLM, which can then decide which 
tools to use
+
+==== Example: Mixed Exposed and Searchable Tools
+
+[source, java]
+----
+// This tool is immediately available to the LLM
+from("langchain4j-tools:queryById?tags=users&description=Query user database 
by user ID&parameter.userId=integer")
+    .to("sql:SELECT name FROM users WHERE id = :#userId");
+
+// This tool is searchable but not immediately exposed
+from("langchain4j-tools:queryBySSN?tags=users&description=Query user database 
by social security number&parameter.ssn=string&exposed=false")
+    .to("sql:SELECT name FROM users WHERE ssn = :#ssn");
+
+// Another searchable tool with different tags
+from("langchain4j-tools:sendEmail?tags=users,email&description=Send email to a 
user&parameter.email=string&parameter.message=string&exposed=false")
+    .to("smtp://mailserver");
+----
+
+In this example:
+
+* The `queryById` tool is immediately available to the LLM
+* The `queryBySSN` and `sendEmail` tools can be discovered by searching for 
tags like "users" or "email"
+* The LLM can use the `toolSearchTool` to find these additional capabilities 
when needed
+
+==== Benefits
+
+* *Reduced Context Usage*: Only expose the most commonly used tools initially
+* *Scalability*: Support hundreds or thousands of tools without overwhelming 
the LLM
+* *Dynamic Discovery*: Let the LLM discover tools as needed based on the 
conversation
+* *Better Organization*: Group related tools by tags for easier discovery
+
+==== Best Practices
+
+When using the Tool Search Tool feature, consider the following best practices:
+
+* *Tag Strategy*: Use meaningful, hierarchical tags (e.g., "users", 
"users.admin", "database.users") to organize tools logically
+* *Expose Common Tools*: Keep frequently used tools exposed (`exposed=true`) 
and make specialized tools searchable (`exposed=false`)
+* *Performance Considerations*: While the search is efficient, having 
thousands of searchable tools may impact search performance. Consider grouping 
tools by functional area
+* *LLM Guidance*: In your system message, inform the LLM about the 
availability of the `toolSearchTool` and when to use it
+* *Tag Naming*: Use consistent, lowercase tag names without special characters 
for best compatibility
+* *Tool Descriptions*: Write clear, descriptive tool descriptions as they are 
returned in search results to help the LLM choose the right tool
+* *Testing*: Test your tool organization with real queries to ensure the LLM 
can discover and use tools effectively
+
+==== Limitations
+
+* The LLM must be instructed to use the `toolSearchTool` - it won't 
automatically know to search for tools
+* Search is based on exact tag matching - fuzzy matching or semantic search is 
not currently supported
+* The feature requires an LLM with good function-calling capabilities to work 
effectively
diff --git 
a/components/camel-ai/camel-langchain4j-tools/src/main/java/org/apache/camel/component/langchain4j/tools/LangChain4jToolsEndpoint.java
 
b/components/camel-ai/camel-langchain4j-tools/src/main/java/org/apache/camel/component/langchain4j/tools/LangChain4jToolsEndpoint.java
index c125e6b3088b..3ab33610503a 100644
--- 
a/components/camel-ai/camel-langchain4j-tools/src/main/java/org/apache/camel/component/langchain4j/tools/LangChain4jToolsEndpoint.java
+++ 
b/components/camel-ai/camel-langchain4j-tools/src/main/java/org/apache/camel/component/langchain4j/tools/LangChain4jToolsEndpoint.java
@@ -40,6 +40,8 @@ import org.apache.camel.spi.UriParam;
 import org.apache.camel.spi.UriPath;
 import org.apache.camel.support.DefaultEndpoint;
 import org.apache.camel.util.StringHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import static 
org.apache.camel.component.langchain4j.tools.LangChain4jTools.SCHEME;
 
@@ -49,6 +51,8 @@ import static 
org.apache.camel.component.langchain4j.tools.LangChain4jTools.SCHE
              category = { Category.AI })
 public class LangChain4jToolsEndpoint extends DefaultEndpoint {
 
+    private static final Logger LOG = 
LoggerFactory.getLogger(LangChain4jToolsEndpoint.class);
+
     @Metadata(required = true)
     @UriPath(description = "The tool id")
     private final String toolId;
@@ -77,6 +81,14 @@ public class LangChain4jToolsEndpoint extends 
DefaultEndpoint {
     @UriParam(description = "Tool's Camel Parameters, programmatically define 
Tool description and parameters")
     private CamelSimpleToolParameter camelToolParameter;
 
+    @Metadata(label = "consumer", defaultValue = "true")
+    @UriParam(description = "Whether the tool is automatically exposed to the 
LLM. When false, the tool is added to a searchable list and can be discovered 
via the tool-search-tool",
+              defaultValue = "true")
+    private boolean exposed = true;
+
+    // Track the tool specification created by this endpoint for proper cleanup
+    private CamelToolSpecification camelToolSpecification;
+
     public LangChain4jToolsEndpoint(String uri, LangChain4jToolsComponent 
component, String toolId, String tags,
                                     LangChain4jToolsConfiguration 
configuration) {
         super(uri, component);
@@ -143,13 +155,18 @@ public class LangChain4jToolsEndpoint extends 
DefaultEndpoint {
         final LangChain4jToolsConsumer langChain4jToolsConsumer = new 
LangChain4jToolsConsumer(this, processor);
         configureConsumer(langChain4jToolsConsumer);
 
-        CamelToolSpecification camelToolSpecification
-                = new CamelToolSpecification(toolSpecification, 
langChain4jToolsConsumer);
+        camelToolSpecification = new CamelToolSpecification(toolSpecification, 
langChain4jToolsConsumer, exposed);
         final CamelToolExecutorCache executorCache = 
CamelToolExecutorCache.getInstance();
 
         String[] splitTags = TagsHelper.splitTags(tags);
         for (String tag : splitTags) {
-            executorCache.put(tag, camelToolSpecification);
+            if (exposed) {
+                LOG.debug("Registering exposed tool: {} with tag: {}", 
toolSpecification.name(), tag);
+                executorCache.put(tag, camelToolSpecification);
+            } else {
+                LOG.debug("Registering searchable tool: {} with tag: {}", 
toolSpecification.name(), tag);
+                executorCache.putSearchable(tag, camelToolSpecification);
+            }
         }
 
         return camelToolSpecification.getConsumer();
@@ -233,11 +250,40 @@ public class LangChain4jToolsEndpoint extends 
DefaultEndpoint {
         return tags;
     }
 
+    /**
+     * Whether the tool is automatically exposed to the LLM
+     *
+     * @return true if the tool is exposed, false if searchable only
+     */
+    public boolean isExposed() {
+        return exposed;
+    }
+
+    public void setExposed(boolean exposed) {
+        this.exposed = exposed;
+    }
+
     @Override
     protected void doStop() throws Exception {
         super.doStop();
 
-        CamelToolExecutorCache.getInstance().getTools().clear();
+        // Only remove tools registered by this endpoint, not all tools
+        if (camelToolSpecification != null) {
+            final CamelToolExecutorCache executorCache = 
CamelToolExecutorCache.getInstance();
+            String[] splitTags = TagsHelper.splitTags(tags);
+
+            for (String tag : splitTags) {
+                if (exposed) {
+                    LOG.debug("Removing exposed tool: {} with tag: {}",
+                            
camelToolSpecification.getToolSpecification().name(), tag);
+                    executorCache.remove(tag, camelToolSpecification);
+                } else {
+                    LOG.debug("Removing searchable tool: {} with tag: {}",
+                            
camelToolSpecification.getToolSpecification().name(), tag);
+                    executorCache.removeSearchable(tag, 
camelToolSpecification);
+                }
+            }
+        }
     }
 
     /**
diff --git 
a/components/camel-ai/camel-langchain4j-tools/src/main/java/org/apache/camel/component/langchain4j/tools/LangChain4jToolsProducer.java
 
b/components/camel-ai/camel-langchain4j-tools/src/main/java/org/apache/camel/component/langchain4j/tools/LangChain4jToolsProducer.java
index 1fd5da30e1ef..522609ee9424 100644
--- 
a/components/camel-ai/camel-langchain4j-tools/src/main/java/org/apache/camel/component/langchain4j/tools/LangChain4jToolsProducer.java
+++ 
b/components/camel-ai/camel-langchain4j-tools/src/main/java/org/apache/camel/component/langchain4j/tools/LangChain4jToolsProducer.java
@@ -35,6 +35,8 @@ import dev.langchain4j.data.message.ChatMessage;
 import dev.langchain4j.data.message.ToolExecutionResultMessage;
 import dev.langchain4j.model.chat.ChatModel;
 import dev.langchain4j.model.chat.request.ChatRequest;
+import dev.langchain4j.model.chat.request.json.JsonObjectSchema;
+import dev.langchain4j.model.chat.request.json.JsonStringSchema;
 import dev.langchain4j.model.chat.response.ChatResponse;
 import dev.langchain4j.model.output.FinishReason;
 import dev.langchain4j.model.output.Response;
@@ -57,6 +59,8 @@ public class LangChain4jToolsProducer extends DefaultProducer 
{
 
     private final ObjectMapper objectMapper = new ObjectMapper();
 
+    private ToolSearchTool toolSearchTool;
+
     public LangChain4jToolsProducer(LangChain4jToolsEndpoint endpoint) {
         super(endpoint);
         this.endpoint = endpoint;
@@ -80,6 +84,11 @@ public class LangChain4jToolsProducer extends 
DefaultProducer {
         super.doStart();
         this.chatModel = this.endpoint.getConfiguration().getChatModel();
         ObjectHelper.notNull(chatModel, "chatModel");
+
+        // Initialize the tool search tool
+        final CamelToolExecutorCache toolCache = 
CamelToolExecutorCache.getInstance();
+        String[] tags = TagsHelper.splitTags(endpoint.getTags());
+        this.toolSearchTool = new ToolSearchTool(toolCache, tags);
     }
 
     private void populateResponse(String response, Exchange exchange) {
@@ -151,6 +160,13 @@ public class LangChain4jToolsProducer extends 
DefaultProducer {
             String toolName = toolExecutionRequest.name();
             LOG.info("Invoking tool {} ({}) of {}", i, toolName, 
toolExecutionRequests.size());
 
+            // Check if this is the ToolSearchTool
+            if (ToolSearchTool.TOOL_NAME.equals(toolName)) {
+                handleToolSearchToolInvocation(toolExecutionRequest, 
chatMessages, exchange);
+                i++;
+                continue;
+            }
+
             final CamelToolSpecification camelToolSpecification = 
toolPair.callableTools().stream()
                     .filter(c -> 
c.getToolSpecification().name().equals(toolName)).findFirst().get();
 
@@ -199,6 +215,55 @@ public class LangChain4jToolsProducer extends 
DefaultProducer {
         }
     }
 
+    /**
+     * Handles the invocation of the ToolSearchTool
+     *
+     * @param toolExecutionRequest the tool execution request
+     * @param chatMessages         the chat messages
+     * @param exchange             the exchange
+     */
+    private void handleToolSearchToolInvocation(
+            ToolExecutionRequest toolExecutionRequest, List<ChatMessage> 
chatMessages, Exchange exchange) {
+        try {
+            // Validate arguments
+            String arguments = toolExecutionRequest.arguments();
+            if (arguments == null || arguments.trim().isEmpty()) {
+                LOG.warn("ToolSearchTool invoked with null or empty 
arguments");
+                chatMessages.add(new ToolExecutionResultMessage(
+                        toolExecutionRequest.id(),
+                        toolExecutionRequest.name(),
+                        "No search criteria provided. Please specify tags to 
search for tools."));
+                return;
+            }
+
+            // Parse the arguments
+            JsonNode jsonNode = objectMapper.readValue(arguments, 
JsonNode.class);
+            String tags = jsonNode.has("tags") ? jsonNode.get("tags").asText() 
: "";
+
+            LOG.debug("ToolSearchTool searching for tags: {}", tags);
+
+            // Search for tools
+            List<CamelToolSpecification> matchingTools = 
toolSearchTool.searchTools(tags);
+
+            // Format the result for the LLM
+            String result = ToolSearchTool.formatToolsForLLM(matchingTools);
+
+            // Add the result to chat messages
+            chatMessages.add(new ToolExecutionResultMessage(
+                    toolExecutionRequest.id(),
+                    toolExecutionRequest.name(),
+                    result));
+
+            LOG.info("ToolSearchTool found {} matching tools for tags: {}", 
matchingTools.size(), tags);
+        } catch (Exception e) {
+            LOG.error("Error executing ToolSearchTool", e);
+            chatMessages.add(new ToolExecutionResultMessage(
+                    toolExecutionRequest.id(),
+                    toolExecutionRequest.name(),
+                    "Error searching for tools: " + e.getMessage()));
+        }
+    }
+
     /**
      * This talks with the LLM to, passing the list of tools, and expects a 
response listing one ore more tools to be
      * called
@@ -264,6 +329,12 @@ public class LangChain4jToolsProducer extends 
DefaultProducer {
             }
         }
 
+        // Add the ToolSearchTool if there are searchable tools
+        if (toolCache.hasSearchableTools()) {
+            ToolSpecification searchToolSpec = 
createToolSearchToolSpecification();
+            toolSpecifications.add(searchToolSpec);
+        }
+
         if (toolSpecifications.isEmpty()) {
             
exchange.getMessage().setHeader(LangChain4jTools.NO_TOOLS_CALLED_HEADER, 
Boolean.TRUE);
             return null;
@@ -272,6 +343,24 @@ public class LangChain4jToolsProducer extends 
DefaultProducer {
         return new ToolPair(toolSpecifications, callableTools);
     }
 
+    /**
+     * Creates the ToolSpecification for the native ToolSearchTool
+     *
+     * @return the tool specification
+     */
+    private ToolSpecification createToolSearchToolSpecification() {
+        return ToolSpecification.builder()
+                .name(ToolSearchTool.TOOL_NAME)
+                .description(ToolSearchTool.TOOL_DESCRIPTION)
+                .parameters(JsonObjectSchema.builder()
+                        .addProperty("tags", JsonStringSchema.builder()
+                                .description(
+                                        "Comma-separated list of tags to 
search for tools. Examples: 'users', 'email,users', 'database'. Leave empty to 
see all available searchable tools.")
+                                .build())
+                        .build())
+                .build();
+    }
+
     /**
      * The pair of tools specifications that the Camel tools (i.e.: routes) 
that can be called for that set
      *
diff --git 
a/components/camel-ai/camel-langchain4j-tools/src/main/java/org/apache/camel/component/langchain4j/tools/ToolSearchTool.java
 
b/components/camel-ai/camel-langchain4j-tools/src/main/java/org/apache/camel/component/langchain4j/tools/ToolSearchTool.java
new file mode 100644
index 000000000000..af616ed277c6
--- /dev/null
+++ 
b/components/camel-ai/camel-langchain4j-tools/src/main/java/org/apache/camel/component/langchain4j/tools/ToolSearchTool.java
@@ -0,0 +1,135 @@
+/*
+ * 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.langchain4j.tools;
+
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import dev.langchain4j.agent.tool.ToolSpecification;
+import 
org.apache.camel.component.langchain4j.tools.spec.CamelToolExecutorCache;
+import 
org.apache.camel.component.langchain4j.tools.spec.CamelToolSpecification;
+
+/**
+ * Native tool that allows LLMs to search for available tools without 
consuming the context window. This tool is
+ * automatically exposed when there are searchable (non-exposed) tools 
registered.
+ */
+public class ToolSearchTool {
+
+    public static final String TOOL_NAME = "toolSearchTool";
+    public static final String TOOL_DESCRIPTION
+            = "Search for available tools by tags or keywords. Use this to 
discover tools that can help accomplish specific tasks.";
+
+    private final CamelToolExecutorCache toolCache;
+    private final String[] producerTags;
+
+    public ToolSearchTool(CamelToolExecutorCache toolCache, String[] 
producerTags) {
+        this.toolCache = toolCache;
+        this.producerTags = producerTags;
+    }
+
+    /**
+     * Searches for tools matching the given tags. The search looks for tools 
in the searchable registry that match any
+     * of the provided tags.
+     *
+     * @param  tags comma-separated list of tags to search for
+     * @return      list of matching tool specifications (without duplicates)
+     */
+    public List<CamelToolSpecification> searchTools(String tags) {
+        // Use LinkedHashSet to maintain insertion order while preventing 
duplicates
+        Set<CamelToolSpecification> matchingTools = new LinkedHashSet<>();
+
+        if (tags == null || tags.trim().isEmpty()) {
+            // Return all searchable tools if no tags specified
+            return getAllSearchableTools();
+        }
+
+        String[] searchTags = TagsHelper.splitTags(tags);
+        Map<String, Set<CamelToolSpecification>> searchableTools = 
toolCache.getSearchableTools();
+
+        // Search for tools matching any of the search tags
+        // Note: We don't filter by producer tags here - the search should 
find all tools
+        // with matching tags in the searchable registry, regardless of 
producer tags
+        for (String searchTag : searchTags) {
+            Set<CamelToolSpecification> toolsForTag = 
searchableTools.get(searchTag);
+            if (toolsForTag != null) {
+                matchingTools.addAll(toolsForTag);
+            }
+        }
+
+        return new ArrayList<>(matchingTools);
+    }
+
+    /**
+     * Gets all searchable tools for the producer's tags
+     *
+     * @return list of all searchable tool specifications
+     */
+    public List<CamelToolSpecification> getAllSearchableTools() {
+        List<CamelToolSpecification> allTools = new ArrayList<>();
+        Map<String, Set<CamelToolSpecification>> searchableTools = 
toolCache.getSearchableTools();
+
+        for (String tag : producerTags) {
+            Set<CamelToolSpecification> toolsForTag = searchableTools.get(tag);
+            if (toolsForTag != null) {
+                allTools.addAll(toolsForTag);
+            }
+        }
+
+        return allTools;
+    }
+
+    /**
+     * Formats tool specifications as a readable string for the LLM
+     *
+     * @param  tools list of tool specifications
+     * @return       formatted string describing the tools
+     */
+    public static String formatToolsForLLM(List<CamelToolSpecification> tools) 
{
+        if (tools.isEmpty()) {
+            return "No tools found matching the search criteria.";
+        }
+
+        StringBuilder result = new StringBuilder();
+        result.append("Found ").append(tools.size()).append(" tool(s):\n\n");
+
+        for (int i = 0; i < tools.size(); i++) {
+            CamelToolSpecification tool = tools.get(i);
+            ToolSpecification spec = tool.getToolSpecification();
+
+            result.append(i + 1).append(". ").append(spec.name()).append("\n");
+            result.append("   Description: 
").append(spec.description()).append("\n");
+
+            if (spec.parameters() != null && spec.parameters().properties() != 
null
+                    && !spec.parameters().properties().isEmpty()) {
+                result.append("   Parameters: ");
+                spec.parameters().properties().forEach((name, schema) -> {
+                    result.append(name).append(", ");
+                });
+                // Remove trailing comma and space
+                result.setLength(result.length() - 2);
+                result.append("\n");
+            }
+
+            result.append("\n");
+        }
+
+        return result.toString();
+    }
+}
diff --git 
a/components/camel-ai/camel-langchain4j-tools/src/main/java/org/apache/camel/component/langchain4j/tools/spec/CamelToolExecutorCache.java
 
b/components/camel-ai/camel-langchain4j-tools/src/main/java/org/apache/camel/component/langchain4j/tools/spec/CamelToolExecutorCache.java
index 6c00e31b7473..102cbdfb0972 100644
--- 
a/components/camel-ai/camel-langchain4j-tools/src/main/java/org/apache/camel/component/langchain4j/tools/spec/CamelToolExecutorCache.java
+++ 
b/components/camel-ai/camel-langchain4j-tools/src/main/java/org/apache/camel/component/langchain4j/tools/spec/CamelToolExecutorCache.java
@@ -23,14 +23,16 @@ import java.util.concurrent.ConcurrentHashMap;
 
 /**
  * Caches Tools Specification and Consumer route reference by the chatId, so 
that different chats can have different
- * Tool implementation
+ * Tool implementation. Also maintains a separate cache for searchable 
(non-exposed) tools.
  */
 public final class CamelToolExecutorCache {
 
     private Map<String, Set<CamelToolSpecification>> tools;
+    private Map<String, Set<CamelToolSpecification>> searchableTools;
 
     private CamelToolExecutorCache() {
         tools = new ConcurrentHashMap<>();
+        searchableTools = new ConcurrentHashMap<>();
     }
 
     private static final class SingletonHolder {
@@ -51,7 +53,57 @@ public final class CamelToolExecutorCache {
         }
     }
 
+    public void putSearchable(String chatId, CamelToolSpecification 
specification) {
+        if (searchableTools.get(chatId) != null) {
+            searchableTools.get(chatId).add(specification);
+        } else {
+            Set<CamelToolSpecification> camelToolSpecifications = new 
LinkedHashSet<>();
+            camelToolSpecifications.add(specification);
+            searchableTools.put(chatId, camelToolSpecifications);
+        }
+    }
+
+    /**
+     * Removes a specific tool specification from the exposed tools cache
+     *
+     * @param chatId        the chat/tag identifier
+     * @param specification the tool specification to remove
+     */
+    public void remove(String chatId, CamelToolSpecification specification) {
+        Set<CamelToolSpecification> toolsForTag = tools.get(chatId);
+        if (toolsForTag != null) {
+            toolsForTag.remove(specification);
+            if (toolsForTag.isEmpty()) {
+                tools.remove(chatId);
+            }
+        }
+    }
+
+    /**
+     * Removes a specific tool specification from the searchable tools cache
+     *
+     * @param chatId        the chat/tag identifier
+     * @param specification the tool specification to remove
+     */
+    public void removeSearchable(String chatId, CamelToolSpecification 
specification) {
+        Set<CamelToolSpecification> toolsForTag = searchableTools.get(chatId);
+        if (toolsForTag != null) {
+            toolsForTag.remove(specification);
+            if (toolsForTag.isEmpty()) {
+                searchableTools.remove(chatId);
+            }
+        }
+    }
+
     public Map<String, Set<CamelToolSpecification>> getTools() {
         return tools;
     }
+
+    public Map<String, Set<CamelToolSpecification>> getSearchableTools() {
+        return searchableTools;
+    }
+
+    public boolean hasSearchableTools() {
+        return !searchableTools.isEmpty();
+    }
 }
diff --git 
a/components/camel-ai/camel-langchain4j-tools/src/main/java/org/apache/camel/component/langchain4j/tools/spec/CamelToolSpecification.java
 
b/components/camel-ai/camel-langchain4j-tools/src/main/java/org/apache/camel/component/langchain4j/tools/spec/CamelToolSpecification.java
index 7cda5f076ae1..678240fa18f9 100644
--- 
a/components/camel-ai/camel-langchain4j-tools/src/main/java/org/apache/camel/component/langchain4j/tools/spec/CamelToolSpecification.java
+++ 
b/components/camel-ai/camel-langchain4j-tools/src/main/java/org/apache/camel/component/langchain4j/tools/spec/CamelToolSpecification.java
@@ -29,10 +29,16 @@ public class CamelToolSpecification {
 
     private ToolSpecification toolSpecification;
     private LangChain4jToolsConsumer consumer;
+    private boolean exposed;
 
     public CamelToolSpecification(ToolSpecification toolSpecification, 
LangChain4jToolsConsumer consumer) {
+        this(toolSpecification, consumer, true);
+    }
+
+    public CamelToolSpecification(ToolSpecification toolSpecification, 
LangChain4jToolsConsumer consumer, boolean exposed) {
         this.toolSpecification = toolSpecification;
         this.consumer = consumer;
+        this.exposed = exposed;
     }
 
     public ToolSpecification getToolSpecification() {
@@ -51,6 +57,14 @@ public class CamelToolSpecification {
         this.consumer = consumer;
     }
 
+    public boolean isExposed() {
+        return exposed;
+    }
+
+    public void setExposed(boolean exposed) {
+        this.exposed = exposed;
+    }
+
     @Override
     public boolean equals(Object o) {
         if (this == o) {
@@ -60,13 +74,13 @@ public class CamelToolSpecification {
             return false;
         }
         CamelToolSpecification that = (CamelToolSpecification) o;
-        return Objects.equals(toolSpecification, that.toolSpecification) && 
Objects.equals(consumer,
-                that.consumer);
+        return exposed == that.exposed && Objects.equals(toolSpecification, 
that.toolSpecification)
+                && Objects.equals(consumer, that.consumer);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(toolSpecification, consumer);
+        return Objects.hash(toolSpecification, consumer, exposed);
     }
 
     @Override
@@ -74,6 +88,7 @@ public class CamelToolSpecification {
         return "CamelToolSpecification{" +
                "toolSpecification=" + toolSpecification +
                ", consumer=" + consumer +
+               ", exposed=" + exposed +
                '}';
     }
 }
diff --git 
a/components/camel-ai/camel-langchain4j-tools/src/test/java/org/apache/camel/component/langchain4j/tools/LangChain4jToolTest.java
 
b/components/camel-ai/camel-langchain4j-tools/src/test/java/org/apache/camel/component/langchain4j/tools/LangChain4jToolTest.java
index 6894fe5bef2f..06ca58cd8f14 100644
--- 
a/components/camel-ai/camel-langchain4j-tools/src/test/java/org/apache/camel/component/langchain4j/tools/LangChain4jToolTest.java
+++ 
b/components/camel-ai/camel-langchain4j-tools/src/test/java/org/apache/camel/component/langchain4j/tools/LangChain4jToolTest.java
@@ -43,6 +43,19 @@ public class LangChain4jToolTest extends CamelTestSupport {
             .when("What is the name of the user 1?\n")
             .invokeTool("QueryUserByNumber")
             .withParam("number", 1)
+            .end()
+            .when("What tools are available for working with users?\n")
+            .replyWith("The following tools are available for working with 
users: queryUserById, queryUserBySSN, sendEmail")
+            .end()
+            .when("Get the user with ID 42.\n")
+            .invokeTool("queryUserById")
+            .withParam("userId", 42)
+            .end()
+            .when("I need to query a user by their social security number. 
First, find the appropriate tool, then use it to query SSN 123-45-6789.\n")
+            .invokeTool("toolSearchTool")
+            .withParam("tags", "users")
+            .andThenInvokeTool("queryUserBySSN")
+            .withParam("ssn", "123-45-6789")
             .build();
 
     @Override
@@ -82,6 +95,25 @@ public class LangChain4jToolTest extends CamelTestSupport {
                 
from("langchain4j-tools:test1?tags=user&name=DoesNothing&description=Also does 
not really do anything, but has a name")
                         .setBody(constant("Hello World"));
 
+                // Search tool test routes
+                from("direct:searchToolTest")
+                        .to("langchain4j-tools:test1?tags=users,products");
+
+                // Exposed tool - should be immediately available to LLM
+                
from("langchain4j-tools:queryUserById?tags=users&description=Query user 
database by user ID&parameter.userId=integer")
+                        .setBody(simple("{\"name\": \"John Doe\", \"id\": 
${header.userId}}"));
+
+                // Non-exposed (searchable) tool - only available via tool 
search
+                
from("langchain4j-tools:queryUserBySSN?tags=users&description=Query user 
database by social security number&parameter.ssn=string&exposed=false")
+                        .setBody(simple("{\"name\": \"Jane Smith\", \"ssn\": 
\"${header.ssn}\"}"));
+
+                // Another non-exposed tool with different tag
+                
from("langchain4j-tools:queryProductById?tags=products&description=Query 
product database by product ID&parameter.productId=integer&exposed=false")
+                        .setBody(simple("{\"product\": \"Widget\", \"id\": 
${header.productId}}"));
+
+                // Non-exposed tool for email operations
+                from("langchain4j-tools:sendEmail?tags=users&description=Send 
email to a user&parameter.email=string&parameter.message=string&exposed=false")
+                        .setBody(simple("Email sent to ${header.email}: 
${header.message}"));
             }
         };
     }
@@ -104,4 +136,57 @@ public class LangChain4jToolTest extends CamelTestSupport {
         
Assertions.assertThat(message.getBody(String.class)).containsIgnoringCase(nameFromDB);
         
Assertions.assertThat(message.getHeader("number")).isInstanceOf(Integer.class);
     }
+
+    @Test
+    public void testToolSearchForUsers() throws Exception {
+        List<ChatMessage> messages = new ArrayList<>();
+        messages.add(new SystemMessage("""
+                You are a helpful assistant with access to various tools.
+                If you need to find available tools, use the toolSearchTool to 
search by tags.
+                """));
+        messages.add(new UserMessage("""
+                What tools are available for working with users?
+                """));
+
+        Exchange result = 
fluentTemplate.to("direct:searchToolTest").withBody(messages).request(Exchange.class);
+
+        Assertions.assertThat(result).isNotNull();
+        String response = result.getMessage().getBody(String.class);
+        Assertions.assertThat(response).isNotNull();
+    }
+
+    @Test
+    public void testExposedToolDirectAccess() throws Exception {
+        List<ChatMessage> messages = new ArrayList<>();
+        messages.add(new SystemMessage("""
+                You are a helpful assistant that can query user information.
+                """));
+        messages.add(new UserMessage("""
+                Get the user with ID 42.
+                """));
+
+        Exchange result = 
fluentTemplate.to("direct:searchToolTest").withBody(messages).request(Exchange.class);
+
+        Assertions.assertThat(result).isNotNull();
+        String response = result.getMessage().getBody(String.class);
+        Assertions.assertThat(response).isNotNull();
+    }
+
+    @Test
+    public void testSearchAndUseNonExposedTool() throws Exception {
+        List<ChatMessage> messages = new ArrayList<>();
+        messages.add(new SystemMessage("""
+                You are a helpful assistant. If you need to find tools, search 
for them first using the toolSearchTool.
+                """));
+        messages.add(new UserMessage(
+                """
+                        I need to query a user by their social security 
number. First, find the appropriate tool, then use it to query SSN 123-45-6789.
+                        """));
+
+        Exchange result = 
fluentTemplate.to("direct:searchToolTest").withBody(messages).request(Exchange.class);
+
+        Assertions.assertThat(result).isNotNull();
+        String response = result.getMessage().getBody(String.class);
+        Assertions.assertThat(response).isNotNull();
+    }
 }
diff --git 
a/components/camel-ai/camel-langchain4j-tools/src/test/java/org/apache/camel/component/langchain4j/tools/ToolSearchToolFormatTest.java
 
b/components/camel-ai/camel-langchain4j-tools/src/test/java/org/apache/camel/component/langchain4j/tools/ToolSearchToolFormatTest.java
new file mode 100644
index 000000000000..deb3f4dbb32c
--- /dev/null
+++ 
b/components/camel-ai/camel-langchain4j-tools/src/test/java/org/apache/camel/component/langchain4j/tools/ToolSearchToolFormatTest.java
@@ -0,0 +1,121 @@
+/*
+ * 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.langchain4j.tools;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import dev.langchain4j.agent.tool.ToolSpecification;
+import dev.langchain4j.model.chat.request.json.JsonObjectSchema;
+import dev.langchain4j.model.chat.request.json.JsonStringSchema;
+import 
org.apache.camel.component.langchain4j.tools.spec.CamelToolSpecification;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Unit tests for ToolSearchTool formatting functionality
+ */
+public class ToolSearchToolFormatTest {
+
+    @Test
+    public void testFormatEmptyToolList() {
+        List<CamelToolSpecification> tools = new ArrayList<>();
+        String result = ToolSearchTool.formatToolsForLLM(tools);
+
+        assertEquals("No tools found matching the search criteria.", result);
+    }
+
+    @Test
+    public void testFormatSingleTool() {
+        ToolSpecification spec = ToolSpecification.builder()
+                .name("queryUser")
+                .description("Query user database by ID")
+                .parameters(JsonObjectSchema.builder()
+                        .addProperty("userId", 
JsonStringSchema.builder().description("User ID").build())
+                        .build())
+                .build();
+
+        List<CamelToolSpecification> tools = new ArrayList<>();
+        tools.add(new CamelToolSpecification(spec, null, false));
+
+        String result = ToolSearchTool.formatToolsForLLM(tools);
+
+        assertTrue(result.contains("Found 1 tool(s)"));
+        assertTrue(result.contains("1. queryUser"));
+        assertTrue(result.contains("Description: Query user database by ID"));
+        assertTrue(result.contains("Parameters: userId"));
+    }
+
+    @Test
+    public void testFormatMultipleTools() {
+        ToolSpecification spec1 = ToolSpecification.builder()
+                .name("queryUser")
+                .description("Query user by ID")
+                .parameters(JsonObjectSchema.builder()
+                        .addProperty("userId", 
JsonStringSchema.builder().description("User ID").build())
+                        .build())
+                .build();
+
+        ToolSpecification spec2 = ToolSpecification.builder()
+                .name("sendEmail")
+                .description("Send email to user")
+                .parameters(JsonObjectSchema.builder()
+                        .addProperty("email", 
JsonStringSchema.builder().description("Email address").build())
+                        .addProperty("message", 
JsonStringSchema.builder().description("Message content").build())
+                        .build())
+                .build();
+
+        List<CamelToolSpecification> tools = new ArrayList<>();
+        tools.add(new CamelToolSpecification(spec1, null, false));
+        tools.add(new CamelToolSpecification(spec2, null, false));
+
+        String result = ToolSearchTool.formatToolsForLLM(tools);
+
+        assertTrue(result.contains("Found 2 tool(s)"));
+        assertTrue(result.contains("1. queryUser"));
+        assertTrue(result.contains("2. sendEmail"));
+        assertTrue(result.contains("Description: Query user by ID"));
+        assertTrue(result.contains("Description: Send email to user"));
+        assertTrue(result.contains("Parameters: userId"));
+        assertTrue(result.contains("Parameters: email, message") || 
result.contains("Parameters: message, email"));
+    }
+
+    @Test
+    public void testFormatToolWithoutParameters() {
+        ToolSpecification spec = ToolSpecification.builder()
+                .name("healthCheck")
+                .description("Check system health")
+                .build();
+
+        List<CamelToolSpecification> tools = new ArrayList<>();
+        tools.add(new CamelToolSpecification(spec, null, false));
+
+        String result = ToolSearchTool.formatToolsForLLM(tools);
+
+        assertTrue(result.contains("Found 1 tool(s)"));
+        assertTrue(result.contains("1. healthCheck"));
+        assertTrue(result.contains("Description: Check system health"));
+        // Should not contain "Parameters:" line
+        assertFalse(result.contains("Parameters:"));
+    }
+
+    private void assertFalse(boolean condition) {
+        assertTrue(!condition);
+    }
+}
diff --git 
a/components/camel-ai/camel-langchain4j-tools/src/test/java/org/apache/camel/component/langchain4j/tools/ToolSearchToolTest.java
 
b/components/camel-ai/camel-langchain4j-tools/src/test/java/org/apache/camel/component/langchain4j/tools/ToolSearchToolTest.java
new file mode 100644
index 000000000000..4d1d2570b300
--- /dev/null
+++ 
b/components/camel-ai/camel-langchain4j-tools/src/test/java/org/apache/camel/component/langchain4j/tools/ToolSearchToolTest.java
@@ -0,0 +1,177 @@
+/*
+ * 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.langchain4j.tools;
+
+import java.util.List;
+
+import dev.langchain4j.agent.tool.ToolSpecification;
+import dev.langchain4j.model.chat.request.json.JsonObjectSchema;
+import dev.langchain4j.model.chat.request.json.JsonStringSchema;
+import 
org.apache.camel.component.langchain4j.tools.spec.CamelToolExecutorCache;
+import 
org.apache.camel.component.langchain4j.tools.spec.CamelToolSpecification;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Unit tests for ToolSearchTool
+ */
+public class ToolSearchToolTest {
+
+    private CamelToolExecutorCache toolCache;
+    private ToolSearchTool toolSearchTool;
+
+    @BeforeEach
+    public void setUp() {
+        toolCache = CamelToolExecutorCache.getInstance();
+        // Clear any existing tools
+        toolCache.getSearchableTools().clear();
+        toolCache.getTools().clear();
+
+        // Create tool search tool with producer tags
+        String[] producerTags = new String[] { "users", "products" };
+        toolSearchTool = new ToolSearchTool(toolCache, producerTags);
+    }
+
+    @AfterEach
+    public void tearDown() {
+        toolCache.getSearchableTools().clear();
+        toolCache.getTools().clear();
+    }
+
+    @Test
+    public void testSearchToolsWithMatchingTag() {
+        // Add a searchable tool
+        ToolSpecification spec = createToolSpec("queryUser", "Query user by 
ID");
+        CamelToolSpecification camelSpec = new CamelToolSpecification(spec, 
null, false);
+        toolCache.putSearchable("users", camelSpec);
+
+        // Search for the tool
+        List<CamelToolSpecification> results = 
toolSearchTool.searchTools("users");
+
+        assertNotNull(results);
+        assertEquals(1, results.size());
+        assertEquals("queryUser", 
results.get(0).getToolSpecification().name());
+    }
+
+    @Test
+    public void testSearchToolsWithMultipleTags() {
+        // Add tools with different tags
+        ToolSpecification spec1 = createToolSpec("queryUser", "Query user");
+        ToolSpecification spec2 = createToolSpec("sendEmail", "Send email");
+        ToolSpecification spec3 = createToolSpec("queryProduct", "Query 
product");
+
+        toolCache.putSearchable("users", new CamelToolSpecification(spec1, 
null, false));
+        toolCache.putSearchable("email", new CamelToolSpecification(spec2, 
null, false));
+        toolCache.putSearchable("products", new CamelToolSpecification(spec3, 
null, false));
+
+        // Search for multiple tags
+        List<CamelToolSpecification> results = 
toolSearchTool.searchTools("users,email");
+
+        assertNotNull(results);
+        assertEquals(2, results.size());
+    }
+
+    @Test
+    public void testSearchToolsNoDuplicates() {
+        // Add a tool with multiple tags
+        ToolSpecification spec = createToolSpec("sendEmail", "Send email to 
user");
+        CamelToolSpecification camelSpec = new CamelToolSpecification(spec, 
null, false);
+
+        toolCache.putSearchable("users", camelSpec);
+        toolCache.putSearchable("email", camelSpec);
+
+        // Search for both tags - should return only one result
+        List<CamelToolSpecification> results = 
toolSearchTool.searchTools("users,email");
+
+        assertNotNull(results);
+        assertEquals(1, results.size());
+        assertEquals("sendEmail", 
results.get(0).getToolSpecification().name());
+    }
+
+    @Test
+    public void testSearchToolsWithEmptyTags() {
+        // Add some tools
+        toolCache.putSearchable("users", new 
CamelToolSpecification(createToolSpec("tool1", "Tool 1"), null, false));
+        toolCache.putSearchable("products", new 
CamelToolSpecification(createToolSpec("tool2", "Tool 2"), null, false));
+
+        // Search with empty tags should return all searchable tools for 
producer tags
+        List<CamelToolSpecification> results = toolSearchTool.searchTools("");
+
+        assertNotNull(results);
+        assertEquals(2, results.size());
+    }
+
+    @Test
+    public void testSearchToolsWithNullTags() {
+        // Add some tools
+        toolCache.putSearchable("users", new 
CamelToolSpecification(createToolSpec("tool1", "Tool 1"), null, false));
+
+        // Search with null tags should return all searchable tools
+        List<CamelToolSpecification> results = 
toolSearchTool.searchTools(null);
+
+        assertNotNull(results);
+        assertEquals(1, results.size());
+    }
+
+    @Test
+    public void testSearchToolsNoMatches() {
+        // Add a tool with a different tag
+        toolCache.putSearchable("admin", new 
CamelToolSpecification(createToolSpec("adminTool", "Admin tool"), null, false));
+
+        // Search for non-existent tag
+        List<CamelToolSpecification> results = 
toolSearchTool.searchTools("users");
+
+        assertNotNull(results);
+        assertTrue(results.isEmpty());
+    }
+
+    @Test
+    public void testSearchNonExistentTagReturnsHelpfulMessage() {
+        // Add some tools with specific tags
+        toolCache.putSearchable("users",
+                new CamelToolSpecification(createToolSpec("queryUser", "Query 
user by ID"), null, false));
+        toolCache.putSearchable("products",
+                new CamelToolSpecification(createToolSpec("queryProduct", 
"Query product by ID"), null, false));
+
+        // Search for a non-existent tag
+        List<CamelToolSpecification> results = 
toolSearchTool.searchTools("nonexistent");
+
+        // Verify empty results
+        assertNotNull(results);
+        assertTrue(results.isEmpty());
+
+        // Verify the formatted message is helpful for an LLM
+        String formattedMessage = ToolSearchTool.formatToolsForLLM(results);
+        assertNotNull(formattedMessage);
+        assertEquals("No tools found matching the search criteria.", 
formattedMessage);
+    }
+
+    private ToolSpecification createToolSpec(String name, String description) {
+        return ToolSpecification.builder()
+                .name(name)
+                .description(description)
+                .parameters(JsonObjectSchema.builder()
+                        .addProperty("param1", 
JsonStringSchema.builder().description("Parameter 1").build())
+                        .build())
+                .build();
+    }
+}
diff --git 
a/components/camel-ai/camel-langchain4j-tools/src/test/java/org/apache/camel/component/langchain4j/tools/spec/CamelToolExecutorCacheTest.java
 
b/components/camel-ai/camel-langchain4j-tools/src/test/java/org/apache/camel/component/langchain4j/tools/spec/CamelToolExecutorCacheTest.java
new file mode 100644
index 000000000000..7037b34d6e32
--- /dev/null
+++ 
b/components/camel-ai/camel-langchain4j-tools/src/test/java/org/apache/camel/component/langchain4j/tools/spec/CamelToolExecutorCacheTest.java
@@ -0,0 +1,160 @@
+/*
+ * 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.langchain4j.tools.spec;
+
+import java.util.Set;
+
+import dev.langchain4j.agent.tool.ToolSpecification;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Unit tests for CamelToolExecutorCache
+ */
+public class CamelToolExecutorCacheTest {
+
+    private CamelToolExecutorCache cache;
+
+    @BeforeEach
+    public void setUp() {
+        cache = CamelToolExecutorCache.getInstance();
+        // Clear any existing tools
+        cache.getTools().clear();
+        cache.getSearchableTools().clear();
+    }
+
+    @AfterEach
+    public void tearDown() {
+        cache.getTools().clear();
+        cache.getSearchableTools().clear();
+    }
+
+    @Test
+    public void testPutAndGetExposedTool() {
+        ToolSpecification spec = ToolSpecification.builder()
+                .name("testTool")
+                .description("Test tool")
+                .build();
+        CamelToolSpecification camelSpec = new CamelToolSpecification(spec, 
null, true);
+
+        cache.put("users", camelSpec);
+
+        Set<CamelToolSpecification> tools = cache.getTools().get("users");
+        assertNotNull(tools);
+        assertEquals(1, tools.size());
+        assertTrue(tools.contains(camelSpec));
+    }
+
+    @Test
+    public void testPutAndGetSearchableTool() {
+        ToolSpecification spec = ToolSpecification.builder()
+                .name("searchableTool")
+                .description("Searchable tool")
+                .build();
+        CamelToolSpecification camelSpec = new CamelToolSpecification(spec, 
null, false);
+
+        cache.putSearchable("products", camelSpec);
+
+        Set<CamelToolSpecification> tools = 
cache.getSearchableTools().get("products");
+        assertNotNull(tools);
+        assertEquals(1, tools.size());
+        assertTrue(tools.contains(camelSpec));
+    }
+
+    @Test
+    public void testRemoveExposedTool() {
+        ToolSpecification spec = ToolSpecification.builder()
+                .name("testTool")
+                .description("Test tool")
+                .build();
+        CamelToolSpecification camelSpec = new CamelToolSpecification(spec, 
null, true);
+
+        cache.put("users", camelSpec);
+        assertEquals(1, cache.getTools().get("users").size());
+
+        cache.remove("users", camelSpec);
+        assertNull(cache.getTools().get("users"));
+    }
+
+    @Test
+    public void testRemoveSearchableTool() {
+        ToolSpecification spec = ToolSpecification.builder()
+                .name("searchableTool")
+                .description("Searchable tool")
+                .build();
+        CamelToolSpecification camelSpec = new CamelToolSpecification(spec, 
null, false);
+
+        cache.putSearchable("products", camelSpec);
+        assertEquals(1, cache.getSearchableTools().get("products").size());
+
+        cache.removeSearchable("products", camelSpec);
+        assertNull(cache.getSearchableTools().get("products"));
+    }
+
+    @Test
+    public void testMultipleToolsWithSameTag() {
+        ToolSpecification spec1 = 
ToolSpecification.builder().name("tool1").description("Tool 1").build();
+        ToolSpecification spec2 = 
ToolSpecification.builder().name("tool2").description("Tool 2").build();
+
+        CamelToolSpecification camelSpec1 = new CamelToolSpecification(spec1, 
null, true);
+        CamelToolSpecification camelSpec2 = new CamelToolSpecification(spec2, 
null, true);
+
+        cache.put("users", camelSpec1);
+        cache.put("users", camelSpec2);
+
+        Set<CamelToolSpecification> tools = cache.getTools().get("users");
+        assertNotNull(tools);
+        assertEquals(2, tools.size());
+    }
+
+    @Test
+    public void testRemoveOneOfMultipleTools() {
+        ToolSpecification spec1 = 
ToolSpecification.builder().name("tool1").description("Tool 1").build();
+        ToolSpecification spec2 = 
ToolSpecification.builder().name("tool2").description("Tool 2").build();
+
+        CamelToolSpecification camelSpec1 = new CamelToolSpecification(spec1, 
null, true);
+        CamelToolSpecification camelSpec2 = new CamelToolSpecification(spec2, 
null, true);
+
+        cache.put("users", camelSpec1);
+        cache.put("users", camelSpec2);
+
+        cache.remove("users", camelSpec1);
+
+        Set<CamelToolSpecification> tools = cache.getTools().get("users");
+        assertNotNull(tools);
+        assertEquals(1, tools.size());
+        assertTrue(tools.contains(camelSpec2));
+        assertFalse(tools.contains(camelSpec1));
+    }
+
+    @Test
+    public void testHasSearchableTools() {
+        assertFalse(cache.hasSearchableTools());
+
+        ToolSpecification spec = 
ToolSpecification.builder().name("tool").description("Tool").build();
+        cache.putSearchable("users", new CamelToolSpecification(spec, null, 
false));
+
+        assertTrue(cache.hasSearchableTools());
+    }
+}
diff --git 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/LangChain4jToolsEndpointBuilderFactory.java
 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/LangChain4jToolsEndpointBuilderFactory.java
index 0e6cf85e50da..b3ef3d1f00c3 100644
--- 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/LangChain4jToolsEndpointBuilderFactory.java
+++ 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/LangChain4jToolsEndpointBuilderFactory.java
@@ -72,6 +72,40 @@ public interface LangChain4jToolsEndpointBuilderFactory {
             doSetProperty("description", description);
             return this;
         }
+        /**
+         * Whether the tool is automatically exposed to the LLM. When false, 
the
+         * tool is added to a searchable list and can be discovered via the
+         * tool-search-tool.
+         * 
+         * The option is a: <code>boolean</code> type.
+         * 
+         * Default: true
+         * Group: consumer
+         * 
+         * @param exposed the value to set
+         * @return the dsl builder
+         */
+        default LangChain4jToolsEndpointConsumerBuilder exposed(boolean 
exposed) {
+            doSetProperty("exposed", exposed);
+            return this;
+        }
+        /**
+         * Whether the tool is automatically exposed to the LLM. When false, 
the
+         * tool is added to a searchable list and can be discovered via the
+         * tool-search-tool.
+         * 
+         * The option will be converted to a <code>boolean</code> type.
+         * 
+         * Default: true
+         * Group: consumer
+         * 
+         * @param exposed the value to set
+         * @return the dsl builder
+         */
+        default LangChain4jToolsEndpointConsumerBuilder exposed(String 
exposed) {
+            doSetProperty("exposed", exposed);
+            return this;
+        }
         /**
          * Tool name.
          * 

Reply via email to