Closes #1795. Enforce localhost-only binding in code (the "never 0.0.0.0" rule was only a spec note): refuse an all-interfaces HOST — across every spelling the OS binds as the wildcard (inet_aton decimal/octal/hex, IPv6, IPv4-mapped, zone-scoped, IDNA/Unicode) — unless DANGEROUSLY_BIND_ALL_INTERFACES=true (Docker's sanctioned opt-in). Fixes the reported stdio-connect 403 by expanding the default loopback origin allow-list to all three interchangeable forms. Hardening surfaced across an extended review: closes an IDNA/fullwidth wildcard bypass, a blank-ALLOWED_ORIGINS fail-open, and the CLI/TUI OAuth-callback wildcard bind (loopback-only now, RFC 8252); canonicalizes the origin allow-list the way a browser does; derives frame-ancestors from the real embedder list (IPv6-literal exclusion verified in headless Chromium); strictPort on all three bind points; and preserves the CLI exit-code map + JSON envelope through the mcp-inspector --cli launcher path. Shared host normalization lives in core/node/hostUrl.ts. Docs + tests + smokes throughout. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
108 lines
6.8 KiB
Markdown
108 lines
6.8 KiB
Markdown
# MCP Inspector TUI Client
|
|
|
|
The Terminal User Interface (TUI) client brings the interactive exploration capabilities of the Web Client directly to your terminal. It is built using [Ink](https://github.com/vadimdemedes/ink) to provide a rich, React-like component experience in a command-line environment.
|
|
|
|

|
|
|
|
## Running the TUI
|
|
|
|
You can run the TUI client via `npx`:
|
|
|
|
```bash
|
|
npx @modelcontextprotocol/inspector --tui node build/index.js
|
|
```
|
|
|
|
### With Configuration Files
|
|
|
|
The TUI can load all servers from an MCP catalog/config file. With no source
|
|
flag it uses the default writable catalog `~/.mcp-inspector/mcp.json` (seeded
|
|
empty if missing):
|
|
|
|
```bash
|
|
npx @modelcontextprotocol/inspector --tui --catalog mcp.json # writable catalog (seeded if missing)
|
|
npx @modelcontextprotocol/inspector --tui --config mcp.json # read-only session (errors if absent)
|
|
```
|
|
|
|
(It does not use `--server`; all servers in the file are available in the TUI.)
|
|
|
|
## Options
|
|
|
|
### MCP server (which server(s) to connect to)
|
|
|
|
Options that specify the MCP server(s) (catalog/config file, ad-hoc command/URL, env vars, headers) are shared by the Web, CLI, and TUI and are documented in [MCP server configuration](../../docs/mcp-server-configuration.md): `--catalog` (writable catalog, seeded if missing; default `~/.mcp-inspector/mcp.json` or `MCP_CATALOG_PATH`), `--config` (read-only session, errors if absent), `-e`, `--cwd`, `--header`, `--transport`, `--server-url`, and the positional `[target...]`. `--catalog` and `--config` are mutually exclusive, and neither combines with an ad-hoc target.
|
|
|
|
### TUI-specific (OAuth for HTTP servers)
|
|
|
|
The TUI supports OAuth for **SSE** and **Streamable HTTP** servers. Per-server OAuth fields in `mcp.json` (static client id/secret, scopes, enterprise-managed flag) are applied automatically when loaded from `--catalog` or `--config`. Install-wide settings (CIMD, enterprise IdP) come from **`~/.mcp-inspector/storage/client.json`** — the same file the web **Client Settings** dialog writes. You can point at a different file with `--client-config` or `MCP_CLIENT_CONFIG_PATH`.
|
|
|
|
#### OAuth callback URL
|
|
|
|
The TUI starts a small loopback HTTP server to receive the authorization redirect after you sign in in the browser. Defaults:
|
|
|
|
| Surface | Default callback |
|
|
| ------- | ---------------- |
|
|
| **Web** | `http://localhost:6274/oauth/callback` (main app server) |
|
|
| **TUI** | `http://127.0.0.1:6276/oauth/callback` (dedicated runner port; avoids colliding with web on 6274) |
|
|
|
|
**Why a fixed default port?** Enterprise-managed auth (EMA), CIMD, and many static OAuth apps require **pre-registered redirect URIs**. A predictable default (`http://127.0.0.1:6276/oauth/callback`) lets you register once on the IdP and reuse it across TUI sessions. Dynamic registration (DCR) can use ephemeral ports instead — see below.
|
|
|
|
**Trade-off:** only **one TUI OAuth flow at a time** can listen on the default port. A second instance starting OAuth while another is in progress may fail with `EADDRINUSE`. Override the listener with `--callback-url` or `MCP_OAUTH_CALLBACK_URL` (e.g. a different fixed port per instance, or `http://127.0.0.1:0/oauth/callback` when the authorization server accepts dynamically registered redirect URIs).
|
|
|
|
OAuth redirect URIs must match **exactly** what you register on the authorization server — `localhost` and `127.0.0.1` are different URIs. Register the TUI default on your OAuth app / IdP when using pre-registered (static), CIMD, or enterprise-managed clients. Override the listener with `--callback-url` or `MCP_OAUTH_CALLBACK_URL`; use `http://127.0.0.1:0/oauth/callback` for an OS-assigned ephemeral port when the authorization server registers redirect URIs dynamically (DCR).
|
|
|
|
#### Flags
|
|
|
|
| Option | Env | Description |
|
|
| ------ | --- | ----------- |
|
|
| `--client-config <path>` | `MCP_CLIENT_CONFIG_PATH` | Install-level client config (default: `~/.mcp-inspector/storage/client.json`). |
|
|
| `--client-id <id>` | — | OAuth client ID (static client); overrides `client.json`. |
|
|
| `--client-secret <secret>` | — | OAuth client secret (confidential clients); overrides `client.json`. |
|
|
| `--client-metadata-url <url>` | — | Client ID Metadata Document URL (CIMD); overrides `client.json`. |
|
|
| `--callback-url <url>` | `MCP_OAUTH_CALLBACK_URL` | OAuth redirect/callback listener (default: `http://127.0.0.1:6276/oauth/callback`). Must bind a **loopback** host (`localhost` / `127.0.0.0/8` / `[::1]`); a non-loopback host hard-errors, since the listener receives the authorization code over plaintext `http`. |
|
|
|
|
#### Authenticating in the TUI
|
|
|
|
1. Select an HTTP/SSE server and press **C** to connect.
|
|
2. If authorization is required, the TUI starts OAuth automatically (browser opens for sign-in).
|
|
3. After the callback completes, connect finishes without a second **C**.
|
|
4. Use the **Auth** tab to inspect OAuth state (same fields as web Connection Info) or **Clear OAuth state** (disconnects when connected).
|
|
|
|
See also [EMA / enterprise-managed auth](../../specification/v2_auth_ema.md) and [OAuth smoke testing](../../specification/v2_auth_smoke_testing.md) for staging servers and verification steps.
|
|
|
|
## Features
|
|
|
|
The TUI provides terminal-native tabs and panes for interacting with your MCP server:
|
|
|
|
- **Resources**: Browse and read resources exposed by the server.
|
|
- **Prompts**: List and test prompts.
|
|
- **Tools**: View available tools and execute them with form-like inputs.
|
|
- **Protocol**: View JSON-RPC request/response/notification history (matches the web Protocol monitor).
|
|
- **Network**: View HTTP fetch traffic for SSE / Streamable HTTP servers (matches the web Network monitor).
|
|
- **Console**: View stdio stderr from the connected server process (matches the web Console monitor).
|
|
|
|
## Navigation
|
|
|
|
- Use the **Arrow Keys** (Left/Right) or **Tab** to switch between the main tabs (Resources, Tools, Prompts, etc.).
|
|
- Use the **Arrow Keys** (Up/Down) to scroll through lists of items.
|
|
- Press **Enter** to select an item, execute a tool, or fetch a resource.
|
|
- Press **Escape** or `Ctrl+C` to exit the application.
|
|
|
|
## Development
|
|
|
|
Like the other clients, the TUI self-validates from its own folder:
|
|
|
|
```bash
|
|
npm run validate # format:check && lint && build && test:coverage
|
|
npm test # run all tests
|
|
npm run test:coverage # run tests under the per-file coverage gate
|
|
```
|
|
|
|
The repo-root `validate:tui` just delegates here. `eslint.config.js` registers
|
|
`react-hooks` for the classic rules only (rules-of-hooks + exhaustive-deps); the
|
|
stricter react-hooks@7 rules are not enforced on the interim component surface
|
|
(#1501).
|
|
|
|
Tests live in `__tests__/`. The coverage gate currently covers the TUI's
|
|
non-React logic (server resolution, logger, tab metadata, and the `utils/`
|
|
form/URL helpers); the Ink components and `App.tsx` are an interim exclusion in
|
|
`vitest.config.ts` pending a renderer-based follow-up.
|