Cameleer

MCP component

The mcp component calls a remote MCP server from a route: call one of its tools, list its tools, read a resource or get a prompt. A tool call goes through the local ai-tool envelope, so arguments are checked, destructive tools wait for approval and every call is audited.

Scheme: mcp: · Crate: cameleer-ai · Cargo feature: ai · Consumer: no · Producer: yes · Apache Camel: none (Cameleer extension)

When to use it

  • Call a tool of a third-party MCP server (GitHub, a file server, an internal service) from an ordinary route, without a model in between.
  • Read a resource or a prompt that an MCP server publishes.
  • Check what a server offers, for example in a health check or a startup route.

To let a model call these tools, you don't need this component: the tools of a configured server are already in the tool registry, see MCP client.

URI format

text
mcp:SERVER/TOOL[?options]
mcp:SERVER[?options]

SERVER is the name of a client configured with camel.ai.mcp.SERVER.* (see MCP client: configuration). TOOL is the tool's name on the remote server, without the local prefix. mcp:SERVER/TOOL calls the tool; mcp:SERVER lists the server's tools.

Example

The server github is configured in the properties:

properties
camel.ai.mcp.github.url=https://mcp.example.com/github
camel.ai.mcp.github.bearerToken={{env:GITHUB_TOKEN}}

A route that opens an issue for each failed build. The body is the tool's arguments, as JSON:

yaml example: mcp-call-tool
- route:
    from:
      uri: direct:build-failed
      steps:
        - setBody:
            simple: '{"repo": "acme/shop", "title": "Build ${header.buildId} failed"}'
        - to: mcp:github/create_issue
        - choice:
            when:
              - simple: "${header.CamelMcpIsError} == true"
                steps:
                  - to: log:mcp-errors

Reading a resource and getting a prompt:

yaml example: mcp-resource-prompt
- route:
    from:
      uri: direct:readme
      steps:
        - setHeader:
            name: CamelMcpResourceUri
            constant: repo://acme/shop/README.md
        - to: mcp:github?operation=readResource
- route:
    from:
      uri: direct:review-prompt
      steps:
        - setBody:
            constant: '{"pr": "42"}'          # the prompt's arguments
        - to: mcp:github?operation=getPrompt&prompt=review_pr

Options

optiondefaultdescription
operationcallTool with a tool, else listToolscallTool, listTools, readResource or getPrompt
toolNameThe tool, instead of /TOOL in the path
urireadResource: the resource's URI when the CamelMcpResourceUri header is not set
promptgetPrompt: the prompt's name (required)
directfalsecallTool: send the call straight to the server and skip the local envelope

Message headers

headerdirectiondescription
CamelMcpResourceUriinreadResource: the resource to read; it wins over uri=
CamelAiToolCallIdincallTool: the call id (the idempotency key)
CamelAiToolConversationIdincallTool: the conversation, for compensation
CamelAiToolPrincipalincallTool: who the call is made for (rate limits, audit)
CamelMcpIsErroroutcallTool: true when the tool failed or the call was refused
CamelAiToolStatusoutcallTool through the envelope: completed, error, approval-required or denied
CamelAiToolContentoutcallTool with direct=true: the content blocks, when the result has more than text

Behavior

Calling a tool

The body is the arguments: a JSON object as text, or a map. Any other body sends no arguments ({}).

When the server's tools were imported (they are, unless include or exclude left this one out), the call goes through the local envelope of the imported tool PREFIX + TOOL (github_create_issue by default). That means the arguments are validated against the remote schema before anything is sent, a destructive tool waits for approval, a repeated call with side effects runs once, and the call is written to the audit log. See ai-tool: a call, step by step. Refusals and failures don't raise an exception: the body is the error text and CamelMcpIsError is true.

With direct=true, or when the tool was not imported, the call goes straight to the server. A result with isError sets CamelMcpIsError=true and keeps the text as the body.

After the call, the body is the structured result (structuredContent) when the server sent one, otherwise the text blocks joined by newlines.

The other operations

  • listTools sets the body to a list of {name, description, inputSchema} maps, following pagination. The names are the remote ones, without the local prefix.
  • readResource sets the body to the text of the resource's contents, joined by newlines. If any part is binary, the body is the list of content items as the server sent them.
  • getPrompt sends the body as the prompt's arguments and sets the body to the prompt's list of messages.

Errors

  • An unknown server fails with IllegalStateException: No MCP client named github (configure camel.ai.mcp.github.url or .command).
  • A JSON-RPC error from the server fails the exchange with the kind org.apache.camel.component.mcp.McpException, and the message names the server and the error code. Connection failures are I/O errors.
  • A server that answers a call with input_required (2026-07-28) or asks for elicitation is refused: Cameleer has no user to ask on that connection.
  • MCP client: configuring servers, importing their tools, and the gateway.
  • ai-tool: the envelope the calls go through.
  • MCP server: serving tools to MCP clients.

Found a problem?

If something on this page doesn't match what Cameleer does, please open an issue, or fork the repository, fix it, add a test, run cargo test --workspace and open a pull request.

Edit this page on GitHub