[ 
https://issues.apache.org/jira/browse/CAMEL-24310?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Federico Mariani updated CAMEL-24310:
-------------------------------------
    Description: 
Create the {{camel-mcp-server}} module(s) under components/camel-ai, split into 
a runtime-agnostic bridge + SPI and a Vert.x serving engine for Camel Main / 
JBang (mirroring the {{PlatformHttpEngine}} precedent so other runtimes plug 
native servers — camel-quarkus provides a quarkus-mcp-server-backed engine, 
camel-spring-boot a Spring AI 2.x-backed engine).

h3. camel-mcp-server (bridge + SPI)

* {{McpServerEngine}} SPI: {{initialize(McpServerInfo)}}, 
{{toolAdded(McpServerTool)}}, {{toolRemoved(String)}}. Single logical MCP 
server per CamelContext.
* {{McpServerTool}}: name, description, pre-built input JSON Schema string AND 
structured {{ParameterDef}} map (both already carried by {{AiToolSpec}}, 
engines pick whichever fits), and a blocking {{McpToolCallHandler}} returning 
{{McpToolCallResult(text, isError)}}.
* The bridge (internal CamelContext service): filters {{AiToolRegistry}} by 
{{mcp-tags}} (never the untagged default pool — note {{getToolsByTag()}} 
includes it, so the bridge must select from the tag-keyed snapshot), refuses 
flat-namespace name collisions with an ERROR log (tools arrive as registry 
listener events during startup, so a uniform refuse-loudly policy replaces 
fail-fast), subscribes to the registry listener (CAMEL-24309) before taking the 
initial snapshot (idempotent {{toolAdded}}), wraps each {{AiToolSpec}} into an 
{{McpServerTool}} whose handler creates the exchange from the tool's endpoint 
({{createExchange}}/{{releaseExchange}}), calls {{AiToolExecutor}} under the 
configured per-call timeout (executor-service + bounded wait; a timed-out route 
keeps running server-side and is documented as such), and maps {{AiToolResult}} 
to a *pre-sanitized* {{McpToolCallResult}} — engines can never see or leak raw 
route exception messages.
* Engine resolution: registry bean of type {{McpServerEngine}} wins; otherwise 
FactoryFinder ({{META-INF/services/org/apache/camel/mcp-server-engine}}); 
enabled-but-no-engine fails startup with a clear message.
* MUST NOT depend on the MCP Java SDK, Vert.x or platform-http — add a 
build-level enforcer rule so no SDK type can leak into the SPI jar (a 
compile-time leak would drag Reactor onto the Quarkus / Spring Boot classpath).
* Ships the engine conformance kit as a test-jar (see CAMEL-24313).

h3. camel-mcp-server-engine-vertx

* Official MCP Java SDK: {{io.modelcontextprotocol.sdk:mcp-core}} + 
{{mcp-json-jackson2}} (version already managed in the parent POM for 
camel-openai).
* Custom {{McpStreamableServerTransportProvider}} for Vert.x (the SDK ships 
only servlet + stdio server transports): registers POST/GET/DELETE handlers for 
{{camel.server.mcp-path}} on the main HTTP server's router via 
{{VertxPlatformHttpRouter.lookup(camelContext)}} — MCP serves on 
{{camel.server.port}} and inherits the main server lifecycle. 
{{Mcp-Session-Id}} handling, {{Last-Event-ID}} replay and message routing are 
delegated to the SDK's {{McpStreamableServerSession}}; the transport writes SSE 
frames directly to the async {{HttpServerResponse}} (chunked, backpressure via 
{{drainHandler}}), strips inbound {{camel*}} / {{org.apache.camel.*}} headers 
and bounds the request body read.
* Verify whether main-server authentication handlers 
({{camel.server.authenticationEnabled}} / JWT) apply to router-registered 
routes or must be attached explicitly.
* Declared as a *runtime* dependency of {{camel-mcp-server}} so plain Camel 
Main / JBang users need a single dependency; camel-quarkus and 
camel-spring-boot exclude it.

Register both modules in {{MojoHelper.getComponentPath()}} for the camel-ai 
parent folder.

----
_This issue was drafted by Claude Code on behalf of Federico Mariani._

  was:
Create the {{camel-mcp-server}} module(s) under components/camel-ai, split into 
a runtime-agnostic bridge + SPI and a default serving engine (mirroring the 
{{PlatformHttpEngine}} precedent so other runtimes can plug native servers — 
the camel-quarkus extension will provide a quarkus-mcp-server-backed engine).

h3. camel-mcp-server (bridge + SPI)

* {{McpServerEngine}} SPI: {{initialize(McpServerInfo)}}, 
{{toolAdded(McpServerTool)}}, {{toolRemoved(String)}}. Single logical MCP 
server per CamelContext.
* {{McpServerTool}}: name, description, pre-built input JSON Schema string AND 
structured {{ParameterDef}} map (both already carried by {{AiToolSpec}}, 
engines pick whichever fits), and a blocking {{McpToolCallHandler}} returning 
{{McpToolCallResult(text, isError)}}.
* The bridge (internal CamelContext service): filters {{AiToolRegistry}} by 
{{mcp-tags}} (never the untagged default pool), fails fast on flat-namespace 
name collisions, subscribes to the registry listener (CAMEL-24309), wraps each 
{{AiToolSpec}} into an {{McpServerTool}} whose handler creates the exchange 
from the tool's consumer, calls {{AiToolExecutor}} with the configured timeout, 
and maps {{AiToolResult}} to a *pre-sanitized* {{McpToolCallResult}} — engines 
can never see or leak raw route exception messages.
* Engine resolution: registry bean of type {{McpServerEngine}} wins; otherwise 
FactoryFinder ({{META-INF/services/org/apache/camel/mcp/server-engine}}); 
enabled-but-no-engine fails startup with a clear message.
* MUST NOT depend on the MCP Java SDK or platform-http — add a build-level 
enforcer rule so no SDK type can leak into the SPI jar (a compile-time leak 
would drag Reactor back onto the Quarkus classpath).

h3. camel-mcp-server-engine-default

* Official MCP Java SDK: {{io.modelcontextprotocol.sdk:mcp-core}} + 
{{mcp-json-jackson2}} (version already managed in the parent POM for 
camel-openai).
* Streamable HTTP transport following the camel-a2a pattern: discover a 
{{RestConsumerFactory}} (typically platform-http) at startup, register the MCP 
endpoint with {{useStreaming=true}} (see {{A2AConsumer}}), stream SSE via a 
queue-backed {{InputStream}} emitter (see {{SseQueueInputStream}} / 
{{A2AStreamEmitter}}). POST answering {{application/json}} or 
{{text/event-stream}}, long-lived GET SSE channel for notifications, 
{{Mcp-Session-Id}} session management, DELETE for session termination.
* Declared as a *runtime* dependency of {{camel-mcp-server}} so plain Camel 
users need a single dependency; downstream runtimes (camel-quarkus) exclude it.

Register both modules in {{MojoHelper.getComponentPath()}} for the camel-ai 
parent folder.

----
_This issue was drafted by Claude Code on behalf of Federico Mariani._


> camel-mcp-server module: bridge, McpServerEngine SPI and default engine
> -----------------------------------------------------------------------
>
>                 Key: CAMEL-24310
>                 URL: https://issues.apache.org/jira/browse/CAMEL-24310
>             Project: Camel
>          Issue Type: Sub-task
>          Components: camel-ai
>            Reporter: Federico Mariani
>            Assignee: Federico Mariani
>            Priority: Major
>              Labels: ai, mcp
>
> Create the {{camel-mcp-server}} module(s) under components/camel-ai, split 
> into a runtime-agnostic bridge + SPI and a Vert.x serving engine for Camel 
> Main / JBang (mirroring the {{PlatformHttpEngine}} precedent so other 
> runtimes plug native servers — camel-quarkus provides a 
> quarkus-mcp-server-backed engine, camel-spring-boot a Spring AI 2.x-backed 
> engine).
> h3. camel-mcp-server (bridge + SPI)
> * {{McpServerEngine}} SPI: {{initialize(McpServerInfo)}}, 
> {{toolAdded(McpServerTool)}}, {{toolRemoved(String)}}. Single logical MCP 
> server per CamelContext.
> * {{McpServerTool}}: name, description, pre-built input JSON Schema string 
> AND structured {{ParameterDef}} map (both already carried by {{AiToolSpec}}, 
> engines pick whichever fits), and a blocking {{McpToolCallHandler}} returning 
> {{McpToolCallResult(text, isError)}}.
> * The bridge (internal CamelContext service): filters {{AiToolRegistry}} by 
> {{mcp-tags}} (never the untagged default pool — note {{getToolsByTag()}} 
> includes it, so the bridge must select from the tag-keyed snapshot), refuses 
> flat-namespace name collisions with an ERROR log (tools arrive as registry 
> listener events during startup, so a uniform refuse-loudly policy replaces 
> fail-fast), subscribes to the registry listener (CAMEL-24309) before taking 
> the initial snapshot (idempotent {{toolAdded}}), wraps each {{AiToolSpec}} 
> into an {{McpServerTool}} whose handler creates the exchange from the tool's 
> endpoint ({{createExchange}}/{{releaseExchange}}), calls {{AiToolExecutor}} 
> under the configured per-call timeout (executor-service + bounded wait; a 
> timed-out route keeps running server-side and is documented as such), and 
> maps {{AiToolResult}} to a *pre-sanitized* {{McpToolCallResult}} — engines 
> can never see or leak raw route exception messages.
> * Engine resolution: registry bean of type {{McpServerEngine}} wins; 
> otherwise FactoryFinder 
> ({{META-INF/services/org/apache/camel/mcp-server-engine}}); 
> enabled-but-no-engine fails startup with a clear message.
> * MUST NOT depend on the MCP Java SDK, Vert.x or platform-http — add a 
> build-level enforcer rule so no SDK type can leak into the SPI jar (a 
> compile-time leak would drag Reactor onto the Quarkus / Spring Boot 
> classpath).
> * Ships the engine conformance kit as a test-jar (see CAMEL-24313).
> h3. camel-mcp-server-engine-vertx
> * Official MCP Java SDK: {{io.modelcontextprotocol.sdk:mcp-core}} + 
> {{mcp-json-jackson2}} (version already managed in the parent POM for 
> camel-openai).
> * Custom {{McpStreamableServerTransportProvider}} for Vert.x (the SDK ships 
> only servlet + stdio server transports): registers POST/GET/DELETE handlers 
> for {{camel.server.mcp-path}} on the main HTTP server's router via 
> {{VertxPlatformHttpRouter.lookup(camelContext)}} — MCP serves on 
> {{camel.server.port}} and inherits the main server lifecycle. 
> {{Mcp-Session-Id}} handling, {{Last-Event-ID}} replay and message routing are 
> delegated to the SDK's {{McpStreamableServerSession}}; the transport writes 
> SSE frames directly to the async {{HttpServerResponse}} (chunked, 
> backpressure via {{drainHandler}}), strips inbound {{camel*}} / 
> {{org.apache.camel.*}} headers and bounds the request body read.
> * Verify whether main-server authentication handlers 
> ({{camel.server.authenticationEnabled}} / JWT) apply to router-registered 
> routes or must be attached explicitly.
> * Declared as a *runtime* dependency of {{camel-mcp-server}} so plain Camel 
> Main / JBang users need a single dependency; camel-quarkus and 
> camel-spring-boot exclude it.
> Register both modules in {{MojoHelper.getComponentPath()}} for the camel-ai 
> parent folder.
> ----
> _This issue was drafted by Claude Code on behalf of Federico Mariani._



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to