Each agent only sees the MCP tools from its own declared servers.
MCP connections are created once at startup, not per request. If a server is unreachable, the engine logs a warning and continues — local tools still work.
Tags are sent as the X-MCP-Tool-Tag header during tool discovery. The server filters — the engine binds only what comes back. The LLM never sees the tags.Multiple tags are sent comma-joined: X-MCP-Tool-Tag: orders,returnsCustom transport — if your server expects a different header or a query param, tool_tag_transport supports two types:
type
Where the tag goes
Required field
header
A custom request header
header_name
query_param
A query string parameter on the MCP url
param_name
mcps: legacy_api: url: "https://legacy.acme.com/mcp" tool_tags: ["v2"] tool_tag_transport: type: query_param param_name: "tag" # result: ?tag=v2 appended to the URL
Declare a tool with a description. That description is what the LLM uses to decide whether to call it.
tools: get_order_status: description: "Get the current status and tracking info for an order. Requires an order ID." create_return: description: "Open a return request for a delivered order. Requires order ID and reason." send_notification: description: "Send an email or SMS notification to the customer."
Run generate (see Quickstart) to create stubs. Then fill in the logic:
# plugins/tools/get_order_status.pydef get_order_status(order_id: str) -> dict: """Get the current status and tracking info for an order. Requires an order ID.""" # your business logic here return { "status": "shipped", "tracking_number": "1Z999AA10123456784", "estimated_delivery": "2026-07-05" }
The docstring becomes the tool description the LLM sees. The engine wraps the function automatically.
Write clear descriptions and typed parameters. The LLM reads both when deciding how to call a tool. Vague descriptions lead to wrong or missed tool calls.
Both are Python code. The difference is when they run and who calls them.
Resolver
Tool
Called by
Engine (always, before the node runs)
LLM (when it decides to)
Visible to LLM
No
Yes (name + description)
Token cost
None
Yes
Purpose
Fill {{variables}} in prompts
Perform actions on request
Use a resolver for context the prompt always needs: current date, user name, account info.Use a tool for actions the user may or may not need: look up an order, create a return, send a message.
Every tool call is tracked in the run result — agent, tool name, provider (local or MCP), success or failure, latency. You can see this in logs and in Langfuse if tracing is enabled.