Skip to content

CAMEL-23853: Embed MCP server on camel run/dev and Camel Main - #25203

Open
atiaomar1978-hub wants to merge 10 commits into
apache:mainfrom
atiaomar1978-hub:CAMEL-23853-jbang-run-mcp
Open

CAMEL-23853: Embed MCP server on camel run/dev and Camel Main#25203
atiaomar1978-hub wants to merge 10 commits into
apache:mainfrom
atiaomar1978-hub:CAMEL-23853-jbang-run-mcp

Conversation

@atiaomar1978-hub

Copy link
Copy Markdown
Contributor

Summary

  • Adds camel.mcp.* configuration and an MCP Streamable HTTP endpoint on the embedded management HTTP server (/mcp by default), wired through EmbeddedMcpRequestHandler.
  • Adds camel run / camel dev --mcp (and camel.jbang.mcp) to enable embedded MCP with JBang ToolRegistry tools against the local process (management server bound to 127.0.0.1 by default).
  • Includes unit tests for the JSON-RPC engine, management HTTP wiring, and CLI flag parsing; documents the feature in Camel Main / JBang docs and the 4.22 upgrade guide.

Test plan

  • mvn test -pl components/camel-platform-http-main,dsl/camel-jbang/camel-jbang-core -am -Dtest=StreamableMcpJsonRpcEngineTest,EmbeddedMcpHttpServerTest,RunMcpOptionTest
  • Manual: camel run hello.yaml --mcp then POST JSON-RPC tools/list to http://127.0.0.1:8080/mcp

https://issues.apache.org/jira/browse/CAMEL-23853

AI-generated PR description on behalf of atiaomar1978-hub

Made with Cursor

@atiaomar1978-hub

Copy link
Copy Markdown
Contributor Author

AI review summary (Bugbot + Grok)

Review comments generated by Cursor on behalf of atiaomar1978-hub.

Bugbot

Severity Location Finding
High BaseMainSupport#setMcpProperties Management host stayed 0.0.0.0 when MCP pre-enabled management — fixed (always apply camel.mcp.host; JBang sets 127.0.0.1)
Medium ManagementHttpServer#setupMcp MCP route not covered by management auth paths — noted (same as other dev consoles; insecure:dev)
Medium Catalog metadata MCP options under camel.main.*fixed (PrepareCamelMainMojocamel.mcp.*)

Grok-style review

Severity Finding Status
High Origin CSRF check case-sensitive Fixed (headerIgnoreCase + test)
High --mcp enabled camel.server / port clash Fixed (management only)
High Localhost bind skipped on JBang path Fixed
High Wrong metadata prefix Fixed
Medium Standalone Main needs registry handler Documented via SPI; JBang registers EmbeddedMcpMainListener
Medium MCP vs management auth Follow-up if we want MCP behind same auth rules

Follow-up commit: 8137ab4 on this branch addresses the high-severity items above.

@github-actions

Copy link
Copy Markdown
Contributor

🌟 Thank you for your contribution to the Apache Camel project! 🌟
🤖 CI automation will test this PR automatically.

🐫 Apache Camel Committers, please review the following items:

  • First-time contributors require MANUAL approval for the GitHub Actions to run
  • You can use the command /component-test (camel-)component-name1 (camel-)component-name2.. to request a test from the test bot although they are normally detected and executed by CI.
  • You can label PRs using skip-tests and test-dependents to fine-tune the checks executed by this PR.
  • Build and test logs are available in the summary page. Only Apache Camel committers have access to the summary.

⚠️ Be careful when sharing logs. Review their contents before sharing them publicly.

@atiaomar1978-hub

Copy link
Copy Markdown
Contributor Author

CI follow-up

AI-generated comment on behalf of atiaomar1978-hub

Addressed the doc failures from run 30398071305 (Antora) and run 30398074689 (incremental build / xref-check on docs):

  • Cause: In camel-4x-upgrade-guide-4_22.adoc, xref:main.adoc does not resolve from the user-manual module (Antora: target of xref not found: main.adoc).
  • Fix: 1f21e97 — use xref:components:others:main.adoc[Camel Main] (same pattern as property-binding.adoc / camelcontext-autoconfigure.adoc).
  • Verified locally: mvn -pl docs -am package -DskipTests -Pcamel-xref-check

Please re-check CI when the new workflow run completes.

@github-actions

github-actions Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

🧪 CI tested the following changed modules:

  • catalog/camel-catalog
  • components/camel-ai/camel-mcp-server
  • core/camel-main
  • docs
  • dsl/camel-jbang/camel-jbang-core
  • dsl/camel-kamelet-main

ℹ️ Dependent modules were not tested because the total number of affected modules exceeded the threshold (50). Use the test-dependents label to force testing all dependents.


🔬 Scalpel shadow comparison — Scalpel: 66 tested, 25 compile-only — current: 62 all tested

Maveniverse Scalpel detected 91 affected modules (current approach: 62).

⚠️ Modules only in Scalpel (29)
  • apache-camel
  • camel-allcomponents
  • camel-catalog
  • camel-catalog-console
  • camel-catalog-lucene
  • camel-catalog-maven
  • camel-catalog-suggest
  • camel-componentdsl
  • camel-csimple-maven-plugin
  • camel-endpointdsl
  • camel-endpointdsl-support
  • camel-itest
  • camel-jbang-core
  • camel-jbang-it
  • camel-jbang-main
  • camel-jbang-plugin-edit
  • camel-jbang-plugin-generate
  • camel-jbang-plugin-kubernetes
  • camel-jbang-plugin-test
  • camel-kamelet-main
  • camel-launcher
  • camel-report-maven-plugin
  • camel-route-parser
  • camel-yaml-dsl
  • camel-yaml-dsl-deserializers
  • camel-yaml-dsl-maven-plugin
  • coverage
  • docs
  • dummy-component

Skip-tests mode would test 66 modules (6 direct + 60 downstream), skip tests for 25 (generated code, meta-modules)

Modules Scalpel would test (66)
  • camel-a2a
  • camel-as2
  • camel-catalog
  • camel-clickup
  • camel-consul
  • camel-core-all
  • camel-csv
  • camel-fhir
  • camel-groovy
  • camel-hazelcast
  • camel-hl7
  • camel-ibm-watsonx-ai
  • camel-iso8583
  • camel-java-joor-dsl
  • camel-jbang-core
  • camel-jbang-mcp
  • camel-jbang-plugin-mcp
  • camel-jbang-plugin-route-parser
  • camel-jbang-plugin-tui
  • camel-jbang-plugin-validate
  • camel-jetty
  • camel-jsonpath
  • camel-kamelet
  • camel-kamelet-main
  • camel-kamelet-main-support
  • camel-knative-http
  • camel-launcher-container
  • camel-mail
  • camel-mail-microsoft-oauth
  • camel-main
  • camel-maven-plugin
  • camel-mcp-server
  • camel-micrometer-prometheus
  • camel-microprofile-health
  • camel-netty
  • camel-netty-http
  • camel-oauth
  • camel-observability-services
  • camel-once
  • camel-openapi-validator
  • camel-platform-http-main
  • camel-platform-http-vertx
  • camel-plc4x
  • camel-pubnub
  • camel-quickfix
  • camel-rest-openapi
  • camel-restdsl-openapi-plugin
  • camel-salesforce
  • camel-salesforce-codegen
  • camel-salesforce-maven-plugin
  • camel-spring-main
  • camel-syslog
  • camel-telegram
  • camel-test-main-junit5
  • camel-test-main-junit6
  • camel-vertx-websocket
  • camel-webhook
  • camel-whatsapp
  • camel-xml-io-dsl
  • camel-xml-jaxb-dsl
  • camel-xml-jaxb-dsl-test-definition
  • camel-xml-jaxb-dsl-test-spring
  • camel-yaml-dsl-validator
  • camel-yaml-dsl-validator-maven-plugin
  • camel-zookeeper
  • docs
