@apify/mcpc 0.1.7 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/.claude/settings.local.json +12 -1
  2. package/.idea/workspace.xml +141 -144
  3. package/README.md +34 -19
  4. package/dist/bridge/index.js +29 -9
  5. package/dist/bridge/index.js.map +1 -1
  6. package/dist/cli/commands/sessions.d.ts.map +1 -1
  7. package/dist/cli/commands/sessions.js +1 -1
  8. package/dist/cli/commands/sessions.js.map +1 -1
  9. package/dist/cli/index.js +8 -6
  10. package/dist/cli/index.js.map +1 -1
  11. package/dist/core/factory.d.ts +1 -0
  12. package/dist/core/factory.d.ts.map +1 -1
  13. package/dist/core/factory.js +9 -1
  14. package/dist/core/factory.js.map +1 -1
  15. package/dist/core/mcp-client.d.ts +2 -0
  16. package/dist/core/mcp-client.d.ts.map +1 -1
  17. package/dist/core/mcp-client.js +9 -0
  18. package/dist/core/mcp-client.js.map +1 -1
  19. package/dist/core/transports.d.ts +1 -0
  20. package/dist/core/transports.d.ts.map +1 -1
  21. package/dist/core/transports.js +4 -0
  22. package/dist/core/transports.js.map +1 -1
  23. package/dist/lib/bridge-manager.d.ts +1 -0
  24. package/dist/lib/bridge-manager.d.ts.map +1 -1
  25. package/dist/lib/bridge-manager.js +10 -2
  26. package/dist/lib/bridge-manager.js.map +1 -1
  27. package/dist/lib/session-client.js +2 -2
  28. package/dist/lib/session-client.js.map +1 -1
  29. package/dist/lib/sessions.d.ts.map +1 -1
  30. package/dist/lib/sessions.js +2 -2
  31. package/dist/lib/sessions.js.map +1 -1
  32. package/dist/lib/types.d.ts +1 -0
  33. package/dist/lib/types.d.ts.map +1 -1
  34. package/dist/lib/utils.d.ts +1 -0
  35. package/dist/lib/utils.d.ts.map +1 -1
  36. package/dist/lib/utils.js +9 -0
  37. package/dist/lib/utils.js.map +1 -1
  38. package/docs/TODOs.md +13 -0
  39. package/package.json +1 -1
@@ -97,7 +97,18 @@
97
97
  "Bash(E2E_ISOLATED_ALL=1 TESTS=\"human-output output-invariants\" ./test/e2e/run.sh:*)",
98
98
  "Bash(E2E_ISOLATED_ALL=1 TESTS=\"output-invariants human-output\" ./test/e2e/run.sh:*)",
99
99
  "Bash(npm publish:*)",
100
- "Bash(MCPC_RELEASE=1 npm publish:*)"
100
+ "Bash(MCPC_RELEASE=1 npm publish:*)",
101
+ "WebFetch(domain:www.philschmid.de)",
102
+ "Bash(mcpc @apify close:*)",
103
+ "Bash(mcpc:*)",
104
+ "Bash(__NEW_LINE_be84ee31121f5014__ echo \"\")",
105
+ "Bash(MCPC_HOME_DIR=/tmp/mcpc-test-restart ./dist/cli/index.js:*)",
106
+ "Bash(./dist/cli/index.js:*)",
107
+ "Bash(./dist/cli/index.js @test-restart close:*)",
108
+ "Bash(MCPC_HOME_DIR=/tmp/mcpc-test-json node:*)",
109
+ "Bash(MCPC_HOME_DIR=/tmp/mcpc-test-json MCPC_VERBOSE=1 node:*)",
110
+ "Bash(MCPC_HOME_DIR=/tmp/mcpc-test-json DEBUG=* node:*)",
111
+ "Bash(MCPC_HOME_DIR=/tmp/mcpc-test-new node:*)"
101
112
  ]
102
113
  }
103
114
  }
@@ -4,17 +4,14 @@
4
4
  <option name="autoReloadType" value="SELECTIVE" />
5
5
  </component>
6
6
  <component name="ChangeListManager">
