Skip to main content
mcpdo is an experimental command-line client that ships in the @modelcontextprotocol/inspector package alongside mcp-inspector. Where the CLI client connects, runs one --method and disconnects, mcpdo connects once and keeps the connection open, so you can run many commands against it from any shell, the way ssh-agent keeps keys loaded. Connections are held by a local background daemon, mcpdod, which mcpdo starts on demand and stops after its last connection closes. You never start it by hand. What it exposes, and how it is protected, is described under The mcpdo connection daemon. Watch the mcpdo tutorial video.

Install

mcpdo is a second bin in the same package, so install the package globally, or run it through npx -p:

Quickstart

mcpdo help, or mcpdo <command> --help, prints the full, authoritative list of commands and flags.

Choosing what to connect

connect takes a catalog entry name or an ad-hoc target:
The catalog and --config behave exactly as for the other clients (see Configuration and flags): the default catalog is ~/.mcp-inspector/mcp.json, overridable with --catalog or MCP_CATALOG_PATH. servers/list and servers/show <name> read entries from disk. connections/* shows what the daemon currently holds. There are no commands to edit the catalog; edit the file directly. A stdio server runs with the working directory and command resolution of the shell that ran connect, not of the daemon, so relative paths and bare command names mean what you would expect.

Addressing a connection

A catalog connection is named after its entry. An ad-hoc one is named after its first token (node, docker, or the URL itself) unless you name it at connect time with @name:
Name the connection on each command with @name, or with --connection <name> (shorthand --conn). A connection named after a URL can only be addressed with --conn <url>, since @name takes only letters, digits, _, . and -:
Omitting the name falls back to the most recently used connection, but only on an interactive TTY. From a script or an agent, where stdin is not a TTY, an unqualified command is an error, so that a background job never acts on whichever server you last used. Set MCP_ALLOW_DEFAULT_CONNECTION=1 to allow the fallback anyway. Connections self-heal: a dropped transport (an expired HTTP session, an exited stdio child) is re-dialed transparently on next use with the stored credentials. Only an auth_required error needs you to run connect again. A connection runs one call at a time. Commands against it from other shells queue behind the call in flight, and while a call is parked on an elicitation, new calls on that connection are refused until it is answered. A long call does not block other connections.

Tasks

A tool that requires task support is refused by a plain tools/call; add --task to make a task-augmented call. It still blocks until the task finishes, then prints the final result:
If the task reaches input_required, its question is handled like any other elicitation.

Output

The global flags are --format, --plain, --connection / --conn, --catalog / --config, and --stored-auth-only. They may go before or after the subcommand, but before any --. The @name shorthand must come before the subcommand. Terminal-bound text (results, elicitation prompts, daemon errors) has control characters stripped, so a server cannot rewrite your terminal. --format json stays verbatim.

Authorization

mcpdo shares oauth.json and the secret store with the other Inspector clients, so a server you have already authorized elsewhere connects without a prompt. OAuth runs at connect time. Mid-session step-up is handled by the one-shot CLI, not by mcpdo. When a browser sign-in is needed and neither stdin nor stderr is a TTY (and MCP_AUTO_OPEN_ENABLED is not forced on), connect exits 0 immediately with pendingAuth: true and an authUrl. Relay that URL to whoever will sign in. The connection completes on its own once they do: the next real command against it finishes the connection, and connections/list reports pendingAuthSignedIn in the meantime. Don’t reconnect to fix a pending sign-in. On a host with no OS keychain, mcpdo stores tokens in the shared secrets.json file, never in memory, because its commands and the daemon are separate processes. That file is plaintext unless you supply a key; see Where secrets are stored.

Elicitation

When a server asks a question mid-call (a legacy elicitation/create, a modern MRTR round, or a task that reaches input_required):
  • On an interactive TTY, mcpdo prompts inline. Form mode renders one prompt per field with a review step. URL mode prints the URL and waits for you to confirm you finished.
  • From a script or agent (--format json, or no TTY), the command returns elicitationPending with an elicitationId, and the call stays parked on the daemon. Answer it from any shell:
A parked elicitation is cancelled after 10 minutes, and a connection holds one at a time; until it is answered, other calls on that connection are refused. URL mode is never auto-accepted. To keep a server from asking at all, connect with --elicit off. --elicit url, form or both (the default) choose which modes are advertised.

Protocol eras

mcpdo negotiates the same protocol eras as the other clients. connect --era legacy|auto|modern overrides a catalog entry’s protocolEra, and is the only way to set it for an ad-hoc target. connections/list tags each connection [legacy] or [modern], and connections/show <name> gives the negotiated version, server info, capabilities, and the supported-versions list when the server was probed.

The daemon

By default every shell you run mcpdo from shares one daemon, so a connection opened in one terminal is usable in another. mcpdo private exports MCP_INSPECTOR_DAEMON_DIR and MCP_INSPECTOR_DAEMON_TOKEN so the current shell gets a separate daemon. That keeps connections apart; it is not a security boundary against other processes running as you. The daemon exits about a minute after its last connection closes. A daemon started before an upgrade keeps running the old code until then, so run mcpdo daemon stop after upgrading the package.

Isolating untrusted stdio servers

The daemon’s token controls who can command the daemon, not what a server can do. A stdio server runs with your full user privileges. To contain one you don’t fully trust, make the stdio command a container:
Without @sandboxed, the connection would be named docker. Adjust the network and mount flags to what the server needs. HTTP and SSE servers run no local code, so they need no process isolation.

Environment variables

mcpdo reads the same catalog, storage and secret-store variables as the other clients (see Environment variables), plus these:

Using mcpdo from a coding agent

The package ships an agent skill that teaches an agent to drive mcpdo: connections it holds then extend the agent’s toolset, and it knows to relay sign-in URLs and answer parked elicitations. mcpdo agent-help prints the guide, mcpdo agent-help --skill-path prints the path of the installable skill file, and mcpdo agent-help --instructions prints a block to append to a project’s CLAUDE.md or AGENTS.md.