Modules with tests skipped (25)
  • apache-camel
  • camel-allcomponents
  • camel-catalog-console
  • camel-catalog-lucene
  • camel-catalog-maven
  • camel-catalog-suggest
  • camel-componentdsl
  • camel-csimple-maven-plugin
  • camel-endpointdsl
  • camel-endpointdsl-support
  • camel-itest
  • camel-jbang-it
  • camel-jbang-main
  • camel-jbang-plugin-edit
  • camel-jbang-plugin-generate
  • camel-jbang-plugin-kubernetes
  • camel-jbang-plugin-test
  • camel-launcher
  • camel-report-maven-plugin
  • camel-route-parser
  • camel-yaml-dsl
  • camel-yaml-dsl-deserializers
  • camel-yaml-dsl-maven-plugin
  • coverage
  • dummy-component

ℹ️ Shadow mode — Scalpel observes but does not affect test execution. Learn more

⚠️ Some tests are disabled on GitHub Actions (@DisabledIfSystemProperty(named = "ci.env.name")) and require manual verification:

  • components/camel-ai/camel-mcp-server: 1 test(s) disabled on GitHub Actions
  • dsl/camel-jbang/camel-jbang-core: 1 test(s) disabled on GitHub Actions

💡 Manual integration tests recommended:

You modified dsl/camel-jbang/camel-jbang-core. The related integration tests in dsl/camel-jbang/camel-jbang-it are excluded from CI. Consider running them manually:

mvn verify -f dsl/camel-jbang/camel-jbang-it -Djbang-it-test
Build reactor — dependencies compiled but only changed modules were tested (91 modules)
  • Camel :: AI :: A2A
  • Camel :: AI :: MCP Server
  • Camel :: AS2 :: Component
  • Camel :: All Components Sync point
  • Camel :: All Core Sync point
  • Camel :: Assembly
  • Camel :: CSV
  • Camel :: Catalog :: CSimple Maven Plugin (deprecated)
  • Camel :: Catalog :: Camel Catalog
  • Camel :: Catalog :: Camel Report Maven Plugin
  • Camel :: Catalog :: Camel Route Parser
  • Camel :: Catalog :: Console
  • Camel :: Catalog :: Dummy Component
  • Camel :: Catalog :: Lucene (deprecated)
  • Camel :: Catalog :: Maven
  • Camel :: Catalog :: Suggest
  • Camel :: ClickUp
  • Camel :: Component DSL
  • Camel :: Consul
  • Camel :: Coverage
  • Camel :: Docs
  • Camel :: Endpoint DSL
  • Camel :: Endpoint DSL :: Support
  • Camel :: FHIR
  • Camel :: Groovy
  • Camel :: HL7
  • Camel :: HazelCast
  • Camel :: IBM :: watsonx.ai
  • Camel :: ISO-8583
  • Camel :: Integration Tests
  • Camel :: JBang :: Core
  • Camel :: JBang :: Integration tests
  • Camel :: JBang :: MCP
  • Camel :: JBang :: Main
  • Camel :: JBang :: Plugin :: Edit
  • Camel :: JBang :: Plugin :: Generate
  • Camel :: JBang :: Plugin :: Kubernetes
  • Camel :: JBang :: Plugin :: MCP
  • Camel :: JBang :: Plugin :: Route Parser
  • Camel :: JBang :: Plugin :: TUI
  • Camel :: JBang :: Plugin :: Testing
  • Camel :: JBang :: Plugin :: Validate
  • Camel :: JSon Path
  • Camel :: Java DSL with jOOR
  • Camel :: Jetty
  • Camel :: Kamelet
  • Camel :: Kamelet Main
  • Camel :: Kamelet Main :: Support
  • Camel :: Knative HTTP
  • Camel :: Launcher
  • Camel :: Launcher :: Container
  • Camel :: Mail
  • Camel :: Mail :: Microsoft OAuth
  • Camel :: Main
  • Camel :: Maven Plugins :: Camel Maven Plugin
  • Camel :: Maven Plugins :: OpenApi REST DSL Generator
  • Camel :: MicroProfile :: Health
  • Camel :: Micrometer :: Prometheus
  • Camel :: Netty
  • Camel :: Netty HTTP
  • Camel :: OAuth
  • Camel :: Observability Services
  • Camel :: Once
  • Camel :: OpenAPI :: Validator
  • Camel :: PLC4X
  • Camel :: Platform HTTP :: Main
  • Camel :: Platform HTTP :: Vert.x
  • Camel :: PubNub
  • Camel :: QuickFIX/J
  • Camel :: REST OpenApi
  • Camel :: Salesforce
  • Camel :: Salesforce :: CodeGen
  • Camel :: Salesforce :: Maven Plugin
  • Camel :: Spring Main
  • Camel :: Syslog
  • Camel :: Telegram
  • Camel :: Test :: Main :: JUnit5
  • Camel :: Test :: Main :: JUnit6
  • Camel :: Vert.x :: WebSocket
  • Camel :: Webhook
  • Camel :: Whatsapp
  • Camel :: XML DSL Jaxb :: Test :: Definition
  • Camel :: XML DSL Jaxb :: Test :: Spring
  • Camel :: XML DSL with camel-xml-io
  • Camel :: XML DSL with camel-xml-jaxb
  • Camel :: YAML DSL
  • Camel :: YAML DSL :: Deserializers
  • Camel :: YAML DSL :: Maven Plugins
  • Camel :: YAML DSL :: Validator
  • Camel :: YAML DSL :: Validator Maven Plugin
  • Camel :: Zookeeper

⚙️ View full build and test results

@gnodet gnodet left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code on behalf of Guillaume Nodet

Review: CAMEL-23853 — Embed MCP server on camel run/dev and Camel Main

This is a well-structured feature with clean separation of concerns: EmbeddedMcpRequestHandler as the SPI in camel-main, StreamableMcpJsonRpcEngine as a reusable JSON-RPC engine, and JbangEmbeddedMcpRequestHandler bridging to the JBang ToolRegistry. The security model is solid — @Metadata(security = "insecure:dev") on both camel.mcp.enabled and camel.management.mcpEnabled, management-server-only exposure, and Origin header CSRF protection all follow established patterns. The test suite and documentation are thorough. Nice work!

A few issues worth addressing:


1. MCP defaults silently override management server host/port

In BaseMainSupport.setMcpProperties(), the guards:

if (mcp.getHost() != null) {
    management.setHost(mcp.getHost());
}
if (mcp.getPort() > 0) {
    management.setPort(mcp.getPort());
}

...are always true because McpConfigurationProperties has defaults of "127.0.0.1" (never null) and 8080 (always > 0). Since the management server's own default host is "0.0.0.0", enabling MCP silently narrows the bind address to localhost.

Mitigating factor: setHttpManagementServerProperties() runs after setMcpProperties(), so explicitly user-set camel.management.host properties would override MCP defaults. But users relying on the default 0.0.0.0 would be silently affected.

Suggested fix: Use null defaults for host and port in McpConfigurationProperties, and only propagate when explicitly set by the user.


2. Run.java overwrites mainListenerClasses without appending

In Run.java:

main.addInitialProperty("camel.main.mainListenerClasses",
        "org.apache.camel.dsl.jbang.core.commands.mcp.EmbeddedMcpMainListener");

This unconditionally sets the property, overwriting any existing value. Compare with KameletMain.java which correctly checks for existing listeners and appends with comma separation:

