@apify/mcpc 0.2.4 → 0.3.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. package/CHANGELOG.md +64 -1
  2. package/CONTRIBUTING.md +12 -0
  3. package/NOTICE +27 -0
  4. package/README.md +219 -226
  5. package/_config.yml +30 -0
  6. package/client-logo.svg +79 -0
  7. package/client-metadata.json +16 -0
  8. package/dist/bridge/index.js +51 -4
  9. package/dist/bridge/index.js.map +1 -1
  10. package/dist/cli/commands/auth.d.ts +2 -0
  11. package/dist/cli/commands/auth.d.ts.map +1 -1
  12. package/dist/cli/commands/auth.js +32 -10
  13. package/dist/cli/commands/auth.js.map +1 -1
  14. package/dist/cli/commands/clean.d.ts.map +1 -1
  15. package/dist/cli/commands/clean.js +13 -2
  16. package/dist/cli/commands/clean.js.map +1 -1
  17. package/dist/cli/commands/grep.d.ts.map +1 -1
  18. package/dist/cli/commands/grep.js +39 -8
  19. package/dist/cli/commands/grep.js.map +1 -1
  20. package/dist/cli/commands/prompts.d.ts.map +1 -1
  21. package/dist/cli/commands/prompts.js +7 -26
  22. package/dist/cli/commands/prompts.js.map +1 -1
  23. package/dist/cli/commands/resources.d.ts.map +1 -1
  24. package/dist/cli/commands/resources.js +9 -3
  25. package/dist/cli/commands/resources.js.map +1 -1
  26. package/dist/cli/commands/sessions.d.ts +45 -2
  27. package/dist/cli/commands/sessions.d.ts.map +1 -1
  28. package/dist/cli/commands/sessions.js +493 -27
  29. package/dist/cli/commands/sessions.js.map +1 -1
  30. package/dist/cli/commands/tasks.d.ts +1 -0
  31. package/dist/cli/commands/tasks.d.ts.map +1 -1
  32. package/dist/cli/commands/tasks.js +15 -1
  33. package/dist/cli/commands/tasks.js.map +1 -1
  34. package/dist/cli/commands/tools.d.ts +6 -1
  35. package/dist/cli/commands/tools.d.ts.map +1 -1
  36. package/dist/cli/commands/tools.js +66 -14
  37. package/dist/cli/commands/tools.js.map +1 -1
  38. package/dist/cli/commands/x402.d.ts.map +1 -1
  39. package/dist/cli/commands/x402.js +7 -7
  40. package/dist/cli/commands/x402.js.map +1 -1
  41. package/dist/cli/helpers.d.ts.map +1 -1
  42. package/dist/cli/helpers.js +3 -6
  43. package/dist/cli/helpers.js.map +1 -1
  44. package/dist/cli/index.js +370 -131
  45. package/dist/cli/index.js.map +1 -1
  46. package/dist/cli/output.d.ts +18 -5
  47. package/dist/cli/output.d.ts.map +1 -1
  48. package/dist/cli/output.js +275 -89
  49. package/dist/cli/output.js.map +1 -1
  50. package/dist/cli/parser.d.ts +4 -0
  51. package/dist/cli/parser.d.ts.map +1 -1
  52. package/dist/cli/parser.js +68 -24
  53. package/dist/cli/parser.js.map +1 -1
  54. package/dist/cli/shell.d.ts.map +1 -1
  55. package/dist/cli/shell.js +44 -21
  56. package/dist/cli/shell.js.map +1 -1
  57. package/dist/cli/tool-result.d.ts +1 -1
  58. package/dist/cli/tool-result.d.ts.map +1 -1
  59. package/dist/cli/tool-result.js +20 -15
  60. package/dist/cli/tool-result.js.map +1 -1
  61. package/dist/core/factory.d.ts +1 -0
  62. package/dist/core/factory.d.ts.map +1 -1
  63. package/dist/core/factory.js +3 -0
  64. package/dist/core/factory.js.map +1 -1
  65. package/dist/core/mcp-client.d.ts +1 -0
  66. package/dist/core/mcp-client.d.ts.map +1 -1
  67. package/dist/core/mcp-client.js +14 -0
  68. package/dist/core/mcp-client.js.map +1 -1
  69. package/dist/core/transports.d.ts +5 -1
  70. package/dist/core/transports.d.ts.map +1 -1
  71. package/dist/core/transports.js +26 -4
  72. package/dist/core/transports.js.map +1 -1
  73. package/dist/lib/auth/auth-page.d.ts +13 -0
  74. package/dist/lib/auth/auth-page.d.ts.map +1 -0
  75. package/dist/lib/auth/auth-page.js +129 -0
  76. package/dist/lib/auth/auth-page.js.map +1 -0
  77. package/dist/lib/auth/oauth-flow.d.ts +2 -1
  78. package/dist/lib/auth/oauth-flow.d.ts.map +1 -1
  79. package/dist/lib/auth/oauth-flow.js +65 -58
  80. package/dist/lib/auth/oauth-flow.js.map +1 -1
  81. package/dist/lib/auth/oauth-provider.d.ts +2 -0
  82. package/dist/lib/auth/oauth-provider.d.ts.map +1 -1
  83. package/dist/lib/auth/oauth-provider.js +6 -0
  84. package/dist/lib/auth/oauth-provider.js.map +1 -1
  85. package/dist/lib/auth/oauth-utils.d.ts +3 -0
  86. package/dist/lib/auth/oauth-utils.d.ts.map +1 -1
  87. package/dist/lib/auth/oauth-utils.js +32 -1
  88. package/dist/lib/auth/oauth-utils.js.map +1 -1
  89. package/dist/lib/auth/profiles.d.ts.map +1 -1
  90. package/dist/lib/auth/profiles.js +3 -3
  91. package/dist/lib/auth/profiles.js.map +1 -1
  92. package/dist/lib/bridge-manager.d.ts.map +1 -1
  93. package/dist/lib/bridge-manager.js +43 -28
  94. package/dist/lib/bridge-manager.js.map +1 -1
  95. package/dist/lib/cleanup.d.ts +5 -0
  96. package/dist/lib/cleanup.d.ts.map +1 -1
  97. package/dist/lib/cleanup.js +38 -1
  98. package/dist/lib/cleanup.js.map +1 -1
  99. package/dist/lib/config.d.ts +21 -0
  100. package/dist/lib/config.d.ts.map +1 -1
  101. package/dist/lib/config.js +99 -5
  102. package/dist/lib/config.js.map +1 -1
  103. package/dist/lib/errors.d.ts +1 -0
  104. package/dist/lib/errors.d.ts.map +1 -1
  105. package/dist/lib/errors.js +4 -1
  106. package/dist/lib/errors.js.map +1 -1
  107. package/dist/lib/session-client.d.ts +1 -0
  108. package/dist/lib/session-client.d.ts.map +1 -1
  109. package/dist/lib/session-client.js +7 -4
  110. package/dist/lib/session-client.js.map +1 -1
  111. package/dist/lib/sessions.d.ts.map +1 -1
  112. package/dist/lib/sessions.js +18 -9
  113. package/dist/lib/sessions.js.map +1 -1
  114. package/dist/lib/types.d.ts +2 -0
  115. package/dist/lib/types.d.ts.map +1 -1
  116. package/dist/lib/utils.d.ts +16 -2
  117. package/dist/lib/utils.d.ts.map +1 -1
  118. package/dist/lib/utils.js +112 -8
  119. package/dist/lib/utils.js.map +1 -1
  120. package/dist/lib/wallets.js +3 -3
  121. package/dist/lib/wallets.js.map +1 -1
  122. package/docs/TODOs.md +5 -0
  123. package/package.json +7 -6
