Cameleer

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.

1 commandcameleer run tools.camel.yaml --mcp, or --mcp-stdio for clients that start the server
2 erasMCP 2026-07-28 and 2025-11-25 (also 06-18 and 03-26), on one endpoint
39 / 39scenarios of the official conformance suite for 2025-11-25; 26 / 26 for 2025-06-18
Camel's namesai-tool options and camel.server.mcp-* properties as in Apache Camel

A 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 /mcp reach 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.

stepwhat it doesoption
Kill switcha withdrawn tool is not listed and its calls are refusedcamel.ai.disabled-tools, cameleer tool disable
Authorizationa policy bean or a Simple predicate over the arguments and the caller may refuse the call; the reason goes back to the modelauthorizationPolicy, authorize
Argumentscamel* and undeclared arguments are dropped; the rest is validated against JSON Schema 2020-12, and the error names each field and shows valid argumentsparameter.*, argSchema
Rate limitcalls per principal per periodrateLimit, rateLimitPeriod
Circuit breakerafter repeated failures the model gets a fallback text and the route does not runcircuitBreakerThreshold
Approvaldestructive or matching calls wait for a persondestructiveHint, approval, approvalEndpoint
Idempotencya retried call returns the recorded result; a repeat that arrives during the first call waits for itidempotency, idempotencyWindow
Compensationthe undo step is registered before the call; if the conversation fails later, undo steps run newest firstcompensation
Timeoutwhen the caller stops waiting, the tool's route is cancelled before its next steptimeout (default 20 s)
Resultobjects 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 logoutputSchema, redact, cacheTtl
Auditone hash-chained record per call: digests of arguments and result, the decision, the approver, the duration. An edited, removed or reordered record fails verificationcamel.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 deny runs nothing.
  • In band, 2026-07-28. The result is input_required with an elicitation/create form and a requestState sealed 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/create on the call's response stream (HTTP) or on stdout (stdio).
  • A client that did not declare the elicitation capability gets -32021 and the call does not run.

Running it

  • cameleer tool list, disable, enable, approvals, approve, deny against a running integration; GET /q/dev/tools on 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_changed and 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/conformance 0.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 cameleer binary 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