String listeners = getInitialProperties().getProperty("camel.main.mainListenerClasses");
if (listeners == null || listeners.isBlank()) {
    addInitialProperty("camel.main.mainListenerClasses", embedded);
} else if (!listeners.contains(embedded)) {
    addInitialProperty("camel.main.mainListenerClasses", listeners + "," + embedded);
}

Currently harmless (no other listener is registered before the MCP block in Run.java), but fragile and inconsistent. I'd suggest aligning Run.java with the KameletMain.java pattern.


3. Triple-redundant configuration in Run.java

The MCP block uses three configuration mechanisms: writeSetting(), another writeSetting() for camel.mcp.enabled, and programmatic main.configure().mcp().withEnabled(true). The existing features (health, metrics, console) each use a single writeSetting() call in Run.java, with programmatic wiring handled in KameletMain.java. I'd suggest following the same pattern for consistency.


4. Wrong JSON-RPC error code for malformed JSON

In StreamableMcpJsonRpcEngine, when Jsoner.deserialize() receives malformed JSON, it silently returns an empty JsonObject (Jsoner catches DeserializationException and returns the default). The engine then returns error code -32600 ("Invalid Request"). Per JSON-RPC 2.0 spec (section 5.1), malformed JSON should return -32700 ("Parse error"). An error IS returned, just with the wrong code — wrapping the deserialization in a try-catch to distinguish parse errors from invalid requests would improve spec compliance.


Minor suggestions

  • Hardcoded server version: SERVER_VERSION = "1.0.0" doesn't reflect the actual Camel version (4.22.0-SNAPSHOT). Consider using a Maven-filtered version property for better MCP client diagnostics.
  • Null params in handleToolsCall: When params is null, toolName is null and passes through to the tool provider. JbangEmbeddedMcpRequestHandler handles this gracefully, but returning -32602 ("Invalid params") at the engine level would be more robust for future ToolProvider implementations.

Overall this is solid work — the architecture, security annotations, and documentation are all well done. The main items to address are the host/port defaults (finding 1) and the listener overwrite inconsistency (finding 2). 👍

@atiaomar1978-hub

Copy link
Copy Markdown
Contributor Author

AI-generated comment on behalf of atiaomar1978-hub

Pushed latest commit addressing @gnodet's review on PR #25203:

  1. MCP host/port defaultsMcpConfigurationProperties no longer defaults to 127.0.0.1/8080; setMcpProperties() only propagates explicitly configured values so enabling MCP no longer narrows management bind from 0.0.0.0. JBang --mcp still binds localhost via KameletMain.
  2. Run.java configuration — Removed redundant writeSetting/configure()/mainListenerClasses block; --mcp now follows the same single writeSetting(camel.jbang.mcp) pattern as --console/--health, with wiring in KameletMain.
  3. JSON-RPC compliance — Malformed JSON returns -32700 (Parse error); missing tools/call params/name returns -32602 (Invalid params).
  4. Server version — MCP initialize reports the Camel version from camel-jbang-core pom.properties.

Tests: StreamableMcpJsonRpcEngineTest (9), EmbeddedMcpHttpServerTest (1), RunMcpOptionTest (1), McpConfigurationPropertiesTest (1) — all green locally.

@apupier
apupier requested a review from gnodet July 31, 2026 07:18
@jamesnetherton

Copy link
Copy Markdown
Contributor

Can we slow down a bit and think things through before PR approval.

From the Jira ticket:

This would allow any Camel application (Spring Boot, Quarkus, standalone) to embed an MCP server, not only applications started via the Camel CLI.

Quarkus already has a solution for MCP optimized for the runtime. So some analysis is needed here and in Camel Quarkus for how best to leverage that.

There's also a notes section in the ticket:

  • This needs more design thinking — created this issue to capture the idea before it gets lost. Key questions to consider:
  • How does the embedded MCP server relate to the standalone MCP server (CAMEL-23852)?
  • Which MCP tools should be exposed — catalog tools, runtime introspection tools, or both?
  • Should routes automatically become MCP tools, or require explicit opt-in (e.g. via route metadata or a service catalog)?
  • How does this relate to Wanaku for enterprise-scale MCP governance?

Not sure if any of those points have been addressed here?

@Croway

Croway commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Hello @davsclaus @atiaomar1978-hub @jamesnetherton please hold before merging this PR, yesterday I opened https://issues.apache.org/jira/browse/CAMEL-24308 that will introduce new camel component that integrate ai-tools with an embedded MCP Server, it will provide a default implementation, and a specific implementation for quarkus (based on quarkus-mcp-server), the configuration of the MCP Server will be done via properties, like

camel.server.mcp-enabled=true
camel.server.mcp-path=/mcp
camel.server.mcp-server-name=my-integration-app
camel.server.mcp-tags=crm,notify

that bridges the ai-tools with the MCP.

I am a little bit concerned about this PR, in particular the configuration part camel.mcp.* I am afraid it can be misleading having multiple configurations. I do understand that this PR is for development/management only, but maybe we can improve/review the implementation given CAMEL-24308

@atiaomar1978-hub

Copy link
Copy Markdown
Contributor Author

AI-generated comment on behalf of atiaomar1978-hub

Fixed the sourcecheck failure in run 30559900193 (Fail if there are uncommitted changes).

The build regenerated main.adoc because camel.mcp.host and camel.mcp.port defaults in the committed docs still showed 127.0.0.1 / 8080, while the code (and generated output) now use empty defaults after the review fix (null host, port 0).

Synced:

  • core/camel-main/src/main/docs/main.adoc
  • catalog/camel-catalog/src/generated/resources/.../main.adoc

Re-ran MCP tests locally — green (McpConfigurationPropertiesTest, StreamableMcpJsonRpcEngineTest). Please re-run or wait for CI on the latest commit.

@atiaomar1978-hub

Copy link
Copy Markdown
Contributor Author

AI-generated reply on behalf of atiaomar1978-hub — no code changes in this update.

Thanks @jamesnetherton — fair point, and I agree we should not rush this to merge without aligning on the broader design first.

To answer your question directly: most of the JIRA “notes” questions are not fully resolved in this PR. This changeset is intentionally a narrow, dev-oriented slice:

JIRA design question Addressed in this PR?
Embedded MCP for Spring Boot / Quarkus / standalone (not just CLI) Partially. Camel Main gets the plumbing (camel.mcp.*, management HTTP endpoint, EmbeddedMcpRequestHandler SPI). Standalone Main can enable it via properties, but only if a handler is registered on the registry. JBang wires JbangEmbeddedMcpRequestHandler for --mcp. No Spring Boot or Camel Quarkus integration — Quarkus should use quarkus-mcp-server as you noted; that analysis is still TODO.
Relation to standalone MCP (CAMEL-23852) Not designed end-to-end here. Standalone remains the Quarkus-based camel mcp server (catalog + tooling). Embedded is a lightweight Streamable HTTP JSON-RPC endpoint on the management server for local dev (--mcp / camel.mcp.enabled). Overlap and long-term consolidation need a design doc.
Which tools — catalog, runtime introspection, or both? JBang path only: exposes existing ToolRegistry tools (same family as CLI AI/MCP tooling — catalog lookup, route validation, runtime introspection against the local process). Not a general “expose any Camel app’s routes as tools” story.
Routes automatically become MCP tools? No. No route metadata / service-catalog opt-in in this PR.
Relation to Wanaku Not addressed.

So this PR is best seen as plumbing + JBang dev flag, not the full CAMEL-23853 vision from the ticket description. Happy to pause merge, open a short design discussion (possibly linked to @Croway’s CAMEL-24308), and clarify boundaries with Quarkus/Spring Boot before we call it done.

