Cameleer / Use cases / MCP tool server
Model Context Protocol
Integration routes as MCP tools
Write a route that looks up an order, issues a refund or opens a ticket, and Cameleer serves it to Claude Desktop, VS Code, Cursor or your agent framework as an MCP tool. The model decides what to call; the route decides how it runs: arguments checked against a schema, a retried call run once, risky calls held for a person, slow calls cancelled, every call in the audit log. Ten use cases with recorded requests through Claude are on the Cameleer MCP page. An existing route becomes a tool by changing one line, and Cameleer is also an MCP client that can import and re-serve other MCP servers' tools.
cameleer run tools.camel.yaml --mcp, or --mcp-stdio for clients that start the serverai-tool options and camel.server.mcp-* properties as in Apache CamelA tool, a resource and a prompt
Three components make what an MCP client sees: ai-tool (an action the model can take), ai-resource (a document it can read) and ai-prompt (a prompt template the user can pick). A tool's arguments arrive as headers and the route's body becomes the result.
# mcp-server.camel.yaml
- route:
id: lookup-order
from:
uri: ai-tool:lookup_order
parameters:
description: Look up an order by id
tags: support
parameter.orderId: string
parameter.orderId.description: The order id, such as EU-4411
parameter.orderId.required: true
readOnlyHint: true
steps:
- setBody:
simple: '{"orderId": "${header.orderId}", "status": "shipped", "carrier": "DHL"}'
- route:
id: refund-policy
from:
uri: ai-resource:refund-policy
parameters:
uri: docs://refund-policy
description: When and how much we refund
mimeType: text/markdown
tags: support
steps:
- setBody:
constant: "# Refund policy\n\nDamaged items are refunded in full within 30 days."
- route:
id: support-reply
from:
uri: ai-prompt:support-reply
parameters:
description: Draft a reply to a customer
tags: support
argument.question.description: The customer's question
argument.question.required: true
argument.tone.values: friendly,formal
steps:
- setBody:
simple: "Write a ${header.tone} reply to this customer question, citing our refund policy: ${header.question}"
The file is examples/agents/mcp-server.camel.yaml. In a real tool the setBody is a call to your order system, a database query or a queue: any of the about 230 components, with the route's own error handling and retries.
Serve it
Streamable HTTP
cameleer run mcp-server.camel.yaml --mcp # MCP endpoint: http://localhost:8080/mcp
The endpoint shares camel.server.port with platform-http routes and the health checks. Requests from browser origins other than localhost get 403 unless camel.server.mcp-allowed-origins lists them.
stdio, for a client that starts the server
{
"mcpServers": {
"orders": {
"command": "cameleer",
"args": ["run", "/path/to/mcp-server.camel.yaml", "--mcp-stdio"]
}
}
}
That is Claude Desktop's claude_desktop_config.json; other clients have a similar file.
On the command line --mcp and --mcp-stdio expose every tool, resource and prompt. In a configuration file nothing is exposed until you choose: camel.server.mcp-enabled=true and camel.server.mcp-tags=support. All properties: MCP server configuration.
Docker, serverless, the edge: the same tools wherever they run
One route file serves MCP from the binary, the container, your own Rust program, a serverless platform or a gateway next to the machines. Every command below is in the MCP server guide.
Docker, over HTTP
docker run --rm -p 8080:8080 -v "$PWD:/routes:ro" pmsudhi/cameleer run /routes/mcp-server.camel.yaml --mcp
Clients connect to http://localhost:8080/mcp. Add --prop camel.server.mcp-tags=support to expose only some tools. The same service runs under Docker Compose and Kubernetes.
Docker, over stdio
{
"mcpServers": {
"orders": {
"command": "docker",
"args": ["run", "-i", "--rm", "-v", "/path/to/tools:/routes:ro",
"pmsudhi/cameleer", "run", "/routes/mcp-server.camel.yaml",
"--mcp-stdio"]
}
}
}
The client starts the container. Logs go to stderr, so stdout carries only protocol messages.
AWS Lambda and Cloud Run
- Lambda: the binary is its own runtime; function URL and API Gateway requests for
/mcpreach the MCP server in process. Stateless 2026-07-28 clients suit it best. - Cloud Run, Knative, Container Apps: the image with
--mcp; routes are running about 3 ms after the container starts, so scaling to zero costs clients little. - Several instances share approvals through one
camel.server.mcp-request-state-key.
An edge gateway
- Tools next to the devices: read the latest MQTT sensor readings, change a setpoint, with setpoints above a limit waiting for a person.
- Readings stay on site; the agent reaches only what the tools expose. arm64 and amd64 images.
- The tested gateway example · MQTT edge gateways
What happens on every call
Every call, from an MCP client, the agent step, a model component or a route, goes through the same envelope, in this order. In Apache Camel the tool hints are advisory; here they set the defaults of these checks.
| step | what it does | option |
|---|---|---|
| Kill switch | a withdrawn tool is not listed and its calls are refused | camel.ai.disabled-tools, cameleer tool disable |
| Authorization | a policy bean or a Simple predicate over the arguments and the caller may refuse the call; the reason goes back to the model | authorizationPolicy, authorize |
| Arguments | camel* and undeclared arguments are dropped; the rest is validated against JSON Schema 2020-12, and the error names each field and shows valid arguments | parameter.*, argSchema |
| Rate limit | calls per principal per period | rateLimit, rateLimitPeriod |
| Circuit breaker | after repeated failures the model gets a fallback text and the route does not run | circuitBreakerThreshold |
| Approval | destructive or matching calls wait for a person | destructiveHint, approval, approvalEndpoint |
| Idempotency | a retried call returns the recorded result; a repeat that arrives during the first call waits for it | idempotency, idempotencyWindow |
| Compensation | the undo step is registered before the call; if the conversation fails later, undo steps run newest first | compensation |
| Timeout | when the caller stops waiting, the tool's route is cancelled before its next step | timeout (default 20 s) |
| Result | objects and arrays stay structured; an outputSchema is checked; secrets, e-mail addresses, card numbers, IBANs and other patterns can be redacted before the result reaches the model, the client or the log | outputSchema, redact, cacheTtl |
| Audit | one hash-chained record per call: digests of arguments and result, the decision, the approver, the duration. An edited, removed or reordered record fails verification | camel.ai.audit.* |
Pinning: a tool's definition hash covers its name, description, schemas and hints. A route that changes a tool but keeps its version fails to start, so a tool cannot change under a client that already trusts it (camel.ai.manifest keeps the hashes across restarts). Details: ai-tool, a call step by step.
Approvals and operators
A person in the loop
- Out of band. With an
approvalEndpoint(Slack, e-mail, a ticket queue) the call is parked with a handle and the client is told it is waiting.cameleer tool approve <handle>runs it once;cameleer tool denyruns nothing. - In band, 2026-07-28. The result is
input_requiredwith anelicitation/createform and arequestStatesealed with AES-256-GCM, bound to the principal, the tool, a digest of the arguments and an expiry. A tampered state, changed arguments or a replay run nothing. - In band, legacy sessions. The server sends
elicitation/createon the call's response stream (HTTP) or on stdout (stdio). - A client that did not declare the
elicitationcapability gets-32021and the call does not run.
Running it
cameleer tool list,disable,enable,approvals,approve,denyagainst a running integration;GET /q/dev/toolson the dev console.- Authentication over HTTP: API keys, JWTs (JWKS or HMAC) or RFC 7662 introspection, with RFC 9728 protected-resource metadata and RFC 8707 audience checks.
- The client's token never reaches the routes; they see the principal in
CamelMcpSecurityPrincipal. - Route exceptions reach clients as a generic message with an error id, as in Camel, unless
camel.server.mcp-expose-errors=true.
From inside a tool route
A long tool can report progress and log lines to the client, ask the client's user a question or ask the client's model, in both protocol eras: ai-tool:x?operation=progress, log, elicit and sample. A route can also return images, audio or embedded resources by setting CamelAiToolContent.
One gateway in front of other MCP servers
Cameleer is also an MCP client. It imports the tools of remote servers into its registry, where they run through the same envelope, and its own server can serve them again next to your tools.
camel.ai.mcp.github.url=https://mcp.example.com/github
camel.ai.mcp.github.bearerToken={{env:GITHUB_TOKEN}}
camel.ai.mcp.files.command=files-server
camel.server.mcp-enabled=true
camel.server.mcp-tags=mcp:*,support
camel.server.mcp-auth=jwt
camel.server.mcp-jwt-jwks-url=https://login.example.com/.well-known/jwks.json
camel.server.mcp-resource-url=https://tools.example.com/mcp
What clients get
- One endpoint and one login instead of a configuration per server; the third-party credentials stay in Cameleer's configuration.
- One hash-chained audit log for local and remote calls, with the client's principal.
- Your rules on their tools: remote arguments are validated locally before anything is sent, destructive remote tools need approval, the kill switch and deduplication apply.
- Clients of either protocol era can use servers of either era.
Rug-pull protection
- Imported tools are pinned. If a server changes a tool's description, schema or annotations after it was imported, the change is refused and the tool is withdrawn, with the reason in the log.
- This stops a server that was trusted when it was added from rewriting a tool into an instruction for the model later.
- Tool lists re-sync on
list_changedand reconnects; a server that is down does not stop the integration.
The agent step uses remote tools with tools: mcp:github, and a route calls one without a model with to: mcp:github/create_issue. Details: MCP client and gateway and the mcp component.
How it is checked
- The official conformance suite (
@modelcontextprotocol/conformance0.1.16, pinned and checksum-verified) passes every scenario: 39 of 39 for 2025-11-25 and 26 of 26 for 2025-06-18. The suite predates 2026-07-28, so that era is covered by the hermetic tests. - Hermetic tests drive both eras over real HTTP and stdio connections, including approvals, subscriptions, authentication, the gateway and a tool that changes upstream.
- An end-to-end test starts the real
cameleerbinary as a stdio MCP server and has an agent step call one of its tools.
Measured on three identical cloud machines: 41,620 tool calls per second in MCP sessions in 53 MB, against 22,458 in 317 MB for Apache Camel's MCP server and 1,536 for a server written on the official TypeScript SDK; a tool call through the envelope costs 3 to 6 µs (the comparison).
Common questions
Which MCP clients work with it?
Any client of the Model Context Protocol: Claude Desktop, VS Code, Cursor and agent frameworks. Clients that start the server themselves use stdio (cameleer run tools.camel.yaml --mcp-stdio); others connect over Streamable HTTP at http://localhost:8080/mcp. Both the 2026-07-28 era and the 2025-11-25, 2025-06-18 and 2025-03-26 versions are served on the same endpoint.
Can I run the MCP server in Docker, on AWS Lambda or at the edge?
Yes. In Docker over HTTP (docker run -p 8080:8080 ... --mcp) or over stdio (docker run -i ... --mcp-stdio as the client's command); on AWS Lambda, where function URL and API Gateway requests for /mcp reach the MCP server in process; on Cloud Run, Knative and Kubernetes as a container; and on an edge gateway, next to the devices its tools control.
What happens when an agent retries a tool call?
A tool with side effects is deduplicated: a repeated call with the same call id (or, without one, the same principal and arguments within idempotencyWindow) returns the recorded result and the route does not run again. A repeat that arrives while the first call is still running waits for it.
How does a person approve a risky call?
A destructiveHint tool, or one with an approval rule such as ${header.amount} > 500, does not run until someone says yes. With an approvalEndpoint the call is parked and resolved out of band, for example with cameleer tool approve <handle>. Without one, the client's user is asked: an input_required result with a sealed requestState in 2026-07-28, an elicitation/create request in legacy sessions.
How do I withdraw a tool in production?
cameleer tool disable <name> against the running integration (or POST /q/dev/tools/{name}/disable on the dev console). The tool disappears from every list, its calls are refused, and connected clients get notifications/tools/list_changed.
Can Cameleer sit in front of other MCP servers?
Yes. With camel.ai.mcp.NAME.* it connects to remote MCP servers over HTTP or stdio, imports their tools into its registry and serves them again next to your own tools, with one authentication, one audit log, approvals for destructive remote tools and pinned definitions, so a server cannot change a tool under your clients.
Is the client's token passed to my routes?
No. The client's token is never passed to the routes or downstream. Tool routes see the authenticated principal in CamelMcpSecurityPrincipal and its scopes in CamelMcpSecurityPrincipalScopes; rate limits, approvals and the audit log use the same principal.
Run it
Clone the examples, then point an MCP client at the endpoint or the stdio command.
git clone https://github.com/pmsudhi/cameleer && cd cameleer/examples/agents cameleer run mcp-server.camel.yaml --mcp # or, without installing anything: docker run --rm -p 8080:8080 -v "$PWD:/routes:ro" pmsudhi/cameleer run /routes/mcp-server.camel.yaml --mcp