This is an automated email from the ASF dual-hosted git repository.
jamesnetherton pushed a commit to branch camel-main
in repository https://gitbox.apache.org/repos/asf/camel-quarkus.git
The following commit(s) were added to refs/heads/camel-main by this push:
new fdaa5a5a2d Add camel-quarkus-mcp-server extension
fdaa5a5a2d is described below
commit fdaa5a5a2d499bb9358ece0c8a2a65019df36cc4
Author: Federico Mariani <[email protected]>
AuthorDate: Thu Aug 6 13:35:24 2026 +0200
Add camel-quarkus-mcp-server extension
Fixes #8949
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Co-authored-by: Claude Fable 5 <[email protected]>
---
catalog/pom.xml | 13 +
docs/modules/ROOT/examples/others/mcp-server.yml | 13 +
docs/modules/ROOT/nav.adoc | 1 +
.../pages/reference/extensions/mcp-server.adoc | 301 +++++++++++++++++++++
extensions/mcp-server/deployment/pom.xml | 67 +++++
.../mcp/server/deployment/McpServerProcessor.java | 53 ++++
extensions/mcp-server/pom.xml | 39 +++
extensions/mcp-server/runtime/pom.xml | 105 +++++++
.../mcp-server/runtime/src/main/doc/intro.adoc | 13 +
.../mcp-server/runtime/src/main/doc/usage.adoc | 200 ++++++++++++++
.../component/mcp/server/CamelMcpServerConfig.java | 58 ++++
.../mcp/server/CamelMcpServerRecorder.java | 54 ++++
.../mcp/server/QuarkusMcpServerEngine.java | 104 +++++++
.../main/resources/META-INF/quarkus-extension.yaml | 38 +++
extensions/pom.xml | 1 +
integration-tests/mcp-server/pom.xml | 146 ++++++++++
.../component/mcp/server/it/McpServerResource.java | 52 ++++
.../component/mcp/server/it/McpServerRoutes.java | 47 ++++
.../mcp/server/it/QuarkusDefinedTools.java | 33 +++
.../src/main/resources/application.properties | 18 ++
.../component/mcp/server/it/McpServerIT.java | 24 ++
.../component/mcp/server/it/McpServerTest.java | 170 ++++++++++++
integration-tests/pom.xml | 1 +
pom.xml | 1 +
poms/bom-test/pom.xml | 6 +
poms/bom/pom.xml | 25 ++
poms/bom/src/main/generated/flattened-full-pom.xml | 25 ++
.../src/main/generated/flattened-reduced-pom.xml | 25 ++
.../generated/flattened-reduced-verbose-pom.xml | 25 ++
tooling/scripts/test-categories.yaml | 1 +
30 files changed, 1659 insertions(+)
diff --git a/catalog/pom.xml b/catalog/pom.xml
index 4da6127a69..82cbaf373a 100644
--- a/catalog/pom.xml
+++ b/catalog/pom.xml
@@ -2827,6 +2827,19 @@
</exclusion>
</exclusions>
</dependency>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-mcp-server</artifactId>
+ <version>${project.version}</version>
+ <type>pom</type>
+ <scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>*</groupId>
+ <artifactId>*</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-mdc</artifactId>
diff --git a/docs/modules/ROOT/examples/others/mcp-server.yml
b/docs/modules/ROOT/examples/others/mcp-server.yml
new file mode 100644
index 0000000000..596ae964bf
--- /dev/null
+++ b/docs/modules/ROOT/examples/others/mcp-server.yml
@@ -0,0 +1,13 @@
+# Do not edit directly!
+# This file was generated by
camel-quarkus-maven-plugin:update-extension-doc-page
+cqArtifactId: camel-quarkus-mcp-server
+cqArtifactIdBase: mcp-server
+cqNativeSupported: true
+cqStatus: Stable
+cqDeprecated: false
+cqJvmSince: 3.39.0
+cqNativeSince: 3.39.0
+cqCamelPartName: mcp-server
+cqCamelPartTitle: MCP Server
+cqCamelPartDescription: Expose ai-tool routes as MCP tools over streamable HTTP
+cqExtensionPageTitle: MCP Server
diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc
index d0cd2289b1..e1ef9f5e51 100644
--- a/docs/modules/ROOT/nav.adoc
+++ b/docs/modules/ROOT/nav.adoc
@@ -226,6 +226,7 @@
*** xref:reference/extensions/log.adoc[Log]
*** xref:reference/extensions/lucene.adoc[Lucene]
*** xref:reference/extensions/lumberjack.adoc[Lumberjack]
+*** xref:reference/extensions/mcp-server.adoc[MCP Server]
*** xref:reference/extensions/mina-sftp.adoc[MINA SFTP]
*** xref:reference/extensions/mllp.adoc[MLLP]
*** xref:reference/extensions/mvel.adoc[MVEL]
diff --git a/docs/modules/ROOT/pages/reference/extensions/mcp-server.adoc
b/docs/modules/ROOT/pages/reference/extensions/mcp-server.adoc
new file mode 100644
index 0000000000..96dae1aa26
--- /dev/null
+++ b/docs/modules/ROOT/pages/reference/extensions/mcp-server.adoc
@@ -0,0 +1,301 @@
+// Do not edit directly!
+// This file was generated by
camel-quarkus-maven-plugin:update-extension-doc-page
+[id="extensions-mcp-server"]
+= MCP Server
+:linkattrs:
+:cq-artifact-id: camel-quarkus-mcp-server
+:cq-native-supported: true
+:cq-status: Stable
+:cq-status-deprecation: Stable
+:cq-description: Expose ai-tool routes as MCP tools over streamable HTTP
+:cq-deprecated: false
+:cq-jvm-since: 3.39.0
+:cq-native-since: 3.39.0
+
+ifeval::[{doc-show-badges} == true]
+[.badges]
+[.badge-key]##JVM since##[.badge-supported]##3.39.0## [.badge-key]##Native
since##[.badge-supported]##3.39.0##
+endif::[]
+
+The MCP Server extension exposes Camel routes registered via the `ai-tool`
+component as tools of a Model Context Protocol (MCP) server, served through
+the quarkiverse
https://docs.quarkiverse.io/quarkus-mcp-server/dev/index.html[quarkus-mcp-server]
+extension. No route is needed for the server itself: add the extension, tag
+the `ai-tool` routes to expose, and any MCP client (another Camel
+application, an IDE, a coding agent) can discover and call them.
+
+Tool semantics — tag-based opt-in (the untagged default pool is never
+exposed), flat-namespace collision refusal, per-call timeout and error
+sanitization — are owned by the runtime-agnostic `camel-mcp-server-api`
+bridge and are identical on every Camel runtime. Serving concerns (endpoint
+path, transports, authentication) are owned by quarkus-mcp-server and
+configured via `quarkus.mcp.server.*`.
+
+
+[id="extensions-mcp-server-whats-inside"]
+== What's inside
+
+* xref:{cq-camel-components}:others:mcp-server.adoc[MCP Server]
+
+Please refer to the above link for usage and configuration details.
+
+[id="extensions-mcp-server-maven-coordinates"]
+== Maven coordinates
+
+https://{link-quarkus-code-generator}/?extension-search=camel-quarkus-mcp-server[Create
a new project with this extension on {link-quarkus-code-generator},
window="_blank"]
+
+Or add the coordinates to your existing project:
+
+[source,xml]
+----
+<dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-mcp-server</artifactId>
+</dependency>
+----
+ifeval::[{doc-show-user-guide-link} == true]
+Check the xref:user-guide/index.adoc[User guide] for more information about
writing Camel Quarkus applications.
+endif::[]
+
+[id="extensions-mcp-server-usage"]
+== Usage
+Define tools as regular `ai-tool` routes and give them tags:
+
+[source,java]
+----
+from("ai-tool:query_db?tags=crm&description=Query customer database"
+ + "¶meter.customerId=string¶meter.customerId.required=true")
+ .to("jdbc:dataSource");
+----
+
+or in YAML DSL:
+
+[source,yaml]
+----
+- route:
+ from:
+ uri: "ai-tool:send_email"
+ parameters:
+ description: "Send email notification"
+ tags: "notify"
+ parameter.to: string
+ parameter.to.description: "Recipient address"
+ parameter.to.required: "true"
+ parameter.subject: string
+ parameter.priority: string
+ parameter.priority.enum: "low,normal,high"
+ steps:
+ - to: "smtp://mail.example.com"
+----
+
+Tool parameters are declared with the `parameter.NAME` options: the value is
+the JSON type (`string`, `integer`, `number`, `boolean`), and the
+`parameter.NAME.description`, `parameter.NAME.required` and
+`parameter.NAME.enum` options refine the generated input schema. Arguments
+arrive as message headers in the route (`${header.customerId}`).
+
+[id="extensions-mcp-server-usage-combining-the-camel-and-quarkus-mcp-server-configuration"]
+=== Combining the Camel and quarkus-mcp-server configuration
+
+The configuration is split by ownership: `quarkus.camel.mcp-server.*`
+decides *which tools exist and how they execute* (identical semantics on
+every Camel runtime), while `quarkus.mcp.server.*` decides *how the server
+is exposed*. Both are set side by side in `application.properties`:
+
+[source,properties]
+----
+# Camel-owned: tool selection and execution
+quarkus.camel.mcp-server.tags = crm,notify
+quarkus.camel.mcp-server.tool-timeout = 10000
+
+# quarkus-mcp-server-owned: serving and server identity
+quarkus.mcp.server.server-info.name = my-integration-app
+quarkus.mcp.server.server-info.version = 1.0.0
+quarkus.mcp.server.http.root-path = /mcp
+
+# quarkus-mcp-server-owned: diagnostics while developing
+quarkus.mcp.server.traffic-logging.enabled = true
+quarkus.mcp.server.traffic-logging.text-limit = 200
+----
+
+See the
+https://docs.quarkiverse.io/quarkus-mcp-server/dev/index.html#configuration-reference[quarkus-mcp-server
configuration reference]
+for the full list of `quarkus.mcp.server.*` properties (transports, dev UI,
+authentication, guardrails, pagination, timeouts).
+
+[id="extensions-mcp-server-usage-connecting-mcp-clients"]
+=== Connecting MCP clients
+
+Any MCP client can connect over streamable HTTP. Another Camel integration
+can consume the tools with the camel-openai MCP client and automatic tool
+execution:
+
+[source,java]
+----
+from("direct:agent")
+ .to("openai:chat-completion"
+ + "?model={{llm.model}}"
+ + "&autoToolExecution=true"
+ + "&mcpServer.myCamelTools.transportType=streamableHttp"
+ + "&mcpServer.myCamelTools.url=http://localhost:8080/mcp");
+----
+
+A coding agent or IDE is configured with the same URL, e.g. in an
+`mcp.json`-style client configuration:
+
+[source,json]
+----
+{
+ "mcpServers": {
+ "my-integration-app": {
+ "type": "http",
+ "url": "http://localhost:8080/mcp"
+ }
+ }
+}
+----
+
+[id="extensions-mcp-server-usage-serving-over-stdio"]
+=== Serving over stdio
+
+Out of the box the tools are served over streamable HTTP. MCP clients that
+launch the server as a subprocess speak over stdin/stdout instead — add the
+stdio transport alongside the extension:
+
+[source,xml]
+----
+<dependency>
+ <groupId>io.quarkiverse.mcp</groupId>
+ <artifactId>quarkus-mcp-server-stdio</artifactId>
+ <!-- the same version as the quarkus-mcp-server-http extension pulled in
+ by camel-quarkus-mcp-server; the transports share their core module
-->
+ <version>1.13.1</version>
+</dependency>
+----
+
+The stdio transport is active as soon as it is on the classpath
+(`quarkus.mcp.server.stdio.enabled` defaults to `true`), and the same Camel
+tools are then served over both transports. To serve over stdio *only*,
+disable the HTTP transport of the default MCP server:
+
+[source,properties]
+----
+quarkus.mcp.server."<default>".http.enabled = false
+----
+
+The server name of the default MCP server is the literal string
+`<default>`, so it has to be quoted. Conversely,
+`quarkus.mcp.server.stdio.enabled = false` keeps the stdio extension on the
+classpath without activating it, which is useful when the same application
+is deployed both ways.
+
+Because stdout carries the MCP protocol, nothing else may be written to it;
+`quarkus-mcp-server-stdio` takes care of this by routing console logging to
+stderr. A stdio server is typically built as a native executable and
+launched by the client:
+
+[source,json]
+----
+{
+ "mcpServers": {
+ "my-integration-app": {
+ "command": "/path/to/target/my-integration-app-1.0.0-runner"
+ }
+ }
+}
+----
+
+See the
+https://docs.quarkiverse.io/quarkus-mcp-server/dev/getting-started-stdio.html[quarkus-mcp-server
stdio guide]
+and the
+https://docs.quarkiverse.io/quarkus-mcp-server/dev/reference-configuration.html[configuration
reference]
+for the transport options. On Spring Boot the equivalent setup is described
+in the
+https://docs.spring.io/spring-ai/reference/api/mcp/mcp-server-boot-starter-docs.html[Spring
AI MCP Server Boot Starter documentation].
+
+[id="extensions-mcp-server-usage-mixing-with-quarkus-mcp-server-annotated-tools"]
+=== Mixing with quarkus-mcp-server annotated tools
+
+Camel tools coexist with tools defined natively with quarkus-mcp-server —
+both are served by the same MCP server and appear in the same `tools/list`.
+For example, a `@Tool`-annotated business method:
+
+[source,java]
+----
+public class CalculatorTools {
+
+ @Tool(name = "add_numbers", description = "Add two numbers")
+ String add(
+ @ToolArg(description = "First addend") long a,
+ @ToolArg(description = "Second addend") long b) {
+ return String.valueOf(a + b);
+ }
+}
+----
+
+is exposed alongside the `ai-tool` routes. Annotated tools are registered at
+build time; Camel tools are added and removed dynamically with the route
+lifecycle. Choose distinct tool names — MCP has a flat tool namespace.
+
+[id="extensions-mcp-server-usage-dynamic-tools"]
+=== Dynamic tools
+
+The exposed tool list follows the route lifecycle: stopping or suspending an
+`ai-tool` route removes its tool, starting or resuming it publishes the tool
+again, and connected clients are notified via
+`notifications/tools/list_changed`:
+
+[source,java]
+----
+camelContext.getRouteController().stopRoute("query-db-route"); // tool
disappears
+camelContext.getRouteController().startRoute("query-db-route"); // tool is
back
+----
+
+[id="extensions-mcp-server-usage-error-handling"]
+=== Error handling
+
+Results returned to MCP clients are sanitized by the bridge: a route
+exception produces an error result with the generic message
+`Tool execution failed` (the cause is logged server-side and never sent to
+the client), a missing or invalid argument returns the validation message,
+and a call exceeding `quarkus.camel.mcp-server.tool-timeout` returns
+`Tool execution timed out` while the route keeps running until it completes
+on its own.
+
+On Camel Main and Camel JBang the equivalent setup is the
+`camel-mcp-server` module with the `camel.server.mcp-*` options; on Spring
+Boot it is the `camel-mcp-server-starter`.
+
+
+[id="extensions-mcp-server-additional-camel-quarkus-configuration"]
+== Additional Camel Quarkus configuration
+
+[width="100%",cols="80,5,15",options="header"]
+|===
+| Configuration property | Type | Default
+
+
+a|icon:lock[title=Fixed at build time]
[[quarkus-camel-mcp-server-enabled]]`link:#quarkus-camel-mcp-server-enabled[quarkus.camel.mcp-server.enabled]`
+
+Whether to expose ai-tool routes as MCP tools through the quarkus-mcp-server
extension.
+| `boolean`
+| `true`
+
+a|icon:lock[title=Fixed at build time]
[[quarkus-camel-mcp-server-tags]]`link:#quarkus-camel-mcp-server-tags[quarkus.camel.mcp-server.tags]`
+
+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`
+|
+
+a|icon:lock[title=Fixed at build time]
[[quarkus-camel-mcp-server-tool-timeout]]`link:#quarkus-camel-mcp-server-tool-timeout[quarkus.camel.mcp-server.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.
+| `long`
+| `20000`
+|===
+
+[.configuration-legend]
+{doc-link-icon-lock}[title=Fixed at build time] Configuration property fixed
at build time. All other configuration properties are overridable at runtime.
+
diff --git a/extensions/mcp-server/deployment/pom.xml
b/extensions/mcp-server/deployment/pom.xml
new file mode 100644
index 0000000000..908eb31960
--- /dev/null
+++ b/extensions/mcp-server/deployment/pom.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-mcp-server-parent</artifactId>
+ <version>3.39.0-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <artifactId>camel-quarkus-mcp-server-deployment</artifactId>
+ <name>Camel Quarkus :: MCP Server :: Deployment</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-core-deployment</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-mcp-server</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.quarkiverse.mcp</groupId>
+ <artifactId>quarkus-mcp-server-http-deployment</artifactId>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <annotationProcessorPaths>
+ <path>
+ <groupId>io.quarkus</groupId>
+
<artifactId>quarkus-extension-processor</artifactId>
+ <version>${quarkus.version}</version>
+ </path>
+ </annotationProcessorPaths>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git
a/extensions/mcp-server/deployment/src/main/java/org/apache/camel/quarkus/component/mcp/server/deployment/McpServerProcessor.java
b/extensions/mcp-server/deployment/src/main/java/org/apache/camel/quarkus/component/mcp/server/deployment/McpServerProcessor.java
new file mode 100644
index 0000000000..f43febbb35
--- /dev/null
+++
b/extensions/mcp-server/deployment/src/main/java/org/apache/camel/quarkus/component/mcp/server/deployment/McpServerProcessor.java
@@ -0,0 +1,53 @@
+/*
+ * 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.quarkus.component.mcp.server.deployment;
+
+import java.util.function.BooleanSupplier;
+
+import io.quarkus.deployment.annotations.BuildStep;
+import io.quarkus.deployment.annotations.ExecutionTime;
+import io.quarkus.deployment.annotations.Record;
+import io.quarkus.deployment.builditem.FeatureBuildItem;
+import org.apache.camel.quarkus.component.mcp.server.CamelMcpServerConfig;
+import org.apache.camel.quarkus.component.mcp.server.CamelMcpServerRecorder;
+import
org.apache.camel.quarkus.core.deployment.spi.RuntimeCamelContextCustomizerBuildItem;
+
+class McpServerProcessor {
+
+ private static final String FEATURE = "camel-mcp-server";
+
+ @BuildStep
+ FeatureBuildItem feature() {
+ return new FeatureBuildItem(FEATURE);
+ }
+
+ @BuildStep(onlyIf = McpServerEnabled.class)
+ @Record(ExecutionTime.RUNTIME_INIT)
+ RuntimeCamelContextCustomizerBuildItem
mcpServerBridge(CamelMcpServerRecorder recorder, CamelMcpServerConfig config) {
+ return new RuntimeCamelContextCustomizerBuildItem(
+ recorder.createContextCustomizer(config.tags().orElse(null),
config.toolTimeout()));
+ }
+
+ static final class McpServerEnabled implements BooleanSupplier {
+ CamelMcpServerConfig config;
+
+ @Override
+ public boolean getAsBoolean() {
+ return config.enabled();
+ }
+ }
+}
diff --git a/extensions/mcp-server/pom.xml b/extensions/mcp-server/pom.xml
new file mode 100644
index 0000000000..f514871de7
--- /dev/null
+++ b/extensions/mcp-server/pom.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-extensions</artifactId>
+ <version>3.39.0-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <artifactId>camel-quarkus-mcp-server-parent</artifactId>
+ <name>Camel Quarkus :: MCP Server</name>
+ <packaging>pom</packaging>
+
+ <modules>
+ <module>deployment</module>
+ <module>runtime</module>
+ </modules>
+</project>
diff --git a/extensions/mcp-server/runtime/pom.xml
b/extensions/mcp-server/runtime/pom.xml
new file mode 100644
index 0000000000..63af0d6f59
--- /dev/null
+++ b/extensions/mcp-server/runtime/pom.xml
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-mcp-server-parent</artifactId>
+ <version>3.39.0-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <artifactId>camel-quarkus-mcp-server</artifactId>
+ <name>Camel Quarkus :: MCP Server :: Runtime</name>
+ <description>Expose ai-tool routes as MCP tools over streamable
HTTP</description>
+
+ <properties>
+ <camel.quarkus.jvmSince>3.39.0</camel.quarkus.jvmSince>
+ <camel.quarkus.nativeSince>3.39.0</camel.quarkus.nativeSince>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-mcp-server-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.quarkiverse.mcp</groupId>
+ <artifactId>quarkus-mcp-server-http</artifactId>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-extension-maven-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <annotationProcessorPaths>
+ <path>
+ <groupId>io.quarkus</groupId>
+
<artifactId>quarkus-extension-processor</artifactId>
+ <version>${quarkus.version}</version>
+ </path>
+ </annotationProcessorPaths>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+
+ <profiles>
+ <profile>
+ <id>full</id>
+ <activation>
+ <property>
+ <name>!quickly</name>
+ </property>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>update-extension-doc-page</id>
+ <goals>
+ <goal>update-extension-doc-page</goal>
+ </goals>
+ <phase>process-classes</phase>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+</project>
diff --git a/extensions/mcp-server/runtime/src/main/doc/intro.adoc
b/extensions/mcp-server/runtime/src/main/doc/intro.adoc
new file mode 100644
index 0000000000..7c60ee6f2d
--- /dev/null
+++ b/extensions/mcp-server/runtime/src/main/doc/intro.adoc
@@ -0,0 +1,13 @@
+The MCP Server extension exposes Camel routes registered via the `ai-tool`
+component as tools of a Model Context Protocol (MCP) server, served through
+the quarkiverse
https://docs.quarkiverse.io/quarkus-mcp-server/dev/index.html[quarkus-mcp-server]
+extension. No route is needed for the server itself: add the extension, tag
+the `ai-tool` routes to expose, and any MCP client (another Camel
+application, an IDE, a coding agent) can discover and call them.
+
+Tool semantics — tag-based opt-in (the untagged default pool is never
+exposed), flat-namespace collision refusal, per-call timeout and error
+sanitization — are owned by the runtime-agnostic `camel-mcp-server-api`
+bridge and are identical on every Camel runtime. Serving concerns (endpoint
+path, transports, authentication) are owned by quarkus-mcp-server and
+configured via `quarkus.mcp.server.*`.
diff --git a/extensions/mcp-server/runtime/src/main/doc/usage.adoc
b/extensions/mcp-server/runtime/src/main/doc/usage.adoc
new file mode 100644
index 0000000000..595f81e6ed
--- /dev/null
+++ b/extensions/mcp-server/runtime/src/main/doc/usage.adoc
@@ -0,0 +1,200 @@
+Define tools as regular `ai-tool` routes and give them tags:
+
+[source,java]
+----
+from("ai-tool:query_db?tags=crm&description=Query customer database"
+ + "¶meter.customerId=string¶meter.customerId.required=true")
+ .to("jdbc:dataSource");
+----
+
+or in YAML DSL:
+
+[source,yaml]
+----
+- route:
+ from:
+ uri: "ai-tool:send_email"
+ parameters:
+ description: "Send email notification"
+ tags: "notify"
+ parameter.to: string
+ parameter.to.description: "Recipient address"
+ parameter.to.required: "true"
+ parameter.subject: string
+ parameter.priority: string
+ parameter.priority.enum: "low,normal,high"
+ steps:
+ - to: "smtp://mail.example.com"
+----
+
+Tool parameters are declared with the `parameter.NAME` options: the value is
+the JSON type (`string`, `integer`, `number`, `boolean`), and the
+`parameter.NAME.description`, `parameter.NAME.required` and
+`parameter.NAME.enum` options refine the generated input schema. Arguments
+arrive as message headers in the route (`${header.customerId}`).
+
+=== Combining the Camel and quarkus-mcp-server configuration
+
+The configuration is split by ownership: `quarkus.camel.mcp-server.*`
+decides *which tools exist and how they execute* (identical semantics on
+every Camel runtime), while `quarkus.mcp.server.*` decides *how the server
+is exposed*. Both are set side by side in `application.properties`:
+
+[source,properties]
+----
+# Camel-owned: tool selection and execution
+quarkus.camel.mcp-server.tags = crm,notify
+quarkus.camel.mcp-server.tool-timeout = 10000
+
+# quarkus-mcp-server-owned: serving and server identity
+quarkus.mcp.server.server-info.name = my-integration-app
+quarkus.mcp.server.server-info.version = 1.0.0
+quarkus.mcp.server.http.root-path = /mcp
+
+# quarkus-mcp-server-owned: diagnostics while developing
+quarkus.mcp.server.traffic-logging.enabled = true
+quarkus.mcp.server.traffic-logging.text-limit = 200
+----
+
+See the
+https://docs.quarkiverse.io/quarkus-mcp-server/dev/index.html#configuration-reference[quarkus-mcp-server
configuration reference]
+for the full list of `quarkus.mcp.server.*` properties (transports, dev UI,
+authentication, guardrails, pagination, timeouts).
+
+=== Connecting MCP clients
+
+Any MCP client can connect over streamable HTTP. Another Camel integration
+can consume the tools with the camel-openai MCP client and automatic tool
+execution:
+
+[source,java]
+----
+from("direct:agent")
+ .to("openai:chat-completion"
+ + "?model={{llm.model}}"
+ + "&autoToolExecution=true"
+ + "&mcpServer.myCamelTools.transportType=streamableHttp"
+ + "&mcpServer.myCamelTools.url=http://localhost:8080/mcp");
+----
+
+A coding agent or IDE is configured with the same URL, e.g. in an
+`mcp.json`-style client configuration:
+
+[source,json]
+----
+{
+ "mcpServers": {
+ "my-integration-app": {
+ "type": "http",
+ "url": "http://localhost:8080/mcp"
+ }
+ }
+}
+----
+
+=== Serving over stdio
+
+Out of the box the tools are served over streamable HTTP. MCP clients that
+launch the server as a subprocess speak over stdin/stdout instead — add the
+stdio transport alongside the extension:
+
+[source,xml]
+----
+<dependency>
+ <groupId>io.quarkiverse.mcp</groupId>
+ <artifactId>quarkus-mcp-server-stdio</artifactId>
+ <!-- the same version as the quarkus-mcp-server-http extension pulled in
+ by camel-quarkus-mcp-server; the transports share their core module
-->
+ <version>1.13.1</version>
+</dependency>
+----
+
+The stdio transport is active as soon as it is on the classpath
+(`quarkus.mcp.server.stdio.enabled` defaults to `true`), and the same Camel
+tools are then served over both transports. To serve over stdio *only*,
+disable the HTTP transport of the default MCP server:
+
+[source,properties]
+----
+quarkus.mcp.server."<default>".http.enabled = false
+----
+
+The server name of the default MCP server is the literal string
+`<default>`, so it has to be quoted. Conversely,
+`quarkus.mcp.server.stdio.enabled = false` keeps the stdio extension on the
+classpath without activating it, which is useful when the same application
+is deployed both ways.
+
+Because stdout carries the MCP protocol, nothing else may be written to it;
+`quarkus-mcp-server-stdio` takes care of this by routing console logging to
+stderr. A stdio server is typically built as a native executable and
+launched by the client:
+
+[source,json]
+----
+{
+ "mcpServers": {
+ "my-integration-app": {
+ "command": "/path/to/target/my-integration-app-1.0.0-runner"
+ }
+ }
+}
+----
+
+See the
+https://docs.quarkiverse.io/quarkus-mcp-server/dev/getting-started-stdio.html[quarkus-mcp-server
stdio guide]
+and the
+https://docs.quarkiverse.io/quarkus-mcp-server/dev/reference-configuration.html[configuration
reference]
+for the transport options. On Spring Boot the equivalent setup is described
+in the
+https://docs.spring.io/spring-ai/reference/api/mcp/mcp-server-boot-starter-docs.html[Spring
AI MCP Server Boot Starter documentation].
+
+=== Mixing with quarkus-mcp-server annotated tools
+
+Camel tools coexist with tools defined natively with quarkus-mcp-server —
+both are served by the same MCP server and appear in the same `tools/list`.
+For example, a `@Tool`-annotated business method:
+
+[source,java]
+----
+public class CalculatorTools {
+
+ @Tool(name = "add_numbers", description = "Add two numbers")
+ String add(
+ @ToolArg(description = "First addend") long a,
+ @ToolArg(description = "Second addend") long b) {
+ return String.valueOf(a + b);
+ }
+}
+----
+
+is exposed alongside the `ai-tool` routes. Annotated tools are registered at
+build time; Camel tools are added and removed dynamically with the route
+lifecycle. Choose distinct tool names — MCP has a flat tool namespace.
+
+=== Dynamic tools
+
+The exposed tool list follows the route lifecycle: stopping or suspending an
+`ai-tool` route removes its tool, starting or resuming it publishes the tool
+again, and connected clients are notified via
+`notifications/tools/list_changed`:
+
+[source,java]
+----
+camelContext.getRouteController().stopRoute("query-db-route"); // tool
disappears
+camelContext.getRouteController().startRoute("query-db-route"); // tool is
back
+----
+
+=== Error handling
+
+Results returned to MCP clients are sanitized by the bridge: a route
+exception produces an error result with the generic message
+`Tool execution failed` (the cause is logged server-side and never sent to
+the client), a missing or invalid argument returns the validation message,
+and a call exceeding `quarkus.camel.mcp-server.tool-timeout` returns
+`Tool execution timed out` while the route keeps running until it completes
+on its own.
+
+On Camel Main and Camel JBang the equivalent setup is the
+`camel-mcp-server` module with the `camel.server.mcp-*` options; on Spring
+Boot it is the `camel-mcp-server-starter`.
diff --git
a/extensions/mcp-server/runtime/src/main/java/org/apache/camel/quarkus/component/mcp/server/CamelMcpServerConfig.java
b/extensions/mcp-server/runtime/src/main/java/org/apache/camel/quarkus/component/mcp/server/CamelMcpServerConfig.java
new file mode 100644
index 0000000000..5975fc5d86
--- /dev/null
+++
b/extensions/mcp-server/runtime/src/main/java/org/apache/camel/quarkus/component/mcp/server/CamelMcpServerConfig.java
@@ -0,0 +1,58 @@
+/*
+ * 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.quarkus.component.mcp.server;
+
+import java.util.Optional;
+
+import io.quarkus.runtime.annotations.ConfigPhase;
+import io.quarkus.runtime.annotations.ConfigRoot;
+import io.smallrye.config.ConfigMapping;
+import io.smallrye.config.WithDefault;
+
+/**
+ * Bridge-owned configuration of the Camel MCP server. Serving concerns
(endpoint path, transports, authentication)
+ * are owned by the quarkiverse quarkus-mcp-server extension and configured
via {@code quarkus.mcp.server.*}.
+ */
+@ConfigRoot(phase = ConfigPhase.BUILD_AND_RUN_TIME_FIXED)
+@ConfigMapping(prefix = "quarkus.camel.mcp-server")
+public interface CamelMcpServerConfig {
+
+ /**
+ * Whether to expose ai-tool routes as MCP tools through the
quarkus-mcp-server extension.
+ *
+ * @asciidoclet
+ */
+ @WithDefault("true")
+ boolean enabled();
+
+ /**
+ * 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.
+ *
+ * @asciidoclet
+ */
+ Optional<String> tags();
+
+ /**
+ * 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.
+ *
+ * @asciidoclet
+ */
+ @WithDefault("20000")
+ long toolTimeout();
+}
diff --git
a/extensions/mcp-server/runtime/src/main/java/org/apache/camel/quarkus/component/mcp/server/CamelMcpServerRecorder.java
b/extensions/mcp-server/runtime/src/main/java/org/apache/camel/quarkus/component/mcp/server/CamelMcpServerRecorder.java
new file mode 100644
index 0000000000..f7d5ef2157
--- /dev/null
+++
b/extensions/mcp-server/runtime/src/main/java/org/apache/camel/quarkus/component/mcp/server/CamelMcpServerRecorder.java
@@ -0,0 +1,54 @@
+/*
+ * 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.quarkus.component.mcp.server;
+
+import io.quarkiverse.mcp.server.ToolManager;
+import io.quarkus.arc.Arc;
+import io.quarkus.runtime.RuntimeValue;
+import io.quarkus.runtime.annotations.Recorder;
+import org.apache.camel.CamelContext;
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.component.mcp.server.McpServerBridge;
+import org.apache.camel.component.mcp.server.McpServerConfiguration;
+import org.apache.camel.component.mcp.server.McpServerEngine;
+import org.apache.camel.spi.CamelContextCustomizer;
+
+@Recorder
+public class CamelMcpServerRecorder {
+
+ public RuntimeValue<CamelContextCustomizer> createContextCustomizer(String
tags, long toolTimeout) {
+ return new RuntimeValue<>(new CamelContextCustomizer() {
+ @Override
+ public void configure(CamelContext camelContext) {
+ ToolManager toolManager =
Arc.container().instance(ToolManager.class).get();
+ QuarkusMcpServerEngine engine = new
QuarkusMcpServerEngine(toolManager);
+
+ McpServerConfiguration configuration = new
McpServerConfiguration();
+ configuration.setTags(tags);
+ configuration.setToolTimeout(toolTimeout);
+ McpServerBridge bridge = new McpServerBridge(configuration);
+ try {
+ // the bridge resolves the engine registry-first
+
camelContext.getRegistry().bind("quarkusCamelMcpServerEngine",
McpServerEngine.class, engine);
+ camelContext.addService(bridge);
+ } catch (Exception e) {
+ throw RuntimeCamelException.wrapRuntimeCamelException(e);
+ }
+ }
+ });
+ }
+}
diff --git
a/extensions/mcp-server/runtime/src/main/java/org/apache/camel/quarkus/component/mcp/server/QuarkusMcpServerEngine.java
b/extensions/mcp-server/runtime/src/main/java/org/apache/camel/quarkus/component/mcp/server/QuarkusMcpServerEngine.java
new file mode 100644
index 0000000000..2f9a19f6be
--- /dev/null
+++
b/extensions/mcp-server/runtime/src/main/java/org/apache/camel/quarkus/component/mcp/server/QuarkusMcpServerEngine.java
@@ -0,0 +1,104 @@
+/*
+ * 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.quarkus.component.mcp.server;
+
+import java.lang.reflect.Type;
+import java.util.Map;
+
+import io.quarkiverse.mcp.server.TextContent;
+import io.quarkiverse.mcp.server.ToolManager;
+import io.quarkiverse.mcp.server.ToolResponse;
+import org.apache.camel.CamelContext;
+import org.apache.camel.component.ai.tool.AiToolParameterHelper.ParameterDef;
+import org.apache.camel.component.mcp.server.McpServerEngine;
+import org.apache.camel.component.mcp.server.McpServerInfo;
+import org.apache.camel.component.mcp.server.McpServerTool;
+import org.apache.camel.component.mcp.server.McpToolCallResult;
+import org.apache.camel.support.service.ServiceSupport;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * {@link McpServerEngine} publishing tools into the quarkiverse
quarkus-mcp-server through its programmatic
+ * {@link ToolManager} API. Serving concerns (endpoint path, transports,
authentication) are owned by
+ * quarkus-mcp-server and configured via {@code quarkus.mcp.server.*}.
+ */
+public class QuarkusMcpServerEngine extends ServiceSupport implements
McpServerEngine {
+
+ private static final Logger LOG =
LoggerFactory.getLogger(QuarkusMcpServerEngine.class);
+
+ private final ToolManager toolManager;
+ private CamelContext camelContext;
+
+ public QuarkusMcpServerEngine(ToolManager toolManager) {
+ this.toolManager = toolManager;
+ }
+
+ @Override
+ public CamelContext getCamelContext() {
+ return camelContext;
+ }
+
+ @Override
+ public void setCamelContext(CamelContext camelContext) {
+ this.camelContext = camelContext;
+ }
+
+ @Override
+ public void initialize(McpServerInfo info) {
+ // serving identity is owned by quarkus.mcp.server.*; the hint is
deliberately ignored
+ LOG.debug("quarkus-mcp-server engine initialized; serving
configuration is owned by quarkus.mcp.server.*");
+ }
+
+ @Override
+ public void toolAdded(McpServerTool tool) {
+ ToolManager.ToolDefinition definition =
toolManager.newTool(tool.name())
+ .setDescription(tool.description());
+ for (Map.Entry<String, ParameterDef> parameter :
tool.parameters().entrySet()) {
+ ParameterDef def = parameter.getValue();
+ definition.addArgument(parameter.getKey(), def.getDescription(),
def.isRequired(), javaType(def));
+ }
+ definition.setHandler(arguments -> {
+ Map<String, Object> args = arguments.args() != null ?
arguments.args() : Map.of();
+ McpToolCallResult result = tool.handler().call(args);
+ return result.isError()
+ ? ToolResponse.error(result.text()) :
ToolResponse.success(new TextContent(result.text()));
+ });
+ definition.register();
+ LOG.debug("MCP tool added: {}", tool.name());
+ }
+
+ @Override
+ public void toolRemoved(String toolName) {
+ try {
+ toolManager.removeTool(toolName);
+ LOG.debug("MCP tool removed: {}", toolName);
+ } catch (Exception e) {
+ LOG.debug("Failed to remove MCP tool {}: {}", toolName,
e.getMessage());
+ }
+ }
+
+ private static Type javaType(ParameterDef def) {
+ String type = def.getType() != null ? def.getType() : "string";
+ return switch (type) {
+ case "integer", "int", "long" -> Long.class;
+ case "number", "double", "float" -> Double.class;
+ case "boolean", "bool" -> Boolean.class;
+ default -> String.class;
+ };
+ }
+}
diff --git
a/extensions/mcp-server/runtime/src/main/resources/META-INF/quarkus-extension.yaml
b/extensions/mcp-server/runtime/src/main/resources/META-INF/quarkus-extension.yaml
new file mode 100644
index 0000000000..875f203389
--- /dev/null
+++
b/extensions/mcp-server/runtime/src/main/resources/META-INF/quarkus-extension.yaml
@@ -0,0 +1,38 @@
+#
+# 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.
+#
+
+# This is a generated file. Do not edit directly!
+# To re-generate, run the following command from the top level directory:
+#
+# mvn -N cq:update-quarkus-metadata
+#
+---
+name: "Camel MCP Server"
+description: "Expose ai-tool routes as MCP tools over streamable HTTP"
+metadata:
+ icon-url:
"https://raw.githubusercontent.com/apache/camel-website/main/antora-ui-camel/src/img/logo-d.svg"
+ sponsor: "Apache Software Foundation"
+ guide:
"https://camel.apache.org/camel-quarkus/latest/reference/extensions/mcp-server.html"
+ categories:
+ - "integration"
+ config:
+ - "quarkus.camel.mcp-server"
+ status: "stable"
+ integrates:
+ - name: "Camel"
+ artifact: "org.apache.camel:camel-base"
+ version: "${camel.version}"
\ No newline at end of file
diff --git a/extensions/pom.xml b/extensions/pom.xml
index bfb301db5e..023c0b2bca 100644
--- a/extensions/pom.xml
+++ b/extensions/pom.xml
@@ -204,6 +204,7 @@
<module>management</module>
<module>mapstruct</module>
<module>master</module>
+ <module>mcp-server</module>
<module>mdc</module>
<module>micrometer</module>
<module>micrometer-observability</module>
diff --git a/integration-tests/mcp-server/pom.xml
b/integration-tests/mcp-server/pom.xml
new file mode 100644
index 0000000000..b6accb9bdf
--- /dev/null
+++ b/integration-tests/mcp-server/pom.xml
@@ -0,0 +1,146 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-build-parent-it</artifactId>
+ <version>3.39.0-SNAPSHOT</version>
+ <relativePath>../../poms/build-parent-it/pom.xml</relativePath>
+ </parent>
+
+ <artifactId>camel-quarkus-integration-test-mcp-server</artifactId>
+ <name>Camel Quarkus :: Integration Tests :: MCP Server</name>
+ <description>Integration tests for Camel Quarkus MCP Server
extension</description>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-mcp-server</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-ai-tool</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-resteasy</artifactId>
+ </dependency>
+
+ <!-- test dependencies -->
+ <dependency>
+ <groupId>io.quarkiverse.mcp</groupId>
+ <artifactId>quarkus-mcp-server-test</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.awaitility</groupId>
+ <artifactId>awaitility</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.assertj</groupId>
+ <artifactId>assertj-core</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>io.rest-assured</groupId>
+ <artifactId>rest-assured</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <profiles>
+ <profile>
+ <id>native</id>
+ <activation>
+ <property>
+ <name>native</name>
+ </property>
+ </activation>
+ <properties>
+ <quarkus.native.enabled>true</quarkus.native.enabled>
+ </properties>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-failsafe-plugin</artifactId>
+ <executions>
+ <execution>
+ <goals>
+ <goal>integration-test</goal>
+ <goal>verify</goal>
+ </goals>
+ <configuration>
+
<rerunFailingTestsCount>${rerun.failing.test.count}</rerunFailingTestsCount>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ <profile>
+ <id>virtualDependencies</id>
+ <activation>
+ <property>
+ <name>!noVirtualDependencies</name>
+ </property>
+ </activation>
+ <dependencies>
+ <!-- The following dependencies guarantee that this module is
built after them. You can update them by running `mvn process-resources
-Pformat -N` from the source tree root directory -->
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-ai-tool-deployment</artifactId>
+ <version>${project.version}</version>
+ <type>pom</type>
+ <scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>*</groupId>
+ <artifactId>*</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+
<artifactId>camel-quarkus-mcp-server-deployment</artifactId>
+ <version>${project.version}</version>
+ <type>pom</type>
+ <scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>*</groupId>
+ <artifactId>*</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ </dependencies>
+ </profile>
+ </profiles>
+</project>
diff --git
a/integration-tests/mcp-server/src/main/java/org/apache/camel/quarkus/component/mcp/server/it/McpServerResource.java
b/integration-tests/mcp-server/src/main/java/org/apache/camel/quarkus/component/mcp/server/it/McpServerResource.java
new file mode 100644
index 0000000000..1012e173fa
--- /dev/null
+++
b/integration-tests/mcp-server/src/main/java/org/apache/camel/quarkus/component/mcp/server/it/McpServerResource.java
@@ -0,0 +1,52 @@
+/*
+ * 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.quarkus.component.mcp.server.it;
+
+import jakarta.inject.Inject;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.POST;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.PathParam;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.core.MediaType;
+import org.apache.camel.CamelContext;
+
+@Path("/mcp-server")
+public class McpServerResource {
+
+ @Inject
+ CamelContext camelContext;
+
+ @Path("/route/{routeId}/start")
+ @POST
+ public void startRoute(@PathParam("routeId") String routeId) throws
Exception {
+ camelContext.getRouteController().startRoute(routeId);
+ }
+
+ @Path("/route/{routeId}/stop")
+ @POST
+ public void stopRoute(@PathParam("routeId") String routeId) throws
Exception {
+ camelContext.getRouteController().stopRoute(routeId);
+ }
+
+ @Path("/route/{routeId}/status")
+ @GET
+ @Produces(MediaType.TEXT_PLAIN)
+ public String routeStatus(@PathParam("routeId") String routeId) {
+ return
camelContext.getRouteController().getRouteStatus(routeId).name();
+ }
+}
diff --git
a/integration-tests/mcp-server/src/main/java/org/apache/camel/quarkus/component/mcp/server/it/McpServerRoutes.java
b/integration-tests/mcp-server/src/main/java/org/apache/camel/quarkus/component/mcp/server/it/McpServerRoutes.java
new file mode 100644
index 0000000000..ab1efba168
--- /dev/null
+++
b/integration-tests/mcp-server/src/main/java/org/apache/camel/quarkus/component/mcp/server/it/McpServerRoutes.java
@@ -0,0 +1,47 @@
+/*
+ * 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.quarkus.component.mcp.server.it;
+
+import jakarta.enterprise.context.ApplicationScoped;
+import org.apache.camel.builder.RouteBuilder;
+
+@ApplicationScoped
+public class McpServerRoutes extends RouteBuilder {
+
+ @Override
+ public void configure() {
+ from("ai-tool:say_hello?tags=conformance&description=Say hello"
+ + "¶meter.name=string¶meter.name.description=Who to
greet¶meter.name.required=true")
+ .routeId("say-hello-route")
+ .setBody(simple("Hello ${header.name}"));
+
+ from("ai-tool:fail_tool?tags=conformance&description=Always fails")
+ .process(e -> {
+ throw new IllegalStateException("secret internal detail");
+ });
+
+ from("ai-tool:slow_tool?tags=conformance&description=Exceeds the tool
timeout")
+ .delay(6000)
+ .setBody(constant("done"));
+
+ from("ai-tool:hidden_tool?description=Untagged tool, must not be
exposed")
+ .setBody(constant("hidden"));
+
+ from("ai-tool:other_tool?tags=untrusted&description=Not a selected
tag, must not be exposed")
+ .setBody(constant("other"));
+ }
+}
diff --git
a/integration-tests/mcp-server/src/main/java/org/apache/camel/quarkus/component/mcp/server/it/QuarkusDefinedTools.java
b/integration-tests/mcp-server/src/main/java/org/apache/camel/quarkus/component/mcp/server/it/QuarkusDefinedTools.java
new file mode 100644
index 0000000000..88a6cf149f
--- /dev/null
+++
b/integration-tests/mcp-server/src/main/java/org/apache/camel/quarkus/component/mcp/server/it/QuarkusDefinedTools.java
@@ -0,0 +1,33 @@
+/*
+ * 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.quarkus.component.mcp.server.it;
+
+import io.quarkiverse.mcp.server.Tool;
+import io.quarkiverse.mcp.server.ToolArg;
+
+/**
+ * A plain quarkus-mcp-server annotated tool living on the same MCP server as
the Camel ai-tool routes.
+ */
+public class QuarkusDefinedTools {
+
+ @Tool(name = "add_numbers", description = "Add two numbers")
+ String add(
+ @ToolArg(description = "First addend") long a,
+ @ToolArg(description = "Second addend") long b) {
+ return String.valueOf(a + b);
+ }
+}
diff --git
a/integration-tests/mcp-server/src/main/resources/application.properties
b/integration-tests/mcp-server/src/main/resources/application.properties
new file mode 100644
index 0000000000..91728bf643
--- /dev/null
+++ b/integration-tests/mcp-server/src/main/resources/application.properties
@@ -0,0 +1,18 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+quarkus.camel.mcp-server.tags=conformance
+quarkus.camel.mcp-server.tool-timeout=2000
diff --git
a/integration-tests/mcp-server/src/test/java/org/apache/camel/quarkus/component/mcp/server/it/McpServerIT.java
b/integration-tests/mcp-server/src/test/java/org/apache/camel/quarkus/component/mcp/server/it/McpServerIT.java
new file mode 100644
index 0000000000..2775bf3183
--- /dev/null
+++
b/integration-tests/mcp-server/src/test/java/org/apache/camel/quarkus/component/mcp/server/it/McpServerIT.java
@@ -0,0 +1,24 @@
+/*
+ * 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.quarkus.component.mcp.server.it;
+
+import io.quarkus.test.junit.QuarkusIntegrationTest;
+
+@QuarkusIntegrationTest
+class McpServerIT extends McpServerTest {
+
+}
diff --git
a/integration-tests/mcp-server/src/test/java/org/apache/camel/quarkus/component/mcp/server/it/McpServerTest.java
b/integration-tests/mcp-server/src/test/java/org/apache/camel/quarkus/component/mcp/server/it/McpServerTest.java
new file mode 100644
index 0000000000..efa0e8945a
--- /dev/null
+++
b/integration-tests/mcp-server/src/test/java/org/apache/camel/quarkus/component/mcp/server/it/McpServerTest.java
@@ -0,0 +1,170 @@
+/*
+ * 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.quarkus.component.mcp.server.it;
+
+import java.net.URI;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+import io.quarkiverse.mcp.server.TextContent;
+import io.quarkiverse.mcp.server.ToolResponse;
+import io.quarkiverse.mcp.server.test.McpAssured;
+import io.quarkiverse.mcp.server.test.McpAssured.McpStreamableTestClient;
+import io.quarkiverse.mcp.server.test.McpAssured.ToolInfo;
+import io.quarkiverse.mcp.server.test.McpAssured.ToolsPage;
+import io.quarkus.test.junit.QuarkusTest;
+import io.restassured.RestAssured;
+import org.eclipse.microprofile.config.ConfigProvider;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.awaitility.Awaitility.await;
+
+/**
+ * The engine conformance scenarios (CAMEL-24313) against the
quarkus-mcp-server engine, driven by McpAssured over
+ * streamable HTTP. Mirrors {@code McpServerConformanceTestSupport} from
camel-mcp-server-api, which cannot be reused
+ * as-is here because it manages its own CamelContext outside Quarkus.
+ */
+@QuarkusTest
+class McpServerTest {
+
+ private McpStreamableTestClient client;
+
+ private McpStreamableTestClient client() {
+ if (client == null) {
+ client = McpAssured.newStreamableClient()
+ .setBaseUri(URI.create("http://localhost:%d".formatted(
+
ConfigProvider.getConfig().getValue("quarkus.http.test-port", Integer.class))))
+ .build()
+ .connect();
+ }
+ return client;
+ }
+
+ @AfterEach
+ void closeClient() {
+ if (client != null) {
+ client.disconnect();
+ client = null;
+ }
+ }
+
+ @Test
+ void testListToolsExposesOnlySelectedTags() {
+ client().when()
+ .toolsList(page -> assertThat(toolNames(page))
+ .contains("say_hello", "fail_tool", "slow_tool")
+ .doesNotContain("hidden_tool", "other_tool"))
+ .thenAssertResults();
+ }
+
+ @Test
+ void testQuarkusAnnotatedToolsCoexistWithCamelTools() {
+ // both tool sources are served by the same MCP server
+ client().when()
+ .toolsList(page ->
assertThat(toolNames(page)).contains("add_numbers", "say_hello"))
+ .toolsCall("add_numbers", Map.of("a", 17, "b", 25), response
-> {
+ assertThat(response.isError()).isNotEqualTo(Boolean.TRUE);
+ assertThat(textOf(response)).isEqualTo("42");
+ })
+ .thenAssertResults();
+ }
+
+ @Test
+ void testCallToolSuccess() {
+ client().when()
+ .toolsCall("say_hello", Map.of("name", "World"), response -> {
+ assertThat(response.isError()).isNotEqualTo(Boolean.TRUE);
+ assertThat(textOf(response)).isEqualTo("Hello World");
+ })
+ .thenAssertResults();
+ }
+
+ @Test
+ void testCallToolExecutionErrorIsSanitized() {
+ client().when()
+ .toolsCall("fail_tool", response -> {
+ assertThat(response.isError()).isTrue();
+ assertThat(textOf(response))
+ .doesNotContain("secret internal detail")
+ .isEqualTo("Tool execution failed");
+ })
+ .thenAssertResults();
+ }
+
+ @Test
+ void testCallToolTimeout() {
+ client().when()
+ .toolsCall("slow_tool", response -> {
+ assertThat(response.isError()).isTrue();
+ assertThat(textOf(response)).contains("timed out");
+ })
+ .thenAssertResults();
+ }
+
+ @Test
+ void testToolsListReflectsRouteStopAndStart() {
+ client().when()
+ .toolsList(page ->
assertThat(toolNames(page)).contains("say_hello"))
+ .thenAssertResults();
+
+ controlRoute("stop");
+ assertThat(routeStatus()).isEqualTo("Stopped");
+ await().atMost(10, TimeUnit.SECONDS).untilAsserted(() ->
client().when()
+ .toolsList(page ->
assertThat(toolNames(page)).doesNotContain("say_hello"))
+ .thenAssertResults());
+
+ controlRoute("start");
+ assertThat(routeStatus()).isEqualTo("Started");
+ await().atMost(10, TimeUnit.SECONDS).untilAsserted(() ->
client().when()
+ .toolsList(page ->
assertThat(toolNames(page)).contains("say_hello"))
+ .thenAssertResults());
+ }
+
+ private static void controlRoute(String action) {
+ RestAssured.given()
+ .when()
+ .post("/mcp-server/route/say-hello-route/" + action)
+ .then()
+ .statusCode(204);
+ }
+
+ private static String routeStatus() {
+ return RestAssured.given()
+ .when()
+ .get("/mcp-server/route/say-hello-route/status")
+ .then()
+ .statusCode(200)
+ .extract()
+ .body()
+ .asString();
+ }
+
+ private static List<String> toolNames(ToolsPage page) {
+ return page.tools().stream().map(ToolInfo::name).toList();
+ }
+
+ private static String textOf(ToolResponse response) {
+ return response.content().stream()
+ .filter(TextContent.class::isInstance)
+ .map(content -> ((TextContent) content).text())
+ .collect(Collectors.joining());
+ }
+}
diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml
index 8ffee5a4dd..3eac678682 100644
--- a/integration-tests/pom.xml
+++ b/integration-tests/pom.xml
@@ -179,6 +179,7 @@
<module>master-file</module>
<module>master-infinispan</module>
<module>master-openshift</module>
+ <module>mcp-server</module>
<module>mdc</module>
<module>micrometer</module>
<module>micrometer-observability</module>
diff --git a/pom.xml b/pom.xml
index bf1e32703e..980459421a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -60,6 +60,7 @@
<quarkiverse-jgit.version>3.6.2</quarkiverse-jgit.version><!--
https://repo1.maven.org/maven2/io/quarkiverse/jgit/quarkus-jgit/ -->
<quarkiverse-jsch.version>3.2.0</quarkiverse-jsch.version><!--
https://repo1.maven.org/maven2/io/quarkiverse/jsch/quarkus-jsch/ -->
<quarkiverse-langchain4j.version>1.12.2</quarkiverse-langchain4j.version><!--
https://repo1.maven.org/maven2/io/quarkiverse/langchain4j/quarkus-langchain4j-parent
-->
+
<quarkiverse-mcp-server.version>1.13.1</quarkiverse-mcp-server.version><!--
https://repo1.maven.org/maven2/io/quarkiverse/mcp/quarkus-mcp-server-parent/ -->
<quarkiverse-micrometer.version>3.5.0</quarkiverse-micrometer.version><!--
https://repo1.maven.org/maven2/io/quarkiverse/micrometer/registry/quarkus-micrometer-registry-jmx/
-->
<quarkiverse-minio.version>3.9.1</quarkiverse-minio.version><!--
https://repo1.maven.org/maven2/io/quarkiverse/minio/quarkus-minio-parent/ -->
<quarkiverse-mybatis.version>2.4.2</quarkiverse-mybatis.version><!--
https://repo1.maven.org/maven2/io/quarkiverse/mybatis/quarkus-mybatis-parent/
-->
diff --git a/poms/bom-test/pom.xml b/poms/bom-test/pom.xml
index ca3cfd8ecf..5454654aca 100644
--- a/poms/bom-test/pom.xml
+++ b/poms/bom-test/pom.xml
@@ -463,6 +463,12 @@
<version>${microsoft.graph.auth.version}</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>io.quarkiverse.mcp</groupId>
+ <artifactId>quarkus-mcp-server-test</artifactId>
+ <version>${quarkiverse-mcp-server.version}</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
</dependencyManagement>
diff --git a/poms/bom/pom.xml b/poms/bom/pom.xml
index ef15e3593e..f2c20ce769 100644
--- a/poms/bom/pom.xml
+++ b/poms/bom/pom.xml
@@ -2310,6 +2310,11 @@
<artifactId>camel-master</artifactId>
<version>${camel.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-mcp-server-api</artifactId>
+ <version>${camel.version}</version>
+ </dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-mdc</artifactId>
@@ -5650,6 +5655,16 @@
<artifactId>camel-quarkus-master-deployment</artifactId>
<version>${camel-quarkus.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-mcp-server</artifactId>
+ <version>${camel-quarkus.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-mcp-server-deployment</artifactId>
+ <version>${camel-quarkus.version}</version>
+ </dependency>
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-mdc</artifactId>
@@ -7932,6 +7947,16 @@
<artifactId>quarkus-jsch-deployment</artifactId>
<version>${quarkiverse-jsch.version}</version>
</dependency>
+ <dependency>
+ <groupId>io.quarkiverse.mcp</groupId>
+ <artifactId>quarkus-mcp-server-http</artifactId>
+ <version>${quarkiverse-mcp-server.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>io.quarkiverse.mcp</groupId>
+ <artifactId>quarkus-mcp-server-http-deployment</artifactId>
+ <version>${quarkiverse-mcp-server.version}</version>
+ </dependency>
<dependency>
<groupId>io.quarkiverse.messaginghub</groupId>
<artifactId>quarkus-pooled-jms</artifactId>
diff --git a/poms/bom/src/main/generated/flattened-full-pom.xml
b/poms/bom/src/main/generated/flattened-full-pom.xml
index ec5e8408aa..c75a85ed05 100644
--- a/poms/bom/src/main/generated/flattened-full-pom.xml
+++ b/poms/bom/src/main/generated/flattened-full-pom.xml
@@ -2223,6 +2223,11 @@
<artifactId>camel-master</artifactId>
<version>4.22.0-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-mcp-server-api</artifactId>
+ <version>4.22.0-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-mdc</artifactId>
@@ -5535,6 +5540,16 @@
<artifactId>camel-quarkus-master-deployment</artifactId>
<version>3.39.0-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-mcp-server</artifactId>
+ <version>3.39.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-mcp-server-deployment</artifactId>
+ <version>3.39.0-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-mdc</artifactId>
@@ -7814,6 +7829,16 @@
<artifactId>quarkus-jsch-deployment</artifactId>
<version>3.2.0</version>
</dependency>
+ <dependency>
+ <groupId>io.quarkiverse.mcp</groupId>
+ <artifactId>quarkus-mcp-server-http</artifactId>
+ <version>1.13.1</version>
+ </dependency>
+ <dependency>
+ <groupId>io.quarkiverse.mcp</groupId>
+ <artifactId>quarkus-mcp-server-http-deployment</artifactId>
+ <version>1.13.1</version>
+ </dependency>
<dependency>
<groupId>io.quarkiverse.messaginghub</groupId>
<artifactId>quarkus-pooled-jms</artifactId>
diff --git a/poms/bom/src/main/generated/flattened-reduced-pom.xml
b/poms/bom/src/main/generated/flattened-reduced-pom.xml
index 1b36331e8c..0a66188c96 100644
--- a/poms/bom/src/main/generated/flattened-reduced-pom.xml
+++ b/poms/bom/src/main/generated/flattened-reduced-pom.xml
@@ -1177,6 +1177,16 @@
<artifactId>quarkus-jsch-deployment</artifactId>
<version>3.2.0</version>
</dependency>
+ <dependency>
+ <groupId>io.quarkiverse.mcp</groupId>
+ <artifactId>quarkus-mcp-server-http</artifactId>
+ <version>1.13.1</version>
+ </dependency>
+ <dependency>
+ <groupId>io.quarkiverse.mcp</groupId>
+ <artifactId>quarkus-mcp-server-http-deployment</artifactId>
+ <version>1.13.1</version>
+ </dependency>
<dependency>
<groupId>io.quarkiverse.messaginghub</groupId>
<artifactId>quarkus-pooled-jms</artifactId>
@@ -3551,6 +3561,11 @@
<artifactId>camel-master</artifactId>
<version>4.22.0-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-mcp-server-api</artifactId>
+ <version>4.22.0-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-mdc</artifactId>
@@ -6868,6 +6883,16 @@
<artifactId>camel-quarkus-master-deployment</artifactId>
<version>3.39.0-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-mcp-server</artifactId>
+ <version>3.39.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-mcp-server-deployment</artifactId>
+ <version>3.39.0-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-mdc</artifactId>
diff --git a/poms/bom/src/main/generated/flattened-reduced-verbose-pom.xml
b/poms/bom/src/main/generated/flattened-reduced-verbose-pom.xml
index 4882931d0d..66614a6368 100644
--- a/poms/bom/src/main/generated/flattened-reduced-verbose-pom.xml
+++ b/poms/bom/src/main/generated/flattened-reduced-verbose-pom.xml
@@ -1177,6 +1177,16 @@
<artifactId>quarkus-jsch-deployment</artifactId>
<version>3.2.0</version>
</dependency>
+ <dependency>
+ <groupId>io.quarkiverse.mcp</groupId>
+ <artifactId>quarkus-mcp-server-http</artifactId>
+ <version>1.13.1</version>
+ </dependency>
+ <dependency>
+ <groupId>io.quarkiverse.mcp</groupId>
+ <artifactId>quarkus-mcp-server-http-deployment</artifactId>
+ <version>1.13.1</version>
+ </dependency>
<dependency>
<groupId>io.quarkiverse.messaginghub</groupId>
<artifactId>quarkus-pooled-jms</artifactId>
@@ -3551,6 +3561,11 @@
<artifactId>camel-master</artifactId>
<version>4.22.0-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-mcp-server-api</artifactId>
+ <version>4.22.0-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-mdc</artifactId>
@@ -6868,6 +6883,16 @@
<artifactId>camel-quarkus-master-deployment</artifactId>
<version>3.39.0-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-mcp-server</artifactId>
+ <version>3.39.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-mcp-server-deployment</artifactId>
+ <version>3.39.0-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-mdc</artifactId>
diff --git a/tooling/scripts/test-categories.yaml
b/tooling/scripts/test-categories.yaml
index a4df390265..98d19bc52c 100644
--- a/tooling/scripts/test-categories.yaml
+++ b/tooling/scripts/test-categories.yaml
@@ -239,6 +239,7 @@ group-12:
- knative
- langchain4j-web-search
- langchain4j-tools
+ - mcp-server
- openapi-java
- openapi-validator
- paho-mqtt5