@apify/mcpc 0.3.0-beta.0 → 0.3.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.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.3.0] - 2026-05-20
11
+
10
12
  ### Added
11
13
 
12
14
  - `mcpc connect` (with no arguments) now auto-discovers standard MCP config files (`.mcp.json`, `mcp.json`, `.cursor/mcp.json`, `.vscode/mcp.json`, `~/.claude.json`, Claude Desktop, Windsurf, Kiro, etc.) in the current directory and home directory, and connects every server defined across them. Entries with duplicate session names are deduplicated (project-scoped files win over global ones). VS Code's `"servers"` key is also supported.
@@ -32,6 +34,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
32
34
 
33
35
  - **Breaking:** Removed `tools`, `resources`, and `prompts` shorthand commands — use the full names (`tools-list`, `resources-list`, `prompts-list`) instead
34
36
 
37
+ ### Security
38
+
39
+ - Migrated the dev/release toolchain to pnpm 10 with a 24-hour package quarantine (`minimumReleaseAge: 1440`) to reduce supply-chain attack risk. End-user installs from npm are unaffected
40
+
35
41
  ## [0.2.6] - 2026-04-15
36
42
 
37
43
  ### Added
@@ -265,7 +271,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
265
271
  - Interactive shell mode
266
272
  - JSON output mode for scripting
267
273
 
268
- [Unreleased]: https://github.com/apify/mcpc/compare/v0.2.6...HEAD
274
+ [Unreleased]: https://github.com/apify/mcpc/compare/v0.3.0...HEAD
275
+ [0.3.0]: https://github.com/apify/mcpc/compare/v0.2.6...v0.3.0
269
276
  [0.2.6]: https://github.com/apify/mcpc/compare/v0.2.5...v0.2.6
270
277
  [0.2.5]: https://github.com/apify/mcpc/compare/v0.2.4...v0.2.5
271
278
  [0.2.4]: https://github.com/apify/mcpc/compare/v0.2.3...v0.2.4
package/CONTRIBUTING.md CHANGED
@@ -21,42 +21,48 @@ When writing examples, tests, README snippets, or help text that reference a rem
21
21
  please use `mcp.apify.com` rather than placeholders like `mcp.example.com` or arbitrary third-party
22
22
  servers. The motivation is purely practical: `mcp.apify.com` is a real, publicly available MCP
23
23
  server that works out of the box, so readers can copy-paste examples and run them unchanged.
24
- Placeholders like `mcp.example.com` don't resolve to anything, which forces every reader to
25
- substitute a URL before they can try an example.
26
24
 
27
25
  This is a soft convention for documentation consistency, not a license condition — mcpc is
28
26
  distributed under Apache 2.0 and you are free to use it with any MCP server.
29
27
 
30
28
  ## Development setup
31
29
 
