Skip to main content
Glama
Gaia-Desk

gaiadesk-mcp

Official
by Gaia-Desk

GaiaDesk MCP server

Let an AI assistant (Claude Desktop, Claude Code, Cursor, VS Code, Windsurf, or any MCP client) work on your GaiaDesk machines ("desks"): run commands and get their exit codes back, copy files, start and watch background jobs, forward ports, and, if you allow it, see and drive the screen.

The MCP server is part of GaiaDesk itself: it is gaiadesk-cli mcp, and it ships with the GaiaDesk app. This repository holds:

  • this guide: every tool, sign-in and scoped tokens, client configs, safety;

  • @gaiadesk/mcp, a small npm launcher (gaiadesk-mcp, written in TypeScript) that runs gaiadesk-cli mcp on stdio, so a client config can say npx -y @gaiadesk/mcp instead of a per-OS path. It brings gaiadesk-cli with it (the optional dependency @gaiadesk/cli), so that works with nothing else installed on the machine;

  • MCP or SDK?: when to give a model this server and when to drive desks from your own code with an SDK.

Writing a program rather than configuring an assistant? Use an SDK: TypeScript (@gaiadesk/sdk) or Python (gaiadesk). Both can also start this MCP server for the screen tools.

GaiaDesk is closed-source. This repository contains no GaiaDesk code; it only starts the gaiadesk-cli you installed. MIT-licensed.


Contents


Related MCP server: ChatGPT Gateway MCP Nyan

