Apache Camel 4 extension that speaks the Model Context Protocol (MCP) over JSON-RPC so agents and automations can call your Camel routes as tools.
Project Home: https://github.com/dscope-io/dscope-camel-mcp#readme
- Description: Apache Camel MCP component enabling Model Context Protocol client/server routes over HTTP/WebSocket.
- Topics:
ai-integration,apache-camel,camel-component,java,json-rpc,mcp,model-context-protocol
Note: These values mirror the GitHub repository settings (Description, Topics, Homepage). Keep both in sync when updating project metadata.
| Channel | Version | Maven Coordinate | Notes |
|---|---|---|---|
| Latest Release | 1.4.1 | io.dscope.camel:camel-mcp:1.4.1 |
Recommended for production use |
| Development Snapshot | 1.4.1 | io.dscope.camel:camel-mcp:1.4.1 |
Build from source (mvn install) to track main |
Maven Central:
- https://central.sonatype.com/artifact/io.dscope.camel/camel-mcp
- https://repo1.maven.org/maven2/io/dscope/camel/camel-mcp/
- Java 21+
- Maven 3.9+
- Apache Camel 4.15.0+
- Producer (client) mode: Send MCP JSON-RPC requests to remote servers via
to("mcp:http://host/mcp?method=tools/list"). - Consumer (server) mode: Expose MCP endpoints with
from("mcp:http://0.0.0.0:3000/mcp")β built-in request validation, JSON-RPC parsing, rate limiting, and response serialization. - Implements core MCP methods:
initialize,ping,resources/list,resources/read,resources/get,tools/list,tools/call,health, andstream. - MCP Apps Bridge support:
ui/initialize,ui/message,ui/update-model-context, andui/tools/callfor embedded UI integration. - Notifications:
notifications/initialized,notifications/cancelled,notifications/progress. - HTTP and WebSocket transports for both producer and consumer modes.
- Ships 20+ registry processors for JSON-RPC envelopes, tool catalogs, resource catalogs, and notification workflows.
- Apache Karavan integration: Generated visual designer metadata for drag-and-drop MCP route building.
- Camel tooling support:
@UriEndpoint-based component descriptor generation (mcp.json) for IDE autocompletion and documentation. - Two sample projects and Postman collections to exercise MCP flows end-to-end.
π Development Guide - Learn how to build your own MCP services with YAML and Java routes.
<dependency>
<groupId>io.dscope.camel</groupId>
<artifactId>camel-mcp</artifactId>
<version>1.4.1</version>
</dependency>dependencies {
implementation "io.dscope.camel:camel-mcp:1.4.1"
}git clone https://github.com/dscope-io/dscope-camel-mcp.git
cd dscope-camel-mcp
mvn clean installProducer (Client) Mode:
mcp:http://host:port/mcp?method=tools/list
mcp:camel:direct:localMcpRoute?method=tools/list
Consumer (Server) Mode:
mcp:http://host:port/path
mcp:http://host:port/path?websocket=true
| Option | Default | Mode | Purpose |
|---|---|---|---|
method |
tools/list |
Producer | MCP JSON-RPC method to invoke when producing |
websocket |
false |
Consumer | Enable WebSocket transport instead of HTTP |
sendToAll |
false |
Consumer | Broadcast WebSocket messages to all clients |
allowedOrigins |
* |
Consumer | CORS allowed origins for WebSocket |
httpMethodRestrict |
POST |
Consumer | Restrict HTTP methods (e.g., POST, GET) |
The exchange body should be a Map representing MCP params. The producer enriches it with jsonrpc, id, and the configured method before invoking the downstream HTTP endpoint.
You can override the endpoint method per message with header CamelMcpMethod.
For local MCP services exposed as Camel routes, use the URI prefix camel: after mcp:.
Dispatch is selected by endpoint URI structure:
mcp:camel:<camel-endpoint-uri>-> local Camel route dispatch (in-process)mcp:http://.../mcp:https://...-> remote JSON transport dispatch
Example local dispatch from Java routes:
from("direct:start")
.setBody(constant(Map.of("clientInfo", Map.of("name", "local-client", "version", "1.0.0"))))
.to("mcp:camel:direct:localMcpService?method=initialize")
.log("${body}");Remote MCP producer route:
- route:
id: remote-mcp-client
from:
uri: "direct:remoteMcp"
steps:
- setBody:
constant:
clientInfo:
name: "camel-client"
version: "1.0.0"
- to:
uri: "mcp:http://localhost:8080/mcp?method=initialize"
- setBody:
simple: "${body[result]}"Local MCP producer route + local service route:
- route:
id: local-mcp-client
from:
uri: "direct:localMcpClient"
steps:
- setBody:
constant:
probe: true
- to:
uri: "mcp:camel:direct:localMcpService?method=ping"
- setBody:
simple: "${body[result]}"
- route:
id: local-mcp-service
from:
uri: "direct:localMcpService"
steps:
- setBody:
simple: |
{
"jsonrpc": "2.0",
"id": "${body[id]}",
"result": {
"method": "${body[method]}",
"pong": true,
"local": true
}
}
- unmarshal:
json:
library: JacksonUse io.dscope.camel.mcp.McpClient for Java-friendly calls that return MCP result payloads directly:
ProducerTemplate template = camelContext.createProducerTemplate();
String endpoint = "mcp:http://localhost:8080/mcp?method=initialize";
Object pingResult = McpClient.pingResult(template, endpoint);
Object toolsResult = McpClient.toolsListResult(template, endpoint);
JsonNode pingJson = McpClient.pingResultJson(template, endpoint);
JsonNode toolsJson = McpClient.toolsListResultJson(template, endpoint);
Object initializeResult = McpClient.callResult(
template,
endpoint,
"initialize",
Map.of("clientInfo", Map.of("name", "java-client", "version", "1.0.0"))
);
JsonNode initializeJson = McpClient.callResultJson(
template,
endpoint,
"initialize",
Map.of("clientInfo", Map.of("name", "java-client", "version", "1.0.0"))
);The consumer creates an HTTP or WebSocket server endpoint that:
- Validates incoming requests (headers, content-type)
- Parses JSON-RPC envelopes
- Extracts method and parameters to exchange properties
- Routes to your processor
- Serializes responses to JSON
Exchange properties set by the consumer:
mcp.jsonrpc.type- REQUEST, NOTIFICATION, or RESPONSEmcp.jsonrpc.id- Request ID for responsesmcp.jsonrpc.method- The MCP method being calledmcp.tool.name- Tool name (for tools/call)
The component supports WebSocket connections for persistent, bidirectional MCP sessions. This is ideal for:
- Long-running agent sessions
- Streaming responses
- Real-time notifications
| Protocol | Endpoint | Purpose |
|---|---|---|
| HTTP | http://localhost:8080/mcp |
Request/response style |
| WebSocket | ws://localhost:8090/mcp |
Persistent bidirectional |
The sample service configures WebSocket via Undertow:
- route:
id: mcp-service-ws
from:
uri: "undertow:ws://0.0.0.0:8090/mcp?sendToAll=false&allowedOrigins=*&exchangePattern=InOut"| Option | Default | Purpose |
|---|---|---|
sendToAll |
false |
Send response only to originating client |
allowedOrigins |
* |
CORS allowed origins (use specific domains in production) |
exchangePattern |
InOut |
Enable request/response pattern |
# Install wscat (one-time)
npm install -g wscat
# Connect to MCP WebSocket
npx wscat -c ws://localhost:8090/mcp- websocat:
websocat ws://localhost:8090/mcp - VS Code: Install "WebSocket Client" extension
- Postman: Import WebSocket collection from
samples/mcp-service/postman/ - Python: Use
websocketslibrary - JavaScript: Native
WebSocketAPI orwspackage
import asyncio
import websockets
import json
async def mcp_client():
async with websockets.connect('ws://localhost:8090/mcp') as ws:
# Initialize session
await ws.send(json.dumps({
"jsonrpc": "2.0",
"id": "1",
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"clientInfo": {"name": "python-client", "version": "1.0.0"}
}
}))
print(await ws.recv())
# List tools
await ws.send(json.dumps({
"jsonrpc": "2.0",
"id": "2",
"method": "tools/list"
}))
print(await ws.recv())
asyncio.run(mcp_client())const WebSocket = require('ws');
const ws = new WebSocket('ws://localhost:8090/mcp');
ws.on('open', () => {
// Initialize session
ws.send(JSON.stringify({
jsonrpc: "2.0",
id: "1",
method: "initialize",
params: {
protocolVersion: "2024-11-05",
clientInfo: { name: "node-client", version: "1.0.0" }
}
}));
});
ws.on('message', (data) => {
console.log('Received:', JSON.parse(data));
});All MCP methods use JSON-RPC 2.0 format. Here's how to call each supported method:
curl -s -H "Content-Type: application/json" -H "Accept: application/json" \
-d '{
"jsonrpc": "2.0",
"id": "1",
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"clientInfo": {
"name": "my-client",
"version": "1.0.0"
},
"capabilities": {}
}
}' \
http://localhost:8080/mcp | jq '.'curl -s -H "Content-Type: application/json" -H "Accept: application/json" \
-d '{"jsonrpc": "2.0", "id": "2", "method": "ping"}' \
http://localhost:8080/mcp | jq '.'curl -s -H "Content-Type: application/json" -H "Accept: application/json" \
-d '{"jsonrpc": "2.0", "id": "3", "method": "tools/list"}' \
http://localhost:8080/mcp | jq '.'curl -s -H "Content-Type: application/json" -H "Accept: application/json" \
-d '{"jsonrpc": "2.0", "id": "4", "method": "resources/list"}' \
http://localhost:8080/mcp | jq '.'curl -s -H "Content-Type: application/json" -H "Accept: application/json" \
-d '{
"jsonrpc": "2.0",
"id": "4",
"method": "tools/call",
"params": {
"name": "echo",
"arguments": {
"message": "Hello from MCP!"
}
}
}' \
http://localhost:8080/mcp | jq '.'# JSON resource
curl -s -H "Content-Type: application/json" -H "Accept: application/json" \
-d '{
"jsonrpc": "2.0",
"id": "5",
"method": "resources/get",
"params": {
"resource": "example-resource"
}
}' \
http://localhost:8080/mcp | jq '.'
# Binary resource (returns base64)
curl -s -H "Content-Type: application/json" -H "Accept: application/json" \
-d '{"jsonrpc": "2.0", "id": "6", "method": "resources/get", "params": {"resource": "sample-image.jpg"}}' \
http://localhost:8080/mcp | jq '.'The component supports the MCP Apps Bridge specification for embedding interactive UIs within AI agent workflows.
curl -s -H "Content-Type: application/json" -H "Accept: application/json" \
-d '{
"jsonrpc": "2.0",
"id": "ui-1",
"method": "ui/initialize",
"params": {
"clientInfo": {"name": "my-ui", "version": "1.0.0"},
"resourceUri": "mcp://resource/chart-editor.html",
"toolName": "chart-editor"
}
}' \
http://localhost:8080/mcp | jq '.'Response includes a sessionId for subsequent UI calls:
{
"result": {
"sessionId": "abc123-...",
"hostInfo": {"name": "camel-mcp", "version": "1.4.1"},
"capabilities": ["tools/call", "ui/message", "ui/update-model-context"]
}
}curl -s -H "Content-Type: application/json" -H "Accept: application/json" \
-d '{
"jsonrpc": "2.0",
"id": "ui-2",
"method": "ui/tools/call",
"params": {
"sessionId": "<sessionId-from-ui-initialize>",
"name": "echo",
"arguments": {"text": "Hello from UI!"}
}
}' \
http://localhost:8080/mcp | jq '.'curl -s -H "Content-Type: application/json" -H "Accept: application/json" \
-d '{
"jsonrpc": "2.0",
"id": "ui-3",
"method": "ui/message",
"params": {
"sessionId": "<sessionId>",
"type": "user-action",
"payload": {"action": "button-clicked"}
}
}' \
http://localhost:8080/mcp | jq '.'curl -s -H "Content-Type: application/json" -H "Accept: application/json" \
-d '{
"jsonrpc": "2.0",
"id": "ui-4",
"method": "ui/update-model-context",
"params": {
"sessionId": "<sessionId>",
"context": {"chartConfig": {"type": "bar", "data": [1,2,3]}},
"mode": "merge"
}
}' \
http://localhost:8080/mcp | jq '.'npx wscat -c ws://localhost:8090/mcp
# Initialize
> {"jsonrpc":"2.0","id":"1","method":"initialize","params":{"protocolVersion":"2024-11-05","clientInfo":{"name":"ws-client","version":"1.0.0"}}}
# Ping
> {"jsonrpc":"2.0","id":"2","method":"ping"}
# List tools
> {"jsonrpc":"2.0","id":"3","method":"tools/list"}
# Call a tool
> {"jsonrpc":"2.0","id":"4","method":"tools/call","params":{"name":"echo","arguments":{"message":"Hello"}}}
# Get a resource
> {"jsonrpc":"2.0","id":"5","method":"resources/get","params":{"resource":"example-resource"}}- route:
id: example-mcp-client
from:
uri: "timer://runOnce?repeatCount=1"
steps:
- setBody:
constant: |
{
"method": "initialize",
"params": {
"clientInfo": {
"name": "camel-mcp",
"version": "1.0.0"
}
}
}
- unmarshal:
json:
library: Jackson
- to:
uri: "mcp:http://localhost:8080/mcp?method=initialize"
- log:
message: "MCP Response: ${body}"The resources/get method supports automatic content type detection:
- Binary (images, PDFs, fonts) β returned as base64
blob - Text (html, css, js, md) β returned as
textwith MIME type - JSON (no extension) β returned as structured data
- route:
id: example-resources-client
from:
uri: "timer://resources?repeatCount=1"
steps:
- setBody:
constant: |
{
"params": {
"resource": "example-resource"
}
}
- unmarshal:
json:
library: Jackson
- to:
uri: "mcp:http://localhost:8080/mcp?method=resources/get"
- log:
message: "Resource payload: ${body[result]}"The MCP consumer allows you to create MCP protocol servers that listen for incoming JSON-RPC requests.
from("mcp:http://localhost:8080/mcp")
.process(exchange -> {
// Your custom MCP request processing
String method = exchange.getProperty("mcp.jsonrpc.method", String.class);
Map<String, Object> params = exchange.getIn().getBody(Map.class);
// Process request and set response
Map<String, Object> response = Map.of(
"jsonrpc", "2.0",
"id", exchange.getProperty("mcp.jsonrpc.id"),
"result", Map.of("status", "ok")
);
exchange.getMessage().setBody(response);
});from("mcp:http://localhost:8090/mcp?websocket=true")
.process(exchange -> {
// Process MCP requests over WebSocket
// Response automatically serialized to JSON
});- route:
id: mcp-server
from:
uri: "mcp:http://0.0.0.0:8080/mcp"
steps:
- choice:
when:
- simple: "${exchangeProperty.mcp.jsonrpc.method} == 'ping'"
steps:
- setBody:
constant:
jsonrpc: "2.0"
result: {}
- simple: "${exchangeProperty.mcp.jsonrpc.method} == 'tools/list'"
steps:
- setBody:
constant:
jsonrpc: "2.0"
result:
tools:
- name: "echo"
description: "Echo the input"The consumer automatically:
- Validates HTTP headers (Content-Type, Accept)
- Parses JSON-RPC envelopes
- Extracts method and parameters as exchange properties
- Applies rate limiting and request size guards
- Serializes response bodies to JSON
AbstractMcpRequestProcessorandAbstractMcpResponseProcessorprovide templates for custom tool handlers.McpResourcesGetProcessorhandles resource loading with automatic content type detection and helper methods:isBinaryResource(name)/isTextResource(name)β check content typegetMimeType(name)β resolve MIME type from extensionblobResource(uri, mimeType, bytes)β create binary responsetextResource(uri, mimeType, content)β create text responsejsonResource(uri, data)β create JSON response
McpNotificationProcessornormalizes JSON-RPC notifications and exchange properties.- Tool catalogs load from
classpath:mcp/methods.yamland feedtools/listresponses automatically.
mvn clean installThe integration test boots a mock MCP server defined in src/test/resources/routes via Camel Main.
Full-featured MCP server with Kamelet-based routing, UI Bridge, resource catalog, and OpenAPI generation.
mvn -f samples/mcp-service/pom.xml exec:java
# HTTP: http://localhost:8080/mcp | WebSocket: ws://localhost:8090/mcpMinimal MCP server demonstrating the from("mcp:...") consumer approach β pure Java, no YAML needed.
mvn -f samples/mcp-consumer/pom.xml exec:java
# HTTP: http://localhost:3000/mcp | WebSocket: ws://localhost:3001/mcpSee samples/mcp-consumer/README.md for details and curl examples.
mvn exec:java -Dexec.mainClass=org.apache.camel.main.MainWhen the sample is running you can exercise the MCP HTTP endpoint:
# JSON resource (no extension)
curl -s -H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":"1","method":"resources/get","params":{"resource":"example-resource"}}' \
http://localhost:8080/mcp
# HTML resource
curl -s -H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":"2","method":"resources/get","params":{"resource":"sample.html"}}' \
http://localhost:8080/mcp
# Binary image resource
curl -s -H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":"3","method":"resources/get","params":{"resource":"sample-image.jpg"}}' \
http://localhost:8080/mcpHTTP endpoints listen on http://localhost:8080; WebSocket helpers are available on ws://localhost:8090/mcp. Generated OpenAPI definitions live under samples/mcp-service/target/openapi/. Postman collections are bundled in samples/mcp-service/postman/ for interactive exploration.
The build generates a standard Camel component descriptor at src/generated/resources/META-INF/io/dscope/camel/mcp/mcp.json. This enables:
- IDE autocompletion for
mcp:URIs in YAML / Java routes - Auto-generated option tables in documentation
- Property validation via
McpEndpointConfigurerandMcpComponentConfigurer
Additional Camel-standard properties are exposed automatically: bridgeErrorHandler, lazyStartProducer, exceptionHandler, exchangePattern, autowiredEnabled.
Generate visual designer metadata for Apache Karavan:
mvn -Pkaravan-metadata compile exec:javaThis produces metadata under src/main/resources/karavan/metadata/:
| File | Purpose |
|---|---|
component/mcp.json |
Component descriptor with all properties and method enums |
mcp-methods.json |
Catalog of 13 request methods + 3 notification methods |
kamelet/mcp-rest-service.json |
REST kamelet descriptor (port 8080) |
kamelet/mcp-ws-service.json |
WebSocket kamelet descriptor (port 8090) |
model-labels.json |
Human-friendly labels for methods and kamelets |
Regenerate after adding new MCP methods or changing component properties.
io.dscope.camel.mcp/
βββ McpComponent # Camel component entry point
βββ McpEndpoint # Holds configuration, creates producer/consumer (@UriEndpoint, Category.AI)
βββ McpConfiguration # URI path/param bindings with Camel annotations
βββ McpProducer # Sends MCP JSON-RPC requests to remote servers (client mode)
βββ McpConsumer # Receives MCP requests via HTTP/WebSocket (server mode)
βββ processor/ # 20+ built-in processors for JSON-RPC, tools, resources, UI, notifications
βββ catalog/ # McpMethodCatalog + McpResourceCatalog (loaded from YAML)
βββ service/ # McpUiSessionRegistry, McpWebSocketNotifier
βββ model/ # Jackson POJOs: requests, responses, resources, UI sessions, notifications
βββ tools/karavan/ # McpKaravanMetadataGenerator for Karavan visual designer
samples/
βββ mcp-service/ # Full-featured MCP server using Kamelets/YAML routes (port 8080/8090)
βββ mcp-consumer/ # Minimal MCP server using direct consumer URI (port 3000/3001)
src/generated/ # Auto-generated component descriptors (mcp.json, configurers, URI factory)
src/main/resources/karavan/metadata/ # Generated Karavan metadata (component, kamelets, labels)
src/main/docs/mcp-component.adoc # AsciiDoc component documentation for Camel tooling
Licensed under the Apache License 2.0. See LICENSE for the full text.