@apify/mcpc 0.1.11-beta.1 â 0.1.11-beta.2
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 +3 -0
- package/README.md +133 -47
- 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 +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
### Changed
|
|
11
|
+
- OS keychain now falls back to `~/.mcpc/credentials.json` (mode 0600) when no keyring daemon is available (e.g. headless Linux servers, containers)
|
|
12
|
+
|
|
10
13
|
## [0.1.10] - 2026-03-01
|
|
11
14
|
|
|
12
15
|
### 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)
|
|
@@ -48,29 +50,29 @@ npm install -g @apify/mcpc
|
|
|
48
50
|
```
|
|
49
51
|
|
|
50
52
|
**Linux users:** `mcpc` uses the OS keychain for secure credential storage via the
|
|
51
|
-
[Secret Service API](https://specifications.freedesktop.org/secret-service/).
|
|
53
|
+
[Secret Service API](https://specifications.freedesktop.org/secret-service/).
|
|
54
|
+
On desktop systems (GNOME, KDE) this works out of the box. On headless/server/CI environments
|
|
55
|
+
without a keyring daemon, `mcpc` automatically falls back to a file-based credential store
|
|
56
|
+
(`~/.mcpc/credentials`, mode `0600`).
|
|
52
57
|
|
|
53
|
-
|
|
54
|
-
```bash
|
|
55
|
-
# Debian/Ubuntu
|
|
56
|
-
sudo apt-get install libsecret-1-0
|
|
58
|
+
To use the OS keychain on a headless system, install `libsecret` and a secret service daemon:
|
|
57
59
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
+
```bash
|
|
61
|
+
# Debian/Ubuntu
|
|
62
|
+
sudo apt-get install libsecret-1-0 gnome-keyring
|
|
60
63
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
```
|
|
64
|
+
# Fedora/RHEL/CentOS
|
|
65
|
+
sudo dnf install libsecret gnome-keyring
|
|
64
66
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
# Debian/Ubuntu
|
|
69
|
-
sudo apt-get install gnome-keyring
|
|
67
|
+
# Arch Linux
|
|
68
|
+
sudo pacman -S libsecret gnome-keyring
|
|
69
|
+
```
|
|
70
70
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
71
|
+
And then run `mcpc` as follows:
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
dbus-run-session -- bash -c "echo -n 'password' | gnome-keyring-daemon --unlock && mcpc ..."
|
|
75
|
+
```
|
|
74
76
|
|
|
75
77
|
## Quickstart
|
|
76
78
|
|
|
@@ -117,6 +119,7 @@ Options:
|
|
|
117
119
|
--timeout <seconds> Request timeout in seconds (default: 300)
|
|
118
120
|
--proxy <[host:]port> Start proxy MCP server for session (with "connect" command)
|
|
119
121
|
--proxy-bearer-token <token> Require authentication for access to proxy server
|
|
122
|
+
--x402 Enable x402 auto-payment using the configured wallet
|
|
120
123
|
--clean[=types] Clean up mcpc data (types: sessions, logs, profiles, all)
|
|
121
124
|
-h, --help Display general help
|
|
122
125
|
|
|
@@ -148,7 +151,14 @@ MCP server commands:
|
|
|
148
151
|
resources-templates-list
|
|
149
152
|
logging-set-level <level>
|
|
150
153
|
ping
|
|
151
|
-
|
|
154
|
+
|
|
155
|
+
x402 payment commands (no target needed):
|
|
156
|
+
x402 init Create a new x402 wallet
|
|
157
|
+
x402 import <key> Import wallet from private key
|
|
158
|
+
x402 info Show wallet info
|
|
159
|
+
x402 sign -r <base64> Sign payment from PAYMENT-REQUIRED header
|
|
160
|
+
x402 remove Remove the wallet
|
|
161
|
+
|
|
152
162
|
Run "mcpc" without <target> to show available sessions and profiles.
|
|
153
163
|
```
|
|
154
164
|
|
|
@@ -181,6 +191,7 @@ To connect and interact with an MCP server, you need to specify a `<target>`, wh
|
|
|
181
191
|
connects, and enables you to interact with it.
|
|
182
192
|
|
|
183
193
|
**URL handling:**
|
|
194
|
+
|
|
184
195
|
- URLs without a scheme (e.g. `mcp.apify.com`) default to `https://`
|
|
185
196
|
- `localhost` and `127.0.0.1` addresses without a scheme default to `http://` (for local dev/proxy servers)
|
|
186
197
|
- To override the default, specify the scheme explicitly (e.g. `http://example.com`)
|
|
@@ -229,6 +240,7 @@ cat args.json | mcpc <target> tools-call <tool-name>
|
|
|
229
240
|
```
|
|
230
241
|
|
|
231
242
|
**Rules:**
|
|
243
|
+
|
|
232
244
|
- All arguments use `:=` syntax: `key:=value`
|
|
233
245
|
- Values are auto-parsed: valid JSON becomes that type, otherwise treated as string
|
|
234
246
|
- `count:=10` â number `10`
|
|
@@ -257,6 +269,7 @@ echo "{\"query\": \"${QUERY}\", \"limit\": 10}" | mcpc @server tools-call search
|
|
|
257
269
|
```
|
|
258
270
|
|
|
259
271
|
**Common pitfall:** Don't put spaces around `:=` - it won't work:
|
|
272
|
+
|
|
260
273
|
```bash
|
|
261
274
|
# Wrong - spaces around :=
|
|
262
275
|
mcpc @server tools-call search query := "hello world"
|
|
@@ -329,7 +342,7 @@ Still, sessions can fail due to network disconnects, bridge process crash, or se
|
|
|
329
342
|
**Session states:**
|
|
330
343
|
|
|
331
344
|
| State | Meaning |
|
|
332
|
-
|
|
345
|
+
| ---------------- | --------------------------------------------------------------------------------------------- |
|
|
333
346
|
| ðĒ **`live`** | Bridge process is running; server might or might not be operational |
|
|
334
347
|
| ðĄ **`crashed`** | Bridge process crashed or was killed; will auto-restart on next use |
|
|
335
348
|
| ðī **`expired`** | Server rejected the session (auth failed, session ID invalid); requires `close` and reconnect |
|
|
@@ -365,7 +378,6 @@ and opens new connection with new `MCP-Session-Id`, by running:
|
|
|
365
378
|
mcpc @apify restart
|
|
366
379
|
```
|
|
367
380
|
|
|
368
|
-
|
|
369
381
|
## Authentication
|
|
370
382
|
|
|
371
383
|
`mcpc` supports all standard [MCP authorization methods](https://modelcontextprotocol.io/specification/latest/basic/authorization).
|
|
@@ -404,8 +416,8 @@ mcpc @apify tools-list
|
|
|
404
416
|
|
|
405
417
|
### OAuth profiles
|
|
406
418
|
|
|
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,
|
|
419
|
+
For OAuth-enabled remote MCP servers, `mcpc` implements the full OAuth 2.1 flow with PKCE,
|
|
420
|
+
including `WWW-Authenticate` header discovery, server metadata discovery, client ID metadata documents,
|
|
409
421
|
dynamic client registration, and automatic token refresh.
|
|
410
422
|
|
|
411
423
|
The OAuth authentication **always** needs to be initiated by the user calling the `login` command,
|
|
@@ -413,11 +425,13 @@ which opens a web browser with login screen. `mcpc` never opens the web browser
|
|
|
413
425
|
|
|
414
426
|
The OAuth credentials to specific servers are securely stored as **authentication profiles** - reusable
|
|
415
427
|
credentials that allow you to:
|
|
428
|
+
|
|
416
429
|
- Authenticate once, use credentials across multiple commands or sessions
|
|
417
430
|
- Use different accounts (profiles) with the same server
|
|
418
431
|
- Manage credentials independently from sessions
|
|
419
432
|
|
|
420
433
|
Key concepts:
|
|
434
|
+
|
|
421
435
|
- **Authentication profile**: Named set of OAuth credentials for a specific server (stored in `~/.mcpc/profiles.json` + OS keychain)
|
|
422
436
|
- **Session**: Active connection to a server that may reference an authentication profile (stored in `~/.mcpc/sessions.json`)
|
|
423
437
|
- **Default profile**: When `--profile` is not specified, `mcpc` uses the authentication profile named `default`
|
|
@@ -456,7 +470,6 @@ When multiple authentication methods are available, `mcpc` uses this precedence
|
|
|
456
470
|
3. **Config file headers** - Headers from `--config` file for the server
|
|
457
471
|
4. **No authentication** - Attempts unauthenticated connection
|
|
458
472
|
|
|
459
|
-
|
|
460
473
|
`mcpc` automatically handles authentication based on whether you specify a profile:
|
|
461
474
|
|
|
462
475
|
**When `--profile <name>` is specified:**
|
|
@@ -478,6 +491,7 @@ When multiple authentication methods are available, `mcpc` uses this precedence
|
|
|
478
491
|
On failure, the error message includes instructions on how to login and save the profile, so you know what to do.
|
|
479
492
|
|
|
480
493
|
This flow ensures:
|
|
494
|
+
|
|
481
495
|
- You only authenticate when necessary
|
|
482
496
|
- Credentials are never silently mixed up (personal â work) or downgraded (authenticated â unauthenticated)
|
|
483
497
|
- You can mix authenticated sessions (with named profiles) and public access on the same server
|
|
@@ -500,7 +514,6 @@ mcpc mcp.apify.com connect @apify-personal
|
|
|
500
514
|
mcpc mcp.apify.com\?tools=docs tools-list
|
|
501
515
|
```
|
|
502
516
|
|
|
503
|
-
|
|
504
517
|
## MCP proxy
|
|
505
518
|
|
|
506
519
|
For stronger isolation, `mcpc` can expose an MCP session under a new local proxy MCP server using the `--proxy` option.
|
|
@@ -534,7 +547,7 @@ mcpc localhost:8081 connect @sandboxed2 --header "Authorization: Bearer secret12
|
|
|
534
547
|
**Proxy options for `connect` command:**
|
|
535
548
|
|
|
536
549
|
| Option | Description |
|
|
537
|
-
|
|
550
|
+
| ------------------------------ | ------------------------------------------------------------------------------ |
|
|
538
551
|
| `--proxy [host:]port` | Start proxy MCP server. Default host: `127.0.0.1` (localhost only) |
|
|
539
552
|
| `--proxy-bearer-token <token>` | Requires `Authorization: Bearer <token>` header to access the proxy MCP server |
|
|
540
553
|
|
|
@@ -565,7 +578,6 @@ mcpc
|
|
|
565
578
|
# @relay â https://mcp.apify.com (HTTP, OAuth: default) [proxy: 127.0.0.1:8080]
|
|
566
579
|
```
|
|
567
580
|
|
|
568
|
-
|
|
569
581
|
## AI agents
|
|
570
582
|
|
|
571
583
|
`mcpc` is designed for CLI-enabled AI agents like Claude Code or Codex CLI, supporting both
|
|
@@ -635,6 +647,7 @@ mcpc @apify tools-call search-actors --schema expected.json keywords:="test"
|
|
|
635
647
|
```
|
|
636
648
|
|
|
637
649
|
Available schema validation modes (`--schema-mode`):
|
|
650
|
+
|
|
638
651
|
- `compatible` (default)
|
|
639
652
|
- Input schema: new optional fields OK, required fields must have the same type.
|
|
640
653
|
- Output schema: new fields OK, removed required fields cause error.
|
|
@@ -668,6 +681,73 @@ To help Claude Code use `mcpc`, you can install this [Claude skill](./docs/claud
|
|
|
668
681
|
|
|
669
682
|
<!-- TODO: Add also AGENTS.md, GitHub skills etc. -->
|
|
670
683
|
|
|
684
|
+
## Agentic payments (x402)
|
|
685
|
+
|
|
686
|
+
> â ïļ **Experimental.** This feature is under active development and may change.
|
|
687
|
+
|
|
688
|
+
`mcpc` has experimental support for the [x402 payment protocol](https://www.x402.org/),
|
|
689
|
+
which enables AI agents to autonomously pay for MCP tool calls using cryptocurrency.
|
|
690
|
+
When an MCP server charges for a tool call (HTTP 402), `mcpc` automatically signs a USDC payment
|
|
691
|
+
on the [Base](https://base.org/) blockchain and retries the request â no human intervention needed.
|
|
692
|
+
|
|
693
|
+
This is entirely **opt-in**: existing functionality is unaffected unless you explicitly pass the `--x402` flag.
|
|
694
|
+
|
|
695
|
+
### How it works
|
|
696
|
+
|
|
697
|
+
1. **Server returns HTTP 402** with a `PAYMENT-REQUIRED` header describing the price and payment details.
|
|
698
|
+
2. `mcpc` parses the header, signs an [EIP-3009](https://eips.ethereum.org/EIPS/eip-3009) `TransferWithAuthorization` using your local wallet.
|
|
699
|
+
3. `mcpc` retries the request with a `PAYMENT-SIGNATURE` header containing the signed payment.
|
|
700
|
+
4. The server verifies the signature and fulfills the request.
|
|
701
|
+
|
|
702
|
+
For tools that advertise pricing in their `_meta.x402` metadata, `mcpc` can **proactively sign** payments
|
|
703
|
+
on the first request, avoiding the 402 round-trip entirely.
|
|
704
|
+
|
|
705
|
+
### Wallet setup
|
|
706
|
+
|
|
707
|
+
`mcpc` stores a single wallet in `~/.mcpc/wallets.json` (file permissions `0600`).
|
|
708
|
+
You need to create or import a wallet before using x402 payments.
|
|
709
|
+
|
|
710
|
+
```bash
|
|
711
|
+
# Create a new wallet (generates a random private key)
|
|
712
|
+
mcpc x402 init
|
|
713
|
+
|
|
714
|
+
# Or import an existing wallet from a private key
|
|
715
|
+
mcpc x402 import <private-key>
|
|
716
|
+
|
|
717
|
+
# Show wallet address and creation date
|
|
718
|
+
mcpc x402 info
|
|
719
|
+
|
|
720
|
+
# Remove the wallet
|
|
721
|
+
mcpc x402 remove
|
|
722
|
+
```
|
|
723
|
+
|
|
724
|
+
After creating a wallet, **fund it with USDC on Base** (mainnet or Sepolia testnet) to enable payments.
|
|
725
|
+
|
|
726
|
+
### Using x402 with MCP servers
|
|
727
|
+
|
|
728
|
+
Pass the `--x402` flag when connecting to a session or running direct commands:
|
|
729
|
+
|
|
730
|
+
```bash
|
|
731
|
+
# Create a session with x402 payment support
|
|
732
|
+
mcpc mcp.apify.com connect @apify --x402
|
|
733
|
+
|
|
734
|
+
# The session now automatically handles 402 responses
|
|
735
|
+
mcpc @apify tools-call expensive-tool query:="hello"
|
|
736
|
+
|
|
737
|
+
# Restart a session with x402 enabled
|
|
738
|
+
mcpc @apify restart --x402
|
|
739
|
+
```
|
|
740
|
+
|
|
741
|
+
When `--x402` is active, a fetch middleware wraps all HTTP requests to the MCP server.
|
|
742
|
+
If any request returns HTTP 402, the middleware transparently signs and retries.
|
|
743
|
+
|
|
744
|
+
### Supported networks
|
|
745
|
+
|
|
746
|
+
| Network | Status |
|
|
747
|
+
| -------------------- | ------------ |
|
|
748
|
+
| Base Mainnet | â
Supported |
|
|
749
|
+
| Base Sepolia testnet | â
Supported |
|
|
750
|
+
|
|
671
751
|
## MCP support
|
|
672
752
|
|
|
673
753
|
`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 +768,7 @@ To help Claude Code use `mcpc`, you can install this [Claude skill](./docs/claud
|
|
|
688
768
|
### MCP session
|
|
689
769
|
|
|
690
770
|
The bridge process manages the full MCP session lifecycle:
|
|
771
|
+
|
|
691
772
|
- Performs initialization handshake (`initialize` â `initialized`)
|
|
692
773
|
- Negotiates protocol version and capabilities
|
|
693
774
|
- Fetches server-provided `instructions`
|
|
@@ -698,21 +779,21 @@ The bridge process manages the full MCP session lifecycle:
|
|
|
698
779
|
|
|
699
780
|
### MCP feature support
|
|
700
781
|
|
|
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)
|
|
782
|
+
| **Feature** | **Status** |
|
|
783
|
+
| :------------------------------------------------- | :-------------------------------- |
|
|
784
|
+
| ð [**Instructions**](#server-instructions) | â
Supported |
|
|
785
|
+
| ð§ [**Tools**](#tools) | â
Supported |
|
|
786
|
+
| ðŽ [**Prompts**](#prompts) | â
Supported |
|
|
787
|
+
| ðĶ [**Resources**](#resources) | â
Supported |
|
|
788
|
+
| ð [**Logging**](#server-logs) | â
Supported |
|
|
789
|
+
| ð [**Notifications**](#list-change-notifications) | â
Supported |
|
|
790
|
+
| ð [**Pagination**](#pagination) | â
Supported |
|
|
791
|
+
| ð [**Ping**](#ping) | â
Supported |
|
|
792
|
+
| âģ **Async tasks** | ð§ Planned |
|
|
793
|
+
| ð **Roots** | ð§ Planned |
|
|
794
|
+
| â **Elicitation** | ð§ Planned |
|
|
795
|
+
| ðĪ **Completion** | ð§ Planned |
|
|
796
|
+
| ðĪ **Sampling** | â Not applicable (no LLM access) |
|
|
716
797
|
|
|
717
798
|
#### Server instructions
|
|
718
799
|
|
|
@@ -865,6 +946,7 @@ mcpc @apify ping --json
|
|
|
865
946
|
You can configure `mcpc` using a config file, environment variables, or command-line flags.
|
|
866
947
|
|
|
867
948
|
**Precedence** (highest to lowest):
|
|
949
|
+
|
|
868
950
|
1. Command-line flags (including `--config` option)
|
|
869
951
|
2. Environment variables
|
|
870
952
|
3. Built-in defaults
|
|
@@ -912,11 +994,13 @@ mcpc --config .vscode/mcp.json apify connect @my-apify
|
|
|
912
994
|
**Server configuration properties:**
|
|
913
995
|
|
|
914
996
|
For **Streamable HTTP servers:**
|
|
997
|
+
|
|
915
998
|
- `url` (required) - MCP server endpoint URL
|
|
916
999
|
- `headers` (optional) - HTTP headers to include with requests
|
|
917
1000
|
- `timeout` (optional) - Request timeout in seconds
|
|
918
1001
|
|
|
919
1002
|
For **stdio servers:**
|
|
1003
|
+
|
|
920
1004
|
- `command` (required) - Command to execute (e.g., `node`, `npx`, `python`)
|
|
921
1005
|
- `args` (optional) - Array of command arguments
|
|
922
1006
|
- `env` (optional) - Environment variables for the process
|
|
@@ -958,6 +1042,7 @@ Config files support environment variable substitution using `${VAR_NAME}` synta
|
|
|
958
1042
|
|
|
959
1043
|
- `~/.mcpc/sessions.json` - Active sessions with references to authentication profiles (file-locked for concurrent access)
|
|
960
1044
|
- `~/.mcpc/profiles.json` - Authentication profiles (OAuth metadata, scopes, expiry)
|
|
1045
|
+
- `~/.mcpc/wallets.json` - x402 wallet data (file permissions `0600`)
|
|
961
1046
|
- `~/.mcpc/bridges/` - Unix domain socket files for each bridge process
|
|
962
1047
|
- `~/.mcpc/logs/bridge-*.log` - Log files for each bridge process
|
|
963
1048
|
- OS keychain - Sensitive credentials (OAuth tokens, bearer tokens, client secrets)
|
|
@@ -1000,11 +1085,12 @@ MCP enables arbitrary tool execution and data access - treat servers like you tr
|
|
|
1000
1085
|
### Credential protection
|
|
1001
1086
|
|
|
1002
1087
|
| What | How |
|
|
1003
|
-
|
|
1088
|
+
| ---------------------- | ----------------------------------------------- |
|
|
1004
1089
|
| **OAuth tokens** | Stored in OS keychain, never on disk |
|
|
1005
1090
|
| **HTTP headers** | Stored in OS keychain per-session |
|
|
1006
1091
|
| **Bridge credentials** | Passed via Unix socket IPC, kept in memory only |
|
|
1007
1092
|
| **Process arguments** | No secrets visible in `ps aux` |
|
|
1093
|
+
| **x402 private key** | Stored in `wallets.json` (`0600` permissions) |
|
|
1008
1094
|
| **Config files** | Contain only metadata, never tokens |
|
|
1009
1095
|
| **File permissions** | `0600` (user-only) for all config files |
|
|
1010
1096
|
|
|
@@ -1055,20 +1141,22 @@ The main `mcpc` process doesn't save log files, but supports [verbose mode](#ver
|
|
|
1055
1141
|
### Troubleshooting
|
|
1056
1142
|
|
|
1057
1143
|
**"Cannot connect to bridge"**
|
|
1144
|
+
|
|
1058
1145
|
- Bridge may have crashed. Try: `mcpc @<session-name> tools-list` to restart the bridge
|
|
1059
1146
|
- Check bridge is running: `ps aux | grep -e 'mcpc-bridge' -e '[m]cpc/dist/bridge'`
|
|
1060
1147
|
- Check socket exists: `ls ~/.mcpc/bridges/`
|
|
1061
1148
|
|
|
1062
1149
|
**"Session not found"**
|
|
1150
|
+
|
|
1063
1151
|
- List existing sessions: `mcpc`
|
|
1064
1152
|
- Create new session if expired: `mcpc @<session-name> close` and `mcpc <target> connect @<session-name>`
|
|
1065
1153
|
|
|
1066
1154
|
**"Authentication failed"**
|
|
1155
|
+
|
|
1067
1156
|
- List saved OAuth profiles: `mcpc`
|
|
1068
1157
|
- Re-authenticate: `mcpc <server> login [--profile <name>]`
|
|
1069
1158
|
- For bearer tokens: provide `--header "Authorization: Bearer ${TOKEN}"` again
|
|
1070
1159
|
|
|
1071
|
-
|
|
1072
1160
|
## Development
|
|
1073
1161
|
|
|
1074
1162
|
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 +1187,6 @@ See [CONTRIBUTING](./CONTRIBUTING.md) for development setup, architecture overvi
|
|
|
1099
1187
|
- Other
|
|
1100
1188
|
- https://github.com/TeamSparkAI/mcpGraph
|
|
1101
1189
|
|
|
1102
|
-
|
|
1103
1190
|
## License
|
|
1104
1191
|
|
|
1105
1192
|
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
|
}
|