package/README.md CHANGED
@@ -1,30 +1,38 @@
1
- # `mcpc`: Universal MCP command-line client
1
+ # mcpc a universal MCP CLI client
2
2
 
3
- `mcpc` is a CLI for the [Model Context Protocol (MCP)](https://modelcontextprotocol.io/)
4
- that maps MCP operations to intuitive commands for interactive shell use, scripts, and AI coding agents.
3
+ ![mcpc logo](https://apify.github.io/mcpc/client-logo.svg?v=2)
5
4
 
6
- `mcpc` is a Swiss Army knife for MCP. It is useful for inspecting servers, scripting,
7
- and enabling AI coding agents to use MCP ["code mode"](#ai-agents) in shell.
8
- After all, UNIX-compatible shell script is THE most universal coding language.
5
+ [![npm version](https://img.shields.io/npm/v/@apify/mcpc.svg)](https://www.npmjs.com/package/@apify/mcpc)
6
+ [![npm downloads](https://img.shields.io/npm/dm/@apify/mcpc.svg)](https://www.npmjs.com/package/@apify/mcpc)
7
+ [![CI](https://github.com/apify/mcpc/actions/workflows/ci.yml/badge.svg)](https://github.com/apify/mcpc/actions/workflows/ci.yml)
8
+ [![License](https://img.shields.io/npm/l/@apify/mcpc.svg)](https://github.com/apify/mcpc/blob/main/LICENSE)
9
9
 
10
- ![mcpc screenshot](https://raw.githubusercontent.com/apify/mcpc/main/docs/images/mcpc-demo.gif)
10
+ `mcpc` is a command-line client for the [Model Context Protocol (MCP)](https://modelcontextprotocol.io/)
11
+ that maps MCP operations to intuitive commands for interactive shell use, scripting, and AI agents.
12
+
13
+ `mcpc` is your new Swiss Army knife for MCP. It's great for manual inspection and debugging of MCP servers,
14
+ as well as for agents to leverage all modern MCP capabilities through the most universal
15
+ coding interface: the UNIX shell.
11
16
 
12
17
  **Key features:**
13
18
 
14
- - 🌎 **Compatible** - Works with any MCP server over Streamable HTTP or stdio.
15
- - 🔄 **Persistent sessions** - Keep multiple server connections alive simultaneously.
16
- - 🔧 **Strong MCP support** - Instructions, tools, resources, prompts, async tasks, dynamic discovery.
17
- - 🔌 **Code mode** - JSON output enables integration with CLI tools like `jq` and scripting.
18
- - 🤖 **AI sandboxing** - MCP proxy server to securely access authenticated sessions from AI-generated code.
19
- - 🔒 **Secure** - Full OAuth 2.1 support, OS keychain for credentials storage.
19
+ - 🔧 **Full MCP support** - HTTP/stdio transports, instructions, tools, async tasks, resources, prompts, ...
20
+ - 🔄 **Persistent sessions** - Keep multiple stateful connections alive simultaneously.
21
+ - 🗺️ **Progressive tool discovery** - Find relevant MCP tools on the fly to save tokens and increase accuracy.
22
+ - 🔌 **Code mode** - JSON output composes with `jq`, `xargs`, and shell pipelines for MCP workflows as shell scripts.
23
+ - 🔒 **Secure** - Full OAuth 2.1 support with CMID and DCR, uses OS keychain for credentials storage.
24
+ - 🤖 **AI sandboxing** - Proxy MCP server connections to protect credentials from AI-generated code.
20
25
  - 🪶 **Lightweight** - Minimal dependencies, works on Mac/Win/Linux, doesn't use LLMs on its own.
21
- - 💸 **[Agentic payments (x402)](#agentic-payments-x402)** - Experimental support for the [x402](https://www.x402.org/) payment protocol, enabling AI agents to pay for MCP tool calls with USDC on [Base](https://www.base.org/).
26
+ - 💸 **Agentic payments** - Experimental support for the [x402](https://www.x402.org/) protocol on [Base](https://www.base.org/).
27
+
28
+ ![mcpc screenshot](https://raw.githubusercontent.com/apify/mcpc/main/docs/images/mcpc-demo.gif)
22
29
 
23
30
  ## Table of contents
24
31
 
25
32
  <!-- START doctoc generated TOC please keep comment here to allow auto update -->
26
33
  <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
27
34
 
35
+ - [Motivation](#motivation)
28
36
  - [Install](#install)
29
37
  - [Quickstart](#quickstart)
30
38
  - [Usage](#usage)
@@ -43,6 +51,33 @@ After all, UNIX-compatible shell script is THE most universal coding language.
43
51
 
44
52
  <!-- END doctoc generated TOC please keep comment here to allow auto update -->
45
53
 
54
+ ## Motivation
55
+
56
+ Many AI agents misuse MCP. They treat tools as prompt-time function calls, repeatedly injecting
57
+ tool definitions and results into the context. Tokens get wasted, context rots, the
58
+ agent gets slower and less reliable, and popular conclusion that: _"MCP sucks, CLIs are better"_.
59
+
60
+ `mcpc` challenges that narrative. It maps every MCP operation to an intuitive CLI command that
61
+ agents pick up from `--help` alone. Any agent with shell access gets full MCP support without
62
+ wiring up dozens of MCP functions. Just one `Bash()` tool, and `mcpc` handles the rest:
63
+
64
+ ```
65
+
66
+ ┌──────────┐ Bash() ┌──────────┐ MCP ┌────────────┐
67
+ │ AI agent │ ────────────────────► │ mcpc │ ────────────────────► │ MCP server │
68
+ └──────────┘ └──────────┘ Sessions, OAuth, └────────────┘
69
+ Tools, Resources,
70
+ Prompts, Tasks,
71
+ x402, ...
72
+ ```
73
+
74
+ CLI is the perfect _local_ interface between agents and MCP, while MCP remains the
75
+ standard _remote_ interface for server discovery, authentication, payments, and access control.
76
+ The two aren't exclusive – they're complementary.
77
+
78
+ As a bonus, the same `mcpc` configuration, OAuth profiles, and live sessions can be shared across
79
+ many AI agents on the same machine. Authenticate once, reuse everywhere.
80
+
46
81
  ## Install
47
82
 
48
83
  ```bash
@@ -52,28 +87,14 @@ npm install -g @apify/mcpc
52
87
  bun install -g @apify/mcpc
53
88
  ```
54
89
 
55
- **Linux users:** `mcpc` uses the OS keychain for secure credential storage via the
56
- [Secret Service API](https://specifications.freedesktop.org/secret-service/).
57
- On desktop systems (GNOME, KDE) this works out of the box. On headless/server/CI environments
58
- without a keyring daemon, `mcpc` automatically falls back to a file-based credential store
59
- (`~/.mcpc/credentials`, mode `0600`).
90
+ **Linux:** credentials use the OS keychain via the [Secret Service API](https://specifications.freedesktop.org/secret-service/).
91
+ GNOME/KDE desktops work out of the box. On headless/CI systems, `mcpc` falls back to a
92
+ file-based store (`~/.mcpc/credentials`, mode `0600`).
60
93
 
61
- To use the OS keychain on a headless system, install `libsecret` and a secret service daemon:
94
+ To force the keychain on headless systems, install `libsecret` + `gnome-keyring`
95
+ (via `apt-get`, `dnf`, or `pacman`) and run:
62
96
 
63
97
  ```bash
64
- # Debian/Ubuntu
65
- sudo apt-get install libsecret-1-0 gnome-keyring
66
-
67
- # Fedora/RHEL/CentOS
68
- sudo dnf install libsecret gnome-keyring
69
-
70
- # Arch Linux
71
- sudo pacman -S libsecret gnome-keyring
72
- ```
73
-
74
- And then run `mcpc` as follows:
75
-
76
- ```
77
98
  dbus-run-session -- bash -c "echo -n 'password' | gnome-keyring-daemon --unlock && mcpc ..."
78
99
  ```
79
100
 
@@ -106,6 +127,54 @@ mcpc @fs tools-list
106
127
  <!-- AUTO-GENERATED: mcpc --help -->
107
128
 
108
129
  ```
130
+ Usage: mcpc [<@session>] [<command>] [options]
131
+
132
+ Universal command-line client for the Model Context Protocol (MCP).
133
+
134
+ Commands:
135
+ connect <server> [@session] Connect to an MCP server and start a new named @session
136
+ close <@session> Close a session
137
+ restart <@session> Restart a session (losing all state)
138
+ shell <@session> Open interactive shell for a session
139
+ login <server> Interactively login to a server using OAuth and save profile
140
+ logout <server> Delete an OAuth profile for a server
141
+ clean [resources...] Clean up mcpc data (sessions, profiles, logs, all)
142
+ grep <pattern> Search tools and instructions across all active sessions
143
+ x402 [subcommand] [args...] Configure an x402 payment wallet (EXPERIMENTAL)
144
+ help [command] [subcommand] Show help for a specific command
145
+
146
+ Options:
147
+ --json Output in JSON format for scripting
148
+ --verbose Enable debug logging
149
+ --profile <name> OAuth profile for the server ("default" if not provided)
150
+ --timeout <seconds> Request timeout in seconds (default: 300)
151
+ --max-chars <n> Truncate output to n characters (ignored in --json mode)
152
+ --insecure Skip TLS certificate verification (for self-signed certs)
153
+ -v, --version Output the version number
154
+ -h, --help Display help
155
+
156
+ MCP session commands (after connecting):
157
+ <@session> Show MCP server info, capabilities, and tools overview
158
+ <@session> grep <pattern> Search tools and instructions
159
+ <@session> tools-list List all server tools
160
+ <@session> tools-get <name> Get tool details and schema
161
+ <@session> tools-call <name> [arg:=val ... | <json> | <stdin]
162
+ <@session> prompts-list
163
+ <@session> prompts-get <name> [arg:=val ... | <json> | <stdin]
164
+ <@session> resources-list
165
+ <@session> resources-read <uri>
166
+ <@session> resources-subscribe <uri>
167
+ <@session> resources-unsubscribe <uri>
168
+ <@session> resources-templates-list
169
+ <@session> tasks-list
170
+ <@session> tasks-get <taskId>
171
+ <@session> tasks-result <taskId>
172
+ <@session> tasks-cancel <taskId>
173
+ <@session> logging-set-level <level>
174
+ <@session> ping
175
+
176
+ Run "mcpc" without arguments to show active sessions and OAuth profiles.
177
+ Run "mcpc --json" to get the same data as `{ sessions: [...], profiles: [...] }`.
109
178
  ```
110
179
 
111
180
  ### General actions
@@ -170,44 +239,15 @@ echo '{"greeting":"hello","count":10}' | mcpc @session tools-call <tool-name>
170
239
  cat args.json | mcpc @session tools-call <tool-name>
171
240
  ```
172
241
 
173
- **Rules:**
174
-
175
- - All arguments use `:=` syntax: `key:=value`
176
- - Values are auto-parsed: valid JSON becomes that type, otherwise treated as string
177
- - `count:=10` number `10`
178
- - `enabled:=true` → boolean `true`
179
- - `greeting:=hello` → string `"hello"` (not valid JSON, so string)
180
- - `id:='"123"'` → string `"123"` (JSON string literal)
181
- - Inline JSON: If first argument starts with `{` or `[`, it's parsed as a JSON object/array
182
- - Stdin: When no positional args are provided and input is piped, reads JSON from stdin
183
-
184
- **Using shell variables:**
185
-
186
- When using shell variables that may contain spaces, use double quotes around the entire argument:
187
-
188
- ```bash
189
- # Variable with spaces - use double quotes
190
- QUERY="hello world"
191
- mcpc @server tools-call search "query:=${QUERY}"
192
-
193
- # Multiple variables
194
- CITY="New York"
195
- TYPE="restaurants"
196
- mcpc @server tools-call search "query:=${CITY} ${TYPE}"
197
-
198
- # For complex inputs, consider using JSON via stdin
199
- echo "{\"query\": \"${QUERY}\", \"limit\": 10}" | mcpc @server tools-call search
200
- ```
201
-
202
- **Common pitfall:** Don't put spaces around `:=` - it won't work:
242
+ **Auto-parsing rules** for `key:=value`: valid JSON keeps its type
243
+ (`count:=10` → number, `enabled:=true` → boolean, `cfg:='{"k":"v"}'` → object); anything
244
+ else is a string (`greeting:=hello` `"hello"`). Force a string literal with JSON quotes:
245
+ `id:='"123"'`. Inline JSON is detected when the first arg starts with `{` or `[`. Stdin is
246
+ read when no positional args are given and input is piped.
203
247
 
204
- ```bash
205
- # Wrong - spaces around :=
206
- mcpc @server tools-call search query := "hello world"
207
-
208
- # Correct - no spaces around :=
209
- mcpc @server tools-call search "query:=hello world"
210
- ```
248
+ **Pitfalls:** no spaces around `:=` (use `query:=hello world`, not `query := ...`); quote
249
+ the whole argument when it contains shell expansions (`"query:=${VAR}"`). For complex
250
+ inputs, prefer piping JSON via stdin.
211
251
 
212
252
  ### Interactive shell
213
253
 
@@ -251,7 +291,7 @@ By default, `grep` searches only tools. Use `--resources` or `--prompts` to sear
251
291
  (combine with `--tools` to include tools too). Sessions that are crashed or unavailable are shown
252
292
  with their status rather than silently skipped.
253
293
 
254
- The `grep` command is useful for **dynamic tool discovery**,
294
+ The `grep` command is useful for **dynamic tool discovery**,
255
295
  also called [Tool search tool](https://www.anthropic.com/engineering/advanced-tool-use) by Anthropic
256
296
  or [Dynamic context discovery](https://cursor.com/blog/dynamic-context-discovery) by Cursor.
257
297
  Rather than loading all tools into AI agent's context, the agent can use `grep` to discover the right tool
@@ -303,59 +343,25 @@ mcpc @apify close # or: mcpc close @apify
303
343
 
304
344
  ### Session lifecycle
305
345
 
306
- The sessions are persistent: metadata is saved in `~/.mcpc/sessions.json` file,
307
- [authentication tokens](#authentication) in OS keychain.
308
- The `mcpc` bridge process keeps the session alive by sending periodic [ping messages](#ping) to the MCP server.
309
- Still, sessions can fail due to network disconnects, bridge process crash, or server dropping it.
346
+ Session metadata is saved in `~/.mcpc/sessions.json`, [authentication tokens](#authentication)
347
+ in the OS keychain. The bridge process keeps the session alive with periodic [pings](#ping)
348
+ and auto-reconnects on network failures or its own crashes (10s cooldown on failed retries).
310
349
 
311
350
  **Session states:**
312
351
 
313
- | State | Meaning |
314
- | --------------------- | -------------------------------------------------------------------------------------------------- |
315
- | 🟢**`live`** | Bridge process running and server responding |
316
- | 🟡**`connecting`** | Initial bridge startup in progress (`mcpc connect`) |
317
- | 🟡**`reconnecting`** | Bridge crashed or lost auth; auto-reconnecting in the background |
318
- | 🟡**`disconnected`** | Bridge process running but server unreachable; auto-recovers when server responds |
319
- | 🟡**`crashed`** | Bridge process crashed or was killed; auto-reconnects in the background |
320
- | 🔴**`unauthorized`** | Server rejected authentication (401/403) or token refresh failed; auto-reconnects or needs `login` |
321
- | 🔴**`expired`** | Server rejected session ID (404); requires `restart` |
322
-
323
- Here's how `mcpc` handles various bridge process and server connection states:
324
-
325
- - While the **bridge process is running**:
326
- - If **server positively responds** to pings, the session is marked 🟢 **`live`**, and everything is fine.
327
- - If **server stops responding**, the session is marked 🟡 **`disconnected`**.
328
- The bridge will keep trying to reconnect in the background and will return to 🟢 **`live`** once the server responds again.
329
- - If **server rejects authentication** (HTTP 401 or 403) or token refresh fails,
330
- the session is marked 🔴 **`unauthorized`**.
331
- `mcpc` will auto-reconnect in the background if another session sharing the same OAuth profile has refreshed the tokens.
332
- Otherwise, re-authenticate with `mcpc login <server>` and then `mcpc @my-session restart`.
333
- - If **server rejects the session ID** (HTTP 404), indicating the MCP session is no longer valid,
334
- the session is marked 🔴 **`expired`**.
335
- You need to restart the session with `mcpc @my-session restart` to establish a new connection.
336
- - If the **bridge process crashes**, `mcpc` will mark the session as 🟡 **`crashed`**
337
- and auto-reconnect the bridge in the background. You can also trigger reconnection manually
338
- by running any `mcpc @my-session ...` command.
339
- - If reconnection **succeeds** and the server resumes the MCP session, the session returns to 🟢 **`live`**.
340
- - If the server issues a **new session ID** instead of resuming, the session is marked 🔴 **`expired`**.
341
- - If reconnection **fails**, the session remains 🟡 **`crashed`** and retries after a 10-second cooldown.
342
-
343
- Note that `mcpc` never automatically removes sessions from the list.
344
- Instead, it keeps them flagged as 🟡 **`crashed`**, 🔴 **`unauthorized`**, or 🔴 **`expired`**,
345
- and any future attempts to use them will show the appropriate error with recovery instructions.
346
-
347
- To **remove the session from the list**, you need to explicitly close it:
352
+ | State | Meaning |
353
+ | ----------------- | ----------------------------------------------------------------------------------------------- |
354
+ | 🟢 `live` | Bridge process running and server responding |
355
+ | 🟡 `connecting` | Initial bridge startup in progress (`mcpc connect`) |
356
+ | 🟡 `reconnecting` | Bridge crashed or lost auth; auto-reconnecting in the background |
357
+ | 🟡 `disconnected` | Bridge process running but server unreachable; auto-recovers when server responds |
358
+ | 🟡 `crashed` | Bridge process crashed or was killed; auto-reconnects in the background |
359
+ | 🔴 `unauthorized` | Server rejected authentication (401/403) or token refresh failed; re-run `login` then `restart` |
360
+ | 🔴 `expired` | Server rejected session ID (404); requires `restart` |
348
361
 
349
- ```bash
350
- mcpc @apify close # or: mcpc close @apify
351
- ```
352
-
353
- You can restart a session anytime, which kills the bridge process
354
- and opens new connection with new `MCP-Session-Id`, by running:
355
-
356
- ```bash
357
- mcpc @apify restart # or: mcpc restart @apify
358
- ```
362
+ `mcpc` never removes sessions automatically — failed ones stay flagged with a recovery hint
363
+ in the error message. Use `mcpc @apify restart` to kill the bridge and open a fresh
364
+ `MCP-Session-Id`, or `mcpc @apify close` to remove the session entirely.
359
365
 
360
366
  ## Authentication
361
367
 
@@ -388,9 +394,12 @@ mcpc @apify tools-list
388
394
 
389
395
  ### OAuth profiles
390
396
 
391
- For OAuth-enabled remote MCP servers, `mcpc` implements the full OAuth 2.1 flow with PKCE,
392
- including `WWW-Authenticate` header discovery, server metadata discovery, client ID metadata documents,
393
- dynamic client registration, and automatic token refresh.
397
+ For OAuth-enabled remote MCP servers, `mcpc` implements the full OAuth 2.1 flow with PKCE as
398
+ mandated by the [MCP authorization spec](https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization):
399
+ `WWW-Authenticate` 401 challenges, Protected Resource Metadata and authorization server metadata
400
+ discovery, all three [client registration approaches](#client-registration-approaches),
401
+ [resource indicators (RFC 8707)](https://www.rfc-editor.org/rfc/rfc8707), and automatic
402
+ refresh-token rotation.
394
403
 
395
404
  The OAuth authentication **always** needs to be initiated by the user calling the `login` command,
396
405
  which opens a web browser with login screen. `mcpc` never opens the web browser on its own.
@@ -433,83 +442,72 @@ mcpc logout mcp.apify.com
433
442
  mcpc logout mcp.apify.com --profile work
434
443
  ```
435
444
 
436
- ### Authentication precedence
437
-
438
- When multiple authentication methods are available, `mcpc` uses this precedence order:
439
-
440
- 1. **Command-line `--header` flag** (highest priority) - Always used if provided
441
- 2. **Saved authentication profiles** - OAuth tokens from saved profile
442
- 3. **Config file headers** - Headers from `--config` file for the server
443
- 4. **No authentication** - Attempts unauthenticated connection
444
-
445
- **Note:** `--profile` and `--header "Authorization: ..."` cannot be combined — they are mutually
446
- exclusive. Providing both will result in a clear error. Use one or the other.
445
+ ### Client registration approaches
447
446
 
448
- `mcpc` automatically handles authentication based on what you specify:
447
+ When logging in, `mcpc` supports all three OAuth client registration approaches defined in the
448
+ [MCP authorization spec](https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization#client-registration-approaches),
449
+ picking the one the authorization server advertises in its OAuth metadata:
449
450
 
450
- **When `--header "Authorization: ..."` is provided:**
451
+ | **Approach** | **`mcpc login` flags** |
452
+ | :-------------------------------------- | :-------------------------------------------------- |
453
+ | **Pre-registration** | `--client-id` (and optional `--client-secret`) |
454
+ | **Client ID Metadata Documents (CIMD)** | default (or `--client-metadata-url <url>`) |
455
+ | **Dynamic Client Registration (DCR)** | fallback (or force with `--no-client-metadata-url`) |
451
456
 
452
- - The explicit header is always used, and OAuth profile auto-detection is skipped entirely
453
- - This works even if a `default` profile exists for the server
454
- - Cannot be combined with `--profile` (returns an error)
457
+ `mcpc` ships with a hosted [Client ID Metadata Document](https://apify.github.io/mcpc/client-metadata.json)
458
+ so every installation presents the same client identity to CIMD-capable authorization servers.
459
+ When the authorization server advertises `client_id_metadata_document_supported: true`, the CIMD
460
+ URL is used as the `client_id`; otherwise mcpc falls back to Dynamic Client Registration.
455
461
 
456
- **When `--profile <name>` is specified:**
457
-
458
- 1. **Profile exists for the server**: Use its stored credentials
459
- - If authentication succeeds → Continue with command/session
460
- - If authentication fails (expired/invalid) → Fail with an error
461
- 2. **Profile doesn't exist**: Fail with an error
462
-
463
- **When `--x402` is specified (without `--profile`):**
464
-
465
- - OAuth profile auto-detection is skipped, since x402 serves as the payment/auth mechanism
466
- - If you also pass `--profile`, the specified profile is still used alongside x402
462
+ ```bash
463
+ # Default: mcpc's hosted CIMD is used automatically (no flags needed).
464
+ mcpc login mcp.apify.com
467
465
 
468
- **When `--no-profile` is specified:**
466
+ # Pre-registered OAuth client (public or confidential) — skips CIMD.
467
+ mcpc login mcp.example.com --client-id <id> [--client-secret <secret>]
469
468
 
470
- - Skip all OAuth profile detection and connect anonymously
471
- - Useful when a `default` profile exists but you want an unauthenticated session
472
- - Can be combined with `--header "Authorization: ..."` for explicit bearer token without profile
469
+ # Custom CIMD: override the default with your own hosted document.
470
+ mcpc login mcp.example.com --client-metadata-url https://example.com/my-client.json
473
471
 
474
- **When no flags are specified (default):**
472
+ # Disable CIMD: force Dynamic Client Registration even if the server supports CIMD.
473
+ mcpc login mcp.example.com --no-client-metadata-url
474
+ ```
475
475
 
476
- 1. **`default` profile exists for the server**: Use its stored credentials
477
- - If authentication succeeds Continue with command/session
478
- - If authentication fails (expired/invalid) → Fail with an error
479
- 2. **`default` profile doesn't exist**: Attempt unauthenticated connection
480
- - If server accepts (no auth required) → Continue without creating profile
481
- - If server rejects with 401 + `WWW-Authenticate` → Fail with an error
476
+ See the [MCP authorization spec](https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization#client-registration-approaches)
477
+ for details on each approach and the format of Client ID Metadata Documents.
482
478
 
483
- On failure, the error message includes instructions on how to login and save the profile, so you know what to do.
479
+ ### Authentication precedence
484
480
 
485
- This flow ensures:
481
+ When connecting, `mcpc` picks one auth source based on the flags you pass — explicit flags
482
+ always win over stored profiles, and credentials are never silently downgraded. If a profile
483
+ is missing, expired, or invalid, `mcpc` fails with an error that includes the right
484
+ `mcpc login` command to recover.
486
485
 
487
- - Explicit CLI flags always take precedence over stored profiles
488
- - Credentials are never silently mixed up (personal → work) or downgraded (authenticated → unauthenticated)
489
- - You can mix authenticated sessions (with named profiles) and public access on the same server
486
+ | Flag | Behavior |
487
+ | ------------------------------- | ------------------------------------------------------------------------------------------- |
488
+ | `--header "Authorization: ..."` | Use explicit header; skip OAuth auto-detection. Cannot combine with `--profile`. |
489
+ | `--profile <name>` | Require the named profile to exist. |
490
+ | `--no-profile` | Connect anonymously even if a `default` profile exists. |
491
+ | `--x402` | Skip OAuth auto-detection; use x402 payments instead. Combine with `--profile` to use both. |
492
+ | _(none)_ | Use `default` profile if it exists; otherwise connect anonymously. |
490
493
 
491
- **Examples:**
494
+ Config file headers (from `--config`) apply to servers loaded from that file.
492
495
 
493
496
  ```bash
494
- # With specific profile - always authenticated:
495
- # - Uses 'work' if it exists
496
- # - Fails if it doesn't exist
497
- mcpc connect mcp.apify.com @apify-work --profile work
498
-
499
- # Without profile - opportunistic authentication:
500
- # - Uses 'default' if it exists
501
- # - Tries unauthenticated if 'default' doesn't exist
502
- # - Fails if the server requires authentication
497
+ # Default: 'default' profile if it exists, else anonymous
503
498
  mcpc connect mcp.apify.com @apify-personal
504
499
 
505
- # Explicit bearer token - skips profile auto-detection:
506
- mcpc connect mcp.apify.com @apify --header "Authorization: Bearer ${APIFY_TOKEN}"
500
+ # Specific profile (fails if missing)
501
+ mcpc connect mcp.apify.com @apify-work --profile work
507
502
 
508
- # x402 payment - skips default profile auto-detection:
509
- mcpc connect mcp.apify.com @apify --x402
503
+ # Explicit bearer token (no profile)
504
+ mcpc connect mcp.apify.com @apify --header "Authorization: Bearer ${APIFY_TOKEN}"
510
505
 
511
- # Anonymous - skips default profile even if it exists:
506
+ # Skip default profile, connect anonymously
512
507
  mcpc connect mcp.apify.com @apify-anon --no-profile
508
+
509
+ # x402 micropayments instead of OAuth
510
+ mcpc connect mcp.apify.com @apify --x402
513
511
  ```
514
512
 
515
513
  ## MCP proxy
@@ -592,22 +590,12 @@ mcpc @server tools-get search
592
590
  mcpc @server tools-call search query:="hello world"
593
591
  ```
594
592
 
595
- **Code mode** - Once agents understand the server's capabilities, they can write shell scripts
596
- that compose multiple `mcpc` commands with `--json` output. This can be
597
- [more accurate](https://www.anthropic.com/engineering/code-execution-with-mcp)
598
- and use fewer tokens than tool calling for complex workflows.
599
-
600
- ```bash
601
- # AI-generated script using --json for structured data
602
- mcpc --json @apify tools-call search-actors keywords:="scraper" \
603
- | jq '.content[0].text | fromjson | .items[0].id' \
604
- | xargs -I {} mcpc @apify tools-call get-actor actorId:="{}"
605
- ```
606
-
607
- With [schema validation](#schema-validation), agents can ensure stability of integrations and faster failure recovery.
608
- Agents, make no harm!
609
-
610
- See an [example](./docs/examples/company-lookup.sh) of an AI-generated shell script.
593
+ **Code mode** - Once agents understand the server's capabilities, they can write shell
594
+ scripts that compose multiple `mcpc` commands with `--json` output see
595
+ [Scripting](#scripting) below. This can be
596
+ [more accurate](https://www.anthropic.com/engineering/code-execution-with-mcp) and use
597
+ fewer tokens than tool calling for complex workflows. Pair with
598
+ [schema validation](#schema-validation) to catch breaking changes early.
611
599
 
612
600
  ### Scripting
613
601
 
@@ -630,12 +618,15 @@ For a complete example script, see [`docs/examples/company-lookup.sh`](./docs/ex
630
618
 
631
619
  ### Schema validation
632
620
 
633
- Validate tool/prompt schemas using the `--schema` option to detect breaking changes early:
621
+ The `tools-get` and `tools-call` commands support `--schema` to validate a tool's schema against an expected snapshot. This helps detect breaking changes early in scripts and CI:
634
622
 
635
623
  ```bash
636
624
  # Save expected schema
637
625
  mcpc --json @apify tools-get search-actors > expected.json
638
626
 
627
+ # Validate without calling (read-only check)
628
+ mcpc @apify tools-get search-actors --schema expected.json
629
+
639
630
  # Validate before calling (fails if schema changed incompatibly)
640
631
  mcpc @apify tools-call search-actors --schema expected.json keywords:="test"
641
632
  ```
@@ -738,10 +729,10 @@ mcpc x402 sign <base64-payment-required> --amount 1.00 --expiry 3600 --json
738
729
 
739
730
  **Options:**
740
731
 
741
- | Option | Description |
742
- | ------------------- | ---------------------------------------------------------------- |
743
- | `--amount <usd>` | Override the payment amount in USD (e.g. `0.50` for $0.50) |
744
- | `--expiry <seconds>`| Override the payment expiry in seconds from now (e.g. `3600`) |
732
+ | Option | Description |
733
+ | -------------------- | ------------------------------------------------------------- |
734
+ | `--amount <usd>` | Override the payment amount in USD (e.g. `0.50` for $0.50) |
735
+ | `--expiry <seconds>` | Override the payment expiry in seconds from now (e.g. `3600`) |
745
736
 
746
737
  The command outputs the signed `PAYMENT-SIGNATURE` header value and an MCP config snippet
747
738
  that can be used directly with other MCP clients.
@@ -812,7 +803,7 @@ The bridge process manages the full MCP session lifecycle:
812
803
  | 🔔 [**Notifications**](#list-change-notifications) | ✅ Supported |
813
804
  | 📄 [**Pagination**](#pagination) | ✅ Supported |
814
805
  | 🏓 [**Ping**](#ping) | ✅ Supported |
815
- | ⏳ [**Async tasks**](#async-tasks) | ✅ Supported |
806
+ | ⏳ [**Async tasks**](#async-tasks) | ✅ Supported |
816
807
  | 📁 **Roots** | 🚧 Planned |
817
808
  | ❓ **Elicitation** | 🚧 Planned |
818
809
  | 🔤 **Completion** | 🚧 Planned |
@@ -982,6 +973,9 @@ mcpc @apify tasks-list
982
973
  # Check task status
983
974
  mcpc @apify tasks-get <taskId>
984
975
 
976
+ # Get the task result (blocks until the task reaches a terminal state)
977
+ mcpc @apify tasks-result <taskId>
978
+
985
979
  # Cancel a running task
986
980
  mcpc @apify tasks-cancel <taskId>
987
981
  ```
@@ -989,6 +983,8 @@ mcpc @apify tasks-cancel <taskId>
989
983
  With `--task`, the CLI shows a progress spinner with elapsed time, server status messages,
990
984
  and progress notifications. Press **ESC** during execution to detach and get the task ID
991
985
  for later retrieval. With `--detach`, the task starts and returns the task ID immediately.
986
+ Use `tasks-result <taskId>` to fetch the final `CallToolResult` payload once the task
987
+ completes.
992
988
 
993
989
  `tools-list` and `tools-get` show task support annotations per tool:
994
990
  `[task:optional]`, `[task:required]`, or `[task:forbidden]`.
@@ -1055,16 +1051,13 @@ For **stdio servers:**
1055
1051
  - `args` (optional) - Array of command arguments
1056
1052
  - `env` (optional) - Environment variables for the process
1057
1053
 
1058
- **Using servers from config file:**
1059
-
1060
- Reference servers by their name using the `file:entry` syntax:
1061
-
1062
- ```bash
1063
- # Create a named session from a server in the config
1064
- mcpc connect .vscode/mcp.json:filesystem @fs
1065
- mcpc @fs tools-list
1066
- mcpc @fs tools-call search
1067
- ```
1054
+ > **Note:** Stdio servers inherit only a minimal env whitelist from the shell
1055
+ > (`PATH`, `HOME`, `SHELL`, …). Other vars — `NODE_EXTRA_CA_CERTS`, `HTTPS_PROXY`,
1056
+ > `SSL_CERT_FILE`, etc. must be forwarded explicitly via the `env` block using
1057
+ > `${VAR_NAME}`. Anything the server writes to stderr is captured to
1058
+ > `~/.mcpc/logs/bridge-<session>.log` with a `[server stderr]` prefix, and the
1059
+ > tail is appended to the error message if `mcpc connect` fails, so you can see
1060
+ > why a stdio server failed to start.
1068
1061
 
1069
1062
  **Environment variable substitution:**
1070
1063
 
@@ -1218,19 +1211,19 @@ See [CONTRIBUTING](./CONTRIBUTING.md) for development setup, architecture overvi
1218
1211
  <!-- Stars, contributors, commits, and activity as of March 2026. -->
1219
1212
 
1220
1213
  | Tool | Lang | Stars | Contrib / Commits | Active | Tools | Resources | Prompts | Tasks | Code mode | Sessions | OAuth | Stdio | HTTP | Tool search | x402 | LLM |
1221
- | ----------------------------------------------------------------------- | ------ | ----: | -----------------: | ------ | ----- | --------- | ------- | ----- | --------- | -------- | ----- | ----- | ---- | ----------- | ---- | --- |
1222
- | **[apify/mcpc](https://github.com/apify/mcpc)** | TS | ~420 | 7 / ~510 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | — |
1223
- | [steipete/mcporter](https://github.com/steipete/mcporter) | TS | ~3.5k | 24 / ~570 | ✅ | ✅ | — | — | — | ✅ | ✅ | ✅ | ✅ | ✅ | — | — | — |
1224
- | [IBM/mcp-cli](https://github.com/IBM/mcp-cli) | Python | ~1.9k | 22 / ~790 | ✅ | ✅ | ✅ | ✅ | — | ✅ | ✅ | ✅ | ✅ | ✅ | — | — | ✅ |
1225
- | [knowsuchagency/mcp2cli](https://github.com/knowsuchagency/mcp2cli) | Python | ~1.8k | 5 / ~76 | ✅ | ✅ | ✅ | ✅ | — | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | — | — |
1226
- | [f/mcptools](https://github.com/f/mcptools) | Go | ~1.5k | 15 / ~170 | ⚠️ | ✅ | ✅ | ✅ | — | ✅ | — | — | ✅ | ✅ | — | — | — |
1227
- | [philschmid/mcp-cli](https://github.com/philschmid/mcp-cli) | TS | ~1.1k | 2 / ~30 | ✅ | ✅ | — | — | — | ✅ | ✅ | — | ✅ | ✅ | ✅ | — | — |
1228
- | [adhikasp/mcp-client-cli](https://github.com/adhikasp/mcp-client-cli) | Python | ~670 | 6 / ~110 | ⚠️ | ✅ | ✅ | ✅ | — | — | — | — | ✅ | — | — | — | ✅ |
1229
- | [thellimist/clihub](https://github.com/thellimist/clihub) | Go | ~640 | 1 / ~60 | ✅ | ✅ | — | — | — | — | — | ✅ | ✅ | ✅ | ✅ | — | — |
1230
- | [wong2/mcp-cli](https://github.com/wong2/mcp-cli) | JS | ~430 | 4 / ~63 | ⚠️ | ✅ | ✅ | ✅ | — | — | — | ✅ | — | ✅ | — | — | — |
1231
- | [mcpshim/mcpshim](https://github.com/mcpshim/mcpshim) | Go | ~54 | 1 / ~13 | ✅ | ✅ | — | — | — | ✅ | ✅ | ✅ | — | ✅ | ✅ | — | — |
1232
- | [evantahler/mcpx](https://github.com/evantahler/mcpx) | TS | ~28 | 1 / ~64 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | — | ✅ | ✅ | ✅ | ✅ | — | — |
1233
- | [EstebanForge/mcp-cli-ent](https://github.com/EstebanForge/mcp-cli-ent) | Go | ~15 | ~2 / ~46 | ✅ | ✅ | — | — | — | ✅ | ✅ | — | ✅ | ✅ | ✅ | — | — |
1214
+ | ----------------------------------------------------------------------- | ------ | ----: | ----------------: | ------ | ----- | --------- | ------- | ----- | --------- | -------- | ----- | ----- | ---- | ----------- | ---- | --- |
1215
+ | **[apify/mcpc](https://github.com/apify/mcpc)** | TS | ~420 | 7 / ~510 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | — |
1216
+ | [steipete/mcporter](https://github.com/steipete/mcporter) | TS | ~3.5k | 24 / ~570 | ✅ | ✅ | — | — | — | ✅ | ✅ | ✅ | ✅ | ✅ | — | — | — |
1217
+ | [IBM/mcp-cli](https://github.com/IBM/mcp-cli) | Python | ~1.9k | 22 / ~790 | ✅ | ✅ | ✅ | ✅ | — | ✅ | ✅ | ✅ | ✅ | ✅ | — | — | ✅ |
1218
+ | [knowsuchagency/mcp2cli](https://github.com/knowsuchagency/mcp2cli) | Python | ~1.8k | 5 / ~76 | ✅ | ✅ | ✅ | ✅ | — | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | — | — |
1219
+ | [f/mcptools](https://github.com/f/mcptools) | Go | ~1.5k | 15 / ~170 | ⚠️ | ✅ | ✅ | ✅ | — | ✅ | — | — | ✅ | ✅ | — | — | — |
1220
+ | [philschmid/mcp-cli](https://github.com/philschmid/mcp-cli) | TS | ~1.1k | 2 / ~30 | ✅ | ✅ | — | — | — | ✅ | ✅ | — | ✅ | ✅ | ✅ | — | — |
1221
+ | [adhikasp/mcp-client-cli](https://github.com/adhikasp/mcp-client-cli) | Python | ~670 | 6 / ~110 | ⚠️ | ✅ | ✅ | ✅ | — | — | — | — | ✅ | — | — | — | ✅ |
1222
+ | [thellimist/clihub](https://github.com/thellimist/clihub) | Go | ~640 | 1 / ~60 | ✅ | ✅ | — | — | — | — | — | ✅ | ✅ | ✅ | ✅ | — | — |
1223
+ | [wong2/mcp-cli](https://github.com/wong2/mcp-cli) | JS | ~430 | 4 / ~63 | ⚠️ | ✅ | ✅ | ✅ | — | — | — | ✅ | — | ✅ | — | — | — |
1224
+ | [mcpshim/mcpshim](https://github.com/mcpshim/mcpshim) | Go | ~54 | 1 / ~13 | ✅ | ✅ | — | — | — | ✅ | ✅ | ✅ | — | ✅ | ✅ | — | — |
1225
+ | [evantahler/mcpx](https://github.com/evantahler/mcpx) | TS | ~28 | 1 / ~64 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | — | ✅ | ✅ | ✅ | ✅ | — | — |
1226
+ | [EstebanForge/mcp-cli-ent](https://github.com/EstebanForge/mcp-cli-ent) | Go | ~15 | ~2 / ~46 | ✅ | ✅ | — | — | — | ✅ | ✅ | — | ✅ | ✅ | ✅ | — | — |
1234
1227
 
1235
1228
  **Legend:** ✅ = supported, ⚠️ = stale (no commits in 3+ months), **Contrib / Commits** = contributors / total commits, **Tasks** = [async tasks](https://modelcontextprotocol.io/specification/latest/server/utilities/tasks), **x402** = [x402 payment protocol](https://www.x402.org/) support, **LLM** = requires/uses an LLM.
1236
1229