A CLI client for Model Context Protocol (MCP) servers that supports two OAuth 2.0 client authentication strategies:
- CIMD (Client ID Metadata Document) — the client's HTTPS metadata URL is used directly as
client_id. The authorization server fetches your public key from that URL; no prior registration is required. - DCR (Dynamic Client Registration, RFC 7591) — the client registers itself with the server's registration endpoint at runtime and receives a
client_id(and optionally aclient_secret).
Tokens and registration data are cached locally (~/.config/mcp-console/) so subsequent connections are instant.
Requirements
- Node.js ≥ 20
- npm ≥ 9
Installation
# From source git clone <repo-url> cd mcp-console npm install npm run build npm link # makes mcp-console available globally
Quick start
CIMD flow
-
Register — generate an RSA key pair and a CIMD metadata document:
mcp-console register \ --client-id-url https://example.com/my-mcp-client.json \ --client-name "My MCP Client"This writes
cimd-client-metadata.jsonto the current directory and saves your keys to~/.config/mcp-console/keys.json. -
Host the metadata file — make the generated JSON reachable at the URL you provided. It must be served over HTTPS and be publicly accessible.
-
Connect — open an interactive session with an MCP server:
mcp-console connect https://api.example.com/mcp
The first time you connect, a browser window opens for OAuth authorization. Tokens are cached automatically.
DCR flow
No registration step required. Just connect and the client registers itself on the fly:
mcp-console --auth dcr connect https://api.example.com/mcp
Authentication modes (--auth)
The --auth flag is a global option — place it before the subcommand:
mcp-console --auth <mode> <command> [args]
| Mode | Behaviour |
|---|---|
auto |
(default) Checks per-server history. If a clientIdUrl is configured, tries CIMD first; falls back to DCR automatically on invalid_client. |
cimd |
Always use CIMD. Requires register to have been run first. |
dcr |
Always use Dynamic Client Registration. Ignores any configured clientIdUrl. |
Once a mode is resolved automatically, it is saved per-server in ~/.config/mcp-console/servers/. Subsequent connects reuse the saved mode without re-probing.
Commands
register
Generate an RSA key pair (RS256, 2048-bit) and a CIMD client metadata document.
mcp-console register --client-id-url <url> [options]
| Option | Default | Description |
|---|---|---|
--client-id-url <url> |
(required) | HTTPS URL where the metadata document will be hosted. Used as the OAuth client_id. |
--client-name <name> |
mcp-console |
Human-readable name included in the metadata. |
--redirect-uri <uri> |
http://localhost:3000/callback |
OAuth redirect URI. |
--out <path> |
cimd-client-metadata.json |
Output file path for the metadata document. |
--regenerate-keys |
— | Force regeneration of the RSA key pair even if one already exists. |
After running, host the generated file at the URL you specified. The authorization server will fetch it when verifying your identity.
connect
Connect to an MCP server and open an interactive REPL.
mcp-console [--auth <mode>] connect <server-url> [--port <number>]
| Option | Default | Description |
|---|---|---|
--port <number> |
3000 |
Local port for the OAuth callback server. |
Inside the REPL you can list and call tools, list and read resources, and list and get prompts — all through an arrow-key menu.
forget
Delete all stored configuration for an MCP server — tokens, client registration, and resolved auth mode.
mcp-console forget <server-url>
After running, the next connect to that server will go through the full OAuth authorization flow again, as if connecting for the first time.
Example:
mcp-console forget https://api.example.com/mcp
tools
List tools
mcp-console [--auth <mode>] tools list <server-url> [--port <number>]
Prints all tools exposed by the server, including their names, descriptions, and argument names.
Call a tool
mcp-console [--auth <mode>] tools call <server-url> <tool-name> [--args <json>] [--port <number>]
| Option | Default | Description |
|---|---|---|
--args <json> |
{} |
Tool arguments as a JSON object. |
Example:
mcp-console tools call https://api.example.com/mcp get_weather \
--args '{"location":"Madrid"}'resources
List resources
mcp-console [--auth <mode>] resources list <server-url> [--port <number>]
Read a resource
mcp-console [--auth <mode>] resources read <server-url> <uri> [--port <number>]
Text resources are printed to stdout. Binary resources (blobs) are written as raw bytes — suitable for piping:
mcp-console resources read https://api.example.com/mcp file://image.png > image.png
prompts
List prompts
mcp-console [--auth <mode>] prompts list <server-url> [--port <number>]
Get a prompt
mcp-console [--auth <mode>] prompts get <server-url> <prompt-name> [--args <json>] [--port <number>]
| Option | Default | Description |
|---|---|---|
--args <json> |
{} |
Prompt arguments as a JSON object. |
Local file layout
~/.config/mcp-console/
├── config.json # Global config (clientIdUrl, clientName, …)
├── keys.json # RSA private + public key (JWK format)
├── clients/
│ └── <hash>.json # DCR-registered client_id / client_secret per server
├── tokens/
│ └── <hash>.json # Cached access + refresh tokens per server
└── servers/
└── <hash>.json # Resolved auth mode per server (avoids re-probing)
<hash> is the first 16 characters of the SHA-256 hash of the server URL.
Per-server configuration
Each MCP server you connect to gets its own set of files under ~/.config/mcp-console/, keyed by a 16-character SHA-256 hash of the server URL.
servers/<hash>.json
Stores the resolved authentication mode so subsequent connects skip re-probing.
| Field | Values | Description |
|---|---|---|
authMode |
cimd | dcr |
Written after the first successful OAuth flow or auto-detection. |
clients/<hash>.json
Stores the OAuth client identity obtained during registration.
{
"client_id": "https://example.com/my-mcp-client.json",
"client_secret": "optional-secret-for-dcr-clients"
}| Field | Description |
|---|---|
client_id |
For CIMD: your clientIdUrl. For DCR: the server-assigned ID. |
client_secret |
Only present for DCR when the server issues one. |
tokens/<hash>.json
Caches the OAuth access and refresh tokens so reconnects are instant.
{
"access_token": "eyJ...",
"token_type": "Bearer",
"expires_in": 3600,
"expires_at": 1748000000,
"refresh_token": "eyJ...",
"scope": "mcp"
}| Field | Description |
|---|---|
access_token |
Bearer token sent with every MCP request. |
expires_at |
Unix timestamp (seconds). The client uses a 60-second buffer before expiry to trigger a refresh. |
refresh_token |
Used to obtain a new access token without re-authorising in the browser. |
To force re-authentication with a specific server, delete or empty its tokens/<hash>.json file.
Development
npm install # install dependencies npm run dev -- <args> # run from source with tsx (e.g. npm run dev -- --help) npm run typecheck # type-check without building npm run build # compile to dist/
Testing
npm test # run all tests once npm run test:watch # re-run tests on file changes npm run test:coverage # run tests and generate a coverage report
Tests are co-located with their source files (src/**/*.test.ts) and run with Vitest.