@apify/mcpc 0.1.11-beta.1 → 0.1.11-beta.3
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 +6 -0
- package/README.md +137 -48
- package/dist/bridge/index.js +78 -4
- package/dist/bridge/index.js.map +1 -1
- package/dist/cli/commands/index.d.ts +1 -0
- package/dist/cli/commands/index.d.ts.map +1 -1
- package/dist/cli/commands/index.js +1 -0
- package/dist/cli/commands/index.js.map +1 -1
- package/dist/cli/commands/sessions.d.ts +1 -0
- package/dist/cli/commands/sessions.d.ts.map +1 -1
- package/dist/cli/commands/sessions.js +15 -0
- package/dist/cli/commands/sessions.js.map +1 -1
- package/dist/cli/commands/x402.d.ts +2 -0
- package/dist/cli/commands/x402.d.ts.map +1 -0
- package/dist/cli/commands/x402.js +203 -0
- package/dist/cli/commands/x402.js.map +1 -0
- package/dist/cli/helpers.d.ts +1 -0
- package/dist/cli/helpers.d.ts.map +1 -1
- package/dist/cli/helpers.js +12 -0
- package/dist/cli/helpers.js.map +1 -1
- package/dist/cli/index.js +18 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/parser.d.ts +1 -0
- package/dist/cli/parser.d.ts.map +1 -1
- package/dist/cli/parser.js +4 -0
- package/dist/cli/parser.js.map +1 -1
- package/dist/core/factory.d.ts +2 -0
- package/dist/core/factory.d.ts.map +1 -1
- package/dist/core/factory.js +4 -0
- package/dist/core/factory.js.map +1 -1
- package/dist/core/transports.d.ts +3 -2
- package/dist/core/transports.d.ts.map +1 -1
- package/dist/core/transports.js +4 -0
- package/dist/core/transports.js.map +1 -1
- package/dist/lib/auth/keychain.d.ts.map +1 -1
- package/dist/lib/auth/keychain.js +85 -67
- package/dist/lib/auth/keychain.js.map +1 -1
- package/dist/lib/auth/profiles.d.ts.map +1 -1
- package/dist/lib/auth/profiles.js.map +1 -1
- package/dist/lib/bridge-client.d.ts +2 -1
- package/dist/lib/bridge-client.d.ts.map +1 -1
- package/dist/lib/bridge-client.js +6 -0
- package/dist/lib/bridge-client.js.map +1 -1
- package/dist/lib/bridge-manager.d.ts +1 -0
- package/dist/lib/bridge-manager.d.ts.map +1 -1
- package/dist/lib/bridge-manager.js +33 -1
- package/dist/lib/bridge-manager.js.map +1 -1
- package/dist/lib/sessions.d.ts.map +1 -1
- package/dist/lib/sessions.js.map +1 -1
- package/dist/lib/types.d.ts +16 -1
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/lib/utils.d.ts +1 -0
- package/dist/lib/utils.d.ts.map +1 -1
- package/dist/lib/utils.js +3 -0
- package/dist/lib/utils.js.map +1 -1
- package/dist/lib/wallets.d.ts +5 -0
- package/dist/lib/wallets.d.ts.map +1 -0
- package/dist/lib/wallets.js +66 -0
- package/dist/lib/wallets.js.map +1 -0
- package/dist/lib/x402/fetch-middleware.d.ts +9 -0
- package/dist/lib/x402/fetch-middleware.d.ts.map +1 -0
- package/dist/lib/x402/fetch-middleware.js +133 -0
- package/dist/lib/x402/fetch-middleware.js.map +1 -0
- package/dist/lib/x402/signer.d.ts +48 -0
- package/dist/lib/x402/signer.d.ts.map +1 -0
- package/dist/lib/x402/signer.js +139 -0
- package/dist/lib/x402/signer.js.map +1 -0
- package/package.json +5 -3
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
### Added
|
|
11
|
+
- E2E tests now run under the Bun runtime (in addition to Node.js); use `./test/e2e/run.sh --runtime bun` or `npm run test:e2e:bun`
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
- OS keychain now falls back to `~/.mcpc/credentials.json` (mode 0600) when no keyring daemon is available (e.g. headless Linux servers, containers)
|
|
15
|
+
|
|
10
16
|
## [0.1.10] - 2026-03-01
|
|
11
17
|
|
|
12
18
|
### Added
|
package/README.md
CHANGED
|
@@ -10,6 +10,7 @@ After all, UNIX-compatible shell script is THE most universal coding language.
|
|
|
10
10
|