7
- <list default="true" id="84071bae-f051-424d-a0e4-1540170b1e94" name="Changes" comment="Docs">
8
- <change beforePath="$PROJECT_DIR$/docs/TODOs.md" beforeDir="false" afterPath="$PROJECT_DIR$/docs/TODOs.md" afterDir="false" />
9
- <change beforePath="$PROJECT_DIR$/src/cli/index.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/cli/index.ts" afterDir="false" />
10
- </list>
7
+ <list default="true" id="84071bae-f051-424d-a0e4-1540170b1e94" name="Changes" comment="Fixes" />
11
8
  <option name="SHOW_DIALOG" value="false" />
12
9
  <option name="HIGHLIGHT_CONFLICTS" value="true" />
13
10
  <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
14
11
  <option name="LAST_RESOLUTION" value="IGNORE" />
15
12
  </component>
16
13
  <component name="EmbeddingIndexingInfo">
17
- <option name="cachedIndexableFilesCount" value="118" />
14
+ <option name="cachedIndexableFilesCount" value="123" />
18
15
  <option name="fileBasedEmbeddingIndicesEnabled" value="true" />
19
16
  </component>
20
17
  <component name="Git.Settings">
@@ -82,9 +79,9 @@
82
79
  <recent name="$PROJECT_DIR$/docs" />
83
80
  </key>
84
81
  <key name="MoveFile.RECENT_KEYS">
82
+ <recent name="$PROJECT_DIR$/docs" />
85
83
  <recent name="$PROJECT_DIR$/docs/images" />
86
84
  <recent name="$PROJECT_DIR$/docs/examples" />
87
- <recent name="$PROJECT_DIR$/docs" />
88
85
  <recent name="$PROJECT_DIR$/test/coverage" />
89
86
  <recent name="$PROJECT_DIR$/test/playground" />
90
87
  </key>
@@ -115,135 +112,7 @@
115
112
  <workItem from="1766435124813" duration="175094000" />
116
113
  <workItem from="1767121309931" duration="139790000" />
117
114
  <workItem from="1767397304824" duration="654000" />
