Skip to content

Add MCP runtime tools and camel ask AI assistant#23346

Open
gnodet wants to merge 3 commits into
apache:mainfrom
gnodet:runtime-mcp-server
Open

Add MCP runtime tools and camel ask AI assistant#23346
gnodet wants to merge 3 commits into
apache:mainfrom
gnodet:runtime-mcp-server

Conversation

@gnodet
Copy link
Copy Markdown
Contributor

@gnodet gnodet commented May 20, 2026

Summary

Two features adding AI-powered capabilities to Camel JBang: runtime MCP tools for live process inspection, and an interactive camel ask AI assistant with function calling.

Depends on: #23479

MCP runtime tools

  • 21 runtime introspection tools (camel_runtime_*) for inspecting and interacting with live Camel applications via the file-based IPC protocol
  • 2 example catalog tools (camel_catalog_examples, camel_catalog_example_file) for browsing Camel JBang examples
  • IPC protocol enhanced with request-ID-suffixed action/output files for concurrent client support (backward compatible)
  • RouteDiagramTools: fix error reporting and empty filter handling
  • Tests for RuntimeService and RuntimeTools
  • Documentation in camel-jbang-mcp.adoc

camel ask — AI assistant with tool calling

An interactive AI assistant for Camel JBang that can inspect running applications, search the component catalog, browse examples, and create/edit route files — all through natural language.

LLM providers:

  • Ollama (local, free) — native /api/chat API with NDJSON streaming, auto-model selection
  • OpenAI — standard chat completions API
  • Anthropic — Claude API with streaming

Auto-detection: The client auto-detects which provider is available (checks ANTHROPIC_API_KEY, OPENAI_API_KEY, then probes Ollama at localhost:11434). Can also use camel infra run ollama to start an Ollama instance automatically.

Ollama model auto-selection: When using Ollama, automatically queries /api/tags and picks the best model for tool calling from a ranked list: qwen3.5, qwen3, nemotron-3-nano, mistral-nemo, qwen2.5, granite4.1, llama3.1, llama3.3, mistral. Works particularly well with Qwen 3.5 which has excellent tool-calling support.

25 function-calling tools:

  • Runtime inspection (12): get_context, get_routes, get_health, get_endpoints, get_inflight, get_blocked, get_consumers, get_properties, get_route_source, get_route_dump, get_route_structure, get_top_processors
  • Runtime control (6): trace_control, stop_route, start_route, suspend_route, resume_route, stop_application
  • Catalog (4): catalog_components, catalog_component_doc, catalog_eips, list_examples, get_example_file
  • File operations (3): list_files, read_file, write_file

Streaming: Responses stream token-by-token to the terminal for immediate feedback.

Modes:

  • Interactive chat (default): multi-turn conversation with follow-up questions
  • Single question: camel ask "what routes are running?" — answers and exits
  • Works with or without a running Camel process (runtime tools gracefully report "no process" when unavailable)

Shared LlmClient: Extracted from Explain.java into a reusable client supporting all three providers, streaming, tool use, conversation history, and verbose debug logging.

Test plan

  • Build: mvn install -B -pl dsl/camel-jbang/camel-jbang-core,dsl/camel-jbang/camel-jbang-mcp -DskipTests
  • Tested camel ask with Ollama + Qwen 3.5: tool calling, streaming, multi-turn conversation
  • Tested with no running process: file tools and catalog work, runtime tools return helpful error
  • MCP runtime tools unit tests pass

@gnodet gnodet requested a review from davsclaus May 20, 2026 05:23
@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.

@github-actions github-actions Bot added the dsl label May 20, 2026
@Croway
Copy link
Copy Markdown
Contributor

Croway commented May 20, 2026

I like the idea.. but I am not so sure about the implementation.. this is some kind of proxy between an LLM and a running camel application.

The proxy idea is good, otherwise you should know a priori the endpoint of the running app, on the other hand:

  • We should use Quarkus MCP Server since we are already using it
  • How does the proxy connect to running Camel apps? I mean, is it possible to prompt something like Investigate the Camel application running at localhost:8081 ? what's the E2E scenario?

@gnodet gnodet changed the title Add runtime MCP server for live Camel application introspection Add embedded MCP server for live Camel application introspection May 20, 2026
@johnpoth
Copy link
Copy Markdown
Member

johnpoth commented May 20, 2026

