Skip to main content
The tool node calls a single integration action — one tool such as github.create_issue or tavily.web_search — with parameters you control, then writes the action’s result into run state under the node’s own id. Use it when you want a deterministic, single-purpose step: you pick the integration, the action, and exactly what goes in. For a step where a language model decides which tools to call and loops over them, use the agent node instead. ModuleX exposes 600+ tools across 175 integrations. Browse them in the integrations overview and the catalog. To call a tool you have not configured yet, first connect the service — see connect an integration and managing credentials.

What the node does

When the engine compiles your workflow, the tool node becomes a single async step (workflow engine). At run time the node:
  1. Resolves input_mapping against the current run state, replacing every {{...}} token with its resolved value. Keys whose resolved value is null or an empty string are dropped from the call.
  2. Loads the tool for tool.integration_name + tool.service_name, scoped to your organization, and resolves a credential (see credential resolution).
  3. Invokes the action. The credential and auth data are injected for you — they never appear in your input_mapping.
  4. Records per-action usage for billing (managed credentials only — see credit impact).
  5. Unwraps the action’s result and writes it into run state under the node’s id (see inputs & outputs).
Each tool node runs the action exactly once per run. When several tool nodes run in parallel, each invocation gets its own isolated database session so concurrent calls do not interfere.
The output of a tool node is always stored in run state under the node’s id — for example a node with id: "create_issue_1" writes to {{create_issue_1}}. The legacy output_key field is deprecated and ignored; do not rely on it. See inputs & outputs.

Configuration (ToolNodeConfig)

These fields live on the node’s tool_config. In the builder you set them through the detail panel; over the API they appear inside the node definition (the builder also accepts a wrapped {config: {...}} form, which the backend normalizes to tool_config).
ToolDefinition object
required
The action to call. Required. Selects the integration, the action, an optional credential, and optional parameter values. See the tool object below.
object
default:"{}"
A map of action-parameter name to value. Each value may be a literal or a {{node_id.field}} reference; references resolve against run state at run time. This is the primary way to feed data into the action. Keys whose resolved value is null or "" are skipped. See feeding parameters.
string
deprecated
Deprecated. Output is always stored under the node id. This field is ignored.

The tool object

The tool field is a ToolDefinition. It identifies which integration action to call and, optionally, which credential and which baseline/forced parameter values to apply.
string
required
The integration on the wire, for example github, tavily, or slack. Required. Use the literal mcp_server to call a tool from a custom MCP server. Browse names in the catalog.
string
required
The action (service) name within the integration, for example create_issue, web_search, or send_message. Required. In ModuleX the action name and the underlying tool function name are the same string. For an MCP server, this is the MCP tool name. See available actions.
string
A specific stored credential to use for this call. Optional. If omitted, ModuleX resolves a credential for the integration in the current organization (see credential resolution). Required when integration_name is mcp_server, where it points at the MCP server credential.
object
Baseline parameter values, applied as a base layer beneath caller-supplied values. Optional. Supports {{node_id.field}} references. On the tool node these are intended as deterministic defaults that fill parameters you do not provide elsewhere. (On the agent node, only parameter_defaults apply — the model’s chosen arguments win, and defaults fill what the model omitted.)
object
Forced parameter values, intended to be applied regardless of other values. Optional. Supports {{node_id.field}} references. The tool node is the node type that exposes overrides; the agent node ignores them. Use overrides to pin a parameter that must not vary — for example forcing a fixed repo or channel.
The tool node is the only node type whose ToolDefinition is meant to use both parameter_defaults and parameter_overrides (the agent node uses defaults only). In current source, however, the tool-node execution path applies only input_mapping to the action and does not visibly merge parameter_defaults/parameter_overrides before invoking. Until that is confirmed, put the values you depend on in input_mapping rather than relying on the parameter fields alone.

Retry configuration

The tool node is retry-wrapped. You can attach a retry_config to the node definition itself (not inside tool_config) to control how a failed action is retried. If you omit it, the engine applies its default retry policy. Errors are only retried when their type is in retry_on_error_types.
integer
default:"3"
Total attempts including the first. Range 1–10. 1 means no retry.
number
default:"1.0"
Seconds to wait before the first retry. Range 0.1–60.
number
default:"2.0"
Multiplier applied to the delay between successive retries (exponential backoff). Range 1–5.
string[]
Exception type names that trigger a retry. Errors not in this list fail immediately. A credit-exhaustion stop is not retried.
See error handling & retries for how retries surface in the run stream.