118
- <workItem from="1767400124038" duration="5456000" />
119
- </task>
120
- <task id="LOCAL-00301" summary="Writing">
121
- <option name="closed" value="true" />
122
- <created>1767256060393</created>
123
- <option name="number" value="00301" />
124
- <option name="presentableId" value="LOCAL-00301" />
125
- <option name="project" value="LOCAL" />
126
- <updated>1767256060393</updated>
127
- </task>
128
- <task id="LOCAL-00302" summary="Writing">
129
- <option name="closed" value="true" />
130
- <created>1767256636124</created>
131
- <option name="number" value="00302" />
132
- <option name="presentableId" value="LOCAL-00302" />
133
- <option name="project" value="LOCAL" />
134
- <updated>1767256636124</updated>
135
- </task>
136
- <task id="LOCAL-00303" summary="Tests">
137
- <option name="closed" value="true" />
138
- <created>1767256961080</created>
139
- <option name="number" value="00303" />
140
- <option name="presentableId" value="LOCAL-00303" />
141
- <option name="project" value="LOCAL" />
142
- <updated>1767256961080</updated>
143
- </task>
144
- <task id="LOCAL-00304" summary="Renamed &quot;session&quot; to &quot;connect&quot;, it's feels better">
145
- <option name="closed" value="true" />
146
- <created>1767257359213</created>
147
- <option name="number" value="00304" />
148
- <option name="presentableId" value="LOCAL-00304" />
149
- <option name="project" value="LOCAL" />
150
- <updated>1767257359213</updated>
151
- </task>
152
- <task id="LOCAL-00305" summary="Fixed --timeout">
153
- <option name="closed" value="true" />
154
- <created>1767258330178</created>
155
- <option name="number" value="00305" />
156
- <option name="presentableId" value="LOCAL-00305" />
157
- <option name="project" value="LOCAL" />
158
- <updated>1767258330178</updated>
159
- </task>
160
- <task id="LOCAL-00306" summary="Fixes">
161
- <option name="closed" value="true" />
162
- <created>1767258961101</created>
163
- <option name="number" value="00306" />
164
- <option name="presentableId" value="LOCAL-00306" />
165
- <option name="project" value="LOCAL" />
166
- <updated>1767258961101</updated>
167
- </task>
168
- <task id="LOCAL-00307" summary="Writing">
169
- <option name="closed" value="true" />
170
- <created>1767260069457</created>
171
- <option name="number" value="00307" />
172
- <option name="presentableId" value="LOCAL-00307" />
173
- <option name="project" value="LOCAL" />
174
- <updated>1767260069457</updated>
175
- </task>
176
- <task id="LOCAL-00308" summary="Cosmetic">
177
- <option name="closed" value="true" />
178
- <created>1767260684183</created>
179
- <option name="number" value="00308" />
180
- <option name="presentableId" value="LOCAL-00308" />
181
- <option name="project" value="LOCAL" />
182
- <updated>1767260684183</updated>
183
- </task>
184
- <task id="LOCAL-00309" summary="Implemented --proxy command">
185
- <option name="closed" value="true" />
186
- <created>1767260968448</created>
187
- <option name="number" value="00309" />
188
- <option name="presentableId" value="LOCAL-00309" />
189
- <option name="project" value="LOCAL" />
190
- <updated>1767260968448</updated>
191
- </task>
192
- <task id="LOCAL-00310" summary="Writing and tests">
193
- <option name="closed" value="true" />
194
- <created>1767262727887</created>
195
- <option name="number" value="00310" />
196
- <option name="presentableId" value="LOCAL-00310" />
197
- <option name="project" value="LOCAL" />
198
- <updated>1767262727887</updated>
199
- </task>
200
- <task id="LOCAL-00311" summary="Writing">
201
- <option name="closed" value="true" />
202
- <created>1767262976779</created>
203
- <option name="number" value="00311" />
204
- <option name="presentableId" value="LOCAL-00311" />
205
- <option name="project" value="LOCAL" />
206
- <updated>1767262976779</updated>
207
- </task>
208
- <task id="LOCAL-00312" summary="Tests and nits">
209
- <option name="closed" value="true" />
210
- <created>1767263177871</created>
211
- <option name="number" value="00312" />
212
- <option name="presentableId" value="LOCAL-00312" />
213
- <option name="project" value="LOCAL" />
214
- <updated>1767263177871</updated>
215
- </task>
216
- <task id="LOCAL-00313" summary="Final touches">
217
- <option name="closed" value="true" />
218
- <created>1767264480849</created>
219
- <option name="number" value="00313" />
220
- <option name="presentableId" value="LOCAL-00313" />
221
- <option name="project" value="LOCAL" />
222
- <updated>1767264480849</updated>
223
- </task>
224
- <task id="LOCAL-00314" summary="Final touches">
225
- <option name="closed" value="true" />
226
- <created>1767264631473</created>
227
- <option name="number" value="00314" />
228
- <option name="presentableId" value="LOCAL-00314" />
229
- <option name="project" value="LOCAL" />
230
- <updated>1767264631473</updated>
231
- </task>
232
- <task id="LOCAL-00315" summary="Final touches">
233
- <option name="closed" value="true" />
234
- <created>1767295534266</created>
235
- <option name="number" value="00315" />
236
- <option name="presentableId" value="LOCAL-00315" />
237
- <option name="project" value="LOCAL" />
238
- <updated>1767295534266</updated>
239
- </task>
240
- <task id="LOCAL-00316" summary="More tests">
241
- <option name="closed" value="true" />
242
- <created>1767300734831</created>
243
- <option name="number" value="00316" />
244
- <option name="presentableId" value="LOCAL-00316" />
245
- <option name="project" value="LOCAL" />
246
- <updated>1767300734831</updated>
115
+ <workItem from="1767400124038" duration="58650000" />
247
116
  </task>
248
117
  <task id="LOCAL-00317" summary="Writing">
249
118
  <option name="closed" value="true" />
@@ -509,7 +378,135 @@
509
378
  <option name="project" value="LOCAL" />
510
379
  <updated>1767467232772</updated>
511
380
  </task>