This is a great feature !

@davsclaus
Copy link
Copy Markdown
Contributor

Yeah this is a great step forward. Since the main instrucmention is dev consoles. I wonder if the description should be tied to that, it may say using dev consoles and other features. So its more open.

Also the AI is good at analyzing the dev consoles, also via jbang cli use of them. But we may consider some kind of formal metadata contract that has more details. There are some dev consoles that have options to filter etc that are not documented. But the AI can scan the code and document them officially in the json metadat file. Currently it just have "console" as entry. But it could have "properties" to include these options.

@gnodet gnodet requested a review from oscerd May 20, 2026 14:13
@gnodet
Copy link
Copy Markdown
Contributor Author

gnodet commented May 20, 2026

I like the idea.. but I am not so sure about the implementation.. this is some kind of proxy between an LLM and a running camel application.

The proxy idea is good, otherwise you should know a priori the endpoint of the running app, on the other hand:

  • We should use Quarkus MCP Server since we are already using it
  • How does the proxy connect to running Camel apps? I mean, is it possible to prompt something like Investigate the Camel application running at localhost:8081 ? what's the E2E scenario?

I rewrote it completely differently by embedding the java MCP server inside Camel.

@Croway
Copy link
Copy Markdown
Contributor

Croway commented May 20, 2026

I like the idea.. but I am not so sure about the implementation.. this is some kind of proxy between an LLM and a running camel application.
The proxy idea is good, otherwise you should know a priori the endpoint of the running app, on the other hand:

  • We should use Quarkus MCP Server since we are already using it
  • How does the proxy connect to running Camel apps? I mean, is it possible to prompt something like Investigate the Camel application running at localhost:8081 ? what's the E2E scenario?

I rewrote it completely differently by embedding the java MCP server inside Camel.

I see, but how do you picture the e2e flow? what if the camel app is running on another port? do you know if AI code assistant can load remote MCP server at runtime?

Copy link
Copy Markdown
Contributor

@orpiske orpiske left a comment

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 Otavio Rodolfo Piske

Review

Well-designed feature — the architecture follows established Camel patterns (@JdkService factory, ServiceSupport, StaticService) and the 24 tools mapped to DevConsole endpoints are a natural fit. The tests cover tool registry, prompt registry, and DevConsole handler well.

Issues

1. Duplicate camel.main.devConsoleEnabled in generated metadata (Bug)

The generated camel-main-configuration-metadata.json now has two entries for camel.main.devConsoleEnabled — one from DefaultConfigurationProperties (default false, description about developer console) and one from McpServerConfigurationProperties (default true, description about MCP tools). The other MCP properties (enabled, serverName, serverVersion, transport, includeTools, excludeTools) also appear under camel.main.* instead of camel.mcp.*. The main.adoc renders them this way too, which will confuse users.

2. Missing @since 4.21 Javadoc tags (Convention)

New public types in camel-main are missing @since 4.21:

  • MainMcpServerFactory
  • McpServerConfigurationProperties

3. Security annotation missing on enabled property

The existing devConsoleEnabled in DefaultConfigurationProperties carries @Metadata(security = "insecure:dev") because DevConsole is development-only. The MCP server's enabled property exposes the same DevConsole data over a communication channel to external agents — arguably a larger attack surface. It should also carry security = "insecure:dev" so the security policy framework (camel.main.profile = prod) blocks it in production by default.

4. FQCN in McpServerService.createTransportProvider()

new JacksonMcpJsonMapper(new com.fasterxml.jackson.databind.ObjectMapper())

Per project conventions, ObjectMapper should be imported rather than fully qualified.

5. Documented transports vs. implemented

McpServerConfigurationProperties.transport Javadoc says (stdio, uds, tcp) but McpServerService.createTransportProvider() throws IllegalArgumentException for anything non-stdio. The docs should reflect current reality or note these are planned.

6. CI failing

All 3 build jobs (JDK 17, 21, 25) are failing.

Suggestions (non-blocking)

  • serverVersion default of "1.0.0": consider using the CamelContext version dynamically so the MCP server version tracks the Camel version.
  • McpToolRegistry.addToolWithCustomHandler is only used for camel_top — could be unified with addTool by adding a console ID mapper instead of a separate method.

@gnodet
Copy link
Copy Markdown
Contributor Author

gnodet commented May 20, 2026

Claude Code on behalf of Guillaume Nodet

