跳转到内容

Tool Node

此内容尚不支持你的语言。

The tool node invokes a tool exposed by a registered MCP connector — an external server implementing the Model Context Protocol. This is the standard way to call out to your own systems (looking up records, checking availability, fetching live data) once you’ve registered an MCP server as a connector.

For registering a connector, discovering its available tools, and known limitations of that side of the integration (schema drift, argument-splicing constraints, and so on), see MCP Connectors — this page covers only the workflow-node side: how to configure a tool node once a connector already exists.

See Workflows Overview for how this node type fits into the broader node/edge model.

ToolNodeConfig:

FieldTypeRequiredDescription
connectorIdnumberYesThe ID of the MCP connector to call, scoped to your tenant.
toolNamestringYesWhich tool on that connector’s MCP server to invoke.
argsTemplatestringNoA Handlebars-templated JSON string providing the tool’s call arguments. Values can reference context variables set by earlier nodes (for example, an LLM node’s extracted outputVar). Rendered with the same escaping used for webhook body templates and action argument templates.
outputVarstringYesThe context variable the tool’s result is stored in — the flattened, plain-text form of the tool’s response. See Workflow Best Practices for the structured (_{outputVar}Structured) form also written alongside it, and how to avoid leaking a raw JSON tool response into the chat reply.
timeoutMsnumberNoRequest timeout in milliseconds. Defaults to 10000 (10 seconds).

An appointment-scheduling workflow that has already extracted a requested date into requestedDate, then checks availability via an MCP-registered scheduling tool:

{
"id": "check_availability",
"type": "tool",
"label": "Check Appointment Availability",
"config": {
"connectorId": 12,
"toolName": "check_availability",
"argsTemplate": "{\"date\": \"{{requestedDate}}\", \"durationMinutes\": 30}",
"outputVar": "availability_result",
"timeoutMs": 8000
},
"position": { "x": 250, "y": 200 }
}

The result then feeds a response node:

{
"id": "respond_availability",
"type": "response",
"label": "Respond with Availability",
"config": {
"messageTemplate": "Here's what I found for {{requestedDate}}: {{availability_result}}",
"mood": "helpful"
},
"position": { "x": 350, "y": 200 }
}

By default, every edge leaving a tool node fires unconditionally once the node finishes — regardless of whether the underlying MCP call succeeded. You can opt a tool node into a two-port routing pattern instead, exactly like a condition node’s true/false pair: draw one edge labeled success and one labeled failure out of the node (in the Workflow Editor UI, toggle “Add success/failure branch” on the node’s card toolbar to get the two colored handles).

  • If a failure edge exists and the tool call throws (a timeout, a connection failure, an MCP schema-drift error, a malformed argsTemplate), the runner routes to that edge instead of failing the whole run. The failure message is written to a _lastNodeError context variable a downstream node can reference.
  • A failure edge requires a matching success edge on the same node — publishing a workflow with one but not the other is rejected with a validation error.
  • A node with neither label keeps today’s behavior exactly: every outgoing edge fires unconditionally, and an unhandled failure still fails the run.
  • This is purely about “did the network call succeed” — it’s unrelated to and doesn’t affect any session-identity/authorization outcome an action node might separately expose via an ${outputVar}Status variable.
  • argsTemplate has zero schema awareness. Nothing validates it against the connector’s actual MCP tool schema, either at workflow-save time or at execution time. If the external MCP server later renames a field or adds a new required one, nothing here will notice — you have to update argsTemplate yourself. See MCP Connectors for more on this.
  • Never point argsTemplate at a bare "{{someVar}}" where someVar already holds a whole pre-serialized JSON string. The templating engine escapes every interpolated value as a plain scalar being inserted inside quotes you’ve already written — pointing it at a value that’s already JSON-shaped double-escapes the whole thing and fails JSON.parse() on every call. Have an extraction LLM node output plain scalar values into separate variables, and write the JSON structure yourself in argsTemplate, referencing each scalar inside quotes you’ve already placed.
  • There’s no way to splice a variable-length array into argsTemplate today. If a tool argument accepts an array (for example, several selected categories) and the user’s message names more than one, there’s no supported templating construct for that — an LLM node’s outputVar is always raw text, never a parsed array. The practical workaround is branching to parallel single-value tool calls (one per selected value) and merging the results in a downstream LLM node before phrasing the reply.
  • For “match this human value to an internal id” lookups, don’t use an LLM node — use the findId template helper instead. Asking an LLM to find the matching entry in an array and output its id is unreliable in a specific, dangerous way: it tends to confuse a different field’s own digits (a code, an ISBN) for the real id. findId performs the lookup deterministically with no LLM involved: {{findId <arrayVariable> "<matchField>" <matchValueVariable> "<idField>"}}, referencing an earlier tool node’s structured result (exposed as _{outputVar}Structured). See Workflow Best Practices for the full pattern and worked example.
  • timeoutMs defaults to 10 seconds — raise it for a connector you know is slow, but keep in mind a long-blocking tool call delays the whole conversation turn.
  • The MCP connector’s serverUrl is now re-validated on every call, not just when the connector is registered (as of 2026-09-08). Previously an MCP connector’s SSRF check only ran when it was created/updated — a hostname that resolved to a public address at registration time but was later repointed at a private one (DNS rebinding) was never re-checked. Every tool node call now re-validates before dispatching, and redirects on the underlying HTTP transport are re-validated hop-by-hop rather than followed blindly.
  • When a tool call fails, the real error is not shown to the user — the conversation gets a generic reply, but the underlying error (a JSON parse failure, an HTTP error from the connector) is available in the workflow run’s node trace and in a live NodeFailedEvent on the session subscription.
  • To see exactly what argsTemplate actually rendered to, check renderedRequest on this node’s nodeTrace entry — captured on both success and failure. See Observability & Debugging Your Agent for the full nodeTrace shape.