512
- <option name="localTasksCounter" value="350" />
381
+ <task id="LOCAL-00350" summary="Docs">
382
+ <option name="closed" value="true" />
383
+ <created>1767495856786</created>
384
+ <option name="number" value="00350" />
385
+ <option name="presentableId" value="LOCAL-00350" />
386
+ <option name="project" value="LOCAL" />
387
+ <updated>1767495856786</updated>
388
+ </task>
389
+ <task id="LOCAL-00351" summary="Docs">
390
+ <option name="closed" value="true" />
391
+ <created>1767496287506</created>
392
+ <option name="number" value="00351" />
393
+ <option name="presentableId" value="LOCAL-00351" />
394
+ <option name="project" value="LOCAL" />
395
+ <updated>1767496287506</updated>
396
+ </task>
397
+ <task id="LOCAL-00352" summary="Docs">
398
+ <option name="closed" value="true" />
399
+ <created>1767501783702</created>
400
+ <option name="number" value="00352" />
401
+ <option name="presentableId" value="LOCAL-00352" />
402
+ <option name="project" value="LOCAL" />
403
+ <updated>1767501783702</updated>
404
+ </task>
405
+ <task id="LOCAL-00353" summary="Docs">
406
+ <option name="closed" value="true" />
407
+ <created>1767555748507</created>
408
+ <option name="number" value="00353" />
409
+ <option name="presentableId" value="LOCAL-00353" />
410
+ <option name="project" value="LOCAL" />
411
+ <updated>1767555748507</updated>
412
+ </task>
413
+ <task id="LOCAL-00354" summary="Docs">
414
+ <option name="closed" value="true" />
415
+ <created>1767561058376</created>
416
+ <option name="number" value="00354" />
417
+ <option name="presentableId" value="LOCAL-00354" />
418
+ <option name="project" value="LOCAL" />
419
+ <updated>1767561058377</updated>
420
+ </task>
421
+ <task id="LOCAL-00355" summary="Docs">
422
+ <option name="closed" value="true" />
423
+ <created>1767949515517</created>
424
+ <option name="number" value="00355" />
425
+ <option name="presentableId" value="LOCAL-00355" />
426
+ <option name="project" value="LOCAL" />
427
+ <updated>1767949515517</updated>
428
+ </task>
429
+ <task id="LOCAL-00356" summary="Docs">
430
+ <option name="closed" value="true" />
431
+ <created>1767950436457</created>
432
+ <option name="number" value="00356" />
433
+ <option name="presentableId" value="LOCAL-00356" />
434
+ <option name="project" value="LOCAL" />
435
+ <updated>1767950436457</updated>
436
+ </task>
437
+ <task id="LOCAL-00357" summary="Docs">
438
+ <option name="closed" value="true" />
439
+ <created>1768313561028</created>
440
+ <option name="number" value="00357" />
441
+ <option name="presentableId" value="LOCAL-00357" />
442
+ <option name="project" value="LOCAL" />
443
+ <updated>1768313561028</updated>
444
+ </task>
445
+ <task id="LOCAL-00358" summary="TS code mode draft">
446
+ <option name="closed" value="true" />
447
+ <created>1768313607831</created>
448
+ <option name="number" value="00358" />
449
+ <option name="presentableId" value="LOCAL-00358" />
450
+ <option name="project" value="LOCAL" />
451
+ <updated>1768313607831</updated>
452
+ </task>
453
+ <task id="LOCAL-00359" summary="Improved session expiration handling">
454
+ <option name="closed" value="true" />
455
+ <created>1768314790513</created>
456
+ <option name="number" value="00359" />
457
+ <option name="presentableId" value="LOCAL-00359" />
458
+ <option name="project" value="LOCAL" />
459
+ <updated>1768314790513</updated>
460
+ </task>
461
+ <task id="LOCAL-00360" summary="Fixed incorrect flagging of expired sessions as dead">
462
+ <option name="closed" value="true" />
463
+ <created>1768469231118</created>
464
+ <option name="number" value="00360" />
465
+ <option name="presentableId" value="LOCAL-00360" />
466
+ <option name="project" value="LOCAL" />
467
+ <updated>1768469231118</updated>
468
+ </task>
469
+ <task id="LOCAL-00361" summary="Copy">
470
+ <option name="closed" value="true" />
471
+ <created>1768470113068</created>
472
+ <option name="number" value="00361" />
473
+ <option name="presentableId" value="LOCAL-00361" />
474
+ <option name="project" value="LOCAL" />
475
+ <updated>1768470113068</updated>
476
+ </task>
477
+ <task id="LOCAL-00362" summary="Fixed help">
478
+ <option name="closed" value="true" />
479
+ <created>1768473976578</created>
480
+ <option name="number" value="00362" />
481
+ <option name="presentableId" value="LOCAL-00362" />
482
+ <option name="project" value="LOCAL" />
483
+ <updated>1768473976578</updated>
484
+ </task>
485
+ <task id="LOCAL-00363" summary="Nits">
486
+ <option name="closed" value="true" />
487
+ <created>1768474365832</created>
488
+ <option name="number" value="00363" />
489
+ <option name="presentableId" value="LOCAL-00363" />
490
+ <option name="project" value="LOCAL" />
491
+ <updated>1768474365832</updated>
492
+ </task>
493
+ <task id="LOCAL-00364" summary="Require explicit restart when server rejects MCP session ID&#10;&#10;Remove automatic reconnection when server rejects session ID during bridge restart. Session is now marked as 'expired' and user must explicitly run 'mcpc @session restart' to create a fresh session.">
494
+ <option name="closed" value="true" />
495
+ <created>1769003190833</created>
496
+ <option name="number" value="00364" />
497
+ <option name="presentableId" value="LOCAL-00364" />
498
+ <option name="project" value="LOCAL" />
499
+ <updated>1769003190833</updated>
500
+ </task>
501
+ <task id="LOCAL-00365" summary="Fixes">
502
+ <option name="closed" value="true" />
503
+ <created>1769003457187</created>
504
+ <option name="number" value="00365" />
505
+ <option name="presentableId" value="LOCAL-00365" />
506
+ <option name="project" value="LOCAL" />
507
+ <updated>1769003457187</updated>
508
+ </task>
509
+ <option name="localTasksCounter" value="366" />
513
510
  <servers />
