AI agents debugging Camel routes have no MCP-based way to inspect live route stats, trace exchanges, check health, or interact with the debugger. Camel has rich runtime observability via the DevConsole SPI (~47 consoles) and a BacklogDebugger, but these are only accessible via the dev console HTTP API or JBang CLI file-based protocol.
This plan introduces a new camel-mcp-server module that embeds an MCP server directly inside a running Camel application using the official MCP Java SDK. Tools call DevConsoleRegistry and BacklogDebugger directly — no file I/O, no polling, no latency. The module supports pluggable transports: STDIO, Unix domain sockets, and TCP sockets.
This complements (not replaces) the existing camel-jbang-mcp catalog server, which remains the standalone tool for catalog lookups, migration guides, and OpenAPI tooling.
Today, AI agent frameworks for Camel (e.g., camel-kit's /camel-debug skill) rely entirely on static / post-mortem analysis: the user pastes a stack trace, the agent classifies errors from log text, and route files are analyzed offline. This works but forces the agent to "guess" at runtime behavior.
With camel-mcp-server, the debugging workflow shifts to live introspection:
| Without runtime MCP (today) | With runtime MCP |
|---|---|
| User pastes stack trace | Agent calls camel_errors — gets structured errors directly |
| "Ask user to share the failing scenario" | Agent calls camel_trace — enables tracing, observes message flow |
"Check for FailedToCreateRouteException patterns" |
Agent calls camel_health — sees which health checks fail |
| Guess at runtime behavior | Agent calls camel_send — sends test message, observes result |
| No visibility into stuck exchanges | Agent calls camel_inflight — sees what's stuck and where |
| No performance insight | Agent calls camel_top — finds the slowest processor |
Agent frameworks like camel-kit provide the structured workflow (when to do what, how to classify errors, when to escalate). camel-mcp-server provides the live data that makes their diagnosis steps dramatically more effective. Neither replaces the other — they stack.
New module at components/camel-mcp-server/ (follows the camel-platform-http-main pattern for server-like services).
components/camel-mcp-server/
├── pom.xml
└── src/main/java/org/apache/camel/mcp/server/
├── DefaultMcpServerFactory.java # @JdkService factory
├── McpServerService.java # ServiceSupport lifecycle
├── McpServerConfigurationProperties.java # camel.mcp.* config
├── McpToolRegistry.java # Maps DevConsoles to MCP tools
├── tools/
│ ├── RouteTools.java # Route listing, stats, control
│ ├── DebugTools.java # Breakpoints, stepping, inspection
│ ├── ObservabilityTools.java # Health, errors, inflight, top
│ ├── TraceTools.java # Message tracing
│ ├── InteractionTools.java # Send, eval, browse
│ └── ContextTools.java # Context info, endpoints, services
└── transport/
├── SocketMcpServerTransportProvider.java # UDS + TCP transport
└── SocketMcpSessionTransport.java # Per-connection transport
<dependency>
<groupId>io.modelcontextprotocol.sdk</groupId>
<artifactId>mcp-core</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>io.modelcontextprotocol.sdk</groupId>
<artifactId>mcp-json-jackson2</artifactId> <!-- Camel uses Jackson 2.21.3 -->
<version>1.1.0</version>
</dependency>Transitive deps already in Camel: slf4j-api, jackson-annotations.
New transitive dep: reactor-core (~1.5MB) — required by mcp-core even when using the sync API.
No dependency on Quarkus, Spring, or any servlet container.
Follows the camel-platform-http-main factory pattern:
@JdkService("mcp-server")
public class DefaultMcpServerFactory implements CamelContextAware {
public Service newMcpServer(CamelContext ctx, McpServerConfigurationProperties config);
}McpServerFactory sf = resolveBootstrapService(camelContext, "mcp-server");
Service mcp = sf.newMcpServer(camelContext, mcpConfig);
camelContext.addService(mcp, true, true); // eager start- Extends
ServiceSupport, implementsCamelContextAware,StaticService doInit(): build MCP server, register tools from DevConsoleRegistrydoStart(): start transport (bind socket / start listening on STDIO)doStop(): close MCP server, release socket
camel.mcp.enabled = true # enable/disable
camel.mcp.transport = stdio # stdio | uds | tcp
camel.mcp.host = localhost # TCP bind address
camel.mcp.port = 0 # TCP port (0 = random, write to status file)
camel.mcp.socket-path = ~/.camel/{pid}.sock # UDS path template- Uses SDK's built-in
StdioServerTransportProvider - Best for
camel jbang runwhere the MCP client launches the process - MCP client config:
{ "command": "camel", "args": ["run", "myroute.yaml"] }
Custom McpServerTransportProvider implementation supporting both UDS and TCP:
- Uses
java.nio.channels.ServerSocketChannelwith NIO selectors StandardProtocolFamily.UNIXfor UDS (JDK 16+)StandardProtocolFamily.INETfor TCP- Multi-session: each accepted connection creates a new
McpServerSession - Message framing: newline-delimited JSON-RPC (same as STDIO)
- Writes socket address to
~/.camel/{PID}-mcp.jsonfor discoverability
Note: the MCP Java SDK has an open PR (#439) for UDS transport. If it merges before we ship, we can use it directly instead of a custom implementation.
When using UDS or TCP, the server writes connection info to ~/.camel/{PID}-mcp.json:
{
"transport": "uds",
"socketPath": "/Users/me/.camel/12345.sock",
"serverInfo": { "name": "camel-mcp-server", "version": "4.21.0" }
}This allows tools (including camel-jbang-mcp) to discover and proxy to running instances.
Scans DevConsoleRegistry at startup and registers MCP tools. Each tool wraps a dev console call:
McpSyncServer server = McpServer.sync(transport)
.serverInfo("camel-runtime", camelVersion)
.capabilities(ServerCapabilities.builder().tools(true).resources(true).prompts(true).build())
.build();
// Register tools from DevConsoleRegistry
for (DevConsole console : registry.stream().toList()) {
server.addTool(buildToolSpec(console));
}Context & Routes:
| Tool | Description | DevConsole |
|---|---|---|
camel_context |
Context name, version, state, uptime, memory, threads | context + status |
camel_routes |
List routes with state and statistics | route |
camel_route_control |
Start/stop/suspend/resume a route by ID | route (with action) |
camel_route_source |
Get route source code (YAML/XML/Java) | source |
camel_route_structure |
Get route structure as tree | route-structure |
Observability:
| Tool | Description | DevConsole |
|---|---|---|
camel_health |
Health checks: readiness, liveness, individual results | health |
camel_errors |
Recent exchange errors with exception details | errors |
camel_inflight |
In-flight exchanges with elapsed time | inflight |
camel_top |
Routes/processors sorted by slowest processing time | top |
camel_endpoints |
List active endpoints | endpoint |
Tracing & Debugging:
| Tool | Description | DevConsole |
|---|---|---|
camel_trace |
Enable/disable tracing, retrieve traced messages | trace |
camel_debug |
Breakpoints, step, resume, inspect suspended exchanges | debug |
camel_message_history |
Exchange path through processors | message-history |
Interaction:
| Tool | Description | DevConsole |
|---|---|---|
camel_send |
Send test message to an endpoint, get response | send |
camel_browse |
Browse pending messages on browsable endpoints | browse |
camel_eval |
Evaluate expression (Simple, JsonPath, etc.) | eval-language |
Each tool wraps the corresponding dev console's doCallJson():
SyncToolSpecification.builder()
.tool(Tool.builder("camel_routes", Map.of(
"type", "object",
"properties", Map.of(
"filter", Map.of("type", "string", "description", "Filter by route ID pattern")
)
)).description("List routes with state and statistics").build())
.callHandler((exchange, request) -> {
DevConsole console = registry.resolveById("route");
Map<String, Object> options = new HashMap<>(request.arguments());
Map<String, Object> result = (Map) console.call(DevConsole.MediaType.JSON, options);
return CallToolResult.builder()
.content(List.of(new McpSchema.TextContent(jsonMapper.toJson(result))))
.build();
})
.build();| Resource | URI | Description |
|---|---|---|
| Context status | camel://context |
Full context information |
| Route list | camel://routes |
All routes with current stats |
| Endpoint list | camel://endpoints |
Active endpoints |
| Health status | camel://health |
Current health check results |
camel_debug_route — Guided workflow to debug a failing route:
camel_health→ check overall healthcamel_routes→ find failing route by error countcamel_traceenable → turn on tracingcamel_tracedump → retrieve messagescamel_top→ identify bottleneck processorscamel_errors→ get error details- Present root cause analysis
camel_performance_analysis — Guided workflow for performance investigation:
camel_context→ overview (uptime, memory)camel_routes→ route stats sorted by throughputcamel_top→ slowest processorscamel_browse→ check queue depthscamel_inflight→ stuck exchanges- Present bottleneck analysis and recommendations
pom.xmlwith MCP SDK dependenciesMcpServerConfigurationProperties(config)DefaultMcpServerFactory+McpServerService(lifecycle)- STDIO transport only (built-in from SDK)
- 3 tools:
camel_context,camel_routes,camel_health - Wire into
BaseMainSupportfor auto-start
- All read-only tools:
camel_errors,camel_inflight,camel_top,camel_endpoints,camel_trace,camel_message_history - Mutation tools:
camel_route_control,camel_send,camel_browse,camel_eval - Debug tools:
camel_debug - Resources and prompts
SocketMcpServerTransportProviderfor UDS and TCP- Socket address written to
~/.camel/{PID}-mcp.json - Configuration:
camel.mcp.transport=uds|tcp
- Unit tests: mock DevConsoleRegistry, verify tool parameter mapping and results
- Integration test: start Camel Main with MCP server, connect MCP client, exercise tools
- AsciiDoc documentation
- Update
camel-jbang-mcp.adocto reference the runtime server as a companion
components/pom.xml— addcamel-mcp-servermodulecore/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java— add MCP server factory resolution and startup (followingMainHttpServerFactorypattern)core/camel-main/src/main/java/org/apache/camel/main/MainConstants.java— addMCP_SERVERconstantparent/pom.xml— addmcp-sdk-versionproperty and BOM entry
- Build:
cd components/camel-mcp-server && mvn install -B - Run a test route with MCP enabled:
camel run myroute.yaml --mcp
- Connect Claude Code or MCP Inspector to the server
- Exercise tools: list routes, check health, enable tracing, send test messages
- Verify STDIO transport works when launched by an MCP client
- Verify UDS/TCP transport works for already-running applications
Once camel-mcp-server ships, agent frameworks like camel-kit can integrate the runtime MCP tools into their structured workflows. Concrete follow-up work:
The /camel-debug skill defines a STOP → PRESERVE → DIAGNOSE → FIX → GUARD workflow with subagent isolation for diagnosis. Its diagnosis subagents map directly to runtime MCP tools:
| Skill subagent | Currently | With camel-mcp-server |
|---|---|---|
| Log analyzer | Parses raw log/stack trace text | camel_errors + camel_trace — structured data, no parsing needed |
| MCP verifier | camel_catalog_component (catalog only) |
Also camel_endpoints to verify what's actually loaded at runtime |
| Route analyzer | Reads YAML files statically | camel_route_structure + camel_route_source for live route state |
Suggested changes to camel-kit:
- Add
camel-mcp-serveras a second MCP server inshared/mcp-setup.md(alongside the catalog server) - Add a "Step 3.0: Live Runtime Check" before static analysis in
debug-workflow.md— if a runtime MCP server is reachable, querycamel_health,camel_errors, andcamel_inflightfirst for immediate insight - Enhance the "Reproduce" step: instead of asking the user to trigger the scenario, use
camel_sendto inject test messages andcamel_traceto observe the flow - The iteration limit (5 fix attempts) becomes more efficient when the agent can observe the effect of each fix via
camel_healthandcamel_errorsin real time
The standalone catalog MCP server (camel-jbang-mcp) could optionally discover running camel-mcp-server instances via ~/.camel/{PID}-mcp.json and proxy runtime tool calls. This would let users configure a single MCP server that provides both catalog and runtime tools — the catalog server forwards runtime queries to whichever instance is running. This is a convenience layer, not a requirement.