-
Notifications
You must be signed in to change notification settings - Fork 5.1k
CAMEL-24310: camel-mcp-server - bridge, McpServerEngine SPI and Vert.x engine #25306
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
adbd221
CAMEL-24310: camel-mcp-server - bridge, McpServerEngine SPI and Vert.…
Croway 8aeb787
CAMEL-24310: camel-mcp-server - use text block for empty object schema
Croway 7b05b9e
CAMEL-24310: camel-mcp-server - integration tests
Croway b72e7d3
CAMEL-24310: camel-mcp-server - address review findings
Croway 399da98
CAMEL-24310: camel-mcp-server - fix docs xrefs and known-dependencies
Croway 2668964
CAMEL-24310: camel-mcp-server - regen camel-bom entries
Croway c1b3f8c
CAMEL-24310: camel-mcp-server - address review observations
Croway 4e40fcd
CAMEL-24310: camel-mcp-server - address review comments
Croway File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -386,6 +386,7 @@ main | |
| mapstruct-component | ||
| marshal-eip | ||
| master-component | ||
| mcp-server | ||
| mdc | ||
| message | ||
| message-broker | ||
|
|
||
210 changes: 210 additions & 0 deletions
210
...l-catalog/src/generated/resources/org/apache/camel/catalog/docs/mcp-server.adoc
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,210 @@ | ||
| = MCP Server Component | ||
| :doctitle: MCP Server | ||
| :shortname: mcp-server | ||
| :artifactid: camel-mcp-server | ||
| :description: Expose ai-tool routes as MCP tools over streamable HTTP | ||
| :since: 4.22 | ||
| :supportlevel: Preview | ||
| :tabs-sync-option: | ||
|
|
||
| *Since Camel {since}* | ||
|
|
||
| The camel-mcp-server module exposes Camel routes registered via the | ||
| xref:ROOT:ai-tool-component.adoc[ai-tool] component as tools of a | ||
| https://modelcontextprotocol.io[Model Context Protocol] (MCP) server, served | ||
| over MCP streamable HTTP. No route is needed for the server itself: add the | ||
| dependency, configure which tags to expose, and every matching `ai-tool` route | ||
| becomes an MCP tool that any MCP client (another Camel application, an IDE, a | ||
| coding agent) can discover and call. | ||
|
|
||
| Maven users will need to add the following dependency to their `pom.xml`: | ||
|
|
||
| [source,xml] | ||
| ---- | ||
| <dependency> | ||
| <groupId>org.apache.camel</groupId> | ||
| <artifactId>camel-mcp-server</artifactId> | ||
| <version>x.x.x</version> | ||
| <!-- use the same version as your Camel core version --> | ||
| </dependency> | ||
| ---- | ||
|
|
||
| == Architecture | ||
|
|
||
| The module is split in two artifacts: | ||
|
|
||
| * `camel-mcp-server-api` — the runtime-agnostic _bridge_ and the small | ||
| `McpServerEngine` SPI. The bridge owns tool selection (tags), execution via | ||
| the shared `AiToolExecutor` (per-call timeout, error sanitization) and reacts | ||
| to `AiToolRegistry` changes when routes start and stop. It has no dependency | ||
| on the MCP Java SDK. | ||
| * `camel-mcp-server` — the serving engine for Camel Main and Camel JBang, | ||
| built on the official MCP Java SDK with a Vert.x streamable HTTP transport. | ||
| The MCP endpoint is registered on the Camel main HTTP server's router, so it | ||
| serves on the main server port (`camel.server.port`) and inherits its | ||
| lifecycle, authentication and CORS configuration. | ||
|
|
||
| Engine resolution mirrors the platform-http engine: a bean of type | ||
| `McpServerEngine` in the Camel registry wins; otherwise the engine is | ||
| discovered on the classpath. Other runtimes plug native engines through the | ||
| same SPI: on Quarkus the `camel-quarkus-mcp-server` extension serves through | ||
| the Quarkiverse `quarkus-mcp-server` (configured via `quarkus.mcp.server.*`), | ||
| and on Spring Boot the starter serves through the Spring AI MCP server | ||
| (configured via `spring.ai.mcp.server.*`). Bridge behavior — tag selection, | ||
| timeout, sanitization — is identical on every runtime and verified by a shared | ||
| conformance test kit. | ||
|
|
||
| == Usage | ||
|
|
||
| Define tools as regular `ai-tool` routes and give them tags: | ||
|
|
||
| [tabs] | ||
| ==== | ||
| Java:: | ||
| + | ||
| [source,java] | ||
| ---- | ||
| from("ai-tool:query_db?tags=crm" + | ||
| "&description=Query customer database" + | ||
| "¶meter.customerId=string" + | ||
| "¶meter.customerId.description=The customer id" + | ||
| "¶meter.customerId.required=true") | ||
| .to("jdbc:dataSource"); | ||
| ---- | ||
|
|
||
| XML:: | ||
| + | ||
| [source,xml] | ||
| ---- | ||
| <route> | ||
| <from uri="ai-tool:query_db?tags=crm&description=Query customer database&parameter.customerId=string&parameter.customerId.description=The customer id&parameter.customerId.required=true"/> | ||
| <to uri="jdbc:dataSource"/> | ||
| </route> | ||
| ---- | ||
|
|
||
| YAML:: | ||
| + | ||
| [source,yaml] | ||
| ---- | ||
| - route: | ||
| from: | ||
| uri: ai-tool:query_db | ||
| parameters: | ||
| tags: crm | ||
| description: "Query customer database" | ||
| parameter.customerId: string | ||
| parameter.customerId.description: "The customer id" | ||
| parameter.customerId.required: "true" | ||
| steps: | ||
| - to: | ||
| uri: jdbc:dataSource | ||
| ---- | ||
| ==== | ||
|
|
||
| Start the MCP server by adding the `McpServerBridge` service to the | ||
| CamelContext, selecting the tags to expose: | ||
|
|
||
| [source,java] | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. show the application properties configuration first. the hand coded is for advanced users
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. will do in #25309 |
||
| ---- | ||
| McpServerConfiguration configuration = new McpServerConfiguration(); | ||
| configuration.setTags("crm,notify"); | ||
| camelContext.addService(new McpServerBridge(configuration)); | ||
| ---- | ||
|
|
||
| The MCP endpoint is then served at `http://<host>:<port>/mcp` on the Camel | ||
| main HTTP server. Any MCP client can connect over streamable HTTP, for | ||
| example another Camel integration using the | ||
| xref:ROOT:openai-component.adoc[camel-openai] MCP client: | ||
|
|
||
| [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"); | ||
| ---- | ||
|
|
||
| == Options | ||
|
|
||
| The `McpServerConfiguration` options: | ||
|
|
||
| [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 | ||
| |=== | ||
|
|
||
| Bridge-owned options are honored identically on every runtime. Engine-owned | ||
| options are consumed by the Vert.x engine only; on runtimes with a native | ||
| engine (Quarkus, Spring Boot) the native configuration decides serving | ||
| concerns and a startup WARN is logged when an ignored option is set. | ||
|
|
||
| == Protocol | ||
|
|
||
| This section describes the Vert.x engine shipped in `camel-mcp-server`, which | ||
| serves on Camel Main and Camel JBang. On Quarkus and Spring Boot the transport | ||
| is owned by the native engine instead — quarkus-mcp-server and the Spring Boot | ||
| embedded HTTP server (Spring AI MCP server) respectively — and the details | ||
| below do not apply. | ||
|
|
||
| The Vert.x engine implements the MCP streamable HTTP transport: | ||
|
Croway marked this conversation as resolved.
|
||
|
|
||
| * `POST /mcp` answering `application/json` or `text/event-stream` depending on | ||
| the request, | ||
| * a long-lived `GET /mcp` SSE channel for server notifications, with | ||
| `Last-Event-ID` replay, | ||
| * session management via the `Mcp-Session-Id` header and `DELETE /mcp` for | ||
| session termination. | ||
|
|
||
| Tools appearing or disappearing (routes starting and stopping) emit | ||
| `notifications/tools/list_changed` to connected clients. | ||
|
|
||
| == Security | ||
|
|
||
| External MCP clients are *untrusted senders* under the | ||
| xref:manual::security-model.adoc[Camel security model]. The module applies the | ||
| following rules: | ||
|
|
||
| * *Explicit opt-in per tool*: only tools whose tags intersect the configured | ||
| `tags` are exposed. The untagged default pool is never exposed implicitly. | ||
| * *Flat namespace protection*: a tool whose name collides with an already | ||
| exposed tool is refused with an ERROR log — never silently replaced. | ||
| * *Error sanitization*: route exceptions are mapped to a generic error | ||
| message; the cause is logged server-side and never sent to the client. | ||
| Argument validation messages (missing or invalid parameters) are returned | ||
| as-is. | ||
| * *Bounded execution*: every call is subject to the `toolTimeout`. Note that a | ||
| timed-out route keeps running server-side until it completes; the timeout | ||
| bounds the MCP request, not the route. | ||
| * *Authentication*: the MCP endpoint is served through the main HTTP server | ||
| router, so platform-http authentication (basic, JWT via | ||
| `camel.server.authentication*` options) applies to it. The MCP | ||
| specification's authorization model is OAuth 2.1; see | ||
| xref:oauth.adoc[camel-oauth] for resource-server style | ||
| protection. On Quarkus and Spring Boot, authentication is owned by the | ||
| native runtime security. | ||
|
|
||
| == Runtime notes | ||
|
|
||
| * *Camel Main / JBang*: requires the Camel main HTTP server | ||
| (`camel.server.enabled=true` with `camel-platform-http-main`, automatic | ||
| with Camel JBang) or a `VertxPlatformHttpServer` service. Serving is fully | ||
| asynchronous: tool calls are offloaded to the Vert.x worker pool and the | ||
| long-lived SSE channel does not occupy a worker thread. | ||
| * *Quarkus*: use the `camel-quarkus-mcp-server` extension (serves through | ||
| quarkus-mcp-server; the MCP Java SDK is not on the classpath). | ||
| * *Spring Boot*: use the `camel-mcp-server-starter` (serves through the | ||
| Spring AI MCP server). | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
15 changes: 15 additions & 0 deletions
15
...log/camel-catalog/src/generated/resources/org/apache/camel/catalog/others/mcp-server.json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| { | ||
| "other": { | ||
| "kind": "other", | ||
| "name": "mcp-server", | ||
| "title": "MCP Server", | ||
| "description": "Expose ai-tool routes as MCP tools over streamable HTTP", | ||
| "deprecated": false, | ||
| "firstVersion": "4.22.0", | ||
| "label": "ai", | ||
| "supportLevel": "Preview", | ||
| "groupId": "org.apache.camel", | ||
| "artifactId": "camel-mcp-server", | ||
| "version": "4.22.0-SNAPSHOT" | ||
| } | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.