Let me know whether you’d prefer this PR closed and redesigned, converted to draft pending CAMEL-24308 alignment, or scoped down further (e.g. JBang-only behind --mcp without the camel.mcp.* Main surface) — I’ll follow your lead.

@atiaomar1978-hub

Copy link
Copy Markdown
Contributor Author

AI-generated reply on behalf of atiaomar1978-hub — no code changes in this update.

Thanks @Croway — noted on CAMEL-24308. I share the concern about two configuration surfaces (camel.mcp.* here vs the camel.server.mcp-* direction you outlined).

This PR was scoped as dev/management-only (insecure:dev, management HTTP server, localhost binding via JBang), but I agree that without coordination it could confuse users once CAMEL-24308 lands with ai-tools integration and Quarkus-specific wiring.

Proposal: hold merge on this PR until we align with CAMEL-24308 — either unify property names/prefixes up front, or clearly document that this path is JBang-local-dev-only and defer production embedded MCP to the component work you’re doing.

Happy to join a design thread on CAMEL-24308 / CAMEL-23853 and adjust scope accordingly. No push from my side to merge before that.

@gnodet gnodet left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prior review findings (host/port defaults, listener append, triple-redundant config, JSON-RPC error codes, server version) are all addressed — good improvement. The remaining concern is the design alignment with CAMEL-24308, which committers have already flagged.

Observations:

  1. CAMEL-24308 namespace alignment — The camel.mcp.* configuration namespace introduced by this PR will conflict with CAMEL-24308's camel.server.mcp-* properties. Committers @Croway and @jamesnetherton have raised this concern, and the contributor agreed to hold merge pending alignment. This should be resolved before proceeding.

  2. Minor: JUnit assertions in testMcpConfigurationPropertiesTest uses JUnit assertions (assertEquals, assertNull) while the other two new test files in this PR correctly use AssertJ. Per project conventions, new test code should use AssertJ.

Positive notes:

  • The overall architecture is clean: EmbeddedMcpRequestHandler as SPI in camel-main, StreamableMcpJsonRpcEngine as a reusable JSON-RPC 2.0 engine, and JbangEmbeddedMcpRequestHandler bridging to the JBang ToolRegistry.
  • The insecure:dev security annotation on camel.mcp.enabled follows established patterns for dev-only management features. The MCP endpoint correctly sits on the management HTTP server.
  • The Origin header CSRF check provides appropriate browser-origin protection for a dev-only feature.
  • Test coverage via StreamableMcpJsonRpcEngineTest (9 tests covering error paths, CSRF, malformed JSON, etc.) is solid.

This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.

Claude Code on behalf of @gnodet

@atiaomar1978-hub

Copy link
Copy Markdown
Contributor Author

AI-generated comment on behalf of atiaomar1978-hub

Review follow-up (bf7e363a68e)

@gnodet — addressed the remaining actionable review item:

  • McpConfigurationPropertiesTest migrated from JUnit to AssertJ (added assertj-core test dependency to camel-main)
  • Expanded property coverage: defaults (enabled, path, unset host/port), fluent with* methods, and setters
  • StreamableMcpJsonRpcEngineTest: added tests for non-JSON Content-Type (415) and blank request body (-32600)
  • RunMcpOptionTest: added --mcp defaults-to-false test

Design hold (unchanged): per @jamesnetherton / @Croway / prior thread, merge remains on hold pending CAMEL-24308 alignment on camel.mcp.* vs camel.server.mcp-* namespace.

Local tests (all green):

  • McpConfigurationPropertiesTest (3)
  • StreamableMcpJsonRpcEngineTest (11)
  • RunMcpOptionTest (2)
  • EmbeddedMcpHttpServerTest (1)

@gnodet gnodet left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-review after latest commit (bf7e363). The AssertJ migration and additional test coverage look good. Two items remain:

1. CAMEL-24308 namespace alignment (high — design hold)

The camel.mcp.* configuration namespace introduced here will conflict with CAMEL-24308's planned camel.server.mcp-* properties. Both @Croway and @jamesnetherton flagged this, and the contributor agreed to hold merge pending alignment. No code changes since the prior review address this — it requires a design decision from committers on whether to unify the namespaces or clearly scope this PR's properties as dev-only. Noting this for visibility since the PR remains open (not draft) despite the hold agreement.

2. Test resource leak in EmbeddedMcpHttpServerTest (low)

mcpEndpointDelegatesToHandler starts a CamelContext + Vert.x ManagementHttpServer but calls camelContext.stop() without a try-finally block. If any assertion or HTTP call fails before reaching stop, the server and context leak for the remainder of the test JVM. Since this test doesn't extend CamelTestSupport, there's no automatic lifecycle cleanup. Wrapping in try-finally would be a straightforward fix.

Positive notes:

  • Latest commit successfully migrates tests to AssertJ and adds good coverage (fluent setters, default values, 415 content-type rejection, empty body handling, CLI default-to-false)
  • Security model is solid: @Metadata(security = "insecure:dev") on enable flags, management-server-only exposure, localhost binding, Origin header CSRF protection, Content-Type validation, proper JSON-RPC error codes

This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.

Claude Code on behalf of @gnodet

@atiaomar1978-hub

Copy link
Copy Markdown
Contributor Author

AI-generated comment on behalf of atiaomar1978-hub

Review follow-up (552be2036eb)

@gnodet — addressed the remaining actionable code review item from the latest re-review:

  • EmbeddedMcpHttpServerTest: wrapped HTTP assertions in try/finally so camelContext.stop() runs even when an assertion or HTTP call fails (avoids leaking Vert.x/management server for the rest of the test JVM).

Prior commits already covered AssertJ migration, expanded MCP test coverage, host/port default fix, JSON-RPC error codes, and Run.java config simplification.

Design hold (unchanged): per @jamesnetherton / @Croway / prior thread, merge remains on hold pending CAMEL-24308 alignment on camel.mcp.* vs camel.server.mcp-*. No code change for that until committers decide on namespace/scope.

Local tests (all green — 17 total):

  • McpConfigurationPropertiesTest (3)
  • StreamableMcpJsonRpcEngineTest (11)
  • RunMcpOptionTest (2)
  • EmbeddedMcpHttpServerTest (1)

@gnodet gnodet left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-review after latest commits. Both code-level items from the prior review are now addressed:

  • Test resource leak fixedEmbeddedMcpHttpServerTest.mcpEndpointDelegatesToHandler now wraps the test body in try-finally, ensuring camelContext.stop() runs even when assertions fail (552be2036eb)
  • AssertJ migration completeMcpConfigurationPropertiesTest fully migrated with expanded coverage (defaults, fluent setters, content-type rejection, empty body handling)

The implementation is well-structured with solid security: @Metadata(security = "insecure:dev") on enable flags, management-server-only exposure, localhost binding, CSRF protection, Content-Type validation, and proper JSON-RPC error codes.

Remaining: The CAMEL-24308 namespace alignment (camel.mcp.* vs camel.server.mcp-*) is the sole remaining concern, pending committer design decision.

This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.

Claude Code on behalf of @gnodet

@atiaomar1978-hub

Copy link
Copy Markdown
Contributor Author

AI-generated comment on behalf of atiaomar1978-hub

Review follow-up (fa49389cde2)

Verified on branch CAMEL-23853-jbang-run-mcp — all actionable code review items from @gnodet are already addressed in prior commits (552be2036eb and earlier):

  • MCP host/port null defaults (no silent 0.0.0.0127.0.0.1 override)
  • Run.java config simplified; listener append pattern in KameletMain
  • JSON-RPC -32700 / -32602 error codes; Camel version in initialize
  • AssertJ migration + expanded test coverage
  • EmbeddedMcpHttpServerTest try/finally cleanup

