mcp-cross 1.1.0 → 1.2.0-beta.1
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/LICENSE +0 -0
- package/README.md +41 -23
- package/examples/claude-code-cli-npx.json +0 -0
- package/examples/claude-code-cli.json +0 -0
- package/examples/claude-desktop-http.json +15 -18
- package/examples/claude-desktop-npx.json +20 -26
- package/examples/claude-desktop.json +0 -0
- package/examples/vscode-settings-http.json +0 -0
- package/examples/vscode-settings-npx.json +0 -0
- package/examples/vscode-settings.json +0 -0
- package/index.js +38 -0
- package/package.json +1 -1
- package/src/lib/header-parser.js +0 -0
- package/src/lib/http-proxy.js +0 -0
- package/src/lib/jsonrpc-error.js +0 -0
- package/src/lib/url-validator.js +0 -0
- package/src/lib/wsl-bridge.js +0 -0
- package/src/scripts/wsl-runner.sh +25 -0
package/LICENSE
CHANGED
|
File without changes
|
package/README.md
CHANGED
|
@@ -404,6 +404,8 @@ GitHub MCP Server (api.githubcopilot.com)
|
|
|
404
404
|
|
|
405
405
|
Use these tested command lines when mirroring Claude Desktop’s configuration. Each snippet lists every flag that must be present for the server to launch successfully under Windows → WSL bridging.
|
|
406
406
|
|
|
407
|
+
> **Windows quoting fix:** Claude Desktop launches stdio servers through `cmd.exe`. When it resolves `command: "npx"` to `C:\Program Files\nodejs\npx.cmd` the resulting command line is emitted without quotes, leading to the classic `'C:\Program' is not recognized` failure. Wrap every `npx` invocation inside `powershell.exe -NoLogo -NoProfile -Command "& { ... }"` so PowerShell handles the quoting before `cmd.exe` runs it.
|
|
408
|
+
|
|
407
409
|
#### 1. Ghostis Brain (Python + WSL)
|
|
408
410
|
|
|
409
411
|
Requirements:
|
|
@@ -424,11 +426,12 @@ Claude config fragment:
|
|
|
424
426
|
|
|
425
427
|
```json
|
|
426
428
|
"ghostis-brain": {
|
|
427
|
-
"command": "
|
|
429
|
+
"command": "powershell.exe",
|
|
428
430
|
"args": [
|
|
429
|
-
"-
|
|
430
|
-
"
|
|
431
|
-
"
|
|
431
|
+
"-NoLogo",
|
|
432
|
+
"-NoProfile",
|
|
433
|
+
"-Command",
|
|
434
|
+
"& { npx -y mcp-cross@latest --wsl --shell zsh -- python3 -m ghostis.mcp }"
|
|
432
435
|
],
|
|
433
436
|
"env": {
|
|
434
437
|
"GHOSTIS_STORAGE_DIR": "/home/epps/.ghostis/memory",
|
|
@@ -456,14 +459,12 @@ Claude config fragment:
|
|
|
456
459
|
|
|
457
460
|
```json
|
|
458
461
|
"filesystem": {
|
|
459
|
-
"command": "
|
|
462
|
+
"command": "powershell.exe",
|
|
460
463
|
"args": [
|
|
461
|
-
"-
|
|
462
|
-
"
|
|
463
|
-
"
|
|
464
|
-
"npx
|
|
465
|
-
"C:\\Users\\seane\\dev",
|
|
466
|
-
"/mnt/dev/workspaces"
|
|
464
|
+
"-NoLogo",
|
|
465
|
+
"-NoProfile",
|
|
466
|
+
"-Command",
|
|
467
|
+
"& { npx -y mcp-cross@latest --wsl --shell zsh -- npx -y @modelcontextprotocol/server-filesystem C:\\Users\\seane\\dev /mnt/dev/workspaces }"
|
|
467
468
|
]
|
|
468
469
|
}
|
|
469
470
|
```
|
|
@@ -487,18 +488,17 @@ Claude config fragment:
|
|
|
487
488
|
|
|
488
489
|
```json
|
|
489
490
|
"github-mcp-server": {
|
|
490
|
-
"command": "
|
|
491
|
+
"command": "powershell.exe",
|
|
491
492
|
"args": [
|
|
492
|
-
"-
|
|
493
|
-
"
|
|
494
|
-
"
|
|
495
|
-
"--http
|
|
496
|
-
"--header", "Authorization: Bearer $GH_TOKEN"
|
|
493
|
+
"-NoLogo",
|
|
494
|
+
"-NoProfile",
|
|
495
|
+
"-Command",
|
|
496
|
+
"& { npx -y mcp-cross@latest --debug --wsl --shell zsh --http https://api.githubcopilot.com/mcp/ --header 'Authorization: Bearer $GH_TOKEN' }"
|
|
497
497
|
]
|
|
498
498
|
}
|
|
499
499
|
```
|
|
500
500
|
|
|
501
|
-
> **Tip:** When
|
|
501
|
+
> **Tip:** When using the PowerShell wrapper (either manually or via Claude), keep `$GH_TOKEN` inside single quotes and pass the actual value with `--env GH_TOKEN=$env:GH_TOKEN` so the proxy can expand it inside WSL exactly like Claude does.
|
|
502
502
|
|
|
503
503
|
### Bridge Usage
|
|
504
504
|
|
|
@@ -527,12 +527,12 @@ mcp-cross --wsl cat C:\data.txt
|
|
|
527
527
|
{
|
|
528
528
|
"mcpServers": {
|
|
529
529
|
"wsl-server": {
|
|
530
|
-
"command": "
|
|
530
|
+
"command": "powershell.exe",
|
|
531
531
|
"args": [
|
|
532
|
-
"
|
|
533
|
-
"
|
|
534
|
-
"
|
|
535
|
-
"/home/user/server.js"
|
|
532
|
+
"-NoLogo",
|
|
533
|
+
"-NoProfile",
|
|
534
|
+
"-Command",
|
|
535
|
+
"& { npx -y mcp-cross@latest --wsl node /home/user/server.js }"
|
|
536
536
|
]
|
|
537
537
|
}
|
|
538
538
|
}
|
|
@@ -659,6 +659,24 @@ Check the debug output for:
|
|
|
659
659
|
- Command resolution problems
|
|
660
660
|
- Process spawning errors
|
|
661
661
|
|
|
662
|
+
### `'C:\\Program' is not recognized`
|
|
663
|
+
|
|
664
|
+
This happens when Claude Desktop (or any Windows host that shells through `cmd.exe`) resolves `command: "npx"` to `C:\Program Files\nodejs\npx.cmd` and runs it without surrounding quotes. Windows interprets everything up to the first space as the executable name, so `cmd.exe` tries to launch `C:\Program` and immediately fails.
|
|
665
|
+
|
|
666
|
+
**Fix:** Wrap the entire `npx` invocation inside PowerShell so the quoting happens before `cmd.exe` ever sees the command line:
|
|
667
|
+
|
|
668
|
+
```json
|
|
669
|
+
"command": "powershell.exe",
|
|
670
|
+
"args": [
|
|
671
|
+
"-NoLogo",
|
|
672
|
+
"-NoProfile",
|
|
673
|
+
"-Command",
|
|
674
|
+
"& { npx -y mcp-cross@latest --wsl --shell zsh -- ... }"
|
|
675
|
+
]
|
|
676
|
+
```
|
|
677
|
+
|
|
678
|
+
All Claude Desktop examples in this README already use that wrapper. If you still prefer `command: "npx"`, move your Node.js installation to a path without spaces (or set `command` to a short path such as `C:\npx\npx.cmd`).
|
|
679
|
+
|
|
662
680
|
### Windows Executable Not Found in WSL
|
|
663
681
|
|
|
664
682
|
Ensure:
|
|
File without changes
|
|
File without changes
|
|
@@ -2,37 +2,34 @@
|
|
|
2
2
|
"mcpServers": {
|
|
3
3
|
"github-mcp-via-wsl": {
|
|
4
4
|
"type": "stdio",
|
|
5
|
-
"command": "
|
|
5
|
+
"command": "powershell.exe",
|
|
6
6
|
"args": [
|
|
7
|
-
"-
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"--http
|
|
11
|
-
"--header", "Authorization: Bearer $GH_TOKEN"
|
|
7
|
+
"-NoLogo",
|
|
8
|
+
"-NoProfile",
|
|
9
|
+
"-Command",
|
|
10
|
+
"& { npx -y mcp-cross@latest --wsl --http https://api.githubcopilot.com/mcp/ --header 'Authorization: Bearer $GH_TOKEN' }"
|
|
12
11
|
],
|
|
13
12
|
"comment": "Access GitHub MCP server with token stored in WSL environment"
|
|
14
13
|
},
|
|
15
14
|
"custom-mcp-server": {
|
|
16
15
|
"type": "stdio",
|
|
17
|
-
"command": "
|
|
16
|
+
"command": "powershell.exe",
|
|
18
17
|
"args": [
|
|
19
|
-
"-
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"--header
|
|
23
|
-
"--header", "X-Tenant-ID: $TENANT_ID",
|
|
24
|
-
"--timeout", "30000"
|
|
18
|
+
"-NoLogo",
|
|
19
|
+
"-NoProfile",
|
|
20
|
+
"-Command",
|
|
21
|
+
"& { npx -y mcp-cross@latest --http https://api.example.com/mcp/ --header 'Authorization: Bearer $API_TOKEN' --header 'X-Tenant-ID: $TENANT_ID' --timeout 30000 }"
|
|
25
22
|
],
|
|
26
23
|
"comment": "HTTP MCP server with multiple custom headers"
|
|
27
24
|
},
|
|
28
25
|
"local-debug": {
|
|
29
26
|
"type": "stdio",
|
|
30
|
-
"command": "
|
|
27
|
+
"command": "powershell.exe",
|
|
31
28
|
"args": [
|
|
32
|
-
"-
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"--http
|
|
29
|
+
"-NoLogo",
|
|
30
|
+
"-NoProfile",
|
|
31
|
+
"-Command",
|
|
32
|
+
"& { npx -y mcp-cross@latest --debug --http http://localhost:3000/mcp }"
|
|
36
33
|
],
|
|
37
34
|
"comment": "Local MCP server for debugging (HTTP allowed for localhost)"
|
|
38
35
|
}
|
|
@@ -1,48 +1,42 @@
|
|
|
1
1
|
{
|
|
2
2
|
"mcpServers": {
|
|
3
3
|
"filesystem": {
|
|
4
|
-
"command": "
|
|
4
|
+
"command": "powershell.exe",
|
|
5
5
|
"args": [
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
"-y"
|
|
10
|
-
"@modelcontextprotocol/server-filesystem",
|
|
11
|
-
"/Users/username/Documents"
|
|
6
|
+
"-NoLogo",
|
|
7
|
+
"-NoProfile",
|
|
8
|
+
"-Command",
|
|
9
|
+
"& { npx -y mcp-cross@latest -- npx -y @modelcontextprotocol/server-filesystem /Users/username/Documents }"
|
|
12
10
|
]
|
|
13
11
|
},
|
|
14
12
|
"brave-search": {
|
|
15
|
-
"command": "
|
|
13
|
+
"command": "powershell.exe",
|
|
16
14
|
"args": [
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"-y"
|
|
21
|
-
"@modelcontextprotocol/server-brave-search"
|
|
15
|
+
"-NoLogo",
|
|
16
|
+
"-NoProfile",
|
|
17
|
+
"-Command",
|
|
18
|
+
"& { npx -y mcp-cross@latest -- npx -y @modelcontextprotocol/server-brave-search }"
|
|
22
19
|
],
|
|
23
20
|
"env": {
|
|
24
21
|
"BRAVE_API_KEY": "your-api-key-here"
|
|
25
22
|
}
|
|
26
23
|
},
|
|
27
24
|
"custom-nodejs-server": {
|
|
28
|
-
"command": "
|
|
25
|
+
"command": "powershell.exe",
|
|
29
26
|
"args": [
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"/path/to/your/server.js"
|
|
34
|
-
"--config",
|
|
35
|
-
"production"
|
|
27
|
+
"-NoLogo",
|
|
28
|
+
"-NoProfile",
|
|
29
|
+
"-Command",
|
|
30
|
+
"& { npx -y mcp-cross@latest -- node /path/to/your/server.js --config production }"
|
|
36
31
|
]
|
|
37
32
|
},
|
|
38
33
|
"with-debug": {
|
|
39
|
-
"command": "
|
|
34
|
+
"command": "powershell.exe",
|
|
40
35
|
"args": [
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
"node"
|
|
45
|
-
"/path/to/server.js"
|
|
36
|
+
"-NoLogo",
|
|
37
|
+
"-NoProfile",
|
|
38
|
+
"-Command",
|
|
39
|
+
"& { npx -y mcp-cross@latest --debug -- node /path/to/server.js }"
|
|
46
40
|
]
|
|
47
41
|
}
|
|
48
42
|
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/index.js
CHANGED
|
@@ -10,6 +10,23 @@ const { platform } = require('os');
|
|
|
10
10
|
const wslBridge = require('./src/lib/wsl-bridge');
|
|
11
11
|
const { startHttpProxy } = require('./src/lib/http-proxy');
|
|
12
12
|
|
|
13
|
+
function extractEnvVarsFromStrings(strings) {
|
|
14
|
+
if (!Array.isArray(strings)) return [];
|
|
15
|
+
const vars = new Set();
|
|
16
|
+
for (const value of strings) {
|
|
17
|
+
if (typeof value !== 'string') continue;
|
|
18
|
+
const regex = /\$\{([A-Za-z_][A-Za-z0-9_]*)(?::-[^}]*)?\}|\$([A-Za-z_][A-Za-z0-9_]*)/g;
|
|
19
|
+
let match;
|
|
20
|
+
while ((match = regex.exec(value)) !== null) {
|
|
21
|
+
const name = match[1] || match[2];
|
|
22
|
+
if (name) {
|
|
23
|
+
vars.add(name);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return Array.from(vars);
|
|
28
|
+
}
|
|
29
|
+
|
|
13
30
|
/**
|
|
14
31
|
* mcp-cross - Cross-platform MCP server bridge
|
|
15
32
|
*
|
|
@@ -398,6 +415,17 @@ async function main() {
|
|
|
398
415
|
wslArgs.push('--debug');
|
|
399
416
|
}
|
|
400
417
|
|
|
418
|
+
if (mcpCrossOptions.includes('--debug')) {
|
|
419
|
+
const debugVars = extractEnvVarsFromStrings(httpHeaders);
|
|
420
|
+
if (debugVars.length > 0) {
|
|
421
|
+
const existing = customEnv.MCP_CROSS_DEBUG_VARS
|
|
422
|
+
? customEnv.MCP_CROSS_DEBUG_VARS.split(',').map(v => v.trim()).filter(Boolean)
|
|
423
|
+
: [];
|
|
424
|
+
const merged = new Set([...existing, ...debugVars]);
|
|
425
|
+
customEnv.MCP_CROSS_DEBUG_VARS = Array.from(merged).join(',');
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
401
429
|
try {
|
|
402
430
|
await wslBridge.execute(wslCommand, wslArgs, mcpCrossOptions, customEnv);
|
|
403
431
|
} catch (err) {
|
|
@@ -429,6 +457,16 @@ async function main() {
|
|
|
429
457
|
|
|
430
458
|
// Check for WSL bridge mode (process bridge)
|
|
431
459
|
if (mcpCrossOptions.includes('--wsl')) {
|
|
460
|
+
if (mcpCrossOptions.includes('--debug')) {
|
|
461
|
+
const debugVars = extractEnvVarsFromStrings([serverCommand, ...serverArgs]);
|
|
462
|
+
if (debugVars.length > 0) {
|
|
463
|
+
const existing = customEnv.MCP_CROSS_DEBUG_VARS
|
|
464
|
+
? customEnv.MCP_CROSS_DEBUG_VARS.split(',').map(v => v.trim()).filter(Boolean)
|
|
465
|
+
: [];
|
|
466
|
+
const merged = new Set([...existing, ...debugVars]);
|
|
467
|
+
customEnv.MCP_CROSS_DEBUG_VARS = Array.from(merged).join(',');
|
|
468
|
+
}
|
|
469
|
+
}
|
|
432
470
|
try {
|
|
433
471
|
await wslBridge.execute(serverCommand, serverArgs, mcpCrossOptions, customEnv);
|
|
434
472
|
} catch (err) {
|
package/package.json
CHANGED
package/src/lib/header-parser.js
CHANGED
|
File without changes
|
package/src/lib/http-proxy.js
CHANGED
|
File without changes
|
package/src/lib/jsonrpc-error.js
CHANGED
|
File without changes
|
package/src/lib/url-validator.js
CHANGED
|
File without changes
|
package/src/lib/wsl-bridge.js
CHANGED
|
File without changes
|
|
@@ -33,6 +33,31 @@ fi
|
|
|
33
33
|
if [ -n "${MCP_CROSS_DEBUG-}" ]; then
|
|
34
34
|
echo "DEBUG: FILTERED PATH=" >&2
|
|
35
35
|
printenv PATH >&2
|
|
36
|
+
|
|
37
|
+
if [ -n "${MCP_CROSS_DEBUG_VARS-}" ]; then
|
|
38
|
+
OLD_IFS_ENV="$IFS"
|
|
39
|
+
IFS=','
|
|
40
|
+
read -ra DEBUG_VARS <<< "$MCP_CROSS_DEBUG_VARS"
|
|
41
|
+
IFS="$OLD_IFS_ENV"
|
|
42
|
+
|
|
43
|
+
for rawVar in "${DEBUG_VARS[@]}"; do
|
|
44
|
+
var="$(echo "$rawVar" | xargs)"
|
|
45
|
+
if [ -z "$var" ]; then
|
|
46
|
+
continue
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
if [ -z "${!var+x}" ]; then
|
|
50
|
+
echo "DEBUG: ENV[$var]=<unset>" >&2
|
|
51
|
+
else
|
|
52
|
+
value="${!var}"
|
|
53
|
+
if [ -z "$value" ]; then
|
|
54
|
+
echo "DEBUG: ENV[$var]=<empty>" >&2
|
|
55
|
+
else
|
|
56
|
+
echo "DEBUG: ENV[$var]=<set length=${#value}>" >&2
|
|
57
|
+
fi
|
|
58
|
+
fi
|
|
59
|
+
done
|
|
60
|
+
fi
|
|
36
61
|
fi
|
|
37
62
|
|
|
38
63
|
# Exec the provided command
|