Feeding parameters

You provide the action’s parameters through input_mapping. Each entry maps an action-parameter name to a literal value or a {{...}} reference:
input_mapping
Resolution rules (the same model used everywhere — see variables & references):
  • A value that is exactly {{node_id.field}} keeps its native type (string, number, object, or array).
  • A reference embedded in surrounding text is string-substituted; objects and arrays are JSON-encoded into the string.
  • {{node_id}} resolves to an upstream node’s whole output; {{node_id.field}} resolves a nested value by dot/bracket path, for example {{search_1.results[0].url}}.
  • An out-of-range index or missing key resolves to nothing; the reference is left intact in any string it appears in.
  • Keys whose resolved value is null or "" are dropped from the call (so an unresolved optional parameter does not send an empty value).
You never put credentials or auth fields (such as api_key, token, access_token) in input_mapping. ModuleX strips those from the action’s caller-facing schema and injects the resolved credential internally before calling the action. See credential resolution.

Available actions

Each integration exposes a fixed set of actions, each with its own parameters and output shape. Find them on the integration’s catalog page in the catalog, or programmatically with the list integrations endpoint. An action’s parameters are declared by the integration’s manifest contract; see manifest & schema contract and the @tool function contract.

Credential resolution

A tool node needs a credential for its integration. You can pin one with tool.credential_id, or let ModuleX resolve one for the organization. When credential_id is omitted, resolution is:
1

Explicit credential

If tool.credential_id is set, that credential is used (it must belong to the organization and match the integration).
2

Default credential

Otherwise the integration’s default credential for the organization (the one marked default) is used.
3

Any valid credential

Otherwise any valid credential for the integration is used — preferring your own connected credentials over the ModuleX-managed key, newest first.
What ModuleX does with the resolved credential, by auth type:
  • It decrypts the stored auth data, scoped to your organization and that credential.
  • For OAuth2 credentials, it refreshes the access token automatically if it expires within five minutes, then persists the refreshed token.
  • It injects the right field for the auth type (access_token for OAuth2, token for bearer auth, api_key for API-key and managed keys), plus any other stored fields the action declares (for example a project_id or base_url entered once when you created the credential).
For how credentials are created, scoped, and encrypted, see authentication & credentials, credentials & OAuth2, and data security & encryption.
Token reconnection during a run resolves through the stored credential. The app’s manual OAuth2 refresh button is a known limitation — when a credential cannot be refreshed, reconnect the integration rather than relying on that button.

Custom MCP tools

A tool node can call a tool from an external Model Context Protocol (MCP) server you have connected, instead of a built-in integration. Set the node’s tool.integration_name to the literal mcp_server and point tool.credential_id at your MCP server credential:
MCP tool definition
How it differs from a catalog integration:
  • tool.credential_id is required — the MCP server’s URL, headers, and transport are stored on that credential, not in the catalog.
  • tool.service_name is the MCP tool’s name as advertised by your server; ModuleX connects to the server, lists its tools, and selects the one that matches.
  • Responses are parsed back into structured data so an MCP tool’s output reads like a built-in tool’s output.
Connect an MCP server before referencing it here — see custom MCP servers for the credential fields (server URL, headers, transport) and setup.

Inputs and outputs

Inputs

The tool node has no fixed input fields of its own. Its inputs are the action’s parameters, supplied through input_mapping (and the optional tool.parameter_defaults / tool.parameter_overrides). Reference upstream values with {{node_id}} and {{node_id.field}}. See feeding parameters and variables & references.

Outputs

The node writes one value into run state under its id. ModuleX unwraps the action’s envelope: actions return a wrapper shaped like {success, action, result: {...}}, and the node flattens the inner result fields up to the top level so you can reference them directly without a .result. segment.
object
The unwrapped action output.
Concretely, a github.create_issue action returns:
action output (before unwrapping)
A downstream node can read {{create_issue_1.issue.number}} or {{create_issue_1.success}} directly.

