Skip to content

MCP

threadle speaks MCP in two directions.

DirectionWhat you getEntry
ServerHosts (Claude Code, Cursor, …) call your saved workflows as toolsthreadle mcp
ClientA canvas node calls one tool on one discovered server (stdio · HTTP · SSE)◈ MCP tool

Repo copy (Markdown + examples): docs/mcp.md · examples/mcp/


Stdout is the MCP JSON-RPC channel. Logs go to stderr.

Terminal window
threadle mcp
FieldSource
Namewf_<graphId>
TitleGraph name
inputSchemaGraph.params (text · int · float · bool · json)
ResultConcatenated ⇤ output node text

Subgraphs are skipped. Calls run with approveAll: false. Workflows that need interactive splice (approval / live handoff) must be run in the UI, not via MCP.

Which workflows appear is controlled by Settings → MCP → publish allowlist: empty / unset = none (default). null = all saved workflows.

Terminal window
threadle run examples/workflows/mcp-brief.json
threadle graphs # note the id

mcp-brief is agent-free: one topic param → markdown brief → output. Ideal for first host calls.


{
"mcpServers": {
"threadle": {
"command": "threadle",
"args": ["mcp"]
}
}
}

Same shape. Reload MCP in the host after saving.

After curl install or npx threadle, command: "threadle" is enough. From a clone without a global binary:

{
"mcpServers": {
"threadle": {
"command": "npx",
"args": ["tsx", "packages/server/src/cli.ts", "mcp"],
"cwd": "/absolute/path/to/threadle"
}
}
}
VariableEffect
THREADLE_CONFIG_DIRGraphs root (default ~/.config/threadle. Windows %USERPROFILE%\.config\threadle)
THREADLE_MCP_PROJECT_DIRProject dir for agent CLIs inside tools (default cwd of the MCP process)

  1. Save a workflow with params for anything the model should fill (≔ on the canvas).
  2. Put at least one ⇤ output on the graph. That text is the tool result.
  3. Fix detached blockers (models on agents, context with a session or Library payload, …). Gates auto-approve under MCP.
  4. Reload MCP → ask the model to list tools → call wf_<id> with args matching param names.

CLI equivalent of one call:

Terminal window
threadle run <graphId> --param topic="…" --approve-all
SituationBehavior
Nested threadle mcp (THREADLE_MCP_DEPTH ≥ 1)Refused
Same graph already on the call stackRefused
Publish allowlist empty (default)No wf_* tools until you list graph ids (or set null / * for all)
Publish allowlist setOnly listed graph ids become wf_* tools
Hard readiness errorsTool fails with the readiness message

Drop MCP tool from the Nodes palette (or the wire-drop menu).

  1. Inspector → server (discovered locally) → tool.
  2. Optional arg port. Inbound text fills that argument name.
  3. Param fields follow the tool’s JSON Schema properties.
  4. Wire prompt → MCP tool → output (or into an agent) → ▶ Run.

First match wins (project → threadle registry → user hosts):

Path
<project>/.mcp.json (walks up to the git root. Monorepo-safe)
<project>/.cursor/mcp.json (same walk-up)
project opencode.json (same walk-up)
~/.config/threadle/mcp/servers.json (threadle-owned registry)
~/.cursor/mcp.json
~/.claude.json (mcpServers)
~/.config/opencode/config.json / opencode.json
~/.gemini/config/mcp_config.json (Antigravity)
<project>/.codex/config.toml · ~/.codex/config.toml (mcp_servers)
TransportConfig shape
stdiocommand + optional args / env / cwd
streamable-httpurl (optional headers). Bare url without a type defaults here
sseurl or serverUrl with type / transport: "sse"

Unix sockets / WebSockets are not supported.

Example registry entry (~/.config/threadle/mcp/servers.json):

{
"mcpServers": {
"docs": {
"url": "https://example.com/mcp",
"headers": { "Authorization": "Bearer …" }
}
}
}
ControlEffect
MCP client off/onWhen off, canvas discovery and /api/mcp/call refuse
disable / enable per serverHides that id from the client. The Settings list still shows it
publish allowlistGraph ids for threadle mcp as wf_*. One per line or comma-separated. Empty = none. null = all
⌘ registryOpens ~/.config/threadle/mcp/

Spawned stdio servers get the same allowlist as custom nodes (PATH, HOME, locale, temp dirs, …), then the server’s own env from .mcp.json. The threadle process’s secrets are not copied wholesale. Declare tokens in the config when a server needs them. HTTP/SSE remotes use optional headers instead.

  1. Copy examples/mcp/mcp.json.echo.example into your project .mcp.json, fixing the path to echo-server.mjs.
  2. threadle --dir <that-project>
  3. Clone Hello MCP from examples, or MCP tool node → server echo → tool echo → set arg port message → run.

Child stderr from stdio servers shows in the Run log (prefixed ◈ <server>:). Stdout stays the MCP protocol channel.

Calling threadle’s own MCP from the canvas is fine. Calling it from inside a workflow that was started via threadle mcp is refused (depth guard).


MethodPath
GET/api/mcp/servers. Discovered list (transport, disabled, registry paths)
GET/api/mcp/servers/:id/tools
POST/api/mcp/call. { server, tool, args?, params?, projectDir? }