v0.51.0 a9d674e

mcp.md RawHistoryFolder

MCP servers

zut includes a native Model Context Protocol client. Configured servers start once per zut process, and their tools appear to the model as ordinary tools named mcp__<server>__<tool>.

Configuration

Servers are read from two JSON files. A project entry replaces a global entry with the same name:

File Scope
$ZUT_HOME/mcp.json Global
<cwd>/.zut/mcp.json Project

Executable configuration. zut starts every configured stdio command and contacts every HTTP endpoint when it launches, before any model turn. There is no trust prompt, --no-yolo does not gate startup, and servers are not sandboxed. Review a repository's .zut/mcp.json before running zut in it, or pass --no-mcp.

The format matches Claude Desktop and Claude Code:

{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "."]
    },
    "docs": {
      "type": "http",
      "url": "https://example.com/mcp",
      "bearerTokenEnvVar": "DOCS_MCP_TOKEN"
    }
  }
}
Field Transport Meaning
type (or transport) both stdio (default with command) or http (default with url; streamable-http is an alias)
command, args stdio Executable and arguments
env stdio Extra environment variables
envVars stdio Host variables to pass through
cwd stdio Working directory; relative paths resolve against the zut cwd
url http Streamable HTTP endpoint
headers http Static HTTP headers
envHeaders http Header name → host variable name
bearerTokenEnvVar http Sends Authorization: Bearer <value>
enabled both false skips the server
required both Abort startup when this server fails
enabledTools, disabledTools both Allow-list, then deny-list of raw MCP tool names
startupTimeoutSec both Start + initialize + tools/list budget (default 30)
toolTimeoutSec both One tools/call budget (default 300)

${VAR} and ${VAR:-default} are expanded in command, args, cwd, env values, url, and headers values. A reference to an unset variable without a default disables only that server; the error names the field and variable, never the value.

Stdio servers receive a minimal environment: common variables such as PATH, HOME, LANG, TMPDIR, and proxy/CA settings, plus envVars and env. Provider API keys and other host variables are not inherited.

The legacy HTTP+SSE transport is not supported; use the server's streamable HTTP endpoint or a stdio command. OAuth login is not built in; use a token through bearerTokenEnvVar, envHeaders, or headers.

Managing servers

zut mcp add fs -- npx -y @modelcontextprotocol/server-filesystem .
zut mcp add docs --url https://example.com/mcp --bearer-token-env-var DOCS_MCP_TOKEN
zut mcp add local --project --env KEY='${LOCAL_KEY}' -- ./bin/server
zut mcp list            # name, transport, target
zut mcp get docs        # entry with env and header values hidden
zut mcp status [NAME]   # connect, then list each tool name
zut mcp remove docs [--project]

zut mcp add writes the global file unless --project is given. Files are written with 0600 permissions because entries may hold secrets.

In the interactive TUI, /mcp shows connection state, tool counts, and startup errors.

Runtime behavior

  • Servers connect in parallel at startup. A failure is reported (stderr in headless modes, the startup panel in the TUI) and zut continues without that server unless it is required. A server that failed at startup exposes no tools for the rest of the run; fix it (zut mcp status NAME) and restart zut. A server that started and later dropped (a crashed stdio process or an expired HTTP session) reconnects on the next call to one of its tools; the failed call itself is not retried.
  • zut negotiates protocol 2025-06-18 and accepts 2025-03-26 and 2024-11-05. It answers ping and roots/list (the zut cwd) and follows tools/list pagination.
  • notifications/tools/list_changed refreshes the server's tool list. New definitions reach the model the next time zut rebuilds its tool registry (for example after /reload-ext or a model switch).
  • Tool names are sanitized to [A-Za-z0-9_-] and limited to 64 characters. Names that collide or overflow receive a stable 8-character hash suffix.
  • Input schemas are normalized to an object root without top-level oneOf/anyOf/allOf, which some providers reject.
  • Results map text and image blocks directly. Embedded text resources are inlined, resource links and audio are described, and structuredContent is used when no content blocks are returned. Text is capped at 50 KiB per result. isError results are reported to the model as tool errors.
  • When a server offers resources, the mcp_list_resources and mcp_read_resource tools are added.
  • Server-provided instructions are added to the system prompt, marked as server-provided. Treat MCP output as untrusted data.
  • Cancelling a turn sends a best-effort notifications/cancelled. Exiting zut closes HTTP sessions and stops stdio servers with their process group (Unix) or job object (Windows). A descendant that starts its own session (setsid) on Unix is not stopped.
  • Errors and status output strip terminal control sequences, URL credentials and query strings, and configured env, header, and bearer-token values. Secrets passed through args are not redacted.

