Source Intelligence
Sweep 28 Aug 2026 ยท 00:00Z Build v2.1.250 478 read Stable v2.1.236 Latest v2.1.250 Next v2.1.250 Feeds RSS JSON llms.txt

DisclaimerUnofficial, and not affiliated with Anthropic. Nearly all of this is read straight out of what ships: npm bundles, captured prompts, published docs. Anthropic's own notes go in verbatim, marked as theirs. The rest is my reading, and every entry carries the strings behind it. If one looks wrong, vote it down and say why.

One change

CLI client

docs/draft/tools/inspector/cli

The page's own history The capture it came from

Nearest release: v2.1.246, published 8 hours before this site recorded the change. Shown because the two are within 24 hours of each other. Nothing here says the release caused the edit.

docs/draft/tools/inspector/cli New page · 196 lines, new page

# CLI client ## Choosing a server ## Methods ### Passing arguments ## Output ## Probing MCP Apps ## Exit codes and error envelopes ## Authorization in scripts ## Recipes ### Verify a server in CI ### Branch on the failure class ### Smoke-test every tool that has a UI ### Inspect a catalog without connecting ## Proxies

A whole new page. There's nothing to diff it against, so here is what it says.

# CLI client

> Scripting the MCP Inspector: methods, output formats, exit codes, and CI recipes

Each CLI run connects to a server, invokes the single request you name with `--method`, prints the result, and exits. That makes it a good fit for CI pipelines, shell one-liners, and coding agents that need to verify a server change immediately.

```bash theme={null}
npx @modelcontextprotocol/inspector --cli node build/index.js --method tools/list
```

The examples below use the installed `mcp-inspector` binary. Without a global install, prefix each command with `npx @modelcontextprotocol/inspector` instead, as above.

## Choosing a server

The CLI accepts a positional command (stdio), a `--server-url` (HTTP/SSE), or a named server out of a catalog or config file:

```bash theme={null}
# stdio: everything positional is the command to spawn
mcp-inspector --cli node build/index.js --method tools/list

# HTTP
mcp-inspector --cli https://api.example.com/mcp --transport http --method tools/list

# From a file
mcp-inspector --cli --config ./mcp.json --server myserver --method tools/list
```

When the server comes from a file, its per-server settings (headers, timeouts, OAuth, [protocol era](/docs/draft/tools/inspector/protocol-eras), and roots) apply to the connection, resolved exactly as the TUI and web client resolve them. A `--header` flag overrides the file's headers for that run while leaving its timeouts and OAuth in place.

Later examples abbreviate whichever of these forms you use, along with its `--transport` or `--config`/`--server` flags, as `<server>`.

<Note>
  **The config file is the only durable way to give a run its
  [roots](/specification/draft/client/roots):** there is no roots flag, and
  `--method roots/set` applies only to that one short-lived connection. Roots
  configured for a server are advertised at connect, so a server that calls
  `roots/list` (as `@modelcontextprotocol/server-filesystem` does, to learn its
  allowed directories) gets them.
</Note>

See [Configuration and flags](/docs/draft/tools/inspector/configuration) for `--catalog` vs. `--config`, the `--` separator, and the shared server-selection flags.

## Methods

| `--method`                     | Required companions                                   | Notes                                                                            |
| ------------------------------ | ----------------------------------------------------- | -------------------------------------------------------------------------------- |
| `initialize`                   | None                                                  | Connect-only probe: `{serverInfo, protocolVersion, capabilities, instructions}`. |
| `tools/list`                   | None                                                  |                                                                                  |
| `tools/call`                   | `--tool-name`, plus `--tool-arg` / `--tool-args-json` |                                                                                  |
| `resources/list`               | None                                                  |                                                                                  |
| `resources/read`               | `--uri`                                               |                                                                                  |
| `resources/templates/list`     | None                                                  |                                                                                  |
| `prompts/list`                 | None                                                  |                                                                                  |
| `prompts/get`                  | `--prompt-name`, `--prompt-args`                      |                                                                                  |
| `logging/setLevel`             | `--log-level`                                         | Legacy era only; modern servers opt in per request instead.                      |
| `servers/list`, `servers/show` | None                                                  | Read the catalog **without connecting** to anything.                             |

Stream- or session-only methods (`logging/tail`, for example) are rejected, since a process that exits can't hold a stream open.

### Passing arguments

`--tool-arg` takes `key=value` and **coerces** values by JSON-parsing them, so `count=1` becomes a number and `"012"` becomes `12`:

```bash theme={null}
mcp-inspector --cli <server> --method tools/call --tool-name mytool \
  --tool-arg key=value --tool-arg count=1 --tool-arg 'options={"format":"json"}'
```

`--tool-args-json` takes the whole argument object at once and passes it **verbatim**, with no coercion, so `"012"` stays the string `012`. The two are mutually exclusive:

```bash theme={null}
mcp-inspector --cli <server> --method tools/call --tool-name mytool \
  --tool-args-json '{"zip":"10001"}'
```

## Output

`--format text` (the default) pretty-prints for humans. `--format json` emits a single JSON object on stdout with no banners, so the whole output pipes cleanly:

