Skip to content

Commit 5cc54c4

Browse files
committed
fix(isolation): detect the runtime of Windows launchers with an .exe/.cmd suffix
DetectRuntimeType switched on the exact base name, so a Windows config naming uvx.exe, npx.cmd, npm.cmd, pip.exe or go.exe fell to the "binary" default. Docker isolation then picked the generic image and ran e.g. npx.cmd inside a Linux container, where it does not exist, so the server never started. Lowercase the base name and strip a .exe, .cmd or .bat suffix before matching.
1 parent c82d515 commit 5cc54c4

2 files changed

Lines changed: 37 additions & 2 deletions

File tree

‎internal/upstream/core/isolation.go‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,8 +220,13 @@ func (im *IsolationManager) warnPerServerIgnoredOnce(serverName string) {
220220

221221
// DetectRuntimeType detects the runtime type based on the command
222222
func (im *IsolationManager) DetectRuntimeType(command string) string {
223-
// Extract just the command name without path
224-
cmdName := filepath.Base(command)
223+
// Extract just the command name without path or a Windows executable
224+
// suffix (uvx.exe, npx.cmd), compared case-insensitively as Windows does.
225+
cmdName := strings.ToLower(filepath.Base(command))
226+
switch filepath.Ext(cmdName) {
227+
case ".exe", ".cmd", ".bat":
228+
cmdName = strings.TrimSuffix(cmdName, filepath.Ext(cmdName))
229+
}
225230

226231
// Handle common runtime commands
227232
switch cmdName {
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package core
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
8+
"github.com/smart-mcp-proxy/mcpproxy-go/internal/config"
9+
)
10+
11+
// Windows configs name launchers with their executable suffix (uvx.exe,
12+
// npx.cmd). Treating those as an unknown "binary" picks the generic image and
13+
// runs "npx.cmd" inside a Linux container, where it does not exist.
14+
func TestDetectRuntimeType_WindowsExecutableSuffix(t *testing.T) {
15+
im := NewIsolationManager(config.DefaultDockerIsolationConfig())
16+
cases := map[string]string{
17+
"uvx.exe": cmdUvx,
18+
"npx.cmd": cmdNpx,
19+
"NPX.CMD": cmdNpx,
20+
"npm.cmd": cmdNpm,
21+
"yarn.cmd": cmdYarn,
22+
"pip.exe": cmdPip,
23+
"go.exe": cmdGo,
24+
"uvx": cmdUvx,
25+
"my-tool": "binary",
26+
}
27+
for cmd, want := range cases {
28+
assert.Equal(t, want, im.DetectRuntimeType(cmd), cmd)
29+
}
30+
}

0 commit comments

Comments
 (0)