Install

  1. Get gaiadesk-cli on the machine where your MCP client runs. The launcher (step 3) installs it for you: npx -y @gaiadesk/mcp pulls in @gaiadesk/cli, the prebuilt CLI for macOS, Linux (glibc) and Windows, and uses it — no GaiaDesk app needed there. Without npm, install it with the scripts or Homebrew from Gaia-Desk/gaiadesk-cli, or install GaiaDesk (https://gaiadesk.net/download), which includes it:

    OS

    Where gaiadesk-cli is

    macOS

    /Applications/GaiaDesk.app/Contents/MacOS/gaiadesk-cli (and /usr/local/bin/gaiadesk-cli after Settings → Terminal over the Mesh → Add the gaiadesk command)

    Windows

    gaiadesk-cli.exe in GaiaDesk's install folder (usually C:\Program Files\GaiaDesk\); the installer adds it to PATH

    Linux (.deb, .rpm)

    /usr/bin/gaiadesk-cli

    Linux (AppImage)

    not on PATH; install the .deb/.rpm instead, or extract the AppImage (see GaiaDesk's docs)

  2. Install GaiaDesk on each desk you want the assistant to reach, and turn on Settings → Agent access there.

  3. Use the launcher (optional). With Node.js 18 or newer:

    npx -y @gaiadesk/mcp --which      # prints the gaiadesk-cli it found

    The launcher looks, in order, at $GAIADESK_CLI (an explicit path; if it is set but wrong, that is an error, never a silent fallback), the binary @gaiadesk/cli installed for this platform, every directory on PATH, then the standard locations above. If it finds nothing (for example after npm install --omit=optional, or on Alpine/musl) it exits 127 and says how to get gaiadesk-cli.

    You can skip the launcher and point your client straight at the absolute path of gaiadesk-cli with args: ["mcp"]. MCP clients do not search your shell's PATH, so use the full path.

Credentials

Never give an assistant the desk's password or access code. Give it a scoped, expiring agent token. It can only do what you allowed, only on the desks you named, optionally only inside one folder, stops working on its own, is revoked with one command, and everything it does is recorded.

Mint a token (the desk's owner)

On your own machine, as the desk's owner (the desk's unattended password is asked for once; a one-time access code is not enough):

gaiadesk-cli token create --desk 123456789 --name claude \
  --scope exec,cp,jobs --expires 3d \
  --cwd /Users/me/projects/site --low-priv \
  --out ~/.config/gaiadesk/claude.token

Flag

Meaning

--desk <id>[,<id>…]

One token per desk, all written to the one --out file. A token names its desk and is never sent to another.

--name <n>

What it is for. Used by list, revoke and audit.

--expires <d>

30m, 24h, 7d, 2w. Default 7d. The desk's owner sets the maximum (30 days unless changed).

--scope <list>

Default exec,cp,jobs. See the table below.

--cwd <dir on the desk>

Commands, shells and jobs start there; every copied path must resolve inside it. Not a sandbox: that is what --low-priv is for.

--low-priv

Its work runs as the desk's low-privilege agent user (set on the desk), or is refused. Never as you.

--out <file>

Written with mode 0600. Without it the token is printed once.

Scope

Allows (CLI, and the MCP tools)

exec

one command: gaiadesk_exec

shell

an interactive gaiadesk-cli shell (no MCP tool)

cp

gaiadesk_copy_files

forward

gaiadesk_forward_start

jobs

gaiadesk_job_run, job_list, job_logs, job_wait, job_kill

screen

the screen tools (gaiadesk_open_session, screenshot, click, …)

You can also issue tokens in the GaiaDesk app: Agents → Agent tokens (screen tokens: Agents → Connect an AI assistant).

List, audit, revoke

gaiadesk-cli token list   --desk 123456789
gaiadesk-cli audit        --desk 123456789 --token claude      # what it ran, with exit codes
gaiadesk-cli token revoke --desk 123456789 claude              # by name or id; at once
gaiadesk-cli token revoke --desk 123456789 --all-for-desk
gaiadesk-cli token revoke --desk 123456789 claude --account    # through your signed-in account, no password

A revoke takes effect immediately: the token's sessions are disconnected and its background jobs stopped. --account needs this machine signed in (gaiadesk-cli login).

What the MCP server presents

The credential always comes from the server's environment, never from a tool argument, so a model cannot be talked into using a different one.

Environment variable

Used for

GAIADESK_TOKEN_FILE

Desk tools (exec, copy_files, job_*, forward_*): path to a token file from token create --out. Must not be readable by other users (chmod 600).

GAIADESK_CODE

Desk tools, if no token file: the desk's code or password. Avoid for assistants.

GAIADESK_AGENT_TOKEN

Screen tools (and the desk tools' fallback): an agent token with the screen scope.

GAIADESK_PERSIST

How long a desk connection is held between calls (10m default, 0 = fresh every call).

Over stdio the desk tools use GAIADESK_TOKEN_FILE, then GAIADESK_CODE, then GAIADESK_AGENT_TOKEN. With none of them set, the server lists no tools and refuses every call (it says why on stderr). The tool list depends on what you set: only desk tools with a token file, desk and screen tools with a screen agent token.

Reaching a desk: on the same LAN or GaiaDesk Mesh nothing more is needed; elsewhere the desk is reached through the GaiaDesk server, and with an agent token that needs no account sign-in.

Client configuration

All examples use the launcher. To skip it, replace "command": "npx" and "args": ["-y", "@gaiadesk/mcp", …] with the absolute path of gaiadesk-cli and "args": ["mcp", …].

Always pass --audit-dir. Screen sessions record what they did (an audit.jsonl and the screenshots the model saw) into the server's working directory by default, and some clients (Claude Desktop) start servers in a directory they cannot write to; a screen session whose record cannot be written is closed before it acts. There is no flag to turn the record off.

Claude Desktop

Settings → Developer → Edit Config (claude_desktop_config.json):

{
  "mcpServers": {
    "gaiadesk": {
      "command": "npx",
      "args": ["-y", "@gaiadesk/mcp", "--audit-dir", "/Users/me/gaiadesk-agent-sessions"],
      "env": { "GAIADESK_TOKEN_FILE": "/Users/me/.config/gaiadesk/claude.token" }
    }
  }
}

Quit Claude Desktop completely and reopen it. (For screen tools, the GaiaDesk app's Agents → Connect an AI assistant card can write this file for you with the real paths.)

Claude Code

claude mcp add gaiadesk \
  -e GAIADESK_TOKEN_FILE="$HOME/.config/gaiadesk/claude.token" \
  -- npx -y @gaiadesk/mcp --audit-dir "$HOME/gaiadesk-agent-sessions"

Add --scope user to use it in every project, or --scope project to write .mcp.json for your team (do not commit token files).

Cursor

~/.cursor/mcp.json (all projects) or .cursor/mcp.json (one project):

{
  "mcpServers": {
    "gaiadesk": {
      "command": "npx",
      "args": ["-y", "@gaiadesk/mcp", "--audit-dir", "/Users/me/gaiadesk-agent-sessions"],
      "env": { "GAIADESK_TOKEN_FILE": "/Users/me/.config/gaiadesk/claude.token" }
    }
  }
}

VS Code

.vscode/mcp.json in the workspace (or MCP: Open User Configuration):

{
  "servers": {
    "gaiadesk": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@gaiadesk/mcp", "--audit-dir", "${userHome}/gaiadesk-agent-sessions"],
      "env": { "GAIADESK_TOKEN_FILE": "${userHome}/.config/gaiadesk/claude.token" }
    }
  }
}

Windsurf

~/.codeium/windsurf/mcp_config.json:

{
  "mcpServers": {
    "gaiadesk": {
      "command": "npx",
      "args": ["-y", "@gaiadesk/mcp", "--audit-dir", "/Users/me/gaiadesk-agent-sessions"],
      "env": { "GAIADESK_TOKEN_FILE": "/Users/me/.config/gaiadesk/claude.token" }
    }
  }
}

Any stdio client

Command npx -y @gaiadesk/mcp [flags] (or gaiadesk-cli mcp [flags]), credentials in the environment, newline-delimited JSON-RPC on stdin/stdout, logs on stderr. On Windows, npx is npx.cmd; some clients need "command": "cmd", "args": ["/c", "npx", "-y", "@gaiadesk/mcp", …].

Streamable HTTP (screen tools only)

gaiadesk-cli mcp --http serves on http://127.0.0.1:7333/mcp and needs GAIADESK_AGENT_TOKEN; clients must send Authorization: Bearer <token> on every request. Over HTTP the desk tools use only that agent token, and gaiadesk_exec is not offered.

GAIADESK_AGENT_TOKEN=gdagt_… gaiadesk-cli mcp --http --audit-dir ~/gaiadesk-agent-sessions

Server flags (gaiadesk-cli mcp --help)

Flag

Meaning

--stdio

The default.

--http

Streamable HTTP instead of stdio.

--bind <ip>

HTTP listen address, default 127.0.0.1 (implies --http). Off loopback it warns; the token is still required.

--port <n>

HTTP port, default 7333 (implies --http).

--allow-origin <o>

Accept this Origin (repeatable, implies --http).

--server <wss://host/ws>

Signaling server to fall back to (default wss://gaiadesk.net/ws).

--allow-domain <d>

Domain allowlist for every screen session (repeatable).

--audit-dir <dir>

Where screen sessions are recorded (default: the working directory).

The launcher passes every flag through unchanged. Its own options: gaiadesk-mcp --which prints the gaiadesk-cli it would run; GAIADESK_CLI=<path> picks the binary.

The tools

Names, arguments and limits are those gaiadesk-cli mcp advertises in tools/list. Every schema has additionalProperties: false: an invented argument is an error, not silently ignored.

Desk tools (no screen involved)

Tool

Arguments

Needs scope

Returns

gaiadesk_exec

desk_id (required); command (one command line for the shell) or argv (exact argument vector); shell: default | none | sh | bash | zsh | cmd | pwsh (or powershell); cwd (where it starts on the desk); env (object of strings, NAME: value, never logged); timeout_seconds (default 1800, 0 = no limit); stdin (text, then end of input)

exec

Text: exit N, then --- stdout --- / --- stderr ---. structuredContent: the same object as gaiadesk-cli exec --json (exit, remote_code, stdout, stderr, duration_ms, desk, route, mode, shell, timed_out, error, notes, truncated). isError when the exit is not 0. A program Windows Smart App Control / WDAC refused to start has error.reason blocked_by_os_policy.

gaiadesk_copy_files

desk_id, direction (upload | download), local (path on this machine), remote (path on the desk; relative = under the desk user's home; trailing / = into that folder), recursive (default false)

cp

JSON text: direction, desk, destination, files, dirs, bytes, resumed_bytes, failed[], seconds. Resumable.

gaiadesk_job_run

desk_id, name (letters, digits, . _ -), command (shell command line); optional cwd, shell (default | sh | bash | zsh | cmd | pwsh; default sh -c / cmd /c), env (object of strings, never logged), priority (low | normal | high), cpu_percent (1-100 of the whole machine), mem_mb, keep_awake

jobs

JSON text {"job": {...}}

gaiadesk_job_list

desk_id

jobs

JSON text {"jobs": [...]} (name, state running/exited/killed/lost, exit code, command, …)

gaiadesk_job_logs

desk_id, name, tail_bytes (1-65536, default 65536)

jobs

JSON text {"job": {...}, "output": "..."} (stdout and stderr together)

gaiadesk_job_wait

desk_id, name; optional timeout_seconds (absent or 0 = wait until it ends)

jobs

JSON text {"job": {...}, "timed_out": false}: the job as it ended (state, exit_code; reason blocked_by_os_policy when Windows Smart App Control / WDAC refused a program in it), or, timed_out: true, as it stands, still running

gaiadesk_job_kill

desk_id, name

jobs

JSON text {"job": {...}}; stops the job and everything it started

gaiadesk_forward_start

desk_id, remote_port (1-65535); optional remote_host (default the desk itself, 127.0.0.1), local_port (0 or absent = pick a free one)

forward

JSON text {"forward_id", "local_port", "note"}; listens on localhost of the machine running the server

gaiadesk_forward_stop

forward_id

-

JSON text {"stopped", "local_port"}

gaiadesk_exec runs one command, like ssh host cmd: no terminal, no prompt, no echo, stdin closed unless you pass stdin. The default shell is the desk's own (the user's login shell on macOS/Linux, cmd.exe on Windows); use shell: "sh" for portable POSIX scripts and shell: "pwsh" for PowerShell. Long work belongs in gaiadesk_job_run, not in a backgrounded exec (exec ends its whole process tree when it returns); start it, then gaiadesk_job_wait for it to end instead of polling gaiadesk_job_list.

The desk tools keep the connection to each desk open between calls (per desk and credential), so the tenth call costs no handshake.

Screen tools (Agent Access)

Need GAIADESK_AGENT_TOKEN holding a token with the screen scope, and Agent access turned on at the desk.

Tool

Arguments

gaiadesk_open_session

desk_id. Returns structuredContent: {session_id, desk_id}. Every other screen tool takes session_id. A session closes after 15 minutes without a call; at most 8 per server.

gaiadesk_close_session

session_id. Releases anything held down.

gaiadesk_screenshot

session_id; optional region [left, top, right, bottom] (a magnified crop for reading detail; never changes the coordinate space). Returns an image.

gaiadesk_click

session_id, x, y; optional button (left | right | middle), count (1, 2, 3; 2 and 3 left button only), hold_keys (e.g. "ctrl+shift")

gaiadesk_move_pointer

session_id, x, y

gaiadesk_drag

session_id, from_x, from_y, to_x, to_y; optional hold_keys

gaiadesk_press_button

session_id, state (down | up): hold or release the left button across calls

gaiadesk_scroll

session_id, x, y, direction (up | down | left | right), clicks (>= 1); optional hold_keys

gaiadesk_type_text

session_id, text; optional secret (a credential: still typed in full, withheld from watchers and logs; too short to redact safely is refused)

gaiadesk_press_keys

session_id, keys (e.g. "Return", "ctrl+c", "cmd+shift+4"); optional repeat

gaiadesk_hold_keys

session_id, keys, seconds

gaiadesk_wait

session_id, seconds

gaiadesk_pointer_position

session_id

x/y are pixels in the most recent full screenshot, origin top-left. Key names are xdotool-style; an unknown name is refused, never guessed. ctrl+c on a Mac is Control-C, not Command-C; super is Command on macOS and the Windows key on Windows.

Safety

  • The desk decides. Every scope, folder (--cwd), agent-user (--low-priv) and expiry check is enforced on the desk, on every request. A missing scope comes back as a tool error in the desk's own words.

  • Opt-in per desk. Agents connect only to desks whose owner turned on Settings → Agent access → Let AI agents connect to this computer. Turning it off refuses the next connect and disconnects running agent sessions.

  • The owner indicator. Screen sessions are announced on the desk with a banner and a corner panel (on by default). Command-line work (exec, copies, jobs) can be announced too: the owner turns on Show when an AI agent or the command line is working on this computer (Agents → Limits and indicator). The panel lists what is running and who started it, with Pause agent jobs, Stop agent jobs and Disconnect agent.

  • Supervision tiers and approvals (screen sessions). A desk or token can require that an agent acts only while someone watches. When the agent is about to do something not undoable (paying, agreeing to terms, sending, deleting), the run stops and asks a watching person; nobody watching, no answer in two minutes, or a dropped session all mean refused.

  • Records. Every action an agent token takes is kept in the desk's audit log for 90 days (gaiadesk-cli audit), and in your account when the desk is signed in. Screen sessions also write audit.jsonl and screenshots under --audit-dir.

  • Prompt injection. A model reading a hostile web page or file can be told to do things you did not ask for. Keep scopes minimal, use --cwd and --low-priv, short expiries, and --allow-domain for screen sessions.

Details: https://gaiadesk.net/docs/cli-for-agents and https://gaiadesk.net/docs/agent-access.

Protocol version

gaiadesk-cli mcp speaks both:

  • the standard MCP lifecycle (initialize, then notifications/initialized, then plain requests) at revisions 2025-11-25, 2025-06-18, 2025-03-26 and 2024-11-05, which is what most clients send today; and

  • the stateless revision 2026-07-28 (no initialize; every request carries params._meta["io.modelcontextprotocol/protocolVersion"] and params._meta["io.modelcontextprotocol/clientCapabilities"]).

gaiadesk-cli --version --json lists the revisions it speaks (mcp_protocol_versions).

Before it starts the server, the launcher runs gaiadesk-cli --version --json. When that has mcp_protocol_versions, stdio is passed straight through, every byte, both ways. When it does not (the CLI prints its version as text, or fails on --json), the CLI is too old: the launcher exits 1 and says to update gaiadesk-cli.

Tool names (gaiadesk_exec, gaiadesk_screenshot, …) match [A-Za-z0-9_-], which every model provider accepts.

Troubleshooting

Symptom

Cause

gaiadesk-cli was not found (exit 127)

npm install -g @gaiadesk/cli (optional dependencies were skipped, or no build for this platform), install GaiaDesk (https://gaiadesk.net/download), or set GAIADESK_CLI.

No tools listed; stderr says no agent token in $GAIADESK_AGENT_TOKEN

No credential in the server's environment. Set GAIADESK_TOKEN_FILE (desk tools) or GAIADESK_AGENT_TOKEN (screen tools). The stderr line appears whenever GAIADESK_AGENT_TOKEN is unset, even if desk tools work.

A tool returns "…the cp scope…"

The token lacks that scope. Mint one with it.

gaiadesk-mcp: … is too old to serve MCP … Update gaiadesk-cli (exit 1)

The gaiadesk-cli found has no mcp_protocol_versions in --version --json. Update it (npm install -g @gaiadesk/cli, or https://gaiadesk.net/download).

Screen session closes at once

--audit-dir is missing or not writable.

Token file refused

Other users can read it: chmod 600.

Development

The launcher is TypeScript in src/ (locate.ts: finding gaiadesk-cli; detect.ts: reading gaiadesk-cli --version --json to refuse a CLI too old to serve MCP; bin.ts: the stdio passthrough), compiled to dist/, which is what npm publishes.

npm ci
npm test       # build src/ to dist/, build test/ to dist-test/, run node:test against dist/

The end-to-end tests run the built dist/bin.js against a fake gaiadesk-cli (test/fixtures/fake-gaiadesk-cli.ts), as a current CLI (--version --json answered) and as one too old (text, or an error); they need a POSIX shell and are skipped on Windows, where the locator and version-check tests still run. CI runs on Linux, macOS and Windows with Node 18, 20 and 22. The only dev dependencies are typescript and @types/node.

License

MIT. See LICENSE. GaiaDesk itself is proprietary software and is not covered by this license.

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    A
    maintenance
    Enables MCP-compatible AI clients to invoke CLI-driven agent tools over Streamable HTTP, including shell execution, file operations, patching, image viewing, web search, and nested agent tasks, with permission modes and real-time progress streaming.
    -
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables agent clients to safely connect to tools and execution resources through MCP with authorization, approvals, audit, chat-context isolation, SSH/Docker access, and long-running command session tracking.
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables MCP clients such as ChatGPT and Claude to administer Linux or macOS hosts through authenticated Streamable HTTP, including running shell commands, reading and writing files within a workspace, listing directories, and retrieving system metrics.
    118 PyPI
    1
    MIT