This push adds two JSON-RPC edge-case tests:

  • unknown method → -32601
  • ping → empty result object

Local tests (19 total — all green):

  • McpConfigurationPropertiesTest (3)
  • StreamableMcpJsonRpcEngineTest (13)
  • RunMcpOptionTest (2)
  • EmbeddedMcpHttpServerTest (1)

Design hold (unchanged): per @jamesnetherton / @Croway / prior thread, merge remains on hold pending CAMEL-24308 alignment on camel.mcp.* vs camel.server.mcp-*. No further code changes until committers decide on namespace/scope.

@davsclaus
davsclaus marked this pull request as draft August 3, 2026 12:20
@Croway

Croway commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Now that CAMEL-24308/24310/24311 are merged, this PR can be simplified considerably while keeping its scope (dev/diagnostics tools on the management server — a valid, complementary use case to the ai-tool business tools on the main server):

  1. Reuse VertxMcpServerEngine from camel-mcp-server instead of the hand-rolled JSON-RPC engine. The McpServerEngine SPI is tool-source-agnostic: McpServerTool is just name/description/handler and accepts a raw inputSchemaJson, so the ToolMcpSchemas output maps 1:1, and McpToolCallResult(text, isError) is the same shape as this PR's ToolCallResult. The JBang side would build McpServerTools from the ToolDescriptors and call initialize(...)/toolAdded(...) directly — no bridge needed. This deletes StreamableMcpJsonRpcEngine, ToolMcpSchemas, the EmbeddedMcpRequestHandler SPI and the ManagementHttpServer dispatch code (~450 lines), and upgrades the endpoint from a POST-only, session-less subset to the full SDK-backed streamable transport (sessions, SSE, GET replay, DELETE, tools/list_changed). It also fixes an interop issue: rejecting every request carrying an Origin header with 403 breaks legitimate clients — the spec asks to validate Origin, not refuse it.

  2. Drop the camel.mcp.* namespace — this PR already contains its replacement. The mcpEnabled/mcpPath fields added to HttpManagementServerConfigurationProperties are reachable as camel.management.mcpEnabled / camel.management.mcpPath, which is the right home for a management-server feature and symmetric with the merged camel.server.mcp-*. That removes McpConfigurationProperties, its generated configurer/metadata, mainConfigurationProperties.mcp() and the setMcpProperties cross-wiring in BaseMainSupport (where the host/port default issues from earlier review rounds kept surfacing). The --mcp flag then just sets camel.management.mcpEnabled=true plus management-server enablement, like the other management flags in Run.java.

  3. With 1+2, core camel-main stays MCP-free (only the existing McpServerFactory hook), and everything new lives in camel-jbang / camel-platform-http-main, with camel-jbang-core depending on camel-mcp-server.

  4. Docs: after this lands there are two MCP surfaces — dev tools at <management-port>/mcp (--mcp) and business ai-tool routes at <server-port>/mcp (camel.server.mcp-enabled=true, already property-only under JBang). Worth stating the distinction and cross-linking mcp-server.adoc.

One enabler is needed on the camel-mcp-server side: VertxMcpServerEngine currently prefers the main server's router when looking up VertxPlatformHttpRouter. ManagementHttpServer already binds its router (with SERVER_TYPE_MANAGEMENT) in the registry, so a small enhancement to make the target server type selectable unblocks this — I can prepare that as a prep PR.

Claude Code on behalf of Federico Mariani (@Croway)

@Croway

Croway commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

The enabler mentioned above is now up: #25329 (CAMEL-24353) makes the VertxMcpServerEngine target server type selectable, so this PR can register on the management router and drop the hand-rolled protocol code.

Claude Code on behalf of Federico Mariani (@Croway)

@cursor
cursor Bot force-pushed the CAMEL-23853-jbang-run-mcp branch from fa49389 to 4ac36e7 Compare August 5, 2026 04:39

@davsclaus davsclaus left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code on behalf of davsclaus

Review: CAMEL-23853 — Embed MCP server on camel run/dev and Camel Main

The reworked PR is much cleaner — good simplification using VertxMcpServerEngine directly instead of a custom JSON-RPC engine. The architecture (listener + service + schema mapper) is well-separated, security gating via insecure:dev is correct, and the test coverage is solid.

Three items to address:

1. camel-mcp-server must not be a compile dependency on camel-jbang-core (blocking)

camel-mcp-server is added as a compile (default scope) dependency. This means every camel run foo.yaml pulls in the MCP server, Vert.x MCP transport, and the MCP Java SDK — even when --mcp is not used.

Other optional features (camel-opentelemetry2, camel-jfr, camel-observability-services) are NOT compile dependencies of camel-jbang-core. They are downloaded on demand via dependencies.add("camel:...") in Run.java, which you already do correctly. The mainListenerClasses property is resolved by class name string at runtime, so JbangDevMcpMainListener does not need to be compiled against.

Make camel-mcp-server pluggable: remove it as a compile dependency from camel-jbang-core/pom.xml, and move the mcp package classes (JbangDevMcpMainListener, JbangDevMcpServer, ToolMcpSchemas) so they are only resolved when camel-mcp-server is on the classpath (downloaded on demand). The runtime download in Run.java already handles fetching the JAR when --mcp is used.

2. Upgrade guide entry is for a new feature, not migration (minor)

The upgrade guide (camel-4x-upgrade-guide-4_22.adoc) describes how to use --mcp. Per project conventions, the upgrade guide is for migration content only — changed defaults, removed options, breaking changes. New features belong in the command documentation pages, where the --mcp flag is already documented.

3. FQCN used inline in ToolMcpSchemasTest (minor)

ToolMcpSchemasTest imports ToolDescriptor at the top but then uses the fully qualified name inline: org.apache.camel.dsl.jbang.core.commands.ai.ToolDescriptor.tool(...). Per project conventions, use the simple name since the import is already present.


Positive notes:

  • Clean architecture: JbangDevMcpMainListener (lifecycle), JbangDevMcpServer (service with proper doStart/doStop), ToolMcpSchemas (schema mapping)
  • Correct insecure:dev security gating on both camel.management.mcpEnabled and camel.jbang.mcp
  • Management-server-only exposure with smart router type resolution fallback
  • Good test coverage with proper try-finally cleanup and AssertJ assertions
  • Clear distinction from business camel.server.mcpEnabled documented in the upgrade guide

This review does not replace specialized AI review tools or static analysis. This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.

<groupId>org.apache.camel</groupId>
<artifactId>camel-kamelet-main</artifactId>
</dependency>
<dependency>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should not be a compile dependency. Other optional features (camel-opentelemetry2, camel-jfr, etc.) are downloaded on demand via dependencies.add("camel:...") in Run.java — you already do this correctly for MCP. Having it as compile scope means every camel run foo.yaml pulls in the MCP server, Vert.x MCP transport, and MCP Java SDK even when --mcp is not used.

Remove this compile dependency and make the MCP classes pluggable — loaded at runtime only when camel-mcp-server is on the classpath (downloaded on demand when --mcp is passed).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 7f46187: removed camel-mcp-server compile dependency from camel-jbang-core. JBang dev MCP classes now live in camel-mcp-server/jbang and load on demand when Run.java downloads camel:mcp-server via --mcp.

AI-generated reply on behalf of atiaomar1978-hub

main server via `camel.server.mcpEnabled`.

The `camel cmd route-diagram` and `camel cmd route-topology` now accept one or more Camel route source files
(instead of only the name/pid of a running integration), so diagrams and inter-route topology can be

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The upgrade guide is for migration content only (changed defaults, removed options, breaking changes). This entry describes a new feature — it belongs in the command documentation pages where --mcp is already documented. Please remove this section from the upgrade guide.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 7f46187: removed the --mcp section from camel-4x-upgrade-guide-4_22.adoc. The feature remains documented on the command pages where --mcp is already described.