514
511
  </component>
515
512
  <component name="TypeScriptGeneratedFilesManager">
@@ -616,12 +613,6 @@
616
613
  </option>
617
614
  </component>
618
615
  <component name="VcsManagerConfiguration">
619
- <MESSAGE value="Fixed handling --schema for outputSchema" />
620
- <MESSAGE value="Tests" />
621
- <MESSAGE value="Renamed &quot;session&quot; to &quot;connect&quot;, it's feels better" />
622
- <MESSAGE value="Fixed --timeout" />
623
- <MESSAGE value="Implemented --proxy command" />
624
- <MESSAGE value="Writing and tests" />
625
616
  <MESSAGE value="Tests and nits" />
626
617
  <MESSAGE value="More tests" />
627
618
  <MESSAGE value="Renamed &quot;dead&quot; to &quot;crashed&quot; session, final touches" />
@@ -638,9 +629,15 @@
638
629
  <MESSAGE value="Cosmetic" />
639
630
  <MESSAGE value="New gif in README" />
640
631
  <MESSAGE value="Cosmetic improvements" />
632
+ <MESSAGE value="Docs" />
633
+ <MESSAGE value="TS code mode draft" />
634
+ <MESSAGE value="Improved session expiration handling" />
635
+ <MESSAGE value="Fixed incorrect flagging of expired sessions as dead" />
636
+ <MESSAGE value="Copy" />
637
+ <MESSAGE value="Fixed help" />
641
638
  <MESSAGE value="Nits" />
639
+ <MESSAGE value="Require explicit restart when server rejects MCP session ID&#10;&#10;Remove automatic reconnection when server rejects session ID during bridge restart. Session is now marked as 'expired' and user must explicitly run 'mcpc @session restart' to create a fresh session." />
642
640
  <MESSAGE value="Fixes" />
643
- <MESSAGE value="Docs" />
644
- <option name="LAST_COMMIT_MESSAGE" value="Docs" />
641
+ <option name="LAST_COMMIT_MESSAGE" value="Fixes" />
645
642
  </component>
646
643
  </project>