Tool selection and confirmation

  • --no-mcp skips MCP for one run. --no-tools also disables it.
  • With --tools, add mcp for every MCP tool, or list exact names such as mcp__docs__search.
  • Packaged agents (zut run), bot runs, and SDK runtimes never start MCP servers.
  • --no-yolo confirmation covers MCP tools like any other tool.
  • Tool annotations such as readOnlyHint are hints from the server, not a security boundary.

Orchestrator mode and subagents

All agents in one zut process share the same MCP connections.

  • Headless --orchestrate: the manager-only orchestrator holds only MCP tools annotated readOnlyHint: true plus the resource tools, for research, still limited by any --tools selection. Its workers receive every MCP tool, so actions that change external state are delegated.
  • Resident subagents inherit MCP tools like other child-safe tools. subagents.allowed_tools and profile tools: lists accept mcp to grant every MCP tool, or exact mcp__<server>__<tool> names.
  • A resumed child whose MCP server is no longer configured continues without that tool.
source
1# MCP servers
2
3zut includes a native [Model Context Protocol](https://modelcontextprotocol.io)
4client. Configured servers start once per zut process, and their tools appear
5to the model as ordinary tools named `mcp__<server>__<tool>`.
6
7## Configuration
8
9Servers are read from two JSON files. A project entry replaces a global entry
10with the same name:
11
12| File | Scope |
13| --- | --- |
14| `$ZUT_HOME/mcp.json` | Global |
15| `<cwd>/.zut/mcp.json` | Project |
16
17> **Executable configuration.** zut starts every configured stdio command and
18> contacts every HTTP endpoint when it launches, before any model turn. There
19> is no trust prompt, `--no-yolo` does not gate startup, and servers are not
20> sandboxed. Review a repository's `.zut/mcp.json` before running zut in it, or
21> pass `--no-mcp`.
22
23The format matches Claude Desktop and Claude Code:
24
25```json
26{
27  "mcpServers": {
28    "filesystem": {
29      "command": "npx",
30      "args": ["-y", "@modelcontextprotocol/server-filesystem", "."]
31    },
32    "docs": {
33      "type": "http",
34      "url": "https://example.com/mcp",
35      "bearerTokenEnvVar": "DOCS_MCP_TOKEN"
36    }
37  }
38}
39```
40
41| Field | Transport | Meaning |
42| --- | --- | --- |
43| `type` (or `transport`) | both | `stdio` (default with `command`) or `http` (default with `url`; `streamable-http` is an alias) |
44| `command`, `args` | stdio | Executable and arguments |
45| `env` | stdio | Extra environment variables |
46| `envVars` | stdio | Host variables to pass through |
47| `cwd` | stdio | Working directory; relative paths resolve against the zut cwd |
48| `url` | http | Streamable HTTP endpoint |
49| `headers` | http | Static HTTP headers |
50| `envHeaders` | http | Header name → host variable name |
51| `bearerTokenEnvVar` | http | Sends `Authorization: Bearer <value>` |
52| `enabled` | both | `false` skips the server |
53| `required` | both | Abort startup when this server fails |
54| `enabledTools`, `disabledTools` | both | Allow-list, then deny-list of raw MCP tool names |
55| `startupTimeoutSec` | both | Start + initialize + `tools/list` budget (default 30) |
56| `toolTimeoutSec` | both | One `tools/call` budget (default 300) |
57
58`${VAR}` and `${VAR:-default}` are expanded in `command`, `args`, `cwd`, `env`
59values, `url`, and `headers` values. A reference to an unset variable without
60a default disables only that server; the error names the field and variable,
61never the value.
62
63Stdio servers receive a minimal environment: common variables such as `PATH`,
64`HOME`, `LANG`, `TMPDIR`, and proxy/CA settings, plus `envVars` and `env`.
65Provider API keys and other host variables are not inherited.
66
67The legacy HTTP+SSE transport is not supported; use the server's streamable
68HTTP endpoint or a stdio command. OAuth login is not built in; use a token
69through `bearerTokenEnvVar`, `envHeaders`, or `headers`.
70
71## Managing servers
72
73```sh
74zut mcp add fs -- npx -y @modelcontextprotocol/server-filesystem .
75zut mcp add docs --url https://example.com/mcp --bearer-token-env-var DOCS_MCP_TOKEN
76zut mcp add local --project --env KEY='${LOCAL_KEY}' -- ./bin/server
77zut mcp list            # name, transport, target
78zut mcp get docs        # entry with env and header values hidden
79zut mcp status [NAME]   # connect, then list each tool name
80zut mcp remove docs [--project]
81```
82
83`zut mcp add` writes the global file unless `--project` is given. Files are
84written with `0600` permissions because entries may hold secrets.
85
86In the interactive TUI, `/mcp` shows connection state, tool counts, and
87startup errors.
88
89## Runtime behavior
90
91- Servers connect in parallel at startup. A failure is reported (stderr in
92  headless modes, the startup panel in the TUI) and zut continues without that
93  server unless it is `required`. A server that failed at startup exposes no
94  tools for the rest of the run; fix it (`zut mcp status NAME`) and restart
95  zut. A server that started and later dropped (a crashed stdio process or an
96  expired HTTP session) reconnects on the next call to one of its tools; the
97  failed call itself is not retried.
98- zut negotiates protocol `2025-06-18` and accepts `2025-03-26` and
99  `2024-11-05`. It answers `ping` and `roots/list` (the zut cwd) and follows
100  `tools/list` pagination.
101- `notifications/tools/list_changed` refreshes the server's tool list. New
102  definitions reach the model the next time zut rebuilds its tool registry
103  (for example after `/reload-ext` or a model switch).
104- Tool names are sanitized to `[A-Za-z0-9_-]` and limited to 64 characters.
105  Names that collide or overflow receive a stable 8-character hash suffix.
106- Input schemas are normalized to an object root without top-level
107  `oneOf`/`anyOf`/`allOf`, which some providers reject.
108- Results map text and image blocks directly. Embedded text resources are
109  inlined, resource links and audio are described, and `structuredContent` is
110  used when no content blocks are returned. Text is capped at 50 KiB per result.
111  `isError` results are reported to the model as tool errors.
112- When a server offers resources, the `mcp_list_resources` and
113  `mcp_read_resource` tools are added.
114- Server-provided `instructions` are added to the system prompt, marked as
115  server-provided. Treat MCP output as untrusted data.
116- Cancelling a turn sends a best-effort `notifications/cancelled`. Exiting zut
117  closes HTTP sessions and stops stdio servers with their process group
118  (Unix) or job object (Windows). A descendant that starts its own session
119  (`setsid`) on Unix is not stopped.
120- Errors and status output strip terminal control sequences, URL credentials
121  and query strings, and configured `env`, header, and bearer-token values.
122  Secrets passed through `args` are not redacted.
123
124## Tool selection and confirmation
125
126- `--no-mcp` skips MCP for one run. `--no-tools` also disables it.
127- With `--tools`, add `mcp` for every MCP tool, or list exact names such as
128  `mcp__docs__search`.
129- Packaged agents (`zut run`), bot runs, and SDK runtimes never start MCP
130  servers.
131- `--no-yolo` confirmation covers MCP tools like any other tool.
132- Tool annotations such as `readOnlyHint` are hints from the server, not a
133  security boundary.
134
135## Orchestrator mode and subagents
136
137All agents in one zut process share the same MCP connections.
138
139- **Headless `--orchestrate`**: the manager-only orchestrator holds only MCP
140  tools annotated `readOnlyHint: true` plus the resource tools, for research,
141  still limited by any `--tools` selection. Its workers receive every MCP tool,
142  so actions that change external state are delegated.
143- **Resident subagents** inherit MCP tools like other child-safe tools.
144  `subagents.allowed_tools` and profile `tools:` lists accept `mcp` to grant
145  every MCP tool, or exact `mcp__<server>__<tool>` names.
146- A resumed child whose MCP server is no longer configured continues without
147  that tool.

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 476

↑↓ moveenter openesc close