Good question. The current STDIO approach requires putting the route filename in the MCP config, which isn't user-friendly — you'd have to update the config and restart your agent every time the route changes.

The plan is to take a different approach: a JBang command jbang camel mcp that acts as a STDIO MCP server connecting to the dev console HTTP endpoint of a running Camel app. The MCP config becomes simply:

{ "command": "jbang", "args": ["camel", "mcp"] }

No URL, no route name, no port — ever. The command auto-discovers the running Camel instance (JBang already has all the process discovery logic). If multiple apps are running, you can pass --pid=<pid> or --name=<name>, but the default just picks the single running instance.

This way:

  1. Start your Camel app however you want (jbang camel run myroute.yaml)
  2. The AI assistant spawns jbang camel mcp and talks to it over stdin/stdout
  3. The MCP command discovers the running app and translates MCP tool calls to dev console HTTP calls
  4. Change routes, restart the app — the MCP config never changes

The embedded Java MCP server stays useful for SSE transport later (native MCP endpoint on the HTTP server), but for the AI assistant use case, this is much cleaner.

@gnodet gnodet changed the title Add embedded MCP server for live Camel application introspection Add runtime MCP tools for live Camel process inspection May 20, 2026
@gnodet
Copy link
Copy Markdown
Contributor Author

gnodet commented May 20, 2026

Claude Code on behalf of Guillaume Nodet

Design Update: Runtime tools via JBang MCP Server

Reworked the approach based on discussion. Instead of embedding an MCP server inside each Camel application (which required hardcoding the route filename or port in the MCP config), the runtime tools now live in the existing camel-jbang-mcp Quarkus MCP Server.

Key advantage: The MCP config is static and trivial:

{"command": "jbang", "args": ["camel", "mcp"]}

No route name, URL, or port — the server auto-discovers running Camel processes via ~/.camel/ status files.

Communication: Uses the existing file-based IPC protocol that LocalCliConnector already supports. Enhanced it with per-request file multiplexing ({pid}-action-{requestId}.json) so multiple MCP clients can operate concurrently without interfering with each other. Fully backward compatible with existing CLI commands.

21 runtime tools added covering process discovery, context/route/health inspection, route control, message sending, tracing, expression evaluation, and endpoint browsing.

@github-actions github-actions Bot added the dsl label May 20, 2026
@davsclaus
Copy link
Copy Markdown
Contributor

Claude Code on behalf of Guillaume Nodet

Good question. The current STDIO approach requires putting the route filename in the MCP config, which isn't user-friendly — you'd have to update the config and restart your agent every time the route changes.

The plan is to take a different approach: a JBang command jbang camel mcp that acts as a STDIO MCP server connecting to the dev console HTTP endpoint of a running Camel app. The MCP config becomes simply:

{ "command": "jbang", "args": ["camel", "mcp"] }

No URL, no route name, no port — ever. The command auto-discovers the running Camel instance (JBang already has all the process discovery logic). If multiple apps are running, you can pass --pid=<pid> or --name=<name>, but the default just picks the single running instance.

This way:

  1. Start your Camel app however you want (jbang camel run myroute.yaml)
  2. The AI assistant spawns jbang camel mcp and talks to it over stdin/stdout
  3. The MCP command discovers the running app and translates MCP tool calls to dev console HTTP calls
  4. Change routes, restart the app — the MCP config never changes

The embedded Java MCP server stays useful for SSE transport later (native MCP endpoint on the HTTP server), but for the AI assistant use case, this is much cleaner.

I would also like for us to be able to include this MCP capability in the new camel tui, so end user can just run "one thing" such as camel tui --mcp (we can come up with a better name than tui).

So you have that possibility as well. Then the TUI can visually show the human what happens and give easy access to all parts of Camel in a nice dashboard / system. While the AI / MCP can do its thing.

But that can be done after this work.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 21, 2026

🧪 CI tested the following changed modules:

  • docs
  • dsl/camel-cli-connector
  • dsl/camel-jbang/camel-jbang-core
  • dsl/camel-jbang/camel-jbang-mcp

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

  • dsl/camel-jbang/camel-jbang-core: 1 test(s) disabled on GitHub Actions
  • dsl/camel-jbang/camel-jbang-mcp: 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