AI-generated reply on behalf of atiaomar1978-hub

void buildsRequiredParametersSchema() {
String schema = ToolMcpSchemas.inputSchemaJson(
org.apache.camel.dsl.jbang.core.commands.ai.ToolDescriptor.tool("demo", "Demo tool")
.param("name", "string", "A name", true)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per project import style conventions: ToolDescriptor is already imported at line 20 — use the simple name here instead of the FQCN.

Suggested change
.param("name", "string", "A name", true)
ToolDescriptor.tool("demo", "Demo tool")

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 7f46187: ToolMcpSchemasTest removed; schema building is inlined in JbangDevMcpServer (camel-mcp-server/jbang). Parameter schema coverage moved to JbangDevMcpServerTest using simple ToolDescriptor name per import conventions.

AI-generated reply on behalf of atiaomar1978-hub

@davsclaus

Copy link
Copy Markdown
Contributor

Claude Code on behalf of davsclaus

To clarify finding #1 from the review: the three new classes in dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/mcp/ (JbangDevMcpMainListener, JbangDevMcpServer, ToolMcpSchemas) are Camel runtime services — they extend ServiceSupport, hook into the CamelContext lifecycle, and wire up Vert.x routers. That kind of code does not belong in camel-jbang-core, which is for CLI commands and tooling.

These classes should be moved to camel-kamelet-main (or into camel-mcp-server itself) where other runtime services live, and loaded dynamically when the JAR is downloaded on demand. The mainListenerClasses property is already string-based, so KameletMain just needs the FQCN — no compile-time dependency required in camel-jbang-core.

@atiaomar1978-hub

Copy link
Copy Markdown
Contributor Author

Review feedback addressed (7f461878c39)

AI-generated summary on behalf of atiaomar1978-hub

Replied inline to @davsclaus's three review comments. Summary:

Review item Fix
Compile dependency on camel-mcp-server Removed from camel-jbang-core. Dev MCP classes moved to camel-mcp-server (org.apache.camel.component.mcp.server.jbang.*), loaded when Run.java downloads camel:mcp-server on --mcp. ToolRegistry accessed reflectively to avoid Maven reactor cycle.
Upgrade guide --mcp section Removed from camel-4x-upgrade-guide-4_22.adoc (migration-only doc).
FQCN in ToolMcpSchemasTest Test removed; schema coverage in JbangDevMcpServerTest with proper imports.

Tests

mvn install -pl components/camel-ai/camel-mcp-server -DskipTests
mvn test -pl dsl/camel-jbang/camel-jbang-core -Dtest=RunMcpOptionTest,JbangDevMcpServerTest

4 tests passing.

Note: CAMEL-24308 namespace alignment (camel.mcp.* vs camel.server.mcp-*) remains pending committer design decision as previously agreed.

@atiaomar1978-hub

Copy link
Copy Markdown
Contributor Author

Grok review follow-up ($(git rev-parse --short HEAD))

AI-generated comment on behalf of atiaomar1978-hub

Additional fixes from automated review:

  • ClassResolver: JbangDevMcpServer now resolves ToolRegistry / ToolContext via camelContext.getClassResolver() (aligns with on-demand dependency classloading)
  • Error handling: tool handler unwraps InvocationTargetException and always returns McpToolCallResult (never throws)
  • Schema test: JbangDevMcpServerTest verifies select_process publishes an inputSchema with required name property

All 4 MCP unit tests passing.

@Croway Croway left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed after 4ac36e7/00b8a87/7f46187/2d65a79 — the refactor looks right: the hand-rolled JSON-RPC engine, the core EmbeddedMcpRequestHandler SPI, and the camel.mcp.* namespace are gone, camel-jbang-core no longer compile-depends on MCP, and the latest commit already fixes tool-error messages and moves to ClassResolver. I also verified the non-obvious lifecycle concern: the HTTP servers are registered as early deferred services during autoconfigure, afterConfigure adds JbangDevMcpServer after them, and early-start preserves insertion order — so the routers are always in the registry before doStart() runs. 👍

Two findings worth addressing before merge (inline): the shared-port fallback silently serving the dev tools on the public main server, and camel.management.mcpEnabled being inert outside JBang. Minor items also inline.

Other small notes:

  • --mcp forcing the management host to 127.0.0.1 also rebinds health/metrics when combined with --observe/--health, which could break container readiness probes — worth a line in the --mcp option description.
  • The camel-mcp-server/pom.xml change is a pure reorder of two test dependencies — can be dropped to keep the diff minimal.

Claude Code on behalf of Federico Mariani (@Croway)

return out;
}

private String resolveTargetServerType() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fallback makes the shared-port case work, but it silently defeats the 127.0.0.1 intent: both camel.server and camel.management default to port 8080, and ManagementHttpServer.doInit reuses the main VertxPlatformHttpServer when the ports match. In that case the withHost("127.0.0.1") set by KameletMain is ignored (the reused server was built from the main config, host 0.0.0.0), so camel run api.yaml --mcp — any app with a platform-http route — serves the ~40 introspection tools on 0.0.0.0:8080/mcp.

The dev console has the same trait, so this may be acceptable for an insecure:dev flag, but it should not be silent: please log a WARN here when no management-typed router is found and the MCP endpoint falls back to the main server, and mention the shared-port behavior in the --mcp option description.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in cc569af (also in 6f857dc): added LOG.warn when no management HTTP router is found so shared-port fallback is visible in logs.

AI-generated reply on behalf of atiaomar1978-hub

* Whether to expose dev/diagnostics MCP tools on this management server (requires camel-mcp-server on the
* classpath). Not intended for production use.
*/
public void setMcpEnabled(boolean mcpEnabled) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This property is documented in main.adoc as a general camel.management.* option, but the only reader is JbangDevMcpMainListener, which is registered only when KameletMain injects it via mainListenerClasses for --mcp. A plain camel-main user who sets camel.management.mcpEnabled=true (with camel-mcp-server on the classpath) gets no endpoint and no error.

Contrast camel.server.mcp-enabled, which camel-main wires via the McpServerFactory SPI. Either state in the description that this option is currently only honored by Camel JBang (--mcp), or wire it in camel-main the same SPI way so it works (or fails meaningfully) everywhere.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in cc569af (6f857dc): javadoc and main.adoc clarify camel.management.mcpEnabled is only honored when Camel JBang registers JbangDevMcpMainListener (camel run --mcp); route-based MCP uses camel.server.mcpEnabled on HttpServerConfigurationProperties.

AI-generated reply on behalf of atiaomar1978-hub


@SuppressWarnings("unchecked")
private List<Object> allToolDescriptors() throws ReflectiveOperationException {
Class<?> registry = camelContext.getClassResolver().resolveClass(TOOL_REGISTRY);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ClassResolver.resolveClass returns null when the class is missing, so this NPEs on getMethod instead of failing with a clear error. resolveMandatoryClass throws ClassNotFoundException naming the class — much better startup diagnostics if someone enables camel.management.mcpEnabled without JBang on the classpath (same in createToolContext and executeTool).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in cc569af: switched to resolveMandatoryClass via mandatoryClass() helper for ToolRegistry/ToolContext reflective access.

AI-generated reply on behalf of atiaomar1978-hub

</dependency>
<dependency>
<groupId>com.networknt</groupId>
<artifactId>json-schema-validator</artifactId>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

json-schema-validator is not used by either new test (leftover from the removed ToolMcpSchemasTest?) — can be dropped.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kept json-schema-validator test dependency (6f857dc clarifies comment): parent property resolves to 2.0.1 which provides Dialects required by MCP SDK; wiremock transitively pulls 1.5.x without it. Removing it breaks JbangDevMcpServerTest.

AI-generated reply on behalf of atiaomar1978-hub

}

@Test
void buildsInputSchemaForParameterizedTools() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: this test exercises the ToolDescriptor builder (which lives elsewhere), not the schema JSON built in JbangDevMcpServer. Now that the HTTP test asserts inputSchema via listTools, consider strengthening that assertion instead (e.g. also check it contains "required" for the mandatory param) and dropping or renaming this one.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in cc569af (6f857dc): removed redundant ToolDescriptor builder test; HTTP integration test now asserts inputSchema contains name and required for select_process.

AI-generated reply on behalf of atiaomar1978-hub

@davsclaus davsclaus left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: CAMEL-23853 — Embed MCP server on camel run/dev and Camel Main

Thank you for this contribution — the overall architecture is sound: reflective bridge from camel-mcp-server to JBang's ToolRegistry, proper 127.0.0.1 binding default, correct security: "insecure:dev" annotation consistent with other dev features, and a nice integration test covering MCP protocol handshake, tool listing, schema validation, and tool execution.

A few issues to address before this can be merged:

1. Inconsistent mcpEnabled description across generated metadata (Medium)

The catalog copy (catalog/camel-catalog/src/generated/resources/.../camel-main-configuration-metadata.json) has a short description:

"Whether to expose dev/diagnostics MCP tools on this management server (requires camel-mcp-server on the classpath). Not intended for production use."

But the core copy (core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json) and the AsciiDoc docs have the longer description mentioning JbangDevMcpMainListener and camel.server.mcpEnabled. These should be identical — please regenerate consistently.

2. Reference to non-existent camel.server.mcpEnabled (Medium)

See inline comment. The setter Javadoc references camel.server.mcpEnabled which does not exist in the codebase. If it is planned for a follow-up PR, the current description should not reference it yet.

3. Missing upgrade guide entry (Medium)

The PR description states the feature is documented in the 4.22 upgrade guide, but the diff contains no changes to any camel-4x-upgrade-guide-*.adoc file. New configuration properties (camel.management.mcpEnabled, camel.management.mcpPath, camel.jbang.mcp) and CLI flags (--mcp) should be noted in the upgrade guide.

4. {code ...} in generated docs (Low)

The Javadoc {@code JbangDevMcpMainListener} and {@code camel run --mcp} are rendered as literal {code ...} (without the @) in the generated AsciiDoc and JSON metadata. Consider using the @Metadata(description=...) annotation directly on the field with the full description text to avoid this.


Note: This review evaluates the PR against project conventions and standards. It does not replace specialized review tools such as CodeRabbit, Sourcery, or SonarCloud.

This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.

/**
* Whether to expose dev/diagnostics MCP tools on this management server (requires camel-mcp-server on the
* classpath). Currently honored only when Camel JBang registers {@code JbangDevMcpMainListener} (for example
* {@code camel run --mcp}); plain camel-main users should use {@code camel.server.mcpEnabled} for route-based MCP.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This Javadoc references camel.server.mcpEnabled for "route-based MCP", but that property does not exist anywhere in the codebase. This will be confusing for users who read this and attempt to use it.

If camel.server.mcpEnabled is planned for a follow-up, consider removing the reference until it ships. If it already exists elsewhere, please point me to it.

This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 6f857dc: camel.server.mcpEnabled exists on HttpServerConfigurationProperties (see BaseMainSupport.setupMcpServer). Updated javadoc/docs to reference it explicitly instead of implying it is missing.

AI-generated reply on behalf of atiaomar1978-hub

<version>${mcp-java-sdk-version}</version>
<scope>test</scope>
</dependency>
<!-- MCP SDK schema validation requires networknt 2.x; wiremock pulls 1.5.x without Dialects -->

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment says "requires networknt 2.x" but ${networknt-json-schema-validator-version} resolves to 1.5.9 (a 1.x version). If 2.x is actually required by the MCP SDK, the version override is insufficient. If 1.5.x works fine, the comment is misleading — consider clarifying.

This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clarified in 6f857dc: the comment now states 2.0.1 explicitly. ${networknt-json-schema-validator-version} in parent pom.xml is 2.0.1 (not 1.5.9); dependency tree confirms 2.0.1:test on camel-jbang-core. Wiremock brings 1.5.x transitively which lacks Dialects.

AI-generated reply on behalf of atiaomar1978-hub

@davsclaus

davsclaus commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

in camel-kamelet-main you can add the classes you load dynamic to a known list of classes that maps to maven dependency then it will automatic download the needed JAR.
https://github.com/apache/camel/blob/main/dsl/camel-kamelet-main/src/main/resources/camel-main-known-dependencies.properties

@atiaomar1978-hub

Copy link
Copy Markdown
Contributor Author

Addressed remaining review feedback and automated review findings in commit 6f857dc1902:

@davsclaus

  • camel.server.mcpEnabled does exist on HttpServerConfigurationProperties (used by BaseMainSupport.setupMcpServer); javadoc/docs now say "configure camel.server.mcpEnabled instead"
  • Fixed networknt pom comment: property resolves to 2.0.1 (verified via dependency tree)

@Croway (replies on each thread below)

Grok/Bugbot fixes

  • Download camel:mcp-server when profile camel.jbang.mcp=true, not only --mcp CLI flag
  • Added JbangDevMcpMainListener to camel-main-known-dependencies.properties
  • Strengthened inputSchema test to assert required field
  • Documented 127.0.0.1 management rebind in --mcp description

Tests: RunMcpOptionTest (2) + JbangDevMcpServerTest (1) — all passing.

AI-generated comment on behalf of atiaomar1978-hub

@atiaomar1978-hub

Copy link
Copy Markdown
Contributor Author

Fixed CI failure (uncommitted catalog generated files) in commit e0375aa6baf: regenerated catalog/camel-catalog main.adoc and camel-main-configuration-metadata.json to sync camel.management.mcpEnabled description with core/camel-main.

AI-generated comment on behalf of atiaomar1978-hub

@davsclaus davsclaus left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the contribution, @atiaomar1978-hub — this is a well-structured PR that follows existing patterns for similar JBang features (--console, --observe, --openapi-ui). CI is green, security model is correctly applied, and tests cover both CLI parsing and end-to-end integration.

Findings

1. [Question] Management server host override side effect

When --mcp is enabled, KameletMain unconditionally sets withHost("127.0.0.1") on the management server. This is good for security, but it has a side effect: if a user runs camel run app.yaml --mcp --observe, the management server (health, metrics, info) will also be bound to 127.0.0.1 instead of 0.0.0.0. This could break external health probes (e.g., Kubernetes liveness/readiness checks).

The CLI help text documents this, which is good. But is the intent that users who need both --mcp and externally-accessible health checks would configure camel.management.host separately? If so, does the property file value override the programmatic withHost() call?

2. [Minor] parameters() returns empty map in JbangDevMcpServer.toMcpTool()

The anonymous McpServerTool implementation returns Map.of() from parameters() while inputSchemaJson() is populated from the descriptor. This works because VertxMcpServerEngine.toolAdded() only uses inputSchemaJson(), but could be a gap if a future engine uses parameters() instead.

Positive observations

  • Security model correctly applied: security = "insecure:dev" on mcpEnabled in both HttpManagementServerConfigurationProperties and CamelJBangConstants
  • 127.0.0.1 binding by default prevents remote access to dev MCP tools
  • Fallback warning in resolveTargetServerType() clearly notes security implication
  • Tests follow project conventions (package-private, AssertJ, no Thread.sleep())
  • JbangDevMcpServerTest is a solid integration test covering server info, tool listing, schema structure, and tool execution
  • Generated files and documentation are all consistent with source changes

This review covers project rules and conventions. It does not replace specialized review tools (CodeRabbit, SonarCloud) or static analysis.

This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.

Claude Code on behalf of davsclaus

if (mcp) {
configure().httpManagementServer().withEnabled(true);
configure().httpManagementServer().withMcpEnabled(true);
configure().httpManagementServer().withHost("127.0.0.1");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This unconditionally overrides the management server host to 127.0.0.1 when MCP is enabled. If a user also uses --observe for health/metrics, external probes (e.g. Kubernetes liveness checks) won't be able to reach the management endpoints.

The CLI help documents this side effect, which is good. But is there a way for the user to override this back (e.g. via camel.management.host in properties)? If property-file values are applied after this code, it would work — worth confirming the ordering.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in cc4679e: withHost("127.0.0.1") is now guarded by !isConfigured("camel.management.host"), matching the pattern used elsewhere in KameletMain. Users combining --mcp with --observe can set camel.management.host explicitly for external probes.

AI-generated reply on behalf of atiaomar1978-hub

@Override
public String name() {
return toolName;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: parameters() returns Map.of() while inputSchemaJson() is populated from the descriptor's params. This works today because VertxMcpServerEngine.toolAdded() only uses inputSchemaJson(), but could be a gap for forward compatibility if a future engine implementation relies on parameters() instead.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in cc4679e: descriptor params are converted to a flat metadata map and parsed with AiToolParameterHelper.parseParameterMetadata(). Both parameters() and inputSchemaJson() now share the same ParameterDef map via buildJsonSchemaFromDefs().

AI-generated reply on behalf of atiaomar1978-hub

@atiaomar1978-hub

Copy link
Copy Markdown
Contributor Author

Addressed the latest review feedback in cc4679e:

  1. KameletMain host override127.0.0.1 is now applied only when camel.management.host is not already configured, so --observe health/metrics probes can still bind externally when the user sets the host explicitly.
  2. parameters() consistencyJbangDevMcpServer now builds ParameterDef via AiToolParameterHelper.parseParameterMetadata() and uses the same defs for both parameters() and inputSchemaJson().
  3. {code ...} in generated docs — replaced {@code ...} in setMcpEnabled javadoc with plain text; regenerated catalog/main metadata (no more {code camel run --mcp} in main.adoc/JSON).

Tests run:

mvn test -pl dsl/camel-jbang/camel-jbang-core,components/camel-ai/camel-mcp-server -Dtest=RunMcpOptionTest,JbangDevMcpServerTest -DskipITs

AI-generated comment on behalf of atiaomar1978-hub

cursoragent and others added 9 commits August 5, 2026 20:12
Rebased onto main and refactored per review feedback (Croway, CAMEL-24308):

- Drop hand-rolled StreamableMcpJsonRpcEngine and camel.mcp.* namespace
- Reuse VertxMcpServerEngine on the management HTTP router (CAMEL-24353)
- Expose JBang ToolRegistry tools via JbangDevMcpServer + --mcp flag
- Configure via camel.management.mcpEnabled/mcpPath and camel.jbang.mcp
- Add RunMcpOptionTest, JbangDevMcpServerTest, ToolMcpSchemasTest

Co-authored-by: Cursor Agent <noreply@cursor.com>
When the management server reuses the main HTTP server on the same port,
only a server-typed VertxPlatformHttpRouter exists. Resolve the MCP engine
target dynamically so --mcp works with --port and co-hosted setups.

Co-authored-by: Cursor Agent <noreply@cursor.com>
Remove camel-mcp-server compile dependency from camel-jbang-core.
Move JBang dev MCP classes to camel-mcp-server/jbang and resolve
ToolRegistry reflectively to avoid Maven reactor cycles. Update
KameletMain listener class name, remove --mcp upgrade guide section,
and keep integration tests in jbang-core with test-scoped mcp-server.

Co-authored-by: Omar Atie <atiaomar1978-hub@users.noreply.github.com>
Resolve JBang tool classes via CamelContext ClassResolver instead of
Class.forName, unwrap invocation failures for MCP error responses, and
assert inputSchema is published for parameterized tools in tests.

Co-authored-by: Omar Atie <atiaomar1978-hub@users.noreply.github.com>
- Log a warning when MCP falls back to the main HTTP server router
- Clarify camel.management.mcpEnabled is only honored by camel run --mcp
- Use resolveMandatoryClass for reflective ToolRegistry access
- Update --mcp option description for shared-port bind address behavior
- Remove redundant ToolDescriptor builder unit test; HTTP test covers schemas
- Keep json-schema-validator 2.x test dep (MCP SDK needs it; wiremock pulls 1.5.x)

Co-authored-by: Cursor <cursoragent@cursor.com>
- Clarify camel.server.mcpEnabled exists (HttpServerConfigurationProperties)
- Fix networknt pom comment to reference actual 2.0.1 version
- Download MCP deps when profile camel.jbang.mcp=true (not only --mcp CLI)
- Register JbangDevMcpMainListener in known-dependencies for auto-download
- Strengthen inputSchema test with required field assertion
- Document 127.0.0.1 management rebind when --mcp is used with --observe

Co-authored-by: Cursor <cursoragent@cursor.com>
…led docs

Sync camel-catalog generated main.adoc and configuration metadata with
core/camel-main after mcpEnabled javadoc update (fixes CI uncommitted changes check).

Co-authored-by: Cursor <cursoragent@cursor.com>
- Only bind management host to 127.0.0.1 when camel.management.host is unset
- Populate JbangDevMcpServer.parameters() via AiToolParameterHelper
- Fix mcpEnabled docs: plain-text javadoc avoids {code ...} in generated metadata
- Regenerate catalog/main configuration metadata

Co-authored-by: Omar Atie <atiaomar1978-hub@users.noreply.github.com>
Rebased onto upstream/main and regenerated jbang/catalog metadata
to merge main changes with --mcp command options.

Co-authored-by: Omar Atie <atiaomar1978-hub@users.noreply.github.com>
@cursor
cursor Bot force-pushed the CAMEL-23853-jbang-run-mcp branch from cc4679e to c7a7be1 Compare August 5, 2026 20:19

@davsclaus davsclaus left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for this contribution, @atiaomar1978-hub — this is well-structured work that follows established JBang patterns (--console, --observe, --openapi-ui). The architecture is clean, the security model is correctly applied, and the code has been thoroughly refined across multiple review rounds.

Summary

  • Security model correctly applied: security = "insecure:dev" on both camel.jbang.mcp and camel.management.mcpEnabled, management-server-only exposure, 127.0.0.1 binding by default
  • Reflective bridge to ToolRegistry is architecturally sound — avoids compile dependency from component to CLI module
  • JbangDevMcpServerTest is a solid integration test covering MCP handshake, tool listing, schema validation, and tool execution
  • All prior review findings addressed

Minor notes (non-blocking)

  1. CI — needs to be triggered and pass (first-time contributor approval required)
  2. json-schema-validator version override — the 1.5.x → 2.0.1 bump in test scope is explained in the comment; CI will validate no WireMock test breakage
  3. --mcp + --observe interaction — management host forced to 127.0.0.1 could affect container health probes; documented in CLI help text, and camel.management.host overrides it

This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.

Claude Code on behalf of davsclaus

@davsclaus

Copy link
Copy Markdown
Contributor

rebase this on main

Sync catalog jbang metadata with camelWrapper from main and keep mcp
entry from this PR. Regenerate camel-spring.xsd with allowedSchemes.

Co-authored-by: Omar Atie <atiaomar1978-hub@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants