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

Croway 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 996f8ce4c7bb CAMEL-24311: camel.server.mcp-* configuration properties 
and camel-main autowiring (#25309)
996f8ce4c7bb is described below

commit 996f8ce4c7bb3b24faf2602071d400d2fc568d81
Author: Federico Mariani <[email protected]>
AuthorDate: Tue Aug 4 12:47:01 2026 +0200

    CAMEL-24311: camel.server.mcp-* configuration properties and camel-main 
autowiring (#25309)
    
    * CAMEL-24311: camel.server.mcp-* configuration properties and camel-main 
autowiring
    
    The MCP server now starts from properties alone, like Jolokia or
    Prometheus - no code and no route for the server itself:
    
      camel.server.enabled = true
      camel.server.mcp-enabled = true
      camel.server.mcp-tags = crm,notify
    
    - HttpServerConfigurationProperties: mcpEnabled, mcpTags,
      mcpToolTimeout (20s), mcpPath (/mcp), mcpServerName options with
      regenerated configurer, main metadata and main.adoc.
    - McpServerFactory SPI in camel-main (mirrors MainHttpServerFactory);
      BaseMainSupport resolves it via bootstrap FactoryFinder when
      mcp-enabled=true and adds the bridge after the HTTP server so the
      engine finds the running router. With the HTTP server disabled the
      bridge still starts and fails fast with an actionable message.
    - DefaultMcpServerFactory in camel-mcp-server maps the options onto
      McpServerConfiguration.
    - Docs (CAMEL-24314): properties-based quick start replaces the
      programmatic example as primary; options table now names the
      camel.server.mcp-* properties.
    - Catalog harvest for the new modules (others.properties,
      others/mcp-server.json, docs copies).
    
    Co-Authored-By: Claude Fable 5 <[email protected]>
    
    * CAMEL-24311: camel-mcp-server - regen catalog docs copy and 
known-dependencies
    
    Co-Authored-By: Claude Fable 5 <[email protected]>
    
    * CAMEL-24311: add @since to McpServerFactory
    
    Co-Authored-By: Claude Fable 5 <[email protected]>
    
    ---------
    
    Co-authored-by: Claude Fable 5 <[email protected]>
---
 .../org/apache/camel/catalog/docs/main.adoc        |   7 +-
 .../org/apache/camel/catalog/docs/mcp-server.adoc  |  44 +++++---
 .../main/camel-main-configuration-metadata.json    |   5 +
 components/camel-ai/camel-mcp-server/pom.xml       |   4 +
 .../META-INF/services/org/apache/camel/mcp-server  |   2 +
 .../camel-mcp-server/src/main/docs/mcp-server.adoc |  44 +++++---
 .../mcp/server/main/DefaultMcpServerFactory.java   |  44 ++++++++
 .../server/main/McpServerMainPropertiesTest.java   | 103 +++++++++++++++++++
 ...ttpServerConfigurationPropertiesConfigurer.java |  35 +++++++
 .../camel-main-configuration-metadata.json         |   5 +
 core/camel-main/src/main/docs/main.adoc            |   7 +-
 .../org/apache/camel/main/BaseMainSupport.java     |  28 +++++-
 .../main/HttpServerConfigurationProperties.java    | 112 +++++++++++++++++++++
 .../java/org/apache/camel/main/MainConstants.java  |   1 +
 .../org/apache/camel/main/McpServerFactory.java    |  39 +++++++
 ...mel-factoryfinder-known-dependencies.properties |   1 +
 16 files changed, 450 insertions(+), 31 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/main.adoc
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/main.adoc
index 352d5a8e8fd5..ffa14c8dfd9d 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/main.adoc
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/main.adoc
@@ -195,7 +195,7 @@ The camel.routecontroller supports 12 options, which are 
listed below.
 
 
 === Camel Embedded HTTP Server (only for standalone; not Spring Boot or 
Quarkus) configurations
-The camel.server supports 21 options, which are listed below.
+The camel.server supports 26 options, which are listed below.
 
 [width="100%",cols="2,5,^1,2",options="header"]
 |===
@@ -215,6 +215,11 @@ The camel.server supports 21 options, which are listed 
below.
 | *camel.server.jwtKeystorePath* | Path to the keystore file used for JWT 
tokens validation. |  | String
 | *camel.server.jwtKeystoreType* | Type of the keystore used for JWT tokens 
validation (jks, pkcs12, etc.). |  | String
 | *camel.server.maxBodySize* | Maximum HTTP body size the embedded HTTP server 
can accept. |  | Long
+| *camel.server.mcpEnabled* | Whether to expose ai-tool routes as MCP tools 
over streamable HTTP. Requires camel-mcp-server on the classpath. By default, 
the MCP server is not enabled. | false | boolean
+| *camel.server.mcpPath* | HTTP path where the MCP endpoint is served. | /mcp 
| String
+| *camel.server.mcpServerName* | MCP server name advertised to clients. 
Defaults to the CamelContext name. |  | String
+| *camel.server.mcpTags* | Comma-separated list of ai-tool tags to expose as 
MCP tools. Only tools registered under one of these tags are exposed; the 
untagged default pool is never exposed. When not set, no tools are exposed. |  
| String
+| *camel.server.mcpToolTimeout* | Per-call MCP tool execution timeout in 
milliseconds. A call exceeding the timeout returns an error result to the MCP 
client; the underlying route keeps running until it completes on its own. | 
20000 | long
 | *camel.server.path* | Context-path to use for embedded HTTP server | / | 
String
 | *camel.server.port* | Port to use for binding embedded HTTP server. Use 0 to 
dynamic assign a free random port number. | 8080 | int
 | *camel.server.staticContextPath* | The context-path to use for serving 
static content. By default, the root path is used. And if there is an 
index.html page then this is automatically loaded. | / | String
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/mcp-server.adoc
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/mcp-server.adoc
index 6b28142ca981..17e3b436e191 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/mcp-server.adoc
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/mcp-server.adoc
@@ -101,8 +101,19 @@ YAML::
 ----
 ====
 
-Start the MCP server by adding the `McpServerBridge` service to the
-CamelContext, selecting the tags to expose:
+On Camel Main and Camel JBang no code is needed — like Jolokia or
+Prometheus, the server starts from configuration properties alone:
+
+[source,properties]
+----
+camel.server.enabled = true
+camel.server.mcp-enabled = true
+camel.server.mcp-tags = crm,notify
+camel.server.mcp-server-name = my-integration-app
+----
+
+On other runtimes, or when wiring programmatically, add the
+`McpServerBridge` service to the CamelContext instead:
 
 [source,java]
 ----
@@ -128,23 +139,28 @@ from("direct:agent")
 
 == Options
 
-The `McpServerConfiguration` options:
+The options, configurable as `camel.server.mcp-*` properties on Camel Main /
+JBang (see the xref:main.adoc[camel-main] options) or on
+`McpServerConfiguration` programmatically:
 
 [width="100%",cols="2,5,2,1",options="header"]
 |===
 | Option | Description | Default | Owner
 
-| `tags` | Comma-separated list of ai-tool tags to expose as MCP tools. Only
-  tools registered under one of these tags are published; the untagged
-  default pool is never exposed. When not set, no tools are published. |  |
-  bridge
-| `toolTimeout` | Per-call tool execution timeout in milliseconds. A call
-  exceeding the timeout returns an error result to the MCP client; the
-  underlying route keeps running until it completes on its own. | `20000` |
-  bridge
-| `path` | HTTP path where the MCP endpoint is served. | `/mcp` | engine
-| `serverName` | MCP server name advertised to clients. | CamelContext name |
-  engine
+| `camel.server.mcp-enabled` | Whether to expose ai-tool routes as MCP tools
+  over streamable HTTP. | `false` | bridge
+| `camel.server.mcp-tags` | Comma-separated list of ai-tool tags to expose as
+  MCP tools. Only tools registered under one of these tags are published; the
+  untagged default pool is never exposed. When not set, no tools are
+  published. |  | bridge
+| `camel.server.mcp-tool-timeout` | Per-call tool execution timeout in
+  milliseconds. A call exceeding the timeout returns an error result to the
+  MCP client; the underlying route keeps running until it completes on its
+  own. | `20000` | bridge
+| `camel.server.mcp-path` | HTTP path where the MCP endpoint is served. |
+  `/mcp` | engine
+| `camel.server.mcp-server-name` | MCP server name advertised to clients. |
+  CamelContext name | engine
 |===
 
 Bridge-owned options are honored identically on every runtime. Engine-owned
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
index 4c5a8c43a5d7..5630025faa29 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
@@ -437,6 +437,11 @@
     { "name": "camel.server.jwtKeystorePath", "required": false, 
"description": "Path to the keystore file used for JWT tokens validation.", 
"sourceType": "org.apache.camel.main.HttpServerConfigurationProperties", 
"type": "string", "javaType": "java.lang.String", "secret": false },
     { "name": "camel.server.jwtKeystoreType", "required": false, 
"description": "Type of the keystore used for JWT tokens validation (jks, 
pkcs12, etc.).", "sourceType": 
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "string", 
"javaType": "java.lang.String", "secret": false },
     { "name": "camel.server.maxBodySize", "required": false, "description": 
"Maximum HTTP body size the embedded HTTP server can accept.", "sourceType": 
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "integer", 
"javaType": "java.lang.Long", "secret": false },
+    { "name": "camel.server.mcpEnabled", "required": false, "description": 
"Whether to expose ai-tool routes as MCP tools over streamable HTTP. Requires 
camel-mcp-server on the classpath. By default, the MCP server is not enabled.", 
"sourceType": "org.apache.camel.main.HttpServerConfigurationProperties", 
"type": "boolean", "javaType": "boolean", "defaultValue": false, "secret": 
false },
+    { "name": "camel.server.mcpPath", "required": false, "description": "HTTP 
path where the MCP endpoint is served.", "sourceType": 
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "string", 
"javaType": "java.lang.String", "defaultValue": "\/mcp", "secret": false },
+    { "name": "camel.server.mcpServerName", "required": false, "description": 
"MCP server name advertised to clients. Defaults to the CamelContext name.", 
"sourceType": "org.apache.camel.main.HttpServerConfigurationProperties", 
"type": "string", "javaType": "java.lang.String", "secret": false },
+    { "name": "camel.server.mcpTags", "required": false, "description": 
"Comma-separated list of ai-tool tags to expose as MCP tools. Only tools 
registered under one of these tags are exposed; the untagged default pool is 
never exposed. When not set, no tools are exposed.", "sourceType": 
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "string", 
"javaType": "java.lang.String", "secret": false },
+    { "name": "camel.server.mcpToolTimeout", "required": false, "description": 
"Per-call MCP tool execution timeout in milliseconds. A call exceeding the 
timeout returns an error result to the MCP client; the underlying route keeps 
running until it completes on its own.", "sourceType": 
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "integer", 
"javaType": "long", "defaultValue": 20000, "secret": false },
     { "name": "camel.server.path", "required": false, "description": 
"Context-path to use for embedded HTTP server", "sourceType": 
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "string", 
"javaType": "java.lang.String", "defaultValue": "\/", "secret": false },
     { "name": "camel.server.port", "required": false, "description": "Port to 
use for binding embedded HTTP server. Use 0 to dynamic assign a free random 
port number.", "sourceType": 
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "integer", 
"javaType": "int", "defaultValue": 8080, "secret": false },
     { "name": "camel.server.staticContextPath", "required": false, 
"description": "The context-path to use for serving static content. By default, 
the root path is used. And if there is an index.html page then this is 
automatically loaded.", "sourceType": 
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "string", 
"javaType": "java.lang.String", "defaultValue": "\/", "secret": false },
diff --git a/components/camel-ai/camel-mcp-server/pom.xml 
b/components/camel-ai/camel-mcp-server/pom.xml
index 40db5a9dc091..2adf333c000d 100644
--- a/components/camel-ai/camel-mcp-server/pom.xml
+++ b/components/camel-ai/camel-mcp-server/pom.xml
@@ -45,6 +45,10 @@
             <groupId>org.apache.camel</groupId>
             <artifactId>camel-mcp-server-api</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-main</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.apache.camel</groupId>
             <artifactId>camel-platform-http-vertx</artifactId>
diff --git 
a/components/camel-ai/camel-mcp-server/src/generated/resources/META-INF/services/org/apache/camel/mcp-server
 
b/components/camel-ai/camel-mcp-server/src/generated/resources/META-INF/services/org/apache/camel/mcp-server
new file mode 100644
index 000000000000..240ad12e3b06
--- /dev/null
+++ 
b/components/camel-ai/camel-mcp-server/src/generated/resources/META-INF/services/org/apache/camel/mcp-server
@@ -0,0 +1,2 @@
+# Generated by camel build tools - do NOT edit this file!
+class=org.apache.camel.component.mcp.server.main.DefaultMcpServerFactory
diff --git a/components/camel-ai/camel-mcp-server/src/main/docs/mcp-server.adoc 
b/components/camel-ai/camel-mcp-server/src/main/docs/mcp-server.adoc
index 6b28142ca981..17e3b436e191 100644
--- a/components/camel-ai/camel-mcp-server/src/main/docs/mcp-server.adoc
+++ b/components/camel-ai/camel-mcp-server/src/main/docs/mcp-server.adoc
@@ -101,8 +101,19 @@ YAML::
 ----
 ====
 
-Start the MCP server by adding the `McpServerBridge` service to the
-CamelContext, selecting the tags to expose:
+On Camel Main and Camel JBang no code is needed — like Jolokia or
+Prometheus, the server starts from configuration properties alone:
+
+[source,properties]
+----
+camel.server.enabled = true
+camel.server.mcp-enabled = true
+camel.server.mcp-tags = crm,notify
+camel.server.mcp-server-name = my-integration-app
+----
+
+On other runtimes, or when wiring programmatically, add the
+`McpServerBridge` service to the CamelContext instead:
 
 [source,java]
 ----
@@ -128,23 +139,28 @@ from("direct:agent")
 
 == Options
 
-The `McpServerConfiguration` options:
+The options, configurable as `camel.server.mcp-*` properties on Camel Main /
+JBang (see the xref:main.adoc[camel-main] options) or on
+`McpServerConfiguration` programmatically:
 
 [width="100%",cols="2,5,2,1",options="header"]
 |===
 | Option | Description | Default | Owner
 
-| `tags` | Comma-separated list of ai-tool tags to expose as MCP tools. Only
-  tools registered under one of these tags are published; the untagged
-  default pool is never exposed. When not set, no tools are published. |  |
-  bridge
-| `toolTimeout` | Per-call tool execution timeout in milliseconds. A call
-  exceeding the timeout returns an error result to the MCP client; the
-  underlying route keeps running until it completes on its own. | `20000` |
-  bridge
-| `path` | HTTP path where the MCP endpoint is served. | `/mcp` | engine
-| `serverName` | MCP server name advertised to clients. | CamelContext name |
-  engine
+| `camel.server.mcp-enabled` | Whether to expose ai-tool routes as MCP tools
+  over streamable HTTP. | `false` | bridge
+| `camel.server.mcp-tags` | Comma-separated list of ai-tool tags to expose as
+  MCP tools. Only tools registered under one of these tags are published; the
+  untagged default pool is never exposed. When not set, no tools are
+  published. |  | bridge
+| `camel.server.mcp-tool-timeout` | Per-call tool execution timeout in
+  milliseconds. A call exceeding the timeout returns an error result to the
+  MCP client; the underlying route keeps running until it completes on its
+  own. | `20000` | bridge
+| `camel.server.mcp-path` | HTTP path where the MCP endpoint is served. |
+  `/mcp` | engine
+| `camel.server.mcp-server-name` | MCP server name advertised to clients. |
+  CamelContext name | engine
 |===
 
 Bridge-owned options are honored identically on every runtime. Engine-owned
diff --git 
a/components/camel-ai/camel-mcp-server/src/main/java/org/apache/camel/component/mcp/server/main/DefaultMcpServerFactory.java
 
b/components/camel-ai/camel-mcp-server/src/main/java/org/apache/camel/component/mcp/server/main/DefaultMcpServerFactory.java
new file mode 100644
index 000000000000..d524fa46fa20
--- /dev/null
+++ 
b/components/camel-ai/camel-mcp-server/src/main/java/org/apache/camel/component/mcp/server/main/DefaultMcpServerFactory.java
@@ -0,0 +1,44 @@
+/*
+ * 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.mcp.server.main;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Service;
+import org.apache.camel.component.mcp.server.McpServerBridge;
+import org.apache.camel.component.mcp.server.McpServerConfiguration;
+import org.apache.camel.main.HttpServerConfigurationProperties;
+import org.apache.camel.main.MainConstants;
+import org.apache.camel.main.McpServerFactory;
+import org.apache.camel.spi.annotations.JdkService;
+
+/**
+ * {@link McpServerFactory} creating the {@link McpServerBridge} from the 
{@code camel.server.mcp-*} options, so the MCP
+ * server starts from properties alone on Camel Main / JBang.
+ */
+@JdkService(MainConstants.MCP_SERVER)
+public class DefaultMcpServerFactory implements McpServerFactory {
+
+    @Override
+    public Service newMcpServer(CamelContext camelContext, 
HttpServerConfigurationProperties configuration) {
+        McpServerConfiguration mcpConfiguration = new McpServerConfiguration();
+        mcpConfiguration.setTags(configuration.getMcpTags());
+        mcpConfiguration.setToolTimeout(configuration.getMcpToolTimeout());
+        mcpConfiguration.setPath(configuration.getMcpPath());
+        mcpConfiguration.setServerName(configuration.getMcpServerName());
+        return new McpServerBridge(mcpConfiguration);
+    }
+}
diff --git 
a/components/camel-ai/camel-mcp-server/src/test/java/org/apache/camel/component/mcp/server/main/McpServerMainPropertiesTest.java
 
b/components/camel-ai/camel-mcp-server/src/test/java/org/apache/camel/component/mcp/server/main/McpServerMainPropertiesTest.java
new file mode 100644
index 000000000000..872d3bb7f93b
--- /dev/null
+++ 
b/components/camel-ai/camel-mcp-server/src/test/java/org/apache/camel/component/mcp/server/main/McpServerMainPropertiesTest.java
@@ -0,0 +1,103 @@
+/*
+ * 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.mcp.server.main;
+
+import java.time.Duration;
+import java.util.Map;
+
+import io.modelcontextprotocol.client.McpClient;
+import io.modelcontextprotocol.client.McpSyncClient;
+import 
io.modelcontextprotocol.client.transport.HttpClientStreamableHttpTransport;
+import io.modelcontextprotocol.spec.McpSchema;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.main.Main;
+import org.apache.camel.test.AvailablePortFinder;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+/**
+ * Verifies the camel-main autowiring (CAMEL-24311): the MCP server starts 
from {@code camel.server.mcp-*} properties
+ * alone — no code and no route for the server itself.
+ */
+class McpServerMainPropertiesTest {
+
+    @Test
+    void testMcpServerStartsFromPropertiesAlone() throws Exception {
+        int port = AvailablePortFinder.getNextAvailable();
+
+        Main main = new Main();
+        main.configure().addRoutesBuilder(new RouteBuilder() {
+            @Override
+            public void configure() {
+                from("ai-tool:say_hello?tags=crm&description=Say hello"
+                     + "&parameter.name=string&parameter.name.required=true")
+                        .setBody(simple("Hello ${header.name}"));
+
+                from("ai-tool:hidden_tool?description=Untagged, not exposed")
+                        .setBody(constant("hidden"));
+            }
+        });
+        main.addInitialProperty("camel.server.enabled", "true");
+        main.addInitialProperty("camel.server.port", String.valueOf(port));
+        main.addInitialProperty("camel.server.mcp-enabled", "true");
+        main.addInitialProperty("camel.server.mcp-tags", "crm");
+        main.addInitialProperty("camel.server.mcp-server-name", 
"my-integration-app");
+        main.start();
+
+        McpSyncClient client = null;
+        try {
+            client = 
McpClient.sync(HttpClientStreamableHttpTransport.builder("http://localhost:"; + 
port).build())
+                    .requestTimeout(Duration.ofSeconds(10))
+                    .initializationTimeout(Duration.ofSeconds(10))
+                    .build();
+
+            McpSchema.InitializeResult init = client.initialize();
+            
assertThat(init.serverInfo().name()).isEqualTo("my-integration-app");
+
+            assertThat(client.listTools().tools())
+                    .extracting(McpSchema.Tool::name)
+                    .contains("say_hello")
+                    .doesNotContain("hidden_tool");
+
+            McpSchema.CallToolResult result
+                    = client.callTool(new 
McpSchema.CallToolRequest("say_hello", Map.of("name", "Camel")));
+            assertThat(result.isError()).isNotEqualTo(Boolean.TRUE);
+            assertThat(result.content().toString()).contains("Hello Camel");
+        } finally {
+            if (client != null) {
+                client.closeGracefully();
+            }
+            main.stop();
+        }
+    }
+
+    @Test
+    void testMcpEnabledWithoutHttpServerFailsFast() {
+        Main main = new Main();
+        main.addInitialProperty("camel.server.mcp-enabled", "true");
+        main.addInitialProperty("camel.server.mcp-tags", "crm");
+
+        try {
+            assertThatThrownBy(main::start)
+                    .hasStackTraceContaining("Vert.x platform HTTP server");
+        } finally {
+            main.stop();
+        }
+    }
+}
diff --git 
a/core/camel-main/src/generated/java/org/apache/camel/main/HttpServerConfigurationPropertiesConfigurer.java
 
b/core/camel-main/src/generated/java/org/apache/camel/main/HttpServerConfigurationPropertiesConfigurer.java
index 7c1d68afe45d..9129b2b45a81 100644
--- 
a/core/camel-main/src/generated/java/org/apache/camel/main/HttpServerConfigurationPropertiesConfigurer.java
+++ 
b/core/camel-main/src/generated/java/org/apache/camel/main/HttpServerConfigurationPropertiesConfigurer.java
@@ -37,6 +37,11 @@ public class HttpServerConfigurationPropertiesConfigurer 
extends org.apache.came
         map.put("JwtKeystorePath", java.lang.String.class);
         map.put("JwtKeystoreType", java.lang.String.class);
         map.put("MaxBodySize", java.lang.Long.class);
+        map.put("McpEnabled", boolean.class);
+        map.put("McpPath", java.lang.String.class);
+        map.put("McpServerName", java.lang.String.class);
+        map.put("McpTags", java.lang.String.class);
+        map.put("McpToolTimeout", long.class);
         map.put("Path", java.lang.String.class);
         map.put("Port", int.class);
         map.put("StaticContextPath", java.lang.String.class);
@@ -78,6 +83,16 @@ public class HttpServerConfigurationPropertiesConfigurer 
extends org.apache.came
         case "jwtKeystoreType": 
target.setJwtKeystoreType(property(camelContext, java.lang.String.class, 
value)); return true;
         case "maxbodysize":
         case "maxBodySize": target.setMaxBodySize(property(camelContext, 
java.lang.Long.class, value)); return true;
+        case "mcpenabled":
+        case "mcpEnabled": target.setMcpEnabled(property(camelContext, 
boolean.class, value)); return true;
+        case "mcppath":
+        case "mcpPath": target.setMcpPath(property(camelContext, 
java.lang.String.class, value)); return true;
+        case "mcpservername":
+        case "mcpServerName": target.setMcpServerName(property(camelContext, 
java.lang.String.class, value)); return true;
+        case "mcptags":
+        case "mcpTags": target.setMcpTags(property(camelContext, 
java.lang.String.class, value)); return true;
+        case "mcptooltimeout":
+        case "mcpToolTimeout": target.setMcpToolTimeout(property(camelContext, 
long.class, value)); return true;
         case "path": target.setPath(property(camelContext, 
java.lang.String.class, value)); return true;
         case "port": target.setPort(property(camelContext, int.class, value)); 
return true;
         case "staticcontextpath":
@@ -128,6 +143,16 @@ public class HttpServerConfigurationPropertiesConfigurer 
extends org.apache.came
         case "jwtKeystoreType": return java.lang.String.class;
         case "maxbodysize":
         case "maxBodySize": return java.lang.Long.class;
+        case "mcpenabled":
+        case "mcpEnabled": return boolean.class;
+        case "mcppath":
+        case "mcpPath": return java.lang.String.class;
+        case "mcpservername":
+        case "mcpServerName": return java.lang.String.class;
+        case "mcptags":
+        case "mcpTags": return java.lang.String.class;
+        case "mcptooltimeout":
+        case "mcpToolTimeout": return long.class;
         case "path": return java.lang.String.class;
         case "port": return int.class;
         case "staticcontextpath":
@@ -174,6 +199,16 @@ public class HttpServerConfigurationPropertiesConfigurer 
extends org.apache.came
         case "jwtKeystoreType": return target.getJwtKeystoreType();
         case "maxbodysize":
         case "maxBodySize": return target.getMaxBodySize();
+        case "mcpenabled":
+        case "mcpEnabled": return target.isMcpEnabled();
+        case "mcppath":
+        case "mcpPath": return target.getMcpPath();
+        case "mcpservername":
+        case "mcpServerName": return target.getMcpServerName();
+        case "mcptags":
+        case "mcpTags": return target.getMcpTags();
+        case "mcptooltimeout":
+        case "mcpToolTimeout": return target.getMcpToolTimeout();
         case "path": return target.getPath();
         case "port": return target.getPort();
         case "staticcontextpath":
diff --git 
a/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
 
b/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
index 4c5a8c43a5d7..5630025faa29 100644
--- 
a/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
+++ 
b/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
@@ -437,6 +437,11 @@
     { "name": "camel.server.jwtKeystorePath", "required": false, 
"description": "Path to the keystore file used for JWT tokens validation.", 
"sourceType": "org.apache.camel.main.HttpServerConfigurationProperties", 
"type": "string", "javaType": "java.lang.String", "secret": false },
     { "name": "camel.server.jwtKeystoreType", "required": false, 
"description": "Type of the keystore used for JWT tokens validation (jks, 
pkcs12, etc.).", "sourceType": 
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "string", 
"javaType": "java.lang.String", "secret": false },
     { "name": "camel.server.maxBodySize", "required": false, "description": 
"Maximum HTTP body size the embedded HTTP server can accept.", "sourceType": 
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "integer", 
"javaType": "java.lang.Long", "secret": false },
+    { "name": "camel.server.mcpEnabled", "required": false, "description": 
"Whether to expose ai-tool routes as MCP tools over streamable HTTP. Requires 
camel-mcp-server on the classpath. By default, the MCP server is not enabled.", 
"sourceType": "org.apache.camel.main.HttpServerConfigurationProperties", 
"type": "boolean", "javaType": "boolean", "defaultValue": false, "secret": 
false },
+    { "name": "camel.server.mcpPath", "required": false, "description": "HTTP 
path where the MCP endpoint is served.", "sourceType": 
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "string", 
"javaType": "java.lang.String", "defaultValue": "\/mcp", "secret": false },
+    { "name": "camel.server.mcpServerName", "required": false, "description": 
"MCP server name advertised to clients. Defaults to the CamelContext name.", 
"sourceType": "org.apache.camel.main.HttpServerConfigurationProperties", 
"type": "string", "javaType": "java.lang.String", "secret": false },
+    { "name": "camel.server.mcpTags", "required": false, "description": 
"Comma-separated list of ai-tool tags to expose as MCP tools. Only tools 
registered under one of these tags are exposed; the untagged default pool is 
never exposed. When not set, no tools are exposed.", "sourceType": 
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "string", 
"javaType": "java.lang.String", "secret": false },
+    { "name": "camel.server.mcpToolTimeout", "required": false, "description": 
"Per-call MCP tool execution timeout in milliseconds. A call exceeding the 
timeout returns an error result to the MCP client; the underlying route keeps 
running until it completes on its own.", "sourceType": 
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "integer", 
"javaType": "long", "defaultValue": 20000, "secret": false },
     { "name": "camel.server.path", "required": false, "description": 
"Context-path to use for embedded HTTP server", "sourceType": 
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "string", 
"javaType": "java.lang.String", "defaultValue": "\/", "secret": false },
     { "name": "camel.server.port", "required": false, "description": "Port to 
use for binding embedded HTTP server. Use 0 to dynamic assign a free random 
port number.", "sourceType": 
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "integer", 
"javaType": "int", "defaultValue": 8080, "secret": false },
     { "name": "camel.server.staticContextPath", "required": false, 
"description": "The context-path to use for serving static content. By default, 
the root path is used. And if there is an index.html page then this is 
automatically loaded.", "sourceType": 
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "string", 
"javaType": "java.lang.String", "defaultValue": "\/", "secret": false },
diff --git a/core/camel-main/src/main/docs/main.adoc 
b/core/camel-main/src/main/docs/main.adoc
index 352d5a8e8fd5..ffa14c8dfd9d 100644
--- a/core/camel-main/src/main/docs/main.adoc
+++ b/core/camel-main/src/main/docs/main.adoc
@@ -195,7 +195,7 @@ The camel.routecontroller supports 12 options, which are 
listed below.
 
 
 === Camel Embedded HTTP Server (only for standalone; not Spring Boot or 
Quarkus) configurations
-The camel.server supports 21 options, which are listed below.
+The camel.server supports 26 options, which are listed below.
 
 [width="100%",cols="2,5,^1,2",options="header"]
 |===
@@ -215,6 +215,11 @@ The camel.server supports 21 options, which are listed 
below.
 | *camel.server.jwtKeystorePath* | Path to the keystore file used for JWT 
tokens validation. |  | String
 | *camel.server.jwtKeystoreType* | Type of the keystore used for JWT tokens 
validation (jks, pkcs12, etc.). |  | String
 | *camel.server.maxBodySize* | Maximum HTTP body size the embedded HTTP server 
can accept. |  | Long
+| *camel.server.mcpEnabled* | Whether to expose ai-tool routes as MCP tools 
over streamable HTTP. Requires camel-mcp-server on the classpath. By default, 
the MCP server is not enabled. | false | boolean
+| *camel.server.mcpPath* | HTTP path where the MCP endpoint is served. | /mcp 
| String
+| *camel.server.mcpServerName* | MCP server name advertised to clients. 
Defaults to the CamelContext name. |  | String
+| *camel.server.mcpTags* | Comma-separated list of ai-tool tags to expose as 
MCP tools. Only tools registered under one of these tags are exposed; the 
untagged default pool is never exposed. When not set, no tools are exposed. |  
| String
+| *camel.server.mcpToolTimeout* | Per-call MCP tool execution timeout in 
milliseconds. A call exceeding the timeout returns an error result to the MCP 
client; the underlying route keeps running until it completes on its own. | 
20000 | long
 | *camel.server.path* | Context-path to use for embedded HTTP server | / | 
String
 | *camel.server.port* | Port to use for binding embedded HTTP server. Use 0 to 
dynamic assign a free random port number. | 8080 | int
 | *camel.server.staticContextPath* | The context-path to use for serving 
static content. By default, the root path is used. And if there is an 
index.html page then this is automatically loaded. | / | String
diff --git 
a/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java 
b/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
index d9560638622f..b9205a0a73b0 100644
--- a/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
+++ b/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
@@ -2188,7 +2188,9 @@ public abstract class BaseMainSupport extends BaseService 
{
                 mainConfigurationProperties.isAutoConfigurationFailFast(), 
true, autoConfiguredProperties);
 
         if (!server.isEnabled()) {
-            // http server is disabled
+            // http server is disabled; the mcp server (if enabled) is still 
set up so it can
+            // fail-fast with an actionable message about the missing http 
server
+            setupMcpServer(camelContext, server);
             return;
         }
 
@@ -2207,6 +2209,20 @@ public abstract class BaseMainSupport extends 
BaseService {
         // force eager starting as embedded http server is used for
         // container platform to check readiness and need to be started eager
         camelContext.addService(http, true, true);
+
+        // the mcp server serves through the http server, so it is set up (and 
started) after it
+        setupMcpServer(camelContext, server);
+    }
+
+    private void setupMcpServer(CamelContext camelContext, 
HttpServerConfigurationProperties server) throws Exception {
+        if (!server.isMcpEnabled()) {
+            return;
+        }
+        // auto-detect camel-mcp-server on classpath
+        McpServerFactory factory = resolveMcpServerFactory(camelContext);
+        Service mcp = factory.newMcpServer(camelContext, server);
+        // force eager starting so the mcp endpoint is served as soon as the 
http server is up
+        camelContext.addService(mcp, true, true);
     }
 
     private void setHttpManagementServerProperties(
@@ -3179,6 +3195,16 @@ public abstract class BaseMainSupport extends 
BaseService {
         return CamelContextAware.trySetCamelContext(answer, camelContext);
     }
 
+    private static McpServerFactory resolveMcpServerFactory(CamelContext 
camelContext) {
+        // lookup in service registry first
+        McpServerFactory answer = 
camelContext.getRegistry().findSingleByType(McpServerFactory.class);
+        if (answer == null) {
+            answer = 
ResolverHelper.resolveMandatoryBootstrapService(camelContext, 
MainConstants.MCP_SERVER,
+                    McpServerFactory.class, "camel-mcp-server");
+        }
+        return CamelContextAware.trySetCamelContext(answer, camelContext);
+    }
+
     private static final class PropertyPlaceholderListener implements 
PropertiesLookupListener {
 
         private final OrderedLocationProperties olp;
diff --git 
a/core/camel-main/src/main/java/org/apache/camel/main/HttpServerConfigurationProperties.java
 
b/core/camel-main/src/main/java/org/apache/camel/main/HttpServerConfigurationProperties.java
index c153b60d1d3f..da2603c3cce3 100644
--- 
a/core/camel-main/src/main/java/org/apache/camel/main/HttpServerConfigurationProperties.java
+++ 
b/core/camel-main/src/main/java/org/apache/camel/main/HttpServerConfigurationProperties.java
@@ -71,6 +71,17 @@ public class HttpServerConfigurationProperties implements 
BootstrapCloseable {
     @Metadata(label = "security", defaultValue = "false", security = 
"insecure:dev")
     private boolean jwtAllowMissingIssuerAndAudience;
 
+    @Metadata
+    private boolean mcpEnabled;
+    @Metadata
+    private String mcpTags;
+    @Metadata(defaultValue = "20000")
+    private long mcpToolTimeout = 20000;
+    @Metadata(defaultValue = "/mcp")
+    private String mcpPath = "/mcp";
+    @Metadata
+    private String mcpServerName;
+
     public HttpServerConfigurationProperties(MainConfigurationProperties 
parent) {
         this.parent = parent;
     }
@@ -326,6 +337,64 @@ public class HttpServerConfigurationProperties implements 
BootstrapCloseable {
         this.jwtAllowMissingIssuerAndAudience = 
jwtAllowMissingIssuerAndAudience;
     }
 
+    public boolean isMcpEnabled() {
+        return mcpEnabled;
+    }
+
+    /**
+     * Whether to expose ai-tool routes as MCP tools over streamable HTTP. 
Requires camel-mcp-server on the classpath.
+     * By default, the MCP server is not enabled.
+     */
+    public void setMcpEnabled(boolean mcpEnabled) {
+        this.mcpEnabled = mcpEnabled;
+    }
+
+    public String getMcpTags() {
+        return mcpTags;
+    }
+
+    /**
+     * Comma-separated list of ai-tool tags to expose as MCP tools. Only tools 
registered under one of these tags are
+     * exposed; the untagged default pool is never exposed. When not set, no 
tools are exposed.
+     */
+    public void setMcpTags(String mcpTags) {
+        this.mcpTags = mcpTags;
+    }
+
+    public long getMcpToolTimeout() {
+        return mcpToolTimeout;
+    }
+
+    /**
+     * Per-call MCP tool execution timeout in milliseconds. A call exceeding 
the timeout returns an error result to the
+     * MCP client; the underlying route keeps running until it completes on 
its own.
+     */
+    public void setMcpToolTimeout(long mcpToolTimeout) {
+        this.mcpToolTimeout = mcpToolTimeout;
+    }
+
+    public String getMcpPath() {
+        return mcpPath;
+    }
+
+    /**
+     * HTTP path where the MCP endpoint is served.
+     */
+    public void setMcpPath(String mcpPath) {
+        this.mcpPath = mcpPath;
+    }
+
+    public String getMcpServerName() {
+        return mcpServerName;
+    }
+
+    /**
+     * MCP server name advertised to clients. Defaults to the CamelContext 
name.
+     */
+    public void setMcpServerName(String mcpServerName) {
+        this.mcpServerName = mcpServerName;
+    }
+
     /**
      * Whether embedded HTTP server is enabled. By default, the server is not 
enabled.
      */
@@ -506,4 +575,47 @@ public class HttpServerConfigurationProperties implements 
BootstrapCloseable {
         return this;
     }
 
+    /**
+     * Whether to expose ai-tool routes as MCP tools over streamable HTTP. 
Requires camel-mcp-server on the classpath.
+     * By default, the MCP server is not enabled.
+     */
+    public HttpServerConfigurationProperties withMcpEnabled(boolean 
mcpEnabled) {
+        this.mcpEnabled = mcpEnabled;
+        return this;
+    }
+
+    /**
+     * Comma-separated list of ai-tool tags to expose as MCP tools. Only tools 
registered under one of these tags are
+     * exposed; the untagged default pool is never exposed. When not set, no 
tools are exposed.
+     */
+    public HttpServerConfigurationProperties withMcpTags(String mcpTags) {
+        this.mcpTags = mcpTags;
+        return this;
+    }
+
+    /**
+     * Per-call MCP tool execution timeout in milliseconds. A call exceeding 
the timeout returns an error result to the
+     * MCP client; the underlying route keeps running until it completes on 
its own.
+     */
+    public HttpServerConfigurationProperties withMcpToolTimeout(long 
mcpToolTimeout) {
+        this.mcpToolTimeout = mcpToolTimeout;
+        return this;
+    }
+
+    /**
+     * HTTP path where the MCP endpoint is served.
+     */
+    public HttpServerConfigurationProperties withMcpPath(String mcpPath) {
+        this.mcpPath = mcpPath;
+        return this;
+    }
+
+    /**
+     * MCP server name advertised to clients. Defaults to the CamelContext 
name.
+     */
+    public HttpServerConfigurationProperties withMcpServerName(String 
mcpServerName) {
+        this.mcpServerName = mcpServerName;
+        return this;
+    }
+
 }
diff --git 
a/core/camel-main/src/main/java/org/apache/camel/main/MainConstants.java 
b/core/camel-main/src/main/java/org/apache/camel/main/MainConstants.java
index 0304faa0acef..e0130140a264 100644
--- a/core/camel-main/src/main/java/org/apache/camel/main/MainConstants.java
+++ b/core/camel-main/src/main/java/org/apache/camel/main/MainConstants.java
@@ -24,6 +24,7 @@ public final class MainConstants {
     public static final String CLOUD_PROPERTIES_LOCATION = 
"camel.main.cloud-properties-location";
     public static final String PROPERTY_PLACEHOLDER_LOCATION = 
"camel.main.property-placeholder-location";
     public static final String PLATFORM_HTTP_SERVER = "platform-http-server";
+    public static final String MCP_SERVER = "mcp-server";
     public static final String PROFILE = "camel.main.profile";
 
     private MainConstants() {
diff --git 
a/core/camel-main/src/main/java/org/apache/camel/main/McpServerFactory.java 
b/core/camel-main/src/main/java/org/apache/camel/main/McpServerFactory.java
new file mode 100644
index 000000000000..0216483ac157
--- /dev/null
+++ b/core/camel-main/src/main/java/org/apache/camel/main/McpServerFactory.java
@@ -0,0 +1,39 @@
+/*
+ * 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.main;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Service;
+
+/**
+ * Factory for creating the MCP server exposing ai-tool routes as MCP tools, 
for standalone Camel (not Spring Boot or
+ * Quarkus). Provided by camel-mcp-server.
+ *
+ * @since 4.22
+ */
+public interface McpServerFactory {
+
+    /**
+     * Creates the MCP server bridge configured from the {@code 
camel.server.mcp-*} options.
+     *
+     * @param  camelContext  the camel context
+     * @param  configuration server configuration carrying the mcp options
+     * @return               the bridge as a {@link Service} to be managed by 
{@link org.apache.camel.CamelContext}.
+     */
+    Service newMcpServer(CamelContext camelContext, 
HttpServerConfigurationProperties configuration);
+
+}
diff --git 
a/dsl/camel-kamelet-main/src/generated/resources/camel-factoryfinder-known-dependencies.properties
 
b/dsl/camel-kamelet-main/src/generated/resources/camel-factoryfinder-known-dependencies.properties
index 1ce0ccf39027..e97aa071a654 100644
--- 
a/dsl/camel-kamelet-main/src/generated/resources/camel-factoryfinder-known-dependencies.properties
+++ 
b/dsl/camel-kamelet-main/src/generated/resources/camel-factoryfinder-known-dependencies.properties
@@ -36,6 +36,7 @@ 
META-INF/services/org/apache/camel/kafka-resume-strategy=camel:kafka
 META-INF/services/org/apache/camel/kinesis-resume-strategy=camel:aws2-kinesis
 META-INF/services/org/apache/camel/lra-saga-service=camel:lra
 META-INF/services/org/apache/camel/mcp-server-engine=camel:mcp-server
+META-INF/services/org/apache/camel/mcp-server=camel:mcp-server
 META-INF/services/org/apache/camel/mdc-service=camel:mdc
 
META-INF/services/org/apache/camel/micrometer-observability-tracer=camel:micrometer-observability
 
META-INF/services/org/apache/camel/micrometer-prometheus=camel:micrometer-prometheus

Reply via email to