All tested modules (8 modules)
  • Camel :: DSL :: CLI Connector
  • Camel :: DSL :: CLI Debug
  • Camel :: JBang :: Core
  • Camel :: JBang :: MCP
  • Camel :: JBang :: Plugin :: Route Parser
  • Camel :: JBang :: Plugin :: TUI
  • Camel :: JBang :: Plugin :: Validate
  • Camel :: Launcher :: Container

⚙️ View full build and test results

@davsclaus
Copy link
Copy Markdown
Contributor

there is a doc issue

[12:48:24.475] WARN (asciidoctor): skipping reference to missing attribute: pid
    file: /home/runner/work/camel/camel/camel/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_21.adoc
    source: /home/runner/work/camel/camel/camel (branch: HEAD <worktree> | start path: docs/user-manual)
[12:48:24.476] WARN (asciidoctor): skipping reference to missing attribute: requestid
    file: /home/runner/work/camel/camel/camel/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_21.adoc
    source: /home/runner/work/camel/camel/camel (branch: HEAD <worktree> | start path: docs/user-manual)
[12:48:24.476] WARN (asciidoctor): skipping reference to missing attribute: pid
    file: /home/runner/work/camel/camel/camel/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_21.adoc
    source: /home/runner/work/camel/camel/camel (branch: HEAD <worktree> | start path: docs/user-manual)
[12:48:24.477] WARN (asciidoctor): skipping reference to missing attribute: requestid
    file: /home/runner/work/camel/camel/camel/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_21.adoc
    source: /home/runner/work/camel/camel/camel (branch: HEAD <worktree> | start path: docs/user-manual)

@gnodet
Copy link
Copy Markdown
Contributor Author

gnodet commented May 22, 2026

New: camel ask command and shared LlmClient

Claude Code on behalf of Guillaume Nodet

LlmClient — shared LLM HTTP client

Extracted from Explain into a reusable LlmClient supporting three API types with auto-detection:

  1. Ollama — local models via camel infra or localhost:11434
  2. OpenAI-compatible — any OpenAI API endpoint (OpenAI, Azure OpenAI, vLLM, LM Studio, etc.)
  3. Anthropic — both direct API (api.anthropic.com) and Vertex AI (rawPredict endpoint)

Auto-detection from environment variables:

  • ANTHROPIC_API_KEY → Anthropic direct API
  • CLOUD_ML_REGION + ANTHROPIC_VERTEX_PROJECT_ID → Vertex AI (auth via gcloud auth print-access-token)
  • OPENAI_API_KEY → OpenAI

No new dependencies — uses java.net.http.HttpClient directly.

camel ask — AI-powered runtime inspection

Sends a question to an LLM with tool-calling support, letting the LLM inspect a running Camel process and return an informed answer.

Agent loop: user question → LLM with tool definitions → LLM calls tools → execute tools → results back to LLM → repeat until text answer.

13 read-only tools: get_context, get_routes, get_health, get_endpoints, get_inflight, get_blocked, get_consumers, get_properties, get_route_source, get_route_dump, get_route_structure, get_top_processors, trace_control

Two modes:

  • One-shot: camel ask "what routes are running?" --show-tools
  • Interactive chat: camel ask — enters a JLine ask> prompt with conversation context maintained across turns

Refactored Explain

Explain now delegates all LLM interaction to LlmClient, gaining Anthropic/Vertex AI support for free.

@gnodet
Copy link
Copy Markdown
Contributor Author

gnodet commented May 22, 2026

    ~/tmp/camel-example  camel ask                                                                                                       ✔  took 24m 22s 
[jbang] [WARN] Detected missing or out-of-date dependencies in cache.
[jbang] Resolving dependencies...
[jbang]    org.apache.camel:camel-jbang-main:4.21.0-SNAPSHOT
[jbang]    org.apache.camel:camel-jbang-core:4.21.0-SNAPSHOT
[jbang] Dependencies resolved
WARNING: A restricted method in java.lang.foreign.MemorySegment has been called
WARNING: java.lang.foreign.MemorySegment::reinterpret has been called by org.jline.terminal.impl.ffm.FfmTerminalProvider in an unnamed module (file:/Users/gnodet/.m2/repository/org/jline/jline/4.0.15/jline-4.0.15.jar)
WARNING: Use --enable-native-access=ALL-UNNAMED to avoid a warning for callers in this module
WARNING: Restricted methods will be blocked in a future release unless native access is enabled

