--mcp to the CLI speaks the Model Context Protocol over stdin/stdout instead of acting as an interactive CLI. Any MCP-aware client can connect, discover workflows, start runs, watch progress, resolve approvals, and revert bad attempts through structured tool calls.
Use the MCP server when an AI agent should drive Smithers autonomously. Use the HTTP Server for REST endpoints for human-written code or webhooks.
Setup
Start the server
--surface:
--surface raw only for direct CLI parity. Prefer the semantic surface for new integrations: every tool returns a { ok, data, error } envelope with Zod-validated input and output schemas.
Scope the semantic surface when a client should not receive every Smithers control tool:
--allowed-tools accepts a comma-separated list of semantic tool names. Passing an empty allowlist intentionally exposes no semantic tools. --read-only removes semantic tools with write or control side effects, such as starting runs, resolving approvals, or reverting attempts. With --surface both, these controls apply to the semantic toolset only; raw CLI-mirroring tools are still registered by the raw surface.
Register manually
For clients that read JSON config directly:smithers-orchestrator is in the local package.json):
If mcp add fails
bunx smithers-orchestrator mcp add hands the launch command to a registration helper that expects it as a single argument. If a runner or shell word-splits it, the helper sees a bare --mcp token and aborts:
-- separator tells the agent that everything after it is the launch command, so it never parses --mcp as one of its own flags:
<agent> mcp add <name> -- <command> shape. Or write the JSON or TOML config by hand using the snippets above. The Smithers CLI prints these fallback commands automatically whenever mcp add fails.
Tool Registration
On start, each tool is registered with its input schema, output schema, and MCP annotations. Every tool carries:inputSchema: Zod object describing accepted parameters.outputSchema: Zod schema for the structured response envelope.annotations: MCP annotation metadata (readOnlyHint,destructiveHint,idempotentHint,openWorldHint).
Structured tool envelope
Every tool returns the same shape:text content block, so clients that do not parse structuredContent still receive the JSON payload.
Tool annotations
| Annotation | Tools | Meaning |
|---|---|---|
readOnlyHint: true | Most query tools | Tool does not modify state |
readOnlyHint: false, openWorldHint: true | run_workflow | Launches external processes |
readOnlyHint: false, destructiveHint: true, idempotentHint: false | resolve_approval, revert_attempt, rewind_run, restore_checkpoint, time_travel | Mutates persisted state irreversibly |
readOnlyHint: false, idempotentHint: false | fork_run, replay_run | Creates new run/branch state |
Tool Reference
list_workflows
List all Smithers workflows discovered in the working directory. Input: none Output:id values as the workflowId parameter for run_workflow.
run_workflow
Start or resume a discovered workflow. Input:| Parameter | Type | Default | Description |
|---|---|---|---|
workflowId | string | required | Workflow ID from list_workflows |
input | Record<string, unknown> | {} | Workflow input object |
prompt | string | - | Shorthand: sets input.prompt when input is not provided |
runId | string | auto | Custom run ID |
resume | boolean | false | Resume an existing run; requires runId |
force | boolean | false | Force-start even if a run with this ID already exists |
waitForTerminal | boolean | false | Block until the run reaches a terminal state |
waitForStartMs | number | 1000 | For background launches, how long to wait for the run row to appear in the database |
maxConcurrency | number | - | Max concurrent nodes |
rootDir | string | - | Root directory for tool sandboxing and path resolution |
logDir | string | - | Directory for log files |
allowNetwork | boolean | false | Allow network access in bash tool |
maxOutputBytes | number | - | Cap on node output size |
toolTimeoutMs | number | - | Per-tool call timeout |
hot | boolean | false | Enable hot-reloading of the workflow file |
waitForTerminal: false) the tool fires the workflow and returns immediately with launchMode: "background". observedRun reflects the run state polled during waitForStartMs. Use watch_run to track progress.
Set waitForTerminal: true to block until the workflow finishes. result is populated and launchMode is "waited".
Run option forwarding
rootDir, logDir, allowNetwork, maxOutputBytes, toolTimeoutMs, and hot are forwarded verbatim to runWorkflow. They override values baked into the workflow file.
list_runs
List recent runs with summary data. Input:| Parameter | Type | Default | Description |
|---|---|---|---|
limit | number (1–200) | 20 | Max runs to return |
status | string | - | Filter by status (running, finished, failed, etc.) |
RunSummary fields: runId, workflowName, workflowPath, parentRunId, status, createdAtMs, startedAtMs, finishedAtMs, heartbeatAtMs, activeNodeId, activeNodeLabel, pendingApprovalCount, waitingTimers, countsByState.
get_run
Get the full detail record for a specific run, including steps, approvals, timers, loop state, lineage, config, and error. Input:| Parameter | Type | Description |
|---|---|---|
runId | string | Run ID |
watch_run
Poll a run at a fixed interval until it reaches a terminal state or a timeout expires. Input:| Parameter | Type | Default | Description |
|---|---|---|---|
runId | string | required | Run to watch |
intervalMs | number | 1000 | Poll interval (minimum enforced by runtime) |
timeoutMs | number | 30000 | Wall-clock budget before giving up |
timedOut is true the run is still active, so call watch_run again or raise timeoutMs. Terminal statuses: any status other than running, waiting-approval, waiting-event, or waiting-timer, including finished, failed, cancelled, and continued.
explain_run
Return a structured diagnosis explaining why a run is blocked, waiting, or stale. Input:| Parameter | Type | Description |
|---|---|---|
runId | string | Run ID |
summary is a human-readable sentence. blockers lists every node preventing progress; unblocker describes what action or event would unblock it.
list_pending_approvals
List approvals that are waiting for a human decision, optionally filtered by run, workflow, or node. Input: All parameters optional. Omit all to list every pending approval across all runs.| Parameter | Type | Description |
|---|---|---|
runId | string | Filter by run ID |
workflowName | string | Filter by workflow name |
nodeId | string | Filter by node ID |
resolve_approval
Approve or deny a pending approval. This tool is destructive and non-idempotent. Input:| Parameter | Type | Description |
|---|---|---|
action | "approve" | "deny" | required, decision to record |
runId | string | Filter to a specific run |
workflowName | string | Filter by workflow name |
nodeId | string | Filter by node ID |
iteration | number | Filter by loop iteration |
note | string | Optional note to record with the decision |
decidedBy | string | Identity of the decision-maker |
decision | unknown | Structured decision payload passed back to the workflow |
INVALID_INPUT. More than one match errors with INVALID_INPUT and returns matches in details.matches; add runId, nodeId, or iteration to narrow the selection. The tool never guesses when multiple approvals match.
Output:
ask_human
Block the current run and ask a human to make a decision, then wait for their answer. Use this whenever the agent is blocked, uncertain, missing information, or about to take an irreversible or destructive action, instead of guessing. The tool creates a durable, pending human request and returns only once it is resolved. When run inside a Smithers task, the run/node context is taken from theSMITHERS_RUN_ID / SMITHERS_NODE_ID / SMITHERS_ITERATION environment variables Smithers injects into the agent; pass runId/nodeId/iteration explicitly to override, or rely on single-active-run autodetection.
The orchestrating agent resolves the request on the human’s behalf: relay the question to the human in conversation, collect their decision, then run bunx smithers-orchestrator human answer <requestId> --value '<json>' (or bunx smithers-orchestrator human cancel <requestId>) yourself; never instruct the human to run these. bunx smithers-orchestrator human inbox lists everything waiting.
Input:
| Parameter | Type | Description |
|---|---|---|
prompt | string | required, the decision or question to put to a human |
context | string | Extra context appended to the prompt |
choices | string[] | Fixed choices; restricts the human’s answer to one of these |
runId | string | Run to attach to (default: SMITHERS_RUN_ID or the single active run) |
nodeId | string | Node to attach to (default: SMITHERS_NODE_ID) |
iteration | number | Loop iteration (default: SMITHERS_ITERATION or 0) |
timeoutSeconds | number | Seconds before the request expires (0/unset = no timeout) |
pollSeconds | number | Poll interval while blocking (default 3s) |
get_node_detail
Get enriched detail for a single node, including all attempts, tool calls, token usage, scorer results, and validated output. Input:| Parameter | Type | Description |
|---|---|---|
runId | string | required |
nodeId | string | required |
iteration | number | Loop iteration (default: latest) |
revert_attempt
Revert the workspace and frame history back to the state captured at a specific attempt. This is destructive and non-idempotent. Input:| Parameter | Type | Default | Description |
|---|---|---|---|
runId | string | required | Run containing the node |
nodeId | string | required | Node to revert |
iteration | number | 0 | Loop iteration |
attempt | number | required | Attempt number to revert to (must be ≥ 1) |
fork_run
Create a branched run from a time-travel snapshot checkpoint without starting it. Input:| Parameter | Type | Description |
|---|---|---|
parentRunId | string | Source run ID |
frameNo | number | Snapshot frame number |
resetNodes | string[] | Node IDs to reset to pending in the fork |
inputOverrides | Record<string, unknown> | Input fields to overlay on the snapshot input |
branchLabel | string | Optional branch label |
{ runId, parentRunId, parentFrameNo, branch, snapshot, run }
replay_run
Fork a run from a checkpoint for replay, optionally restoring VCS state. Resume the returnedrunId with run_workflow when needed.
Input: same as fork_run, plus:
| Parameter | Type | Default | Description |
|---|---|---|---|
restoreVcs | boolean | false | Restore the working copy to the source frame revision |
cwd | string | - | Working directory used for VCS restore |
{ runId, parentRunId, parentFrameNo, branch, snapshot, vcsRestored, vcsPointer, vcsError?, run }
rewind_run
Rewind a run to a previous frame, deleting later frames and invalidating derived state. This is destructive and requiresconfirm: true.
Input:
| Parameter | Type | Description |
|---|---|---|
runId | string | Run to rewind |
frameNo | number | Target frame number |
confirm | boolean | Must be true |
{ result, run }
restore_checkpoint
Restore the worktree to a durability checkpoint for a node. Ifseq is omitted, the latest matching checkpoint is used.
Input:
| Parameter | Type | Description |
|---|---|---|
runId | string | Run containing the checkpoint |
nodeId | string | Node whose checkpoint should be restored |
iteration | number | Optional loop iteration |
seq | number | Optional checkpoint sequence |
{ runId, nodeId, iteration, seq, commitId, cwd, success, error? }
list_snapshots
List durability workspace checkpoints for a run with matching VCS operation IDs when available. Input:{ runId: string }
Output: { snapshots: Array<{ seq, nodeId, iteration, attempt, tier, source, label, commitId, operationId, cwd, createdAtMs }> }
get_timeline
Return the time-travel timeline for a run, optionally including all child forks recursively. Input:| Parameter | Type | Default | Description |
|---|---|---|---|
runId | string | required | Run ID |
tree | boolean | false | Include child forks recursively |
{ timeline: unknown }
time_travel
Reset a run back to a prior node attempt and optionally restore VCS state. If the run is still marked running, passforce: true.
Input:
| Parameter | Type | Default | Description |
|---|---|---|---|
runId | string | required | Run ID |
nodeId | string | required | Node to travel back to |
iteration | number | 0 | Loop iteration |
attempt | number | latest | Attempt number |
restoreVcs | boolean | true | Restore filesystem state |
resetDependents | boolean | true | Reset dependent nodes too |
force | boolean | false | Allow time travel when the run is still running |
{ result, run }
list_artifacts
List structured output artifacts produced by nodes in a run. Input:| Parameter | Type | Default | Description |
|---|---|---|---|
runId | string | required | Run ID |
nodeId | string | - | Limit to a specific node |
includeRaw | boolean | false | Include raw (pre-validation) output values |
outputTable and a non-none output source are included.
get_chat_transcript
Return the structured agent chat transcript for a run, grouped by attempts. Input:| Parameter | Type | Default | Description |
|---|---|---|---|
runId | string | required | Run ID |
all | boolean | false | Include all attempts, not just those with known output events |
includeStderr | boolean | true | Include stderr messages |
tail | number | - | Return only the last N messages |
timestampMs. Use tail to limit context window usage on long transcripts.
get_run_events
Return the raw structured event history for a run with optional filtering. Input:| Parameter | Type | Default | Description |
|---|---|---|---|
runId | string | required | Run ID |
afterSeq | number | - | Only events with seq greater than this value |
limit | number (1–10000) | 200 | Max events to return |
nodeId | string | - | Filter to events for a specific node |
types | string[] | - | Filter to specific event types (e.g. ["NodeFinished", "NodeFailed"]) |
sinceTimestampMs | number | - | Only events at or after this timestamp |
afterSeq: pass the seq of the last received event to fetch the next page.
Usage Examples
List workflows and start a run
Watch until complete
Resolve a pending approval
Debug a blocked run
Revert a failed attempt
Error Codes
Errors follow the structured envelope. Common codes:| Code | Meaning |
|---|---|
RUN_NOT_FOUND | No run or workflow exists with the given ID |
INVALID_INPUT | Missing required field, failed validation, or ambiguous approval filter |
WORKFLOW_MISSING_DEFAULT | Workflow file has no default export |