nodetool-mcp serve starts NodeTool as a Model Context Protocol (MCP) server over stdio. A harness such as Claude Code, Codex, or OpenCode launches it and calls the tools below. The desktop app is optional.
npx -y @nodetool-ai/cli-mcp install
The command writes this entry into each client it finds (Node.js 22 or later):
{
"mcpServers": {
"nodetool": {
"command": "nodetool-mcp",
"args": ["serve"]
}
}
}
A tool call the harness then sends:
{
"jsonrpc": "2.0", "id": 2, "method": "tools/call",
"params": { "name": "search_nodes", "arguments": { "query": ["resize"], "n_results": 5 } }
}
Restart the harness, then ask it: “Use NodeTool to list my workflows.”
Install
Runs: locally over stdio, or against a running NodeTool server over HTTP. Needs: Node.js 22 or later. Generation tools need provider keys (see Provider keys).
Or install the executable globally:
npm install -g @nodetool-ai/cli-mcp
nodetool-mcp install
install does these steps:
- It finds Claude Code, Codex, and OpenCode on the machine.
- It starts the server once and lists its tools. This proves that the server works and fills the
npxcache, so the harness’s first start is fast. - It writes a
nodetoolentry into each client’s config.
To install for one client, add --claude, --codex, or --opencode. Add --no-verify to write the config without starting the server first. Check the result with nodetool-mcp status --check. Remove the entries with nodetool-mcp uninstall.
To use the same feature through the default CLI, run nodetool packs add cli-mcp --yes, then use nodetool mcp in place of nodetool-mcp. Pack-managed features do not add global binaries.
What the install writes
The entry starts nodetool-mcp serve over stdio. The command is nodetool-mcp when the CLI is on PATH, and npx -y @nodetool-ai/cli-mcp serve when it is not. Add --npx to always use npx.
| Client | File | Scope |
|---|---|---|
| Claude Code | ~/.claude.json, key mcpServers |
User scope, every project |
| Codex | ~/.codex/config.toml, block [mcp_servers.nodetool] |
Every session |
| OpenCode | ~/.config/opencode/opencode.json, key mcp |
Every session |
Codex gets a 120-second start timeout and a 900-second tool timeout, because a video generation can run for minutes. OpenCode gets the 120-second timeout.
Earlier versions wrote the Claude Code entry under projects["<home>"], so it
worked only in sessions started in the home directory. A new install moves that
entry to the user scope.
Other clients
Print the mcpServers block above for Cursor, Claude Desktop, Windsurf, or any client that reads that JSON:
nodetool-mcp config
To register the server with Claude Code by hand, run:
claude mcp add --scope user nodetool -- npx -y @nodetool-ai/cli-mcp serve
Claude Desktop also installs the bundled extension from Studio: open Settings → MCP Servers → Install Extension.
Provider keys
Store a key once in the NodeTool secret store:
nodetool secrets store FAL_API_KEY
nodetool secrets store OPENAI_API_KEY
Keys you add in Studio settings go to the same store. When a key is not in
the store, the server reads the environment variable with the same name. To
pass one through Claude Code, add -e FAL_API_KEY=... to claude mcp add.
Tools that need no provider work without keys: node search, workflow validation, assets, and the local file tools.
With and without Studio
nodetool-mcp serve checks for a running classic API server on 127.0.0.1 at
port 7777 (or PORT), over HTTPS when TLS_CERT and TLS_KEY are set. When
one answers its MCP handshake, the stdio process forwards every request to it.
Actions then run in that process, and an open editor shows the agent’s changes
as they happen.
When no server answers, mcp serve runs its own MCP server over the default
NodeTool data directory. The agent keeps full access to workflows, assets, and
generation.
To connect a client to a running server over HTTP instead, install with
--http. That entry works only while the server runs:
nodetool-mcp install --http # http://127.0.0.1:7777/mcp
nodetool-mcp install --url http://127.0.0.1:8000/mcp
For a NodeTool server on another machine, create an access token in Settings → MCP Servers → Connect an agent remotely. See MCP on a production server for the server side.
What the agent gets
Direct tools answer with full 32-character resource ids. Inside execute_code, results carry the 12-character prefix of each id instead, to save tokens. Every tool, direct or in the sandbox, accepts either form.
Everything beyond the direct tools goes through execute_code, which runs sandboxed JavaScript that calls nodetool.<namespace>.<method>(). The agent finds a tool with nodetool.searchTools("query"). The full list of sandbox tools is in the CLI reference.
Direct tools
| Tool | Purpose |
|---|---|
execute_code |
Run sandboxed JavaScript that calls the nodetool.* modules. The main tool. |
view_image |
Return an image as MCP image content so the agent can see the pixels. Takes an asset id, asset:// URI, public https:// URL, or data: URI. A local connection also accepts an absolute disk path. For a stored asset or an https:// input, the result also carries a public url the chat can display. It shows the image at its stored size, or downscaled to 768 pixels on the long side with detail: "low", and the result reports which. It does not crop. |
upload_asset |
Save bytes in your asset library. Takes content_base64, or an absolute file_path on a local connection. Returns the asset id and URI. |
download_asset |
Return a signed public url for an asset you own, or write it to an absolute output_path on a local connection. It never returns the bytes inline. |
list_skills |
List NodeTool skills, the shipped ones and your own, by name and description. Takes an optional query. |
load_skill |
Return one skill’s full instructions by name. |
list_directory |
List files and subdirectories in a workspace directory. |
download_file |
Download a file from a URL, or from an asset:// URI, a /api/storage/ key, or a data: URI, into the workspace. |
run_subtask |
Hand a task to a child agent that has the NodeTool toolbelt. |
list_generations |
List your media generations, newest first, with status, cost and asset ids. Generations an MCP tool call started are included. |
get_generation |
Return one generation’s record by its generation_id. |
await_generation |
Wait for a generation started with background: true to settle, then return its record with the asset ids. |
find_model |
Find a real provider and model id for a capability such as image, video, or speech. |
list_providers |
List configured providers, their capabilities, the tool that runs each capability, and unavailable_reason when a provider cannot serve calls here. |
list_models |
List the models available from the providers you configured. |
list_provider_models |
List the language models of one provider. |
search_nodes |
Search node types by keyword. |
get_node_info |
Return a node type’s inputs, outputs, types, and defaults. |
list_nodes |
List node types, optionally filtered by namespace. |
open_app |
Open one of your mini apps. Hosts that support MCP Apps show the app’s screen in the conversation. See Mini apps in the host. |
One tool per provider capability is also direct: generate_text, generate_image, edit_image, segment_image, generate_video, animate_image, generate_video_from_references, generate_speech, generate_music, transcribe_audio, and embed_text. Each takes a provider and model from find_model. Generated media is saved as an asset and the result carries its asset:// URI. With background: true a generation tool answers at once with a generation_id. Collect the result with await_generation.
search_nodes, get_node_info, and list_nodes are offered only when the session has the node registry loaded. read_file, write_file, edit_file, glob, grep, and web_search are not direct tools, because Claude Code and similar clients provide their own. browser, http_request, and todo_write are also not direct on this server. All of them stay available inside execute_code.
Tool list updates
The tools/list schema of a direct tool and the signature nodetool.searchTools() shows inside execute_code come from the same capability spec. packages/websocket/tests/mcp-schema-parity.test.ts fails when they differ.
A client reads the tool list when it connects and may keep it after that. This server cannot tell a connected client that the list changed. It answers every request as JSON and offers no SSE stream, so notifications/tools/list_changed has no channel to travel on, and a session revived after a deploy keeps its id, so the client sees no new handshake. After a server update, remove and re-add the connector, or start a new conversation, to load new parameters. Inside execute_code the new parameters work at once.
Resources and prompts
| Name | Kind | Purpose |
|---|---|---|
nodetool://capabilities |
Resource | The modules mounted for the session, every tool an action can call, and each tool’s permission category, as JSON. |
nodetool://sandbox |
Resource | How to write execute_code: the guest contract, blocked globals, unavailable bridges, and worked examples. |
ui://nodetool/mini-app.html |
Resource | The mini app renderer, an HTML page of type text/html;profile=mcp-app that open_app links to. |
sandbox-action |
Prompt | A complete execute_code body that lists workflows, picks a model, and generates one image. |
sandbox-asset |
Prompt | A complete execute_code body that lists one asset and fetches its ref. |
<skill-name> |
Prompt | One prompt for each skill the user can load: the shipped system skills and the user’s own skills. The prompt returns the skill body. The optional request argument adds the task. Claude Code shows each prompt as a slash command. |
Mini apps in the host
open_app takes an app id or its 12-character short id. In a host that supports
the MCP Apps extension,
the app’s screen appears in the conversation. The user fills its fields and
presses its buttons there. Other hosts get a text summary of the app and its
operations.
The screen is the app’s default working instance, the same one Run opens
in Studio. It runs the released version when the app has one, otherwise the
draft. Each run is an app run with origin agent: the app’s spend budget
applies, and the run appears in the app’s run history.
| Part | What it does |
|---|---|
ui://nodetool/mini-app.html |
One self-contained page. It draws the widgets the same way an exported app does, and loads nothing from the network. |
run_app_operation |
Starts one operation and waits up to 8 seconds. A short run finishes in this one call. |
poll_app_run |
Returns the messages a run produced since the last call, or cancels the run. |
The page calls run_app_operation and poll_app_run through the host. Both are
marked app-only (_meta.ui.visibility: ["app"]), so the model does not see them.
upload_asset stores files that the page’s file inputs pick.
Results up to 8 MB per value arrive inline as data: URLs. With S3 or Supabase
asset storage, a larger asset loads from a signed URL whose origin the page’s
Content Security Policy lists. On the local file backend, a larger result does
not display in the host. Model pickers offer the models the app’s own graphs
use. Widgets that edit NodeTool documents, such as Storyboard and Timeline,
show a note that they work only in NodeTool.
A run is tracked by the server process that started it. When a poll reaches a different replica or a restarted server, the page reports that the run is gone. The run still finishes, and its result is in the app’s run history in Studio.
Troubleshooting
| Symptom | Fix |
|---|---|
| The harness shows the server as failed | Run nodetool-mcp status --check. It starts each registered server and prints the error. |
npm error could not determine executable to run |
Use npx -y @nodetool-ai/cli-mcp install. This package supplies one executable, which npm selects automatically. |
| The first start times out | Run nodetool-mcp install again. It fills the npx cache before the harness starts the server. |
nodetool-mcp serve fails, but npx works |
The MCP executable is missing from PATH or is an older install. Use --npx, or update the global @nodetool-ai/cli-mcp package. |
| A generation fails with a missing key | Store the key with nodetool secrets store <NAME>. |