Camel AI Assistant (claude-sonnet-4-6, anthropic)
Target: random-numbers.camel.yaml (PID 28879)
Type your question, or 'exit' to quit.

ask> what routes are running?
There is 1 route currently running:

Route ID:       random-numbers
State:          Started
Uptime:         8h57m
From:           timer://random?period=5000 (fires every 5 seconds)
Throughput:     1.00 msg/sec
Total Exchanges: 6,447
Failed:         5,447  <-- WARNING: very high failure rate (~84%)
In-flight:      0

Processors:
  setBody1  - generates a random number (1-1000)  -- 0 failures
  log1      - logs the generated number           -- 0 failures
  to1       - sends to seda:numbers               -- 5,447 failures  <-- this is the source of all failures

The route itself is healthy in terms of generating and logging numbers, but almost all exchanges are failing at the final step when sending to seda:numbers. This likely means nothing is consuming from that seda:numbers queue, causing messages to be rejected or dropped.

You may want to check if there is a missing consumer route for seda:numbers, or inspect the endpoints for more detail. Would you like me to dig deeper into this?

ask> no consumer means the exchange is in error? if that's the case, why we only have 5,151 out of 6,151 exchanges ?
Good catch on the numbers — and the endpoint data helps clarify things. Let me correct myself:

First, the numbers I quoted were slightly off because the stats updated between my summary and the raw data. Let's use the latest snapshot:

  Total exchanges fired by timer:  6,451
  Exchanges failed (at to1/seda):  5,447
  Exchanges completed successfully: ~1,004

So the real question is: why did ~1,004 exchanges succeed if there is no consumer?

The answer is SEDA queue behavior. seda:numbers is an in-memory queue with a default capacity of 1,000 slots. When the queue has space, sending to it succeeds immediately — the producer does not need a consumer to be present. Once the queue fills up to its 1,000-message limit, subsequent sends are rejected and the exchange fails.

So what likely happened:

1. The route started and the first ~1,000 messages filled the seda queue successfully.
2. Once the queue was full, all subsequent sends failed because there was no consumer draining it.
3. The ~1,000 successes match exactly the default seda queue capacity.

To fix this you have two options:
- Add a consumer route that reads from seda:numbers.
- If seda:numbers is no longer needed, remove the "to seda:numbers" step from the route.

Would you like help with either of those?

ask>

@gnodet gnodet force-pushed the runtime-mcp-server branch 3 times, most recently from f9e6cc1 to 34a645b Compare May 22, 2026 09:51
gnodet and others added 3 commits May 22, 2026 15:00
Inside the JLine shell, System.console() returns null, causing
subcommands that read interactive input to silently fail. This moves
the active terminal reference to EnvironmentHelper so all commands
can detect and use the shell's terminal for input/output.

Commands fixed:
- debug: user input (step, quit) now works inside shell
- infra run: "press ENTER to stop" now works inside shell
- init: interactive template picker now works inside shell
- watch commands: "press enter" to stop now works inside shell
- confirmOperation: interactive confirmation now works inside shell

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add runtime inspection tools to the MCP server: context info, routes,
  health checks, endpoints, consumers, inflight/blocked exchanges,
  route source/dump/structure, trace control, and route lifecycle
- Add route diagram tools for visualizing route structure
- Update ExampleTools to use shared ExampleHelper
- Add IPC actions in LocalCliConnector for runtime inspection
- Update MCP documentation with new tool descriptions

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add interactive AI assistant that can inspect running Camel apps,
  search the catalog, browse examples, and create/edit route files
- Support Ollama (native /api/chat), OpenAI, and Anthropic APIs with
  auto-detection and Ollama model auto-selection for tool calling
- Add streaming support for Ollama responses (progressive token output)
- Add --verbose flag for debugging LLM requests and responses
- Disable thinking mode on Ollama models (Qwen 3.5 etc.) via think:false
- Refactor Explain command to share LlmClient with Ask
- Add documentation for ask and explain commands

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@gnodet gnodet force-pushed the runtime-mcp-server branch from 4c8b11a to 0c30d5d Compare May 22, 2026 17:07
@gnodet gnodet changed the title Add runtime MCP tools for live Camel process inspection Add MCP runtime tools and camel ask AI assistant May 22, 2026
@gnodet gnodet marked this pull request as ready for review May 22, 2026 17:12
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.

5 participants