30
+ This repo uses [pnpm](https://pnpm.io/) 10 (pinned via `packageManager` in `package.json`). If you
31
+ don't have it, the easiest way is `corepack enable && corepack prepare pnpm@10 --activate`.
32
+
32
33
  ```bash
33
34
  # Clone repository
34
35
  git clone https://github.com/apify/mcpc.git
35
36
  cd mcpc
36
37
 
37
38
  # Install dependencies
38
- npm install
39
+ pnpm install
39
40
 
40
41
  # Run tests
41
- npm test
42
+ pnpm test
42
43
 
43
44
  # Build
44
- npm run build
45
+ pnpm run build
45
46
 
46
47
  # Test locally
47
- npm link
48
+ pnpm link --global
48
49
  mcpc --help
49
50
  ```
50
51
 
52
+ As a supply-chain hardening measure, `pnpm-workspace.yaml` sets `minimumReleaseAge: 1440`, so newly
53
+ published third-party packages aren't installed until they're at least 24 hours old. If a fresh
54
+ dependency bump seems "stuck," that's why — wait it out, or add a targeted exclusion in
55
+ `minimumReleaseAgeExclude` if you have a justified reason.
56
+
51
57
  ## Testing
52
58
 
53
59
  See [`test/README.md`](./test/README.md) for details on running unit and E2E tests.
54
60
 
55
61
  ```bash
56
- npm test # Run all tests (unit + e2e)
57
- npm run test:unit # Run unit tests only
58
- npm run test:e2e # Run e2e tests only
59
- npm run test:coverage # Run all tests with coverage
62
+ pnpm test # Run all tests (unit + e2e)
63
+ pnpm run test:unit # Run unit tests only
64
+ pnpm run test:e2e # Run e2e tests only
65
+ pnpm run test:coverage # Run all tests with coverage
60
66
  ```
61
67
 
62
68
  ### E2E test prerequisites
@@ -64,8 +70,8 @@ npm run test:coverage # Run all tests with coverage
64
70
  E2E tests require `mcpc` to be built first:
65
71
 
66
72
  ```bash
67
- npm run build
68
- npm link
73
+ pnpm run build
74
+ pnpm link --global
69
75
  ```
70
76
 
71
77
  Some E2E tests connect to a real remote MCP server and require OAuth authentication profiles.
@@ -83,154 +89,39 @@ The test runner does not take any destructive actions.
83
89
  ## Release process
84
90
 
85
91
  Use the release script to publish a new version
86
- of the [@apify/mcpc](https://www.npmjs.com/package/@apify/mcpc) package on NPM:
92
+ of the [@apify/mcpc](https://www.npmjs.com/package/@apify/mcpc) package on npm:
87
93
 
88
94
  ```bash
89
- npm run release # patch version bump (0.1.2 → 0.1.3)
90
- npm run release:minor # minor version bump (0.1.2 → 0.2.0)
91
- npm run release:major # major version bump (0.1.2 → 1.0.0)
95
+ pnpm run release # patch version bump (0.1.2 → 0.1.3)
96
+ pnpm run release:minor # minor version bump (0.1.2 → 0.2.0)
97
+ pnpm run release:major # major version bump (0.1.2 → 1.0.0)
92
98
  ```
93
99
 
94
- The script automatically:
95
- - Ensures you're on `main` branch
96
- - Ensures working directory is clean (no uncommitted changes)
97
- - Ensures branch is up-to-date with remote
98
- - Runs lint, build, and tests
99
- - Bumps the version in package.json
100
- - Creates a git commit and annotated tag (`v{version}`)
101
- - Pushes the commit and tag to origin
102
- - Publishes to npm
100
+ The script validates preconditions locally (clean branch, up-to-date with `origin/main`, CI green),
101
+ then triggers the `release.yml` GitHub Actions workflow which handles lint, build, test, version
102
+ bump, changelog update, README update, git commit/tag/push, npm publish (with provenance), and
103
+ GitHub release creation.
103
104
 
104
- After publishing, create a GitHub release at the provided link.
105
+ ## Architecture
105
106
 
106
- ## Architecture overview
107
+ The codebase is a single TypeScript package with three internal modules:
107
108
 
108
109
  ```
109
- mcpc (single package)
110
- ├── src/
111
- ├── core/ # Core MCP protocol implementation
112
- ├── bridge/ # Bridge process logic
113
- │ ├── cli/ # CLI interface
114
- │ └── lib/ # Shared utilities
115
- ├── bin/
116
- │ ├── mcpc # Main CLI executable
117
- │ └── mcpc-bridge # Bridge process executable
118
- └── test/
119
- └── e2e/
120
- └── server/ # Test MCP server for E2E tests
110
+ src/
111
+ ├── core/ # Runtime-agnostic MCP protocol implementation (Node ≥18, Bun ≥1)
112
+ ├── bridge/ # Persistent bridge process — one per session, owns the MCP connection
113
+ ├── cli/ # `mcpc` command — argument parsing, output formatting, IPC to the bridge
114
+ └── lib/ # Shared utilities (auth, keychain, file locking, …)
121
115
  ```
122
116
 
123
- ### Core module (runtime-agnostic)
124
-
125
- Implemented with minimal dependencies to support both Node.js (≥18.0.0) and Bun (≥1.0.0).
126
-
127
- **Core responsibilities:**
128
- - Transport selection and initialization (Streamable HTTP vs stdio)
129
- - MCP protocol implementation and version negotiation
130
- - Session state machine management
131
- - Streamable HTTP connection management (reconnection with exponential backoff)
132
- - Request/response correlation (JSON-RPC style with request IDs)
133
- - Multiplexing concurrent requests (up to 10 concurrent)
134
- - Event emitter for async notifications
135
-
136
- **Key dependencies:**
137
- - Native `fetch` API (available in Node.js 18+ and Bun)
138
- - Native process APIs for stdio transport
139
- - Minimal: UUID generation, event emitter abstraction
140
-
141
- ### Bridge process
142
-
143
- Implemented as a separate executable (`mcpc-bridge`) that maintains persistent connections.
144
-
145
- **Bridge responsibilities:**
146
- - Session persistence (reads/writes `~/.mcpc/sessions.json` with file locking)
147
- - Process lifecycle management for local package servers
148
- - Stdio framing and protocol handling
149
- - Unix domain socket server for CLI communication
150
- - Heartbeat mechanism for health monitoring
151
- - Orphaned process cleanup on startup
152
-
153
- **IPC protocol:**
154
- - Unix domain sockets (located in `~/.mcpc/bridges/<session-name>.sock`)
155
- - Named pipes on Windows
156
- - JSON-RPC style messages over socket
157
- - Control messages: init, request, cancel, close, health-check
158
-
159
- **Bridge discovery:**
160
- - CLI reads `~/.mcpc/sessions.json` to find socket path and PID
161
- - Validates bridge is alive (connect to socket + health-check)
162
- - Auto-restarts crashed bridges (detected via socket connection failure)
163
- - Cleanup: removes stale socket files for dead processes
164
-
165
- **Concurrency safety:**
166
- - `~/.mcpc/sessions.json` protected with file locking (`proper-lockfile` package)
167
- - Atomic writes (write to temp file, then rename)
168
- - Lock timeout: 5 seconds (fails if can't acquire lock)
169
-
170
- ### CLI executable
171
-
172
- The main `mcpc` command provides the user interface.
173
-
174
- **CLI responsibilities:**
175
- - Argument parsing using Commander.js
176
- - Output formatting (human-readable vs `--json`)
177
- - Bridge lifecycle: start/connect/stop
178
- - Communication with bridge via socket
179
- - Interactive shell (REPL using Node.js `readline`)
180
- - Configuration file loading (standard MCP JSON format)
181
- - Credential management (OS keychain via `keytar` package)
182
-
183
- **Shell implementation:**
184
- - Built on Node.js `readline` module for input handling with history support
185
- - Command history using `~/.mcpc/history` (last 1000 commands)
186
- - Real-time notification display during shell sessions
187
- - Graceful exit handling (cleanup on Ctrl+C/Ctrl+D)
188
-
189
- ### Session lifecycle
190
-
191
- 1. User: `mcpc https://mcp.apify.com session @apify`
192
- 2. CLI: Atomically creates session entry in `~/.mcpc/sessions.json`
193
- 3. CLI: Spawns bridge process (`mcpc-bridge`)
194
- 4. Bridge: Creates Unix socket at `~/.mcpc/bridges/apify.sock`
195
- 5. Bridge: Performs MCP initialization handshake with server:
196
- - Sends initialize request with protocol version and capabilities
197
- - Receives server info, version, and capabilities
198
- - Sends initialized notification to activate session
199
- 6. Bridge: Updates session in `~/.mcpc/sessions.json` (adds PID, socket path, protocol version)
200
- 7. CLI: Confirms session created
201
- 8. User: mcpc @apify tools-list
202
- 9. CLI: Reads `~/.mcpc/sessions.json`, finds socket path
203
- 10. CLI: Connects to bridge socket
204
- 11. CLI: Sends `tools/list` JSON-RPC request via socket
205
- 12. Bridge: Forwards to MCP server via Streamable HTTP
206
- 13. Bridge: Returns response via socket
207
- 14. CLI: Formats and displays to user
208
-
209
-
210
- ### Error recovery
211
-
212
- **Bridge crashes:**
213
- 1. CLI detects socket connection failure
214
- 2. Reads `~/.mcpc/sessions.json` for last known config
215
- 3. Spawns new bridge process
216
- 4. Bridge re-initializes connection to MCP server
217
- 5. Continues request
218
-
219
- **Network failures:**
220
- 1. Bridge detects connection error
221
- 2. Begins exponential backoff reconnection
222
- 3. Queues incoming requests (up to 100, max 3min)
223
- 4. On reconnect: drains queue
224
- 5. On timeout: fails queued requests with network error
225
-
226
- **Orphaned processes:**
227
- 1. On startup, CLI scans `~/.mcpc/bridges/` directory
228
- 2. For each socket file, attempts connection
229
- 3. If connection fails, reads PID from sessions.json
230
- 4. Checks if process exists (via `kill -0` or similar)
231
- 5. If dead: removes socket file and session entry
232
- 6. If alive but unresponsive: kills process, removes entries
117
+ The CLI talks to bridges over Unix domain sockets (named pipes on Windows) located in
118
+ `~/.mcpc/bridges/`. Session state lives in `~/.mcpc/sessions.json` (file-locked). Credentials live
119
+ in the OS keychain via [`@napi-rs/keyring`](https://www.npmjs.com/package/@napi-rs/keyring), with a
120
+ `0600` file fallback on headless systems.
233
121
 
122
+ For a deeper walkthrough of the protocol implementation, session lifecycle, error recovery, and
123
+ security model, see [`CLAUDE.md`](./CLAUDE.md) — it's the reference document maintained for AI
124
+ coding agents, but it's plain Markdown and useful to humans too.
234
125
 
235
126
  ## References
236
127
 
package/README.md CHANGED
@@ -127,54 +127,6 @@ mcpc @fs tools-list
127
127
  <!-- AUTO-GENERATED: mcpc --help -->
128
128
 
129
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: [...] }`.
178
130
  ```
179
131
 
180
132
  ### General actions
@@ -349,19 +301,21 @@ and auto-reconnects on network failures or its own crashes (10s cooldown on fail
349
301
 
350
302
  **Session states:**
351
303
 
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` |
304
+ | State | Meaning |
305
+ |------------------| ----------------------------------------------------------------------------------------------- |
306
+ | 🟢`live` | Bridge process running and server responding |
307
+ | 🟡`connecting` | Initial bridge startup in progress (`mcpc connect`) |
308
+ | 🟡`reconnecting` | Bridge crashed or lost auth; auto-reconnecting in the background |
309
+ | 🟡`disconnected` | Bridge process running but server unreachable; auto-recovers when server responds |
310
+ | 🟡`crashed` | Bridge process crashed or was killed; auto-reconnects in the background |
311
+ | 🔴`unauthorized` | Server rejected authentication (401/403) or token refresh failed; re-run `login` then `restart` |
312
+ | 🔴`expired` | Server rejected session ID (404); requires `restart` |
361
313
 
362
314
  `mcpc` never removes sessions automatically — failed ones stay flagged with a recovery hint
363
315
  in the error message. Use `mcpc @apify restart` to kill the bridge and open a fresh
364
316
  `MCP-Session-Id`, or `mcpc @apify close` to remove the session entirely.
317
+ You can also remove dead sessions by running `mcpc clean`,
318
+ and all sessions by running `mcpc clean all` (see [Cleanup](#cleanup)).
365
319
 
366
320
  ## Authentication
367
321
 
@@ -1208,22 +1162,22 @@ See [CONTRIBUTING](./CONTRIBUTING.md) for development setup, architecture overvi
1208
1162
 
1209
1163
  ### MCP CLI clients
1210
1164
 
1211
- <!-- Stars, contributors, commits, and activity as of March 2026. -->
1165
+ <!-- Stars, contributors, commits, and activity as of May 2026. -->
1212
1166
 
1213
1167
  | Tool | Lang | Stars | Contrib / Commits | Active | Tools | Resources | Prompts | Tasks | Code mode | Sessions | OAuth | Stdio | HTTP | Tool search | x402 | LLM |
1214
1168
  | ----------------------------------------------------------------------- | ------ | ----: | ----------------: | ------ | ----- | --------- | ------- | ----- | --------- | -------- | ----- | ----- | ---- | ----------- | ---- | --- |
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 | | ✅ | — | — | — | ✅ | ✅ | — | ✅ | ✅ | ✅ | — | — |
1169
+ | **[apify/mcpc](https://github.com/apify/mcpc)** | TS | ~590 | 8 / ~640 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | — |
1170
+ | [steipete/mcporter](https://github.com/steipete/mcporter) | TS | ~4.4k | 29 / ~650 | ✅ | ✅ | — | — | — | ✅ | ✅ | ✅ | ✅ | ✅ | — | — | — |
1171
+ | [knowsuchagency/mcp2cli](https://github.com/knowsuchagency/mcp2cli) | Python | ~2.1k | 11 / ~91 | ✅ | ✅ | ✅ | ✅ | — | ✅ | ✅ | ✅ | ✅ | ✅ | | — | |
1172
+ | [IBM/mcp-cli](https://github.com/IBM/mcp-cli) | Python | ~2.0k | 24 / ~790 | ✅ | ✅ | ✅ | ✅ | — | ✅ | ✅ | ✅ | ✅ | ✅ | | — | |
1173
+ | [f/mcptools](https://github.com/f/mcptools) | Go | ~1.6k | 15 / ~175 | ⚠️ | ✅ | ✅ | ✅ | — | ✅ | — | — | ✅ | ✅ | — | — | — |
1174
+ | [philschmid/mcp-cli](https://github.com/philschmid/mcp-cli) | TS | ~1.1k | 3 / ~30 | ⚠️ | ✅ | — | — | — | ✅ | ✅ | — | ✅ | ✅ | ✅ | — | — |
1221
1175
  | [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 | ✅ | ✅ | — | — | — | — | — | ✅ | ✅ | ✅ | ✅ | — | — |
1176
+ | [thellimist/clihub](https://github.com/thellimist/clihub) | Go | ~670 | 1 / ~60 | ✅ | ✅ | — | — | — | — | — | ✅ | ✅ | ✅ | ✅ | — | — |
1223
1177
  | [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 | ✅ | ✅ | — | — | — | ✅ | ✅ | — | ✅ | ✅ | ✅ | — | — |
1178
+ | [mcpshim/mcpshim](https://github.com/mcpshim/mcpshim) | Go | ~58 | 1 / ~13 | ✅ | ✅ | — | — | — | ✅ | ✅ | ✅ | — | ✅ | ✅ | — | — |
1179
+ | [evantahler/mcpx](https://github.com/evantahler/mcpx) | TS | ~32 | 2 / ~100 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | — | ✅ | ✅ | ✅ | ✅ | — | — |
1180
+ | [EstebanForge/mcp-cli-ent](https://github.com/EstebanForge/mcp-cli-ent) | Go | ~15 | 3 / ~46 | ✅ | ✅ | — | — | — | ✅ | ✅ | — | ✅ | ✅ | ✅ | — | — |
1227
1181
 
1228
1182
  **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.
1229
1183
 
@@ -0,0 +1,134 @@
1
+ #!/bin/bash
2
+ #
3
+ # Company Lookup Script using mcpc + Apify RAG Web Browser
4
+ #
5
+ # This is an example of an AI-generated "code mode" script that uses mcpc
6
+ # to call MCP tools programmatically. It was generated by Claude Code + Opus 4.5.
7
+ #
8
+ # Prerequisites:
9
+ # 1. Install mcpc: npm install -g @apify/mcpc
10
+ # 2. Login to Apify MCP server: mcpc mcp.apify.com login
11
+ # 3. Create a session: mcpc mcp.apify.com connect @apify
12
+ #
13
+ # Usage:
14
+ # ./company-lookup.sh "Company Name"
15
+ #
16
+ # Example:
17
+ # ./company-lookup.sh "Stripe"
18
+ # ./company-lookup.sh "Anthropic"
19
+ #
20
+
21
+ set -e
22
+
23
+ # Configuration
24
+ SESSION="${MCPC_SESSION:-@apify}"
25
+ REQUIRED_TOOL="apify-slash-rag-web-browser"
26
+
27
+ # Colors for output
28
+ RED='\033[0;31m'
29
+ GREEN='\033[0;32m'
30
+ YELLOW='\033[0;33m'
31
+ BLUE='\033[0;34m'
32
+ NC='\033[0m' # No Color
33
+
34
+ # Helper functions
35
+ error() { echo -e "${RED}❌ Error: $1${NC}" >&2; exit 1; }
36
+ info() { echo -e "${BLUE}$1${NC}"; }
37
+ success() { echo -e "${GREEN}$1${NC}"; }
38
+ warn() { echo -e "${YELLOW}$1${NC}"; }
39
+
40
+ # Check if mcpc is installed
41
+ if ! command -v mcpc &> /dev/null; then
42
+ error "mcpc is not installed. Install it with: npm install -g @apify/mcpc"
43
+ fi
44
+
45
+ # Parse arguments
46
+ COMPANY="${1:-}"
47
+ if [ -z "$COMPANY" ]; then
48
+ echo "Usage: $0 \"Company Name\""
49
+ echo ""
50
+ echo "Examples:"
51
+ echo " $0 \"Stripe\""
52
+ echo " $0 \"Anthropic\""
53
+ echo ""
54
+ echo "Environment variables:"
55
+ echo " MCPC_SESSION Session to use (default: @apify)"
56
+ exit 1
57
+ fi
58
+
59
+ # Check if the session exists and is live
60
+ info "🔌 Checking session ${SESSION}..."
61
+
62
+ SESSION_STATUS=$(mcpc --json 2>/dev/null | jq -r ".sessions[] | select(.name == \"${SESSION}\") | .status" 2>/dev/null || echo "")
63
+
64
+ if [ -z "$SESSION_STATUS" ]; then
65
+ echo ""
66
+ error "Session ${SESSION} not found.
67
+
68
+ To set up the required session:
69
+ 1. Login to Apify: mcpc mcp.apify.com login
70
+ 2. Create session: mcpc mcp.apify.com connect ${SESSION}
71
+
72
+ Or use a different session by setting MCPC_SESSION environment variable."
73
+ fi
74
+
75
+ if [ "$SESSION_STATUS" = "expired" ]; then
76
+ error "Session ${SESSION} has expired. Please recreate it:
77
+ mcpc ${SESSION} close
78
+ mcpc mcp.apify.com connect ${SESSION}"
79
+ fi
80
+
81
+ if [ "$SESSION_STATUS" = "crashed" ]; then
82
+ warn "⚠️ Session ${SESSION} has crashed, will attempt to restart..."
83
+ fi
84
+
85
+ # Verify the required tool is available
86
+ info "🔧 Checking for required tool..."
87
+
88
+ TOOL_EXISTS=$(mcpc --json "${SESSION}" tools-list 2>/dev/null | jq -r ".[] | select(.name == \"${REQUIRED_TOOL}\") | .name" 2>/dev/null || echo "")
89
+
90
+ if [ -z "$TOOL_EXISTS" ]; then
91
+ error "Required tool '${REQUIRED_TOOL}' not found on server.
92
+ Make sure you're connected to the correct MCP server (mcp.apify.com)."
93
+ fi
94
+
95
+ # All checks passed, proceed with the lookup
96
+ echo ""
97
+ info "🔍 Looking up: $COMPANY"
98
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
99
+ echo ""
100
+ info "⏳ Searching the web..."
101
+ echo ""
102
+
103
+ # Build the query - company name + search terms
104
+ QUERY="${COMPANY} company headquarters address"
105
+
106
+ # Use mcpc with the RAG web browser to fetch results as JSON
107
+ RESULT=$(mcpc "${SESSION}" tools-call "${REQUIRED_TOOL}" \
108
+ query:="$QUERY" \
109
+ maxResults:=1 \
110
+ outputFormats:='["markdown"]' \
111
+ --json 2>/dev/null) || error "Failed to call tool. Check your session and try again."
112
+
113
+ # Parse the markdown from the result
114
+ MARKDOWN=$(echo "$RESULT" \
115
+ | jq -r '.content[0].text // empty' 2>/dev/null \
116
+ | jq -r '.[0].markdown // empty' 2>/dev/null)
117
+
118
+ # Check if we got results
119
+ if [ -z "$MARKDOWN" ]; then
120
+ warn "⚠️ No results found for '$COMPANY'"
121
+ echo ""
122
+ echo "Raw response:"
123
+ echo "$RESULT" | jq '.' 2>/dev/null || echo "$RESULT"
124
+ exit 1
125
+ fi
126
+
127
+ echo "📄 Company Information:"
128
+ echo "────────────────────────────────────────────────────"
129
+ # Show first 50 lines of markdown
130
+ echo "$MARKDOWN" | head -50
131
+
132
+ echo ""
133
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
134
+ success "✅ Done"
@@ -0,0 +1,28 @@
1
+ {
2
+ "mcpServers": {
3
+ "playwright": {
4
+ "command": "npx",
5
+ "args": ["@playwright/mcp@latest"]
6
+ },
7
+
8
+ "fs": {
9
+ "command": "npx",
10
+ "args": ["-y", "@modelcontextprotocol/server-filesystem", "${PWD}"]
11
+ },
12
+
13
+ "apify-public": {
14
+ "url": "https://mcp.apify.com/?tools=docs,search-actors"
15
+ },
16
+
17
+ "apify-bearer": {
18
+ "url": "https://mcp.apify.com",
19
+ "headers": {
20
+ "Authorization": "Bearer ${APIFY_TOKEN}"
21
+ }
22
+ },
23
+
24
+ "apify-oauth": {
25
+ "url": "https://mcp.apify.com"
26
+ }
27
+ }
28
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apify/mcpc",
3
- "version": "0.3.0-beta.0",
3
+ "version": "0.3.0",
4
4
  "description": "Universal command-line client for the Model Context Protocol (MCP).",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -28,32 +28,6 @@
28
28
  "engines": {
29
29
  "node": ">=20.0.0"
30
30
  },
31
- "scripts": {
32
- "build": "tsc",
33
- "build:watch": "tsc --watch",
34
- "build:readme": "./scripts/update-readme.sh",
35
- "test": "npm run build && npm run test:unit && ./test/e2e/run.sh --no-build --parallel 8 && ./test/e2e/run.sh --no-build --parallel 8 --runtime bun",
36
- "test:unit": "jest",
37
- "test:watch": "jest --watch",
38
- "test:coverage": "npm run test:coverage:unit && npm run test:coverage:e2e && npm run test:coverage:merge",
39
- "test:coverage:unit": "jest --coverage && find test/coverage/unit -name '*.html' -exec sed -i '' -e 's/Code coverage report for All files/mcpc Coverage (Unit Tests)/g' -e 's/<h1>All files<\\/h1>/<h1>Unit Test Coverage<\\/h1>/g' {} \\;",
40
- "test:coverage:e2e": "./test/e2e/run.sh --coverage",
41
- "test:coverage:merge": "test/coverage/coverage-merge.sh",
42
- "test:e2e": "./test/e2e/run.sh --keep",
43
- "test:e2e:bun": "./test/e2e/run.sh --no-build --runtime bun",
44
- "test:conformance": "npm run build && npx -y @modelcontextprotocol/conformance client --command \"node test/conformance/client.mjs\" --scenario initialize",
45
- "lint": "eslint src/**/*.ts && prettier --check \"src/**/*.ts\" \"test/**/*.ts\"",
46
- "lint:fix": "eslint src/**/*.ts --fix && prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
47
- "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
48
- "format:check": "prettier --check \"src/**/*.ts\" \"test/**/*.ts\"",
49
- "clean": "rm -rf dist",
50
- "prebuild": "npm run clean",
51
- "prepublishOnly": "if [ -z \"$MCPC_RELEASE\" ]; then echo '\\n❌ Direct npm publish is not allowed.\\n Please use: npm run release\\n' && exit 1; fi",
52
- "release": "bash scripts/publish.sh",
53
- "release:minor": "bash scripts/publish.sh minor",
54
- "release:major": "bash scripts/publish.sh major",
55
- "release:pre": "bash scripts/publish.sh --pre-release"
56
- },
57
31
  "dependencies": {
58
32
  "@inquirer/input": "^5.0.3",
59
33
  "@inquirer/select": "^5.0.3",
@@ -69,23 +43,54 @@
69
43
  "viem": "^2.46.3"
70
44
  },
71
45
  "devDependencies": {
72
- "@types/jest": "^30.0.0",
73
46
  "@types/node": "^25.0.3",
74
47
  "@types/proper-lockfile": "^4.1.4",
75
48
  "@types/qrcode-terminal": "^0.12.2",
76
49
  "@types/uuid": "^11.0.0",
77
- "@typescript-eslint/eslint-plugin": "^8.50.0",
78
- "@typescript-eslint/parser": "^8.50.0",
50
+ "@typescript-eslint/eslint-plugin": "8.57.2",
51
+ "@typescript-eslint/parser": "8.57.2",
52
+ "@vitest/coverage-v8": "4.1.5",
79
53
  "c8": "^11.0.0",
80
54
  "doctoc": "^2.2.1",
81
55
  "eslint": "^8.57.1",
82
- "jest": "^30.2.0",
83
56
  "markdown-link-check": "^3.14.2",
84
57
  "nyc": "^18.0.0",
85
58
  "prettier": "^3.7.4",
86
59
  "proxy-chain": "^2.7.1",
87
- "ts-jest": "^29.4.6",
88
60
  "tsx": "^4.21.0",
89
- "typescript": "^5.9.3"
61
+ "typescript": "^5.9.3",
62
+ "vitest": "4.1.5"
63
+ },
64
+ "devEngines": {
65
+ "packageManager": {
66
+ "name": "pnpm",
67
+ "version": "10.33.4",
68
+ "onFail": "warn"
69
+ }
70
+ },
71
+ "scripts": {
72
+ "build": "tsc",
73
+ "build:watch": "tsc --watch",
74
+ "build:readme": "./scripts/update-readme.sh",
75
+ "test": "pnpm run build && pnpm run test:unit && ./test/e2e/run.sh --no-build --parallel 8 && ./test/e2e/run.sh --no-build --parallel 8 --runtime bun",
76
+ "test:unit": "vitest run",
77
+ "test:watch": "vitest",
78
+ "test:coverage": "pnpm run test:coverage:unit && pnpm run test:coverage:e2e && pnpm run test:coverage:merge",
79
+ "test:coverage:unit": "vitest run --coverage",
80
+ "test:coverage:e2e": "./test/e2e/run.sh --coverage",
81
+ "test:coverage:merge": "test/coverage/coverage-merge.sh",
82
+ "test:e2e": "./test/e2e/run.sh --keep",
83
+ "test:e2e:bun": "./test/e2e/run.sh --no-build --runtime bun",
84
+ "test:conformance": "pnpm run build && npx -y @modelcontextprotocol/conformance client --command \"node test/conformance/client.mjs\" --scenario initialize",
85
+ "lint": "eslint src/**/*.ts && prettier --check \"src/**/*.ts\" \"test/**/*.ts\"",
86
+ "lint:fix": "eslint src/**/*.ts --fix && prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
87
+ "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
88
+ "format:check": "prettier --check \"src/**/*.ts\" \"test/**/*.ts\"",
89
+ "clean": "rm -rf dist",
90
+ "prebuild": "pnpm run clean",
91
+ "release": "bash scripts/publish.sh",
92
+ "release:minor": "bash scripts/publish.sh minor",
93
+ "release:major": "bash scripts/publish.sh major",
94
+ "release:pre": "bash scripts/publish.sh --pre-release"
90
95
  }
91
- }
96
+ }
@@ -0,0 +1,10 @@
1
+ # Supply-chain protection: require packages to be at least X days old before pnpm will install them.
2
+ # Mitigates compromised npm packages discovered and yanked within the first day (shai-hulud worm,
3
+ # nx self-replicator, etc.). 7200 minutes = 5 days.
4
+ minimumReleaseAge: 7200
5
+
6
+ # @napi-rs/keyring ships a native node binding that needs to be built/copied
7
+ # into place on install. Without this entry pnpm v10 refuses to run its
8
+ # postinstall script and the keychain feature breaks at runtime.
9
+ onlyBuiltDependencies:
10
+ - "@napi-rs/keyring"
@@ -2,7 +2,8 @@
2
2
  "extends": "./tsconfig.json",
3
3
  "compilerOptions": {
4
4
  "module": "ES2022",
5
- "moduleResolution": "bundler"
5
+ "moduleResolution": "bundler",
6
+ "types": ["vitest/globals", "node"]
6
7
  },
7
8
  "include": [
8
9
  "test/**/*",
@@ -0,0 +1,26 @@
1
+ import { defineConfig } from 'vitest/config';
2
+
3
+ // Coverage thresholds match the previous Jest setup (70% across the board).
4
+ // See test/README.md for the test layout.
5
+ export default defineConfig({
6
+ test: {
7
+ include: ['test/unit/**/*.test.ts', 'test/unit/**/*.spec.ts'],
8
+ environment: 'node',
9
+ // `globals: true` keeps the existing test bodies (`describe`/`it`/`expect`)
10
+ // working without changing every file's imports. Jest-compatible API.
11
+ globals: true,
12
+ coverage: {
13
+ provider: 'v8',
14
+ reportsDirectory: 'test/coverage/unit',
15
+ reporter: ['text', 'lcov', 'html', 'json'],
16
+ include: ['src/**/*.ts'],
17
+ exclude: ['src/**/*.d.ts', 'src/**/index.ts'],
18
+ thresholds: {
19
+ branches: 70,
20
+ functions: 70,
21
+ lines: 70,
22
+ statements: 70,
23
+ },
24
+ },
25
+ },
26
+ });