Streaming

A tool node streams at the node level over SSE. When the action finishes, the engine publishes a node_update event carrying the node’s unwrapped output. On the wire this event is flat and uses the keys node and output — for example {type, node, output} — not the typed model field names. The run then continues to the next node and ends with a done event.
The realtime wire dicts differ from the typed event models: the node_update frame uses node and output, and done carries only a message. Parse each SSE frame as JSON and switch on its type field — there is no SSE event: line. See SSE run streaming.

Credit impact

There is no fixed per-node credit charge decided by the node type. A tool action is metered per call, and whether it costs credits depends on the credential:
  • ModuleX-managed key — the call is charged a flat per-action cost in credits. The base is 1 credit per action (anchored to 0.01at100credits=0.01 at 100 credits = 1.00), multiplied by a per-integration multiplier (default 1.0). So a typical managed action costs 1 credit; some integrations carry a higher multiplier. Managed-key calls are also subject to the monthly credit limit — when the plan budget is exhausted and wallet overage is unavailable, the call is denied.
  • Your own connected credential (BYOK) — usage is recorded for analytics, but no credits are charged; you pay the upstream provider directly with no ModuleX markup.
Usage is logged for both successful and failed managed calls. Logging is best-effort: if writing the usage record fails, the tool call is not failed because of it.
Workflow run, Composer, Assistant, and managed-knowledge surfaces are gated by the billing admission gate, which can return a DenialEnvelope as 402 / 403 / 429. The flat envelope shape is {code, layer, key, current, limit, reason}. See errors & status codes and usage gating & limits.
The workflow run goes through the usage gate, which admits the run before it starts. Once a run is executing the gate is best-effort: if a managed tool call cannot be billed because credits are exhausted, the node’s error event carries a stable reason token (credit_exhausted) so clients can detect a budget stop deterministically — see errors.

Errors

The tool node surfaces failures through the run’s node-error event after retries are exhausted. The underlying tool runtime raises (it does not return an error envelope), and the engine lets these fail the node:
A tool node with no tool_config fails compilation with Tool node <id> missing tool_config. Ensure the tool object with integration_name and service_name is set.
If the integration or action cannot be loaded — an unknown integration_name/service_name, or an MCP server that returns no matching tool — the node fails with Failed to load tool: <integration>.<action>. Check the names against the catalog and, for MCP, that the credential and tool name are correct.
If no credential exists for the integration in your organization, the runtime raises a no-credential error and the node fails. Connect the integration first — see authentication & credentials and managing credentials.
If a managed-key call cannot be billed because the monthly credit budget is exhausted and no wallet overage is available, the runtime raises a credit-limit error whose stable code is credit_exhausted; the node’s node_error event carries it as reason. Resolve by topping up the wallet or upgrading your plan. BYOK credentials are not credit-limited.
A decryption or OAuth2-refresh failure surfaces as a tool execution error and fails the node. Reconnect the affected integration. The app’s manual OAuth refresh control is a known limitation.
Any error the action itself raises (a 4xx/5xx from the upstream service, a validation failure, an unexpected exception) surfaces as a tool execution error. Provider/network errors are retried per retry_config; when retries are exhausted the node emits a node_error event with error_type, error_message, the attempt count, and recoverable: false, then the run fails. See error handling & retries.
For the full taxonomy of error-envelope shapes and which surface emits each, see errors & status codes.

Full example

A two-node workflow: an upstream llm node triages an incoming message into a structured object, and a tool node opens a GitHub issue from it. The first tab is the tool node definition; the remaining tabs run a deployed workflow that contains it. Running a workflow is asynchronous: the run call returns immediately with run metadata (status is running), and you observe node output by streaming events. The created issue arrives on the node_update event for create_issue_1. See SSE run streaming and run a workflow.
Every request authenticates with Authorization: Bearer mx_live_… plus X-Organization-ID. See authentication and the run-a-workflow guide.

Agent node

When a model should decide which tools to call and loop, not a fixed single action.

Integrations overview

Connect services and browse the 600+ tools across 175 integrations.

Custom MCP servers

Connect an external MCP server and call its tools from a tool node.

Variables & references

How {{node_id.field}} references resolve against run state.