MCP integration (Claude Code and Codex)
@takazudo/zudotext-mcp is the official local stdio Model Context Protocol server for one encrypted zudo-text cloud workspace. Claude Code or Codex can call 20 direct document/history/change/asset tools and one optional cloud-agent tool without driving the app UI.
This is the shipped way to edit workspace documents with a local coding agent. It does not restore the retired in-app terminal/PTY or a local workspace directory. There is no public remote MCP endpoint and no per-published-site MCP endpoint.
The server package is public on npm while its source repository remains private. Users do not need repository access or GitHub credentials to install it.
This page is the user workflow: setup, registration, and day-to-day operation. Local Agent Authoring is the design and safety authority. The @takazudo/zudotext-mcp package page is the distribution, configuration, exact-inventory, and release-verification reference. Agent task recipes is the task-shaped companion to this page: what to type for a given job, which tools it should trigger, and the caveat attached to each one.
Install
Choose one setup path. The recommended Settings-generated command installs and registers the server in one pass; do not precede it with the manual global install. Use the manual path when you need to assemble the package, token, and harness registration yourself. Both paths require Node.js 22.19 or newer.
Recommended: run the Settings-generated command
Open Settings → Local AI Agent:
Pick Claude Code or Codex.
Choose an absolute password-file path (recommended) or the
/prompt. For a password file, create it yourself with a trusted editor, write only the workspace password, and rundev/ tty chmod 600 /before continuing. The Settings screen never reads, displays, copies, or stores the password.absolute/ path/ to/ workspace- password Leave the encryption-salt override off; it is a debugging escape hatch, not normal configuration.
Choose Create token & config.
Copy the one-time config before discarding it or closing Settings. Paste it into a trusted local shell and run it as one executable command block. It installs and verifies the exact npm release, registers the selected harness with the generated environment, and ends with
mcp list.
The / option means the external harness process prompts through its controlling OS shell while keeping stdin available for MCP framing. It does not refer to the retired in-app terminal.
This flow mints a PAT bound to the current workspace with exactly documents:read, documents:write, assets:read, and assets:write. The raw token appears only in the one-time config reveal. Closing or discarding the reveal drops the UI's copy but does not revoke the token; revoke an unused one under Settings → Access Tokens.
Manual: install the npm package
The package is a public npm-registry publication. Replace <VERSION> with the version shown on the package release reference:
ZUDOTEXT_MCP_VERSION="<VERSION>"
npm install --global "@takazudo/zudotext-mcp@${ZUDOTEXT_MCP_VERSION}"
zudotext-mcp --versionThe verification command must print the selected version.
Mint a scoped token
For the manual path, create a PAT under Settings → Access Tokens. Its settled least-privilege default is documents:read, documents:write, assets:read, and assets:write. Add agent:invoke only for ask_zudo_agent, or choose mutually exclusive Full access only for compatibility work that truly needs the wider server surface. Bind an MCP PAT to one workspace and set an expiry.
The server API still interprets an omitted scopes field as full for pre-scoped-token compatibility. The current UI does not silently choose that default.
Add it to Claude Code or Codex
If you ran the generated command from Settings → Local AI Agent, registration is already complete and you can skip these manual examples. Use them when you minted a PAT in the generic token screen or are assembling configuration by hand.
Before running either password-file example, create the absolute-path file with a trusted editor, write only the workspace password, and run chmod 600 /.
claude mcp add zudotext \
--env ZUDOTEXT_SERVER_URL=https://your-sync-server.example.com \
--env ZUDOTEXT_PAT=your_personal_access_token \
--env ZUDOTEXT_WORKSPACE_ID=your-workspace-id \
--env ZUDOTEXT_WORKSPACE_PASSWORD_FILE=/absolute/path/to/workspace-password \
-- zudotext-mcp
claude mcp listThe Codex command has the same shape:
codex mcp add zudotext \
--env ZUDOTEXT_SERVER_URL=https://your-sync-server.example.com \
--env ZUDOTEXT_PAT=your_personal_access_token \
--env ZUDOTEXT_WORKSPACE_ID=your-workspace-id \
--env ZUDOTEXT_WORKSPACE_PASSWORD_FILE=/absolute/path/to/workspace-password \
-- zudotext-mcp
codex mcp listThen ask the harness to call list_notes. Installing the official skill gives it the complete safety policy and exact tool inventory.
Configuration reference
| Variable | Required | Meaning |
|---|---|---|
ZUDOTEXT_SERVER_URL | yes | Sync-server origin. |
ZUDOTEXT_PAT | yes | Workspace-bound PAT with the required narrow scopes. |
ZUDOTEXT_WORKSPACE_ID | yes | The one workspace this process exposes. |
ZUDOTEXT_WORKSPACE_PASSWORD_FILE | one password source | Recommended absolute path to a file you create, containing only the workspace password. Protect it with chmod 600. |
ZUDOTEXT_WORKSPACE_PASSWORD | one password source | Inline password; convenient but visible to environment/config readers. |
| neither password variable | one password source | Prompt once from the external process's controlling OS shell through /, without echo. This is not the retired in-app terminal; stdin remains the MCP protocol channel. |
ZUDOTEXT_WORKSPACE_SALT | no | Hex debugging override. Normally the server returns metadata, including for an assets:read PAT on a free account. |
ZUDOTEXT_AGENT_URL | no | Agent-server origin for ask_zudo_agent; defaults to the operator-run service. |
ZUDOTEXT_MCP_LOG_LEVEL | no | debug, info, warn, error, or silent; default info, stderr only. |
If both password variables are set, the inline environment value wins over the file. The password stays in process memory so an expired document key session can be reopened; the process never writes it to disk.
Install the official authoring skill
After completing either setup path, install the behaviorally equivalent policy skill for the harness you use:
# User scope
zudotext-mcp-install-skill --harness claude-code
zudotext-mcp-install-skill --harness codex
# Repository scope; --project requires an absolute path
zudotext-mcp-install-skill --harness claude-code --project "$PWD"
zudotext-mcp-install-skill --harness codex --project "$PWD"The user destinations are $CLAUDE_ (falling back to ~/) and $HOME/. Repository installs use . and ..
After installing a newer npm release, replace and byte-check the skills explicitly:
zudotext-mcp-install-skill --harness claude-code --update
zudotext-mcp-install-skill --harness claude-code --check
zudotext-mcp-install-skill --harness codex --update
zudotext-mcp-install-skill --harness codex --checkWithout --update, an existing skill is never overwritten. An owner may edit the installed destructive-confirmation defaults; such an intentional edit makes the byte-exact --check fail, and --update replaces it. Back up and reapply custom policy around an update. Claude Code explicitly invokes /; Codex uses $zudotext-authoring or the / selector.
Do not install these external-agent skills under .zudotext/skills/. That is the separate flat-file namespace for zudo-text's in-app inline AI.
Tool tour
The registry contains exactly 21 tools.
Documents and changes
| Tool | Contract |
|---|---|
list_notes(prefix?, limit?, cursor?) | List workspace-relative paths and current versions, with pagination. archives/ is an ordinary prefix and needs no special tool. |
read_note(path, maxBytes?) | Read a UTF-8 window plus version. Default 1 MiB, maximum 8 MiB; truncated and total size remain explicit. |
search_notes(query, mode?, prefix?, limit?) | Regex search in files, content, or count mode. |
write_note(path, content, expectedVersion?, idempotencyKey?) | Omit the version only for create; pass the current version to replace one whole document. |
stash_log(project, title, content) | Create a dated, collision-safe Markdown work log under logs/. |
delete_note(path, expectedVersion, idempotencyKey?) | Soft-delete the current document while keeping its tombstone and version history. |
move_note(fromPath, toPath, expectedVersion, idempotencyKey?) | Atomically move the stable document identity and preserve its history. |
what_changed(afterCursor?, limit?) | Poll ordered document upserts/deletes after a cursor. |
what_changed has a process-local implicit cursor. Successful implicit calls advance it, including intermediate pages; explicit afterCursor calls do not. It resets to zero when the MCP process restarts. The cursor is document-only: asset mutations never appear.
One search scans at most 2,000 candidate paths and reads content from at most 240 documents. Scope with prefix; a truncated response is incomplete, not evidence that no later match exists.
Authoring sessions and document history
| Tool | Contract |
|---|---|
begin_authoring_session(label) | Create the explicit document checkpoint that marks an agent undo boundary. |
list_note_versions(path) | List versions of the stable document currently at a path, including history before a move. |
read_note_version(path, versionId) | Read one complete historical document version. |
restore_note_version(path, versionId, expectedVersion, idempotencyKey) | Restore one version as a new head with an optimistic precondition. |
list_checkpoints() | List named document change-log cursors. |
get_checkpoint_summary(checkpointId, fromCursor?) | Project document changes ending at a checkpoint. |
get_checkpoint_restore_manifest(checkpointId) | Return the document work order for a client-orchestrated rollback. |
Call begin_authoring_session before the first document mutation when an undo boundary matters. A checkpoint is not a workspace snapshot. There is no one-call or atomic rollback: the client fetches the manifest, compares its expectedHeadCursor with a fresh explicit walk: call what_changed(afterCursor: 0), keep passing each response's changeCursor as the next afterCursor until hasMore is false, then compare the final cursor. It applies normal restore/delete/noop work and stops on conflict while reporting possible partial progress. A same-fileId old-path restore plus new-path delete is a move-back. HISTORY_COMPACTED remains distinguishable from empty history. The sync server's nightly version-retention job does not touch the changes log or compaction_floor, so it does not change HISTORY_COMPACTED semantics; it only thins unpinned version rows and queues their unreferenced R2 blobs for delayed reclaim.
Versions, checkpoints, summaries, restore manifests, and what_changed cover documents only.
Assets
| Tool | Contract |
|---|---|
list_assets() | List decrypted asset paths, sizes, and modification times. |
get_asset_usage() | Report plan, quota, used/add-on bytes, and soft-lock state. |
download_asset(path, destinationPath) | Decrypt into a new absolute local file; never overwrite a destination. |
upload_asset(sourcePath, path, idempotencyKey) | Encrypt and create from an explicit regular, non-symlink local file up to 25 MiB. |
create_asset_folder(path, idempotencyKey) | Create an encrypted empty-folder marker without replacing an existing path. |
Asset plaintext bytes and base64 never enter MCP text or structured results. Transfers cross an explicit local-path boundary: confirm the source before an upload and the new destination before a download. Check usage before material uploads; quota or soft lock can reject creation, while an over-quota account may still list and download.
Assets have no versions, checkpoints, history restore, document cursor, or undo. The narrow family deliberately has no move, rename, delete, recursive delete, replace, or delete-and-recreate tool; do not emulate one. Interactive asset moves/renames and document moves do not rewrite Markdown references.
Cloud agent
| Tool | Contract |
|---|---|
ask_zudo_agent(message, conversationId?) | Delegate semantic, open-ended, or multi-step work to the same cloud assistant used by the app. |
Direct tools spend zero AI turns. Every admitted ask_zudo_agent call spends one of the user's shared 100 AI turns per UTC day at admission, even if that turn later fails. Assistant-panel and inline-AI calls share the pool. All Automation API routes also share 120 requests per user per minute; cloud-agent internal calls consume that same budget, so avoid bursts and honor typed retry timing. One bounded internal query_kanban call can consume up to 85 of those requests.
Calls without conversationId share one process-local default conversation; passing an id pins a thread. Successful propose_edit activity returns validated editPreviews. A preview is not applied automatically: review its candidate newContent, then use write_note before expiry with baseVersion as expectedVersion and a fresh idempotency key. create_note is the deliberate direct-write exception: it commits a new note create-only and fails if the selected path already exists.
Write conflicts and retries
Whole-document writes use optimistic concurrency. On VERSION_CONFLICT, read the returned current-version details, re-read the document, reconcile with the owner's intent, and use a new precondition. If the payload or precondition changes, use a fresh idempotency key; the old key belongs only to an exact retry of the old fingerprint. A conflict writes nothing.
write_note,delete_note, andmove_noteaccept an optional key. The MCP client creates one for that request and keeps it across its internal key-session retry. Supply and reuse a stable key when retrying the same MCP-level operation yourself.restore_note_version,upload_asset, andcreate_asset_folderrequire a caller-stable key. Reuse it only for the exact same payload.stash_logavoids overwrites by choosing the next free dated filename.begin_authoring_sessionandask_zudo_agentare not idempotent.
The log-stash recipe
stash_log(project, title, content) replaces a machine-local agent-logs/ directory with synced workspace documents. Logs land directly under logs/:
logs/YYYYMMDD-<project>-<title>.mdThe project is retained in both the filename and frontmatter. A collision takes the next -2, -3, … suffix and never overwrites an existing document. Pin logs/ as a Note Tray to browse the direct children in the app.
Resource safety
The official skills apply these defaults to direct and cloud-agent-proposed whole-document writes:
Ordinary notes and
archives/documents are writable.Preserve existing YAML frontmatter byte-for-byte unless the owner explicitly asks to change a field; malformed raw edits can desynchronize indexed data.
Directive round-tripping is unverified. Preserve directive syntax unless the owner explicitly accepts the risk.
Treat all boards as read-mostly. Kanban has an evidenced 400 ms debounced whole-board race. Todo, timeline, mindmap, spreadsheet, and slide use separate persistence paths whose agent-write safety is unverified.
Treat
.zudotext.settings.json, frameset state, and pins as read-only. They are whole-document last-writer-wins state, and malformed settings may silently revert to defaults.
By default the packaged skill asks for owner confirmation immediately before a whole-note replacement, delete, move, version restore, checkpoint manifest application, or cloud-agent preview application. That policy is owner-editable in the installed skill.
Optional active-note pointer
On desktop, the off-by-default active-note pointer can help a local tool orient to the note currently visible in the app. It writes only path, workspace, pane/view, selection coordinates, and timestamp — never note content — to ~/.
The app refreshes it every 10 seconds and on note/pane/view changes; readers treat data older than 30 seconds as stale. Disable, workspace switch, no active workspace note, and clean shutdown remove it, while a crash can leave a stale file. It is a strictly read-only sidecar, not an MCP command channel, and token creation never enables it.
Security notes
Document keys reach bounded server memory. The local process derives raw keys with PBKDF2-SHA-256 at 600,000 iterations and opens a key session held in Durable Object memory for at most one hour. It is never persisted. Normal close and process signals start best-effort deletion; abnormal death relies on expiry.
Asset keys and plaintext remain local. Non-extractable asset keys stay in the stdio process.
/receives opaque path tokens and encrypted envelopes only; an asset-only process opens no document key session.api/ assets Credentials remain local. Protect the PAT, MCP config, password, and password file like SSH credentials. Workspace binding prevents redirecting a bound PAT to another workspace.
Logs are protocol-safe. Known credentials, key material, and session ids are redacted; stdout is MCP-only and logs use stderr.
Cloud-agent history is a separate disclosure. Tool results and edit proposals can persist as plaintext excerpts in the durable conversation record. Retiring a conversation makes it unlisted and unreachable but does not immediately erase Flue's append-only storage.
Verification status
Each release is checked by building, packing, installing into a temporary prefix, verifying the installed version and exact 21-tool inventory, inspecting the tarball, and byte-checking both packaged skills. See the package reference for the durable release contract. Authenticated deployment behavior still requires operator verification with a real workspace, bound PAT, and password source; missing credentials mean unverified, never a pass.
See also
Local Agent Authoring — canonical architecture and safety boundary.
Personal Access Tokens — UI defaults, scopes, workspace binding, and revocation.
Automation API — document wire contract, key sessions, limits, and typed failures.
Assets — interactive filer and narrow agent boundary.
Flue Agent Platform — cloud-agent ingress, edit safety, quota, and retention.
@takazudo/zudotext-mcp — package/release and installer reference.