|
|
11
11
|
|
|
12
12
|
**Key features:**
|
|
13
|
+
|
|
13
14
|
- 🌎 **Compatible** - Works with any MCP server over Streamable HTTP or stdio.
|
|
14
15
|
- 🔄 **Persistent sessions** - Keep multiple server connections alive simultaneously.
|
|
15
16
|
- 🔧 **Strong MCP support** - Instructions, tools, resources, prompts, dynamic discovery.
|
|
@@ -17,7 +18,7 @@ After all, UNIX-compatible shell script is THE most universal coding language.
|
|
|
17
18
|
- 🤖 **AI sandboxing** - MCP proxy server to securely access authenticated sessions from AI-generated code.
|
|
18
19
|
- 🔒 **Secure** - Full OAuth 2.1 support, OS keychain for credentials storage.
|
|
19
20
|
- 🪶 **Lightweight** - Minimal dependencies, works on Mac/Win/Linux, doesn't use LLMs on its own.
|
|
20
|
-
|
|
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/).
|
|
21
22
|
|
|
22
23
|
## Table of contents
|
|
23
24
|
|
|
@@ -31,6 +32,7 @@ After all, UNIX-compatible shell script is THE most universal coding language.
|
|
|
31
32
|
- [Authentication](#authentication)
|
|
32
33
|
- [MCP proxy](#mcp-proxy)
|
|
33
34
|
- [AI agents](#ai-agents)
|
|
35
|
+
- [Agentic payments (x402)](#agentic-payments-x402)
|
|
34
36
|
- [MCP support](#mcp-support)
|
|
35
37
|
- [Configuration](#configuration)
|
|
36
38
|
- [Security](#security)
|
|
@@ -45,32 +47,35 @@ After all, UNIX-compatible shell script is THE most universal coding language.
|
|
|
45
47
|
|
|
46
48
|
```bash
|
|
47
49
|
npm install -g @apify/mcpc
|
|
50
|
+
|
|
51
|
+
# Or with Bun
|
|
52
|
+
bun install -g @apify/mcpc
|
|
48
53
|
```
|
|
49
54
|
|
|
50
55
|
**Linux users:** `mcpc` uses the OS keychain for secure credential storage via the
|
|
51
|
-
[Secret Service API](https://specifications.freedesktop.org/secret-service/).
|
|
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`).
|
|
60
|
+
|
|
61
|
+
To use the OS keychain on a headless system, install `libsecret` and a secret service daemon:
|
|
52
62
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
sudo apt-get install libsecret-1-0
|
|
63
|
+
```bash
|
|
64
|
+
# Debian/Ubuntu
|
|
65
|
+
sudo apt-get install libsecret-1-0 gnome-keyring
|
|
57
66
|
|
|
58
|
-
|
|
59
|
-
|
|
67
|
+
# Fedora/RHEL/CentOS
|
|
68
|
+
sudo dnf install libsecret gnome-keyring
|
|
60
69
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
70
|
+
# Arch Linux
|
|
71
|
+
sudo pacman -S libsecret gnome-keyring
|
|
72
|
+
```
|
|
64
73
|
|
|
65
|
-
|
|
66
|
-
by gnome-keyring or KWallet. On headless/server/CI environments you need to install and start one:
|
|
67
|
-
```bash
|
|
68
|
-
# Debian/Ubuntu
|
|
69
|
-
sudo apt-get install gnome-keyring
|
|
74
|
+
And then run `mcpc` as follows:
|
|
70
75
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
76
|
+
```
|
|
77
|
+
dbus-run-session -- bash -c "echo -n 'password' | gnome-keyring-daemon --unlock && mcpc ..."
|
|
78
|
+
```
|
|
74
79
|
|
|
75
80
|
## Quickstart
|
|
76
81
|
|
|
@@ -117,6 +122,7 @@ Options:
|
|
|
117
122
|
--timeout <seconds> Request timeout in seconds (default: 300)
|
|
118
123
|
--proxy <[host:]port> Start proxy MCP server for session (with "connect" command)
|
|
119
124
|
--proxy-bearer-token <token> Require authentication for access to proxy server
|
|
125
|
+
--x402 Enable x402 auto-payment using the configured wallet
|
|
120
126
|
--clean[=types] Clean up mcpc data (types: sessions, logs, profiles, all)
|
|
121
127
|
-h, --help Display general help
|
|
122
128
|
|
|
@@ -148,7 +154,14 @@ MCP server commands:
|
|
|
148
154
|
resources-templates-list
|
|
149
155
|
logging-set-level <level>
|
|
150
156
|
ping
|
|
151
|
-
|
|
157
|
+
|
|
158
|
+
x402 payment commands (no target needed):
|
|
159
|
+
x402 init Create a new x402 wallet
|
|
160
|
+
x402 import <key> Import wallet from private key
|
|
161
|
+
x402 info Show wallet info
|
|
162
|
+
x402 sign -r <base64> Sign payment from PAYMENT-REQUIRED header
|
|
163
|
+
x402 remove Remove the wallet
|
|
164
|
+
|
|
152
165
|
Run "mcpc" without <target> to show available sessions and profiles.
|
|
153
166
|
```
|
|
154
167
|
|
|
@@ -181,6 +194,7 @@ To connect and interact with an MCP server, you need to specify a `<target>`, wh
|
|
|
181
194
|
connects, and enables you to interact with it.
|
|
182
195
|
|
|
183
196
|
**URL handling:**
|
|
197
|
+
|
|
184
198
|
- URLs without a scheme (e.g. `mcp.apify.com`) default to `https://`
|
|
185
199
|
- `localhost` and `127.0.0.1` addresses without a scheme default to `http://` (for local dev/proxy servers)
|
|
186
200
|
- To override the default, specify the scheme explicitly (e.g. `http://example.com`)
|
|
@@ -229,6 +243,7 @@ cat args.json | mcpc <target> tools-call <tool-name>
|
|
|
229
243
|
```
|
|
230
244
|
|
|
231
245
|
**Rules:**
|
|
246
|
+
|
|
232
247
|
- All arguments use `:=` syntax: `key:=value`
|
|
233
248
|
- Values are auto-parsed: valid JSON becomes that type, otherwise treated as string
|
|
234
249
|
- `count:=10` → number `10`
|
|
@@ -257,6 +272,7 @@ echo "{\"query\": \"${QUERY}\", \"limit\": 10}" | mcpc @server tools-call search
|
|
|
257
272
|
```
|
|
258
273
|
|
|
259
274
|
**Common pitfall:** Don't put spaces around `:=` - it won't work:
|
|
275
|
+
|
|
260
276
|
```bash
|
|
261
277
|
# Wrong - spaces around :=
|
|
262
278
|
mcpc @server tools-call search query := "hello world"
|
|
@@ -329,7 +345,7 @@ Still, sessions can fail due to network disconnects, bridge process crash, or se
|
|
|
329
345
|
**Session states:**
|
|
330
346
|
|
|
331
347
|
| State | Meaning |
|
|
332
|
-
|
|
348
|
+
| ---------------- | --------------------------------------------------------------------------------------------- |
|
|
333
349
|
| 🟢 **`live`** | Bridge process is running; server might or might not be operational |
|
|
334
350
|
| 🟡 **`crashed`** | Bridge process crashed or was killed; will auto-restart on next use |
|
|
335
351
|
| 🔴 **`expired`** | Server rejected the session (auth failed, session ID invalid); requires `close` and reconnect |
|
|
@@ -365,7 +381,6 @@ and opens new connection with new `MCP-Session-Id`, by running:
|
|
|
365
381
|
mcpc @apify restart
|
|
366
382
|
```
|
|
367
383
|
|
|
368
|
-
|
|
369
384
|
## Authentication
|
|
370
385
|
|
|
371
386
|
`mcpc` supports all standard [MCP authorization methods](https://modelcontextprotocol.io/specification/latest/basic/authorization).
|
|
@@ -404,8 +419,8 @@ mcpc @apify tools-list
|
|
|
404
419
|
|
|
405
420
|
### OAuth profiles
|
|
406
421
|
|
|
407
|
-
For OAuth-enabled remote MCP servers, `mcpc` implements the full OAuth 2.1 flow with PKCE,
|
|
408
|
-
including `WWW-Authenticate` header discovery, server metadata discovery, client ID metadata documents,
|
|
422
|
+
For OAuth-enabled remote MCP servers, `mcpc` implements the full OAuth 2.1 flow with PKCE,
|
|
423
|
+
including `WWW-Authenticate` header discovery, server metadata discovery, client ID metadata documents,
|
|
409
424
|
dynamic client registration, and automatic token refresh.
|
|
410
425
|
|
|
411
426
|
The OAuth authentication **always** needs to be initiated by the user calling the `login` command,
|
|
@@ -413,11 +428,13 @@ which opens a web browser with login screen. `mcpc` never opens the web browser
|
|
|
413
428
|
|
|
414
429
|
The OAuth credentials to specific servers are securely stored as **authentication profiles** - reusable
|
|
415
430
|
credentials that allow you to:
|
|
431
|
+
|
|
416
432
|
- Authenticate once, use credentials across multiple commands or sessions
|
|
417
433
|
- Use different accounts (profiles) with the same server
|
|
418
434
|
- Manage credentials independently from sessions
|
|
419
435
|
|
|
420
436
|
Key concepts:
|
|
437
|
+
|
|
421
438
|
- **Authentication profile**: Named set of OAuth credentials for a specific server (stored in `~/.mcpc/profiles.json` + OS keychain)
|
|
422
439
|
- **Session**: Active connection to a server that may reference an authentication profile (stored in `~/.mcpc/sessions.json`)
|
|
423
440
|
- **Default profile**: When `--profile` is not specified, `mcpc` uses the authentication profile named `default`
|
|
@@ -456,7 +473,6 @@ When multiple authentication methods are available, `mcpc` uses this precedence
|
|
|
456
473
|
3. **Config file headers** - Headers from `--config` file for the server
|
|
457
474
|
4. **No authentication** - Attempts unauthenticated connection
|
|
458
475
|
|
|
459
|
-
|
|
460
476
|
`mcpc` automatically handles authentication based on whether you specify a profile:
|
|
461
477
|
|
|
462
478
|
**When `--profile <name>` is specified:**
|
|
@@ -478,6 +494,7 @@ When multiple authentication methods are available, `mcpc` uses this precedence
|
|
|
478
494
|
On failure, the error message includes instructions on how to login and save the profile, so you know what to do.
|
|
479
495
|
|
|
480
496
|
This flow ensures:
|
|
497
|
+
|
|
481
498
|
- You only authenticate when necessary
|
|
482
499
|
- Credentials are never silently mixed up (personal → work) or downgraded (authenticated → unauthenticated)
|
|
483
500
|
- You can mix authenticated sessions (with named profiles) and public access on the same server
|
|
@@ -500,7 +517,6 @@ mcpc mcp.apify.com connect @apify-personal
|
|
|
500
517
|
mcpc mcp.apify.com\?tools=docs tools-list
|
|
501
518
|
```
|
|
502
519
|
|
|
503
|
-
|
|
504
520
|
## MCP proxy
|
|
505
521
|
|
|
506
522
|
For stronger isolation, `mcpc` can expose an MCP session under a new local proxy MCP server using the `--proxy` option.
|
|
@@ -534,7 +550,7 @@ mcpc localhost:8081 connect @sandboxed2 --header "Authorization: Bearer secret12
|
|
|
534
550
|
**Proxy options for `connect` command:**
|
|
535
551
|
|
|
536
552
|
| Option | Description |
|
|
537
|
-
|
|
553
|
+
| ------------------------------ | ------------------------------------------------------------------------------ |
|
|
538
554
|
| `--proxy [host:]port` | Start proxy MCP server. Default host: `127.0.0.1` (localhost only) |
|
|
539
555
|
| `--proxy-bearer-token <token>` | Requires `Authorization: Bearer <token>` header to access the proxy MCP server |
|
|
540
556
|
|
|
@@ -565,7 +581,6 @@ mcpc
|
|
|
565
581
|
# @relay → https://mcp.apify.com (HTTP, OAuth: default) [proxy: 127.0.0.1:8080]
|
|
566
582
|
```
|
|
567
583
|
|
|
568
|
-
|
|
569
584
|
## AI agents
|
|
570
585
|
|
|
571
586
|
`mcpc` is designed for CLI-enabled AI agents like Claude Code or Codex CLI, supporting both
|
|
@@ -635,6 +650,7 @@ mcpc @apify tools-call search-actors --schema expected.json keywords:="test"
|
|
|
635
650
|
```
|
|
636
651
|
|
|
637
652
|
Available schema validation modes (`--schema-mode`):
|
|
653
|
+
|
|
638
654
|
- `compatible` (default)
|
|
639
655
|
- Input schema: new optional fields OK, required fields must have the same type.
|
|
640
656
|
- Output schema: new fields OK, removed required fields cause error.
|
|
@@ -668,6 +684,73 @@ To help Claude Code use `mcpc`, you can install this [Claude skill](./docs/claud
|
|
|
668
684
|
|
|
669
685
|
<!-- TODO: Add also AGENTS.md, GitHub skills etc. -->
|
|
670
686
|
|
|
687
|
+
## Agentic payments (x402)
|
|
688
|
+
|
|
689
|
+
> ⚠️ **Experimental.** This feature is under active development and may change.
|
|
690
|
+
|
|
691
|
+
`mcpc` has experimental support for the [x402 payment protocol](https://www.x402.org/),
|
|
692
|
+
which enables AI agents to autonomously pay for MCP tool calls using cryptocurrency.
|
|
693
|
+
When an MCP server charges for a tool call (HTTP 402), `mcpc` automatically signs a USDC payment
|
|
694
|
+
on the [Base](https://base.org/) blockchain and retries the request — no human intervention needed.
|
|
695
|
+
|
|
696
|
+
This is entirely **opt-in**: existing functionality is unaffected unless you explicitly pass the `--x402` flag.
|
|
697
|
+
|
|
698
|
+
### How it works
|
|
699
|
+
|
|
700
|
+
1. **Server returns HTTP 402** with a `PAYMENT-REQUIRED` header describing the price and payment details.
|
|
701
|
+
2. `mcpc` parses the header, signs an [EIP-3009](https://eips.ethereum.org/EIPS/eip-3009) `TransferWithAuthorization` using your local wallet.
|
|
702
|
+
3. `mcpc` retries the request with a `PAYMENT-SIGNATURE` header containing the signed payment.
|
|
703
|
+
4. The server verifies the signature and fulfills the request.
|
|
704
|
+
|
|
705
|
+
For tools that advertise pricing in their `_meta.x402` metadata, `mcpc` can **proactively sign** payments
|
|
706
|
+
on the first request, avoiding the 402 round-trip entirely.
|
|
707
|
+
|
|
708
|
+
### Wallet setup
|
|
709
|
+
|
|
710
|
+
`mcpc` stores a single wallet in `~/.mcpc/wallets.json` (file permissions `0600`).
|
|
711
|
+
You need to create or import a wallet before using x402 payments.
|
|
712
|
+
|
|
713
|
+
```bash
|
|
714
|
+
# Create a new wallet (generates a random private key)
|
|
715
|
+
mcpc x402 init
|
|
716
|
+
|
|
717
|
+
# Or import an existing wallet from a private key
|
|
718
|
+
mcpc x402 import <private-key>
|
|
719
|
+
|
|
720
|
+
# Show wallet address and creation date
|
|
721
|
+
mcpc x402 info
|
|
722
|
+
|
|
723
|
+
# Remove the wallet
|
|
724
|
+
mcpc x402 remove
|
|
725
|
+
```
|
|
726
|
+
|
|
727
|
+
After creating a wallet, **fund it with USDC on Base** (mainnet or Sepolia testnet) to enable payments.
|
|
728
|
+
|
|
729
|
+
### Using x402 with MCP servers
|
|
730
|
+
|
|
731
|
+
Pass the `--x402` flag when connecting to a session or running direct commands:
|
|
732
|
+
|
|
733
|
+
```bash
|
|
734
|
+
# Create a session with x402 payment support
|
|
735
|
+
mcpc mcp.apify.com connect @apify --x402
|
|
736
|
+
|
|
737
|
+
# The session now automatically handles 402 responses
|
|
738
|
+
mcpc @apify tools-call expensive-tool query:="hello"
|
|
739
|
+
|
|
740
|
+
# Restart a session with x402 enabled
|
|
741
|
+
mcpc @apify restart --x402
|
|
742
|
+
```
|
|
743
|
+
|
|
744
|
+
When `--x402` is active, a fetch middleware wraps all HTTP requests to the MCP server.
|
|
745
|
+
If any request returns HTTP 402, the middleware transparently signs and retries.
|
|
746
|
+
|
|
747
|
+
### Supported networks
|
|
748
|
+
|
|
749
|
+
| Network | Status |
|
|
750
|
+
| -------------------- | ------------ |
|
|
751
|
+
| Base Mainnet | ✅ Supported |
|
|
752
|
+
| Base Sepolia testnet | ✅ Supported |
|
|
753
|
+
|
|
671
754
|
## MCP support
|
|
672
755
|
|
|
673
756
|
`mcpc` is built on the official [MCP SDK for TypeScript](https://github.com/modelcontextprotocol/typescript-sdk) and supports most [MCP protocol features](https://modelcontextprotocol.io/specification/latest).
|
|
@@ -688,6 +771,7 @@ To help Claude Code use `mcpc`, you can install this [Claude skill](./docs/claud
|
|
|
688
771
|
### MCP session
|
|
689
772
|
|
|
690
773
|
The bridge process manages the full MCP session lifecycle:
|
|
774
|
+
|
|
691
775
|
- Performs initialization handshake (`initialize` → `initialized`)
|
|
692
776
|
- Negotiates protocol version and capabilities
|
|
693
777
|
- Fetches server-provided `instructions`
|
|
@@ -698,21 +782,21 @@ The bridge process manages the full MCP session lifecycle:
|
|
|
698
782
|
|
|
699
783
|
### MCP feature support
|
|
700
784
|
|
|
701
|
-
| **Feature** | **Status**
|
|
702
|
-
|
|
703
|
-
| 📖 [**Instructions**](#server-instructions) | ✅ Supported
|
|
704
|
-
| 🔧 [**Tools**](#tools) | ✅ Supported
|
|
705
|
-
| 💬 [**Prompts**](#prompts) | ✅ Supported
|
|
706
|
-
| 📦 [**Resources**](#resources) | ✅ Supported
|
|
707
|
-
| 📝 [**Logging**](#server-logs) | ✅ Supported
|
|
708
|
-
| 🔔 [**Notifications**](#list-change-notifications) | ✅ Supported
|
|
709
|
-
| 📄 [**Pagination**](#pagination) | ✅ Supported
|
|
710
|
-
| 🏓 [**Ping**](#ping) | ✅ Supported
|
|
711
|
-
| ⏳ **Async tasks**
|
|
712
|
-
| 📁 **Roots** | 🚧 Planned
|
|
713
|
-
| ❓ **Elicitation**
|
|
714
|
-
| 🔤 **Completion** | 🚧 Planned
|
|
715
|
-
| 🤖 **Sampling** | ❌ Not applicable (no LLM access)
|
|
785
|
+
| **Feature** | **Status** |
|
|
786
|
+
| :------------------------------------------------- | :-------------------------------- |
|
|
787
|
+
| 📖 [**Instructions**](#server-instructions) | ✅ Supported |
|
|
788
|
+
| 🔧 [**Tools**](#tools) | ✅ Supported |
|
|
789
|
+
| 💬 [**Prompts**](#prompts) | ✅ Supported |
|
|
790
|
+
| 📦 [**Resources**](#resources) | ✅ Supported |
|
|
791
|
+
| 📝 [**Logging**](#server-logs) | ✅ Supported |
|
|
792
|
+
| 🔔 [**Notifications**](#list-change-notifications) | ✅ Supported |
|
|
793
|
+
| 📄 [**Pagination**](#pagination) | ✅ Supported |
|
|
794
|
+
| 🏓 [**Ping**](#ping) | ✅ Supported |
|
|
795
|
+
| ⏳ **Async tasks** | 🚧 Planned |
|
|
796
|
+
| 📁 **Roots** | 🚧 Planned |
|
|
797
|
+
| ❓ **Elicitation** | 🚧 Planned |
|
|
798
|
+
| 🔤 **Completion** | 🚧 Planned |
|
|
799
|
+
| 🤖 **Sampling** | ❌ Not applicable (no LLM access) |
|
|
716
800
|
|
|
717
801
|
#### Server instructions
|
|
718
802
|
|
|
@@ -865,6 +949,7 @@ mcpc @apify ping --json
|
|
|
865
949
|
You can configure `mcpc` using a config file, environment variables, or command-line flags.
|
|
866
950
|
|
|
867
951
|
**Precedence** (highest to lowest):
|
|
952
|
+
|
|
868
953
|
1. Command-line flags (including `--config` option)
|
|
869
954
|
2. Environment variables
|
|
870
955
|
3. Built-in defaults
|
|
@@ -912,11 +997,13 @@ mcpc --config .vscode/mcp.json apify connect @my-apify
|
|
|
912
997
|
**Server configuration properties:**
|
|
913
998
|
|
|
914
999
|
For **Streamable HTTP servers:**
|
|
1000
|
+
|
|
915
1001
|
- `url` (required) - MCP server endpoint URL
|
|
916
1002
|
- `headers` (optional) - HTTP headers to include with requests
|
|
917
1003
|
- `timeout` (optional) - Request timeout in seconds
|
|
918
1004
|
|
|
919
1005
|
For **stdio servers:**
|
|
1006
|
+
|
|
920
1007
|
- `command` (required) - Command to execute (e.g., `node`, `npx`, `python`)
|
|
921
1008
|
- `args` (optional) - Array of command arguments
|
|
922
1009
|
- `env` (optional) - Environment variables for the process
|
|
@@ -944,7 +1031,7 @@ Config files support environment variable substitution using `${VAR_NAME}` synta
|
|
|
944
1031
|
"secure-server": {
|
|
945
1032
|
"url": "https://mcp.apify.com",
|
|
946
1033
|
"headers": {
|
|
947
|
-
"Authorization": "Bearer ${
|
|
1034
|
+
"Authorization": "Bearer ${APIFY_TOKEN}",
|
|
948
1035
|
"X-User-ID": "${USER_ID}"
|
|
949
1036
|
}
|
|
950
1037
|
}
|
|
@@ -958,6 +1045,7 @@ Config files support environment variable substitution using `${VAR_NAME}` synta
|
|
|
958
1045
|
|
|
959
1046
|
- `~/.mcpc/sessions.json` - Active sessions with references to authentication profiles (file-locked for concurrent access)
|
|
960
1047
|
- `~/.mcpc/profiles.json` - Authentication profiles (OAuth metadata, scopes, expiry)
|
|
1048
|
+
- `~/.mcpc/wallets.json` - x402 wallet data (file permissions `0600`)
|
|
961
1049
|
- `~/.mcpc/bridges/` - Unix domain socket files for each bridge process
|
|
962
1050
|
- `~/.mcpc/logs/bridge-*.log` - Log files for each bridge process
|
|
963
1051
|
- OS keychain - Sensitive credentials (OAuth tokens, bearer tokens, client secrets)
|
|
@@ -1000,11 +1088,12 @@ MCP enables arbitrary tool execution and data access - treat servers like you tr
|
|
|
1000
1088
|
### Credential protection
|
|
1001
1089
|
|
|
1002
1090
|
| What | How |
|
|
1003
|
-
|
|
1091
|
+
| ---------------------- | ----------------------------------------------- |
|
|
1004
1092
|
| **OAuth tokens** | Stored in OS keychain, never on disk |
|
|
1005
1093
|
| **HTTP headers** | Stored in OS keychain per-session |
|
|
1006
1094
|
| **Bridge credentials** | Passed via Unix socket IPC, kept in memory only |
|
|
1007
1095
|
| **Process arguments** | No secrets visible in `ps aux` |
|
|
1096
|
+
| **x402 private key** | Stored in `wallets.json` (`0600` permissions) |
|
|
1008
1097
|
| **Config files** | Contain only metadata, never tokens |
|
|
1009
1098
|
| **File permissions** | `0600` (user-only) for all config files |
|
|
1010
1099
|
|
|
@@ -1055,20 +1144,22 @@ The main `mcpc` process doesn't save log files, but supports [verbose mode](#ver
|
|
|
1055
1144
|
### Troubleshooting
|
|
1056
1145
|
|
|
1057
1146
|
**"Cannot connect to bridge"**
|
|
1147
|
+
|
|
1058
1148
|
- Bridge may have crashed. Try: `mcpc @<session-name> tools-list` to restart the bridge
|
|
1059
1149
|
- Check bridge is running: `ps aux | grep -e 'mcpc-bridge' -e '[m]cpc/dist/bridge'`
|
|
1060
1150
|
- Check socket exists: `ls ~/.mcpc/bridges/`
|
|
1061
1151
|
|
|
1062
1152
|
**"Session not found"**
|
|
1153
|
+
|
|
1063
1154
|
- List existing sessions: `mcpc`
|
|
1064
1155
|
- Create new session if expired: `mcpc @<session-name> close` and `mcpc <target> connect @<session-name>`
|
|
1065
1156
|
|
|
1066
1157
|
**"Authentication failed"**
|
|
1158
|
+
|
|
1067
1159
|
- List saved OAuth profiles: `mcpc`
|
|
1068
1160
|
- Re-authenticate: `mcpc <server> login [--profile <name>]`
|
|
1069
1161
|
- For bearer tokens: provide `--header "Authorization: Bearer ${TOKEN}"` again
|
|
1070
1162
|
|
|
1071
|
-
|
|
1072
1163
|
## Development
|
|
1073
1164
|
|
|
1074
1165
|
The initial version of `mcpc` was developed and [launched by Jan Curn](https://x.com/jancurn/status/2007144080959291756) of [Apify](https://apify.com)
|
|
@@ -1099,8 +1190,6 @@ See [CONTRIBUTING](./CONTRIBUTING.md) for development setup, architecture overvi
|
|
|
1099
1190
|
- Other
|
|
1100
1191
|
- https://github.com/TeamSparkAI/mcpGraph
|
|
1101
1192
|
|
|
1102
|
-
|
|
1103
1193
|
## License
|
|
1104
1194
|
|
|
1105
1195
|
Apache-2.0 - see [LICENSE](./LICENSE) for details.
|
|
1106
|
-
|
package/dist/bridge/index.js
CHANGED
|
@@ -15,6 +15,7 @@ import { readKeychainProxyBearerToken } from '../lib/auth/keychain.js';
|
|
|
15
15
|
import { createRequire } from 'module';
|
|
16
16
|
const { version: mcpcVersion } = createRequire(import.meta.url)('../../package.json');
|
|
17
17
|
import { ProxyServer } from './proxy-server.js';
|
|
18
|
+
import { createX402FetchMiddleware } from '../lib/x402/fetch-middleware.js';
|
|
18
19
|
setGlobalDispatcher(new EnvHttpProxyAgent());
|
|
19
20
|
const KEEPALIVE_INTERVAL_MS = 30_000;
|
|
20
21
|
const logger = createLogger('bridge');
|
|
@@ -30,8 +31,12 @@ class BridgeProcess {
|
|
|
30
31
|
tokenManager = null;
|
|
31
32
|
authProvider = null;
|
|
32
33
|
headers = null;
|
|
34
|
+
x402Wallet = null;
|
|
35
|
+
cachedTools = null;
|
|
33
36
|
authCredentialsReceived = null;
|
|
34
37
|
authCredentialsResolver = null;
|
|
38
|
+
x402WalletReceived = null;
|
|
39
|
+
x402WalletResolver = null;
|
|
35
40
|
mcpClientReady;
|
|
36
41
|
mcpClientReadyResolver;
|
|
37
42
|
mcpClientReadyRejecter;
|
|
@@ -120,6 +125,18 @@ class BridgeProcess {
|
|
|
120
125
|
this.authCredentialsResolver = null;
|
|
121
126
|
}
|
|
122
127
|
}
|
|
128
|
+
setX402Wallet(credentials) {
|
|
129
|
+
logger.info(`Received x402 wallet: ${credentials.address}`);
|
|
130
|
+
this.x402Wallet = {
|
|
131
|
+
privateKey: credentials.privateKey,
|
|
132
|
+
address: credentials.address,
|
|
133
|
+
};
|
|
134
|
+
logger.debug('x402 wallet stored in memory');
|
|
135
|
+
if (this.x402WalletResolver) {
|
|
136
|
+
this.x402WalletResolver();
|
|
137
|
+
this.x402WalletResolver = null;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
123
140
|
async updateTransportAuth() {
|
|
124
141
|
const config = { ...this.options.serverConfig };
|
|
125
142
|
if (!config.url) {
|
|
@@ -177,16 +194,27 @@ class BridgeProcess {
|
|
|
177
194
|
this.runOrphanedLogCleanup();
|
|
178
195
|
try {
|
|
179
196
|
await this.createSocketServer();
|
|
197
|
+
const ipcWaiters = [];
|
|
180
198
|
if (this.options.profileName) {
|
|
181
199
|
logger.debug(`Waiting for auth credentials (profile: ${this.options.profileName})...`);
|
|
182
200
|
this.authCredentialsReceived = new Promise((resolve) => {
|
|
183
201
|
this.authCredentialsResolver = resolve;
|
|
184
202
|
});
|
|
203
|
+
ipcWaiters.push(this.authCredentialsReceived);
|
|
204
|
+
}
|
|
205
|
+
if (this.options.x402) {
|
|
206
|
+
logger.debug('Waiting for x402 wallet...');
|
|
207
|
+
this.x402WalletReceived = new Promise((resolve) => {
|
|
208
|
+
this.x402WalletResolver = resolve;
|
|
209
|
+
});
|
|
210
|
+
ipcWaiters.push(this.x402WalletReceived);
|
|
211
|
+
}
|
|
212
|
+
if (ipcWaiters.length > 0) {
|
|
185
213
|
const timeout = new Promise((_, reject) => {
|
|
186
|
-
setTimeout(() => reject(new Error('Timeout waiting for
|
|
214
|
+
setTimeout(() => reject(new Error('Timeout waiting for IPC credentials')), 5000);
|
|
187
215
|
});
|
|
188
|
-
await Promise.race([
|
|
189
|
-
logger.debug('
|
|
216
|
+
await Promise.race([Promise.all(ipcWaiters), timeout]);
|
|
217
|
+
logger.debug('IPC credentials received, proceeding with MCP connection');
|
|
190
218
|
}
|
|
191
219
|
try {
|
|
192
220
|
await this.connectToMcp();
|
|
@@ -270,9 +298,19 @@ class BridgeProcess {
|
|
|
270
298
|
}
|
|
271
299
|
logger.debug('Building MCP client config...');
|
|
272
300
|
logger.debug(` this.authProvider is set: ${!!this.authProvider}`);
|
|
301
|
+
logger.debug(` this.x402Wallet is set: ${!!this.x402Wallet}`);
|
|
273
302
|
if (this.authProvider) {
|
|
274
303
|
logger.debug(` authProvider type: ${this.authProvider.constructor.name}`);
|
|
275
304
|
}
|
|
305
|
+
let customFetch;
|
|
306
|
+
if (this.x402Wallet && serverConfig.url) {
|
|
307
|
+
logger.debug('Creating x402 fetch middleware for payment signing');
|
|
308
|
+
const wallet = this.x402Wallet;
|
|
309
|
+
const getToolByName = (name) => {
|
|
310
|
+
return this.cachedTools?.find((t) => t.name === name);
|
|
311
|
+
};
|
|
312
|
+
customFetch = createX402FetchMiddleware(fetch, { wallet, getToolByName });
|
|
313
|
+
}
|
|
276
314
|
const clientConfig = {
|
|
277
315
|
clientInfo: { name: 'mcpc', version: mcpcVersion },
|
|
278
316
|
serverConfig,
|
|
@@ -282,11 +320,16 @@ class BridgeProcess {
|
|
|
282
320
|
},
|
|
283
321
|
...(this.authProvider && { authProvider: this.authProvider }),
|
|
284
322
|
...(this.options.mcpSessionId && { mcpSessionId: this.options.mcpSessionId }),
|
|
323
|
+
...(customFetch && { customFetch }),
|
|
285
324
|
listChanged: {
|
|
286
325
|
tools: {
|
|
287
326
|
autoRefresh: true,
|
|
288
327
|
onChanged: (error, tools) => {
|
|
289
328
|
logger.debug('Tools list changed', { error, count: tools?.length });
|
|
329
|
+
if (tools) {
|
|
330
|
+
this.cachedTools = tools;
|
|
331
|
+
logger.debug(`Updated cached tools list (${tools.length} tools)`);
|
|
332
|
+
}
|
|
290
333
|
this.broadcastNotification('tools/list_changed');
|
|
291
334
|
this.updateNotificationTimestamp('tools').catch((err) => {
|
|
292
335
|
logger.warn('Failed to update tools notification timestamp:', err);
|
|
@@ -340,6 +383,18 @@ class BridgeProcess {
|
|
|
340
383
|
logger.info(`MCP-Session-Id saved for resumption: ${newMcpSessionId}`);
|
|
341
384
|
}
|
|
342
385
|
await updateSession(this.options.sessionName, sessionUpdate);
|
|
386
|
+
if (this.x402Wallet) {
|
|
387
|
+
try {
|
|
388
|
+
const toolsResult = await this.client.listTools();
|
|
389
|
+
if (toolsResult.tools) {
|
|
390
|
+
this.cachedTools = toolsResult.tools;
|
|
391
|
+
logger.debug(`Pre-populated tools cache (${this.cachedTools.length} tools) for x402`);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
catch (error) {
|
|
395
|
+
logger.warn('Failed to pre-populate tools cache for x402:', error);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
343
398
|
}
|
|
344
399
|
async startProxyServer() {
|
|
345
400
|
if (!this.options.proxyConfig || !this.client) {
|
|
@@ -499,6 +554,21 @@ class BridgeProcess {
|
|
|
499
554
|
throw new ClientError('Missing authCredentials in set-auth-credentials message');
|
|
500
555
|
}
|
|
501
556
|
break;
|
|
557
|
+
case 'set-x402-wallet':
|
|
558
|
+
if (message.x402Wallet) {
|
|
559
|
+
this.setX402Wallet(message.x402Wallet);
|
|
560
|
+
if (message.id) {
|
|
561
|
+
this.sendResponse(socket, {
|
|
562
|
+
type: 'response',
|
|
563
|
+
id: message.id,
|
|
564
|
+
result: { success: true },
|
|
565
|
+
});
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
else {
|
|
569
|
+
throw new ClientError('Missing x402Wallet in set-x402-wallet message');
|
|
570
|
+
}
|
|
571
|
+
break;
|
|
502
572
|
default:
|
|
503
573
|
throw new ClientError(`Unknown message type: ${message.type}`);
|
|
504
574
|
}
|
|
@@ -696,7 +766,7 @@ class BridgeProcess {
|
|
|
696
766
|
async function main() {
|
|
697
767
|
const args = process.argv.slice(2);
|
|
698
768
|
if (args.length < 2) {
|
|
699
|
-
console.error('Usage: mcpc-bridge <sessionName> <transportConfigJson> [--verbose] [--profile <name>] [--proxy-host <host>] [--proxy-port <port>] [--mcp-session-id <id>]');
|
|
769
|
+
console.error('Usage: mcpc-bridge <sessionName> <transportConfigJson> [--verbose] [--profile <name>] [--proxy-host <host>] [--proxy-port <port>] [--mcp-session-id <id>] [--x402]');
|
|
700
770
|
process.exit(1);
|
|
701
771
|
}
|
|
702
772
|
const sessionName = args[0];
|
|
@@ -722,6 +792,7 @@ async function main() {
|
|
|
722
792
|
if (mcpSessionIdIndex !== -1 && args[mcpSessionIdIndex + 1]) {
|
|
723
793
|
mcpSessionId = args[mcpSessionIdIndex + 1];
|
|
724
794
|
}
|
|
795
|
+
const x402 = args.includes('--x402');
|
|
725
796
|
try {
|
|
726
797
|
const bridgeOptions = {
|
|
727
798
|
sessionName,
|
|
@@ -737,6 +808,9 @@ async function main() {
|
|
|
737
808
|
if (mcpSessionId) {
|
|
738
809
|
bridgeOptions.mcpSessionId = mcpSessionId;
|
|
739
810
|
}
|
|
811
|
+
if (x402) {
|
|
812
|
+
bridgeOptions.x402 = true;
|
|
813
|
+
}
|
|
740
814
|
const bridge = new BridgeProcess(bridgeOptions);
|
|
741
815
|
await bridge.start();
|
|
742
816
|
}
|