```bash theme={null}
mcp-inspector --cli <server> --method tools/list --format json | jq '.result.tools[].name'
```

## Probing MCP Apps

`--app-info` reports whether a tool ships an [MCP App](/extensions/apps/overview) UI (its `ui://` resource, CSP, and permissions) **without calling the tool**, so a pipeline can decide whether it needs a browser before invoking anything:

```bash theme={null}
# One tool -> one JSON line
mcp-inspector --cli <server> --method tools/call --tool-name my_tool --app-info
# {"hasApp":true,"toolName":"my_tool","resourceUri":"ui://...","csp":{...},"permissions":{...}}

# Every tool -> NDJSON, one line each, over a single connection
mcp-inspector --cli <server> --method tools/list --app-info | jq -c 'select(.hasApp)'
```

Exit codes distinguish the outcomes: a tool with an app exits `0`, one with no app exits `2`, and a missing tool exits `5`, so a typo isn't mistaken for "no app". A probe failure (unreadable UI resource, malformed `resourceUri`) is reported in a `resourceError` field rather than aborting, so one bad tool never kills a whole listing.

<Note>
  `tools/list --app-info` always emits NDJSON (one line per tool) regardless of
  `--format`; `--format json` reshapes only the single-tool output of
  `tools/call --app-info`.
</Note>

## Exit codes and error envelopes

Every non-zero exit maps to a stable failure class, so a caller can branch on *why* without scraping prose:

| Code | Meaning                                                                      |
| ---- | ---------------------------------------------------------------------------- |
| `0`  | Success.                                                                     |
| `1`  | Usage or unexpected error (the catch-all).                                   |
| `2`  | No MCP App found on the tool (`--app-info` probe).                           |
| `3`  | Server requires authentication (401/403, `WWW-Authenticate`, OAuth).         |
| `4`  | Server unreachable (DNS, connection refused, timeout, `fetch failed`).       |
| `5`  | Tool error: `tools/call` returned `isError: true`, or the tool wasn't found. |

On any non-zero exit the CLI also writes a **single JSON line to stderr**:

```json theme={null}
{
  "error": {
    "code": "auth_required",
    "message": "Unauthorized",
    "status": 401,
    "url": "https://api.example/mcp"
  }
}
```

Because it's one line, a caller can parse it with `2>&1 | tail -1 | jq .error`.

A `tools/call` that returns `isError: true` still prints its payload, but exits `5`, so an `&&` chain doesn't proceed on a failed call.

## Authorization in scripts

By default the CLI runs the same loopback OAuth flow as the TUI: it opens a browser and waits on a localhost callback that a CI job can't complete. Two flags make non-interactive runs predictable:

* `--stored-auth-only`: never start interactive OAuth or step-up, and never auto-open a browser. Use tokens from the shared store if present, otherwise fail immediately with `auth_required`. This is the flag CI wants.
* `--use-stored-auth`: reuse a token that the web Inspector already obtained on this machine, refreshing it first when a refresh token is stored.

Without either, and with no TTY on stdin or stderr, the CLI fails fast with `auth_required` rather than hanging for fifteen minutes on a callback nobody will complete.

See [Authorization](/docs/draft/tools/inspector/authorization) for the full flow, the web-to-CLI handoff, and `--print-handoff`.

## Recipes

### Verify a server in CI

```bash theme={null}
set -euo pipefail

# Fail the build if the server can't be reached or doesn't expose the tool
mcp-inspector --cli --config ./ci-servers.json --server my-server \
  --stored-auth-only --method tools/list --format json \
  | jq -e '.result.tools | map(.name) | index("get_weather")' > /dev/null
```

### Branch on the failure class

```bash theme={null}
if out=$(mcp-inspector --cli "$URL" --transport http --method tools/list 2>err.json); then
  echo "$out"
else
  case $? in
    3) echo "needs auth: run the web inspector once to sign in" ;;
    4) echo "server unreachable" ;;
    *) jq .error < err.json ;;
  esac
fi
```

### Smoke-test every tool that has a UI

```bash theme={null}
mcp-inspector --cli "$URL" --transport http --method tools/list --app-info \
  | jq -r 'select(.hasApp) | .toolName'
```

### Inspect a catalog without connecting

```bash theme={null}
mcp-inspector --cli --catalog ~/.mcp-inspector/mcp.json --method servers/list
mcp-inspector --cli --catalog ~/.mcp-inspector/mcp.json --method servers/show --server my-server
```

<Warning>
  `servers/show` redacts secret-bearing fields (`env` values, sensitive headers,
  OAuth client secrets), but it does **not** scrub credentials embedded in a
  server `url` (userinfo or query tokens) or in stdio `args`. Treat raw URL and
  `detail` fields as sensitive before pasting them into an issue.
</Warning>

## Proxies

Connections to remote HTTP/SSE servers honor the conventional proxy variables: `HTTPS_PROXY` / `HTTP_PROXY` (and their lowercase forms) select the proxy and `NO_PROXY` exempts hosts. No Inspector-specific flag is needed, and the proxy agent is loaded lazily, so runs without a proxy pay nothing. The same applies to the web client's backend.