package/README.md CHANGED
@@ -10,13 +10,13 @@ After all, UNIX-compatible shell script is THE most universal coding language.
10
10
  ![mcpc screenshot](https://raw.githubusercontent.com/apify/mcpc/main/docs/images/mcpc-demo.gif)
11
11
 
12
12
  **Key features:**
13
- - 🌎 **Highly compatible** - Works with any MCP server over Streamable HTTP or stdio.
13
+ - 🌎 **Compatible** - Works with any MCP server over Streamable HTTP or stdio.
14
14
  - 🔄 **Persistent sessions** - Keep multiple server connections alive simultaneously.
15
- - 🚀 **Zero setup** - Connect to remote servers instantly with just a URL.
16
15
  - 🔧 **Strong MCP support** - Instructions, tools, resources, prompts, dynamic discovery.
17
- - 🔌 **JSON output** - Easy integration with `jq`, scripts, and other CLI tools.
18
- - 🤖 **AI-friendly** - Designed for both function calling and code mode with sandboxing.
16
+ - 🔌 **Code mode** - JSON output enables integration with CLI tools like `jq` and scripting.
17
+ - 🤖 **AI sandboxing** - MCP proxy server to securely access authenticated sessions from AI-generated code.
19
18
  - 🔒 **Secure** - Full OAuth 2.1 support, OS keychain for credentials storage.
19
+ - 🪶 **Lightweight** - Minimal dependencies, works on Mac/Win/Linux, doesn't use LLMs on its own.
20
20
 
21
21
 
22
22
  ## Table of contents
@@ -36,6 +36,7 @@ After all, UNIX-compatible shell script is THE most universal coding language.
36
36
  - [Security](#security)
37
37
  - [Errors](#errors)
38
38
  - [Development](#development)
39
+ - [Related work](#related-work)
39
40
  - [License](#license)
40
41
 
41
42
  <!-- END doctoc generated TOC please keep comment here to allow auto update -->
@@ -101,7 +102,7 @@ Options:
101
102
  -H, --header <header> HTTP header for remote MCP server (can be repeated)
102
103
  -v, --version Output the version number
103
104
  --verbose Enable debug logging
104
- --profile <name> OAuth profile for the server ("default" if skipped)
105
+ --profile <name> OAuth profile for the server ("default" if not provided)
105
106
  --schema <file> Validate tool/prompt schema against expected schema
106
107
  --schema-mode <mode> Schema validation mode: strict, compatible (default), ignore
107
108
  --timeout <seconds> Request timeout in seconds (default: 300)
@@ -115,14 +116,14 @@ Targets:
115
116
  <config-entry> Entry in MCP config file specified by --config (e.g. "fs")
116
117
  <server-url> Remote MCP server URL (e.g. "mcp.apify.com")
117
118
 
118
- Management commands (<target> missing):
119
- login Create OAuth profile with credentials to access remote server
119
+ Management commands:
120
+ login Create OAuth profile with credentials for remote server
120
121
  logout Remove OAuth profile for remote server
121
122
  connect @<session> Connect to server and create named persistent session
122
- restart @<session> Kill and restart a session
123
- close @<session> Close a session
123
+ restart Kill and restart a session
124
+ close Close a session
124
125
 
125
- MCP commands (<target> provided):
126
+ MCP server commands:
126
127
  help Show server info ("help" can be omitted)
127
128
  shell Open interactive shell
128
129
  tools-list Send "tools/list" MCP request...
@@ -138,12 +139,13 @@ MCP commands (<target> provided):
138
139
  resources-templates-list
139
140
  logging-set-level <level>
140
141
  ping
141
-
142
+
143
+ Run "mcpc" (without <target>) to show available sessions and profiles.
142
144
  ```
143
145
 
144
- ### Management commands
146
+ ### General actions
145
147
 
146
- When `<target>` is missing, `mcpc` provides general management commands.
148
+ When `<target>` is omitted, `mcpc` provides general actions:
147
149
 
148
150
  ```bash
149
151
  # List all sessions and OAuth profiles (also in JSON mode)
@@ -154,15 +156,13 @@ mcpc --json
154
156
  mcpc --help
155
157
  mcpc --version
156
158
 
157
- # Clean expired sessions and old log files
159
+ # Clean expired sessions and old log files (see below for details)
158
160
  mcpc --clean
159
161
  ```
160
162
 
161
- For additional management commands, see [OAuth profiles](#oauth-profiles) and [Cleanup](#cleanup).
162
-
163
163
  ### Targets
164
164
 
165
- To connect to an MCP server, you need to specify a `<target>`, which can be one of (in order of precedence):
165
+ To connect and interact with an MCP server, you need to specify a `<target>`, which can be one of (in this order of precedence):
166
166
 
167
167
  - **Entry in a config file** (e.g. `--config .vscode/mcp.json filesystem`) - see [Config file](#mcp-server-config-file)
168
168
  - **Remote MCP server URL** (e.g. `https://mcp.apify.com`)
@@ -178,7 +178,7 @@ connects, and enables you to interact with it.
178
178
 
179
179
  ### MCP commands
180
180
 
181
- Examples of sending MCP commands to various targets:
181
+ When `<target>` is provided, `mcpc` sends MCP requests to the target server:
182
182
 
183
183
  ```bash
184
184
  # Server from config file (stdio)
@@ -1057,11 +1057,26 @@ The main `mcpc` process doesn't save log files, but supports [verbose mode](#ver
1057
1057
 
1058
1058
  ## Development
1059
1059
 
1060
- The initial version of `mcpc` was developed by [Jan Curn](https://x.com/jancurn) of [Apify](https://apify.com)
1060
+ The initial version of `mcpc` was developed and [launched by Jan Curn](https://x.com/jancurn/status/2007144080959291756) of [Apify](https://apify.com)
1061
1061
  with the help of Claude Code, during late nights over Christmas 2025 in North Beach, San Francisco.
1062
1062
 
1063
1063
  See [CONTRIBUTING](./CONTRIBUTING.md) for development setup, architecture overview, and contribution guidelines.
1064
1064
 
1065
+ ## Related work
1066
+
1067
+ - https://github.com/steipete/mcporter
1068
+ - https://github.com/philschmid/mcp-cli (https://www.philschmid.de/mcp-cli)
1069
+ - https://github.com/chrishayuk/mcp-cli
1070
+ - https://github.com/wong2/mcp-cli
1071
+ - https://github.com/f/mcptools
1072
+ - https://github.com/adhikasp/mcp-client-cli
1073
+ - https://github.com/mattzcarey/cloudflare-mcp
1074
+ - https://github.com/TeamSparkAI/mcpGraph
1075
+ - https://platform.claude.com/docs/en/agents-and-tools/tool-use/tool-search-tool (https://x.com/trq212/status/2011523109871108570)
1076
+ - https://cursor.com/blog/dynamic-context-discovery
1077
+ - https://www.anthropic.com/engineering/code-execution-with-mcp
1078
+ - https://blog.cloudflare.com/code-mode/
1079
+
1065
1080
  ## License
1066
1081
 
1067
1082
  Apache-2.0 - see [LICENSE](./LICENSE) for details.
@@ -3,7 +3,7 @@ import { createServer } from 'net';
3
3
  import { unlink } from 'fs/promises';
4
4
  import { createMcpClient } from '../core/index.js';
5
5
  import { createLogger, setVerbose, initFileLogger, closeFileLogger } from '../lib/index.js';
6
- import { fileExists, getBridgesDir, getSocketPath, ensureDir, cleanupOrphanedLogFiles } from '../lib/index.js';
6
+ import { fileExists, getBridgesDir, getSocketPath, ensureDir, cleanupOrphanedLogFiles, isSessionExpiredError } from '../lib/index.js';
7
7
  import { ClientError, NetworkError } from '../lib/index.js';
8
8
  import { loadSessions, updateSession } from '../lib/sessions.js';
9
9
  import { OAuthTokenManager } from '../lib/auth/oauth-token-manager.js';
@@ -195,6 +195,15 @@ class BridgeProcess {
195
195
  catch (error) {
196
196
  logger.error('Bridge startup failed, will stay alive briefly for CLI to receive error:', error);
197
197
  this.mcpClientReadyRejecter(error);
198
+ if (isSessionExpiredError(error.message)) {
199
+ logger.warn('Session ID was rejected by server, marking session as expired');
200
+ try {
201
+ await updateSession(this.options.sessionName, { status: 'expired' });
202
+ }
203
+ catch (updateError) {
204
+ logger.error('Failed to mark session as expired:', updateError);
205
+ }
206
+ }
198
207
  this.setupSignalHandlers();
199
208
  setTimeout(() => {
200
209
  logger.info('Shutting down after startup failure');
@@ -269,6 +278,7 @@ class BridgeProcess {
269
278
  sampling: {},
270
279
  },
271
280
  ...(this.authProvider && { authProvider: this.authProvider }),
281
+ ...(this.options.mcpSessionId && { mcpSessionId: this.options.mcpSessionId }),
272
282
  listChanged: {
273
283
  tools: {
274
284
  autoRefresh: true,
@@ -305,10 +315,14 @@ class BridgeProcess {
305
315
  verbose: this.options.verbose || false,
306
316
  };
307
317
  logger.debug('Calling createMcpClient with authProvider:', !!clientConfig.authProvider);
318
+ if (clientConfig.mcpSessionId) {
319
+ logger.info(`Attempting session resumption with MCP-Session-Id: ${clientConfig.mcpSessionId}`);
320
+ }
308
321
  this.client = await createMcpClient(clientConfig);
309
322
  logger.info('Connected to MCP server');
310
323
  logger.debug('MCP client created successfully, authProvider was:', !!clientConfig.authProvider);
311
324
  const serverDetails = await this.client.getServerDetails();
325
+ const newMcpSessionId = this.client.getMcpSessionId();
312
326
  const sessionUpdate = {
313
327
  lastSeenAt: new Date().toISOString(),
314
328
  };
@@ -318,6 +332,10 @@ class BridgeProcess {
318
332
  if (serverDetails.serverInfo) {
319
333
  sessionUpdate.serverInfo = serverDetails.serverInfo;
320
334
  }
335
+ if (newMcpSessionId) {
336
+ sessionUpdate.mcpSessionId = newMcpSessionId;
337
+ logger.info(`MCP-Session-Id saved for resumption: ${newMcpSessionId}`);
338
+ }
321
339
  await updateSession(this.options.sessionName, sessionUpdate);
322
340
  }
323
341
  async startProxyServer() {
@@ -378,13 +396,7 @@ class BridgeProcess {
378
396
  }
379
397
  }
380
398
  handlePossibleExpiration(error) {
381
- const errorMessage = error.message.toLowerCase();
382
- const isExpired = (errorMessage.includes('404') && !errorMessage.includes('tool')) ||
383
- errorMessage.includes('session expired') ||
384
- errorMessage.includes('session not found') ||
385
- errorMessage.includes('invalid session') ||
386
- errorMessage.includes('session is no longer valid');
387
- if (isExpired) {
399
+ if (isSessionExpiredError(error.message)) {
388
400
  logger.warn('Session appears to be expired, marking as expired and shutting down');
389
401
  this.markSessionExpiredAndExit().catch((e) => {
390
402
  logger.error('Failed to mark session as expired:', e);
@@ -681,7 +693,7 @@ class BridgeProcess {
681
693
  async function main() {
682
694
  const args = process.argv.slice(2);
683
695
  if (args.length < 2) {
684
- console.error('Usage: mcpc-bridge <sessionName> <transportConfigJson> [--verbose] [--profile <name>] [--proxy-host <host>] [--proxy-port <port>]');
696
+ console.error('Usage: mcpc-bridge <sessionName> <transportConfigJson> [--verbose] [--profile <name>] [--proxy-host <host>] [--proxy-port <port>] [--mcp-session-id <id>]');
685
697
  process.exit(1);
686
698
  }
687
699
  const sessionName = args[0];
@@ -702,6 +714,11 @@ async function main() {
702
714
  proxyConfig = { host, port };
703
715
  }
704
716
  }
717
+ let mcpSessionId;
718
+ const mcpSessionIdIndex = args.indexOf('--mcp-session-id');
719
+ if (mcpSessionIdIndex !== -1 && args[mcpSessionIdIndex + 1]) {
720
+ mcpSessionId = args[mcpSessionIdIndex + 1];
721
+ }
705
722
  try {
706
723
  const bridgeOptions = {
707
724
  sessionName,
@@ -714,6 +731,9 @@ async function main() {
714
731
  if (proxyConfig) {
715
732
  bridgeOptions.proxyConfig = proxyConfig;
716
733
  }
734
+ if (mcpSessionId) {
735
+ bridgeOptions.mcpSessionId = mcpSessionId;
736
+ }
717
737
  const bridge = new BridgeProcess(bridgeOptions);
718
738
  await bridge.start();
719
739
  }