Skip to content

Commit c25ed72

Browse files
fix: create MCP toolset even when command binary is unavailable
When EnsureCommand fails (binary not on PATH, no aqua package, etc.), createMCPTool now logs a warning and creates the toolset with the original command string instead of returning an error. Previously, the error caused the toolset to be discarded entirely at config-load time, so it was never added to the agent's toolset list. The Start() retry (from the previous commit) was never reached because there was no toolset object to retry. Now the toolset is always created. On the first conversation turn, Start() detects the missing binary and returns errServerUnavailable (keeping started=false). On subsequent turns, ensureToolSetsAreStarted retries Start() — once the binary is available, the MCP server connects successfully. Assisted-By: docker-agent
1 parent 42e6d44 commit c25ed72

2 files changed

Lines changed: 52 additions & 2 deletions

File tree

pkg/teamloader/registry.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"context"
66
"errors"
77
"fmt"
8+
"log/slog"
89
"os"
910
"path/filepath"
1011
"time"
@@ -268,10 +269,15 @@ func createMCPTool(ctx context.Context, toolset latest.Toolset, _ string, runCon
268269

269270
// STDIO MCP Server from shell command
270271
case toolset.Command != "":
271-
// Auto-install missing command binary if needed
272+
// Auto-install missing command binary if needed.
273+
// If EnsureCommand fails (binary not on PATH, no aqua package, etc.),
274+
// treat as transient: create the toolset with the original command
275+
// and let mcp.Toolset.Start() retry on each conversation turn.
272276
resolvedCommand, err := toolinstall.EnsureCommand(ctx, toolset.Command, toolset.Version)
273277
if err != nil {
274-
return nil, fmt.Errorf("resolving command %q: %w", toolset.Command, err)
278+
slog.Warn("MCP command not yet available, will retry on next turn",
279+
"command", toolset.Command, "error", err)
280+
resolvedCommand = toolset.Command
275281
}
276282

277283
env, err := environment.ExpandAll(ctx, environment.ToValues(toolset.Env), envProvider)

pkg/teamloader/registry_test.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@ package teamloader
33
import (
44
"testing"
55

6+
"github.com/stretchr/testify/assert"
67
"github.com/stretchr/testify/require"
78

89
"github.com/docker/docker-agent/pkg/config"
910
"github.com/docker/docker-agent/pkg/config/latest"
1011
"github.com/docker/docker-agent/pkg/environment"
12+
"github.com/docker/docker-agent/pkg/tools"
1113
)
1214

1315
func TestCreateShellTool(t *testing.T) {
@@ -26,3 +28,45 @@ func TestCreateShellTool(t *testing.T) {
2628
require.NoError(t, err)
2729
require.NotNil(t, tool)
2830
}
31+
32+
func TestCreateMCPTool_CommandNotFound_CreatesToolsetAnyway(t *testing.T) {
33+
t.Setenv("DOCKER_AGENT_TOOLS_DIR", t.TempDir())
34+
35+
toolset := latest.Toolset{
36+
Type: "mcp",
37+
Command: "./bin/nonexistent-mcp-server",
38+
}
39+
40+
registry := NewDefaultToolsetRegistry()
41+
42+
runConfig := &config.RuntimeConfig{
43+
Config: config.Config{WorkingDir: t.TempDir()},
44+
EnvProviderForTests: environment.NewOsEnvProvider(),
45+
}
46+
47+
tool, err := registry.CreateTool(t.Context(), toolset, ".", runConfig, "test-agent")
48+
require.NoError(t, err)
49+
require.NotNil(t, tool)
50+
assert.Equal(t, "mcp(stdio cmd=./bin/nonexistent-mcp-server)", tools.DescribeToolSet(tool))
51+
}
52+
53+
func TestCreateMCPTool_BareCommandNotFound_CreatesToolsetAnyway(t *testing.T) {
54+
t.Setenv("DOCKER_AGENT_TOOLS_DIR", t.TempDir())
55+
56+
toolset := latest.Toolset{
57+
Type: "mcp",
58+
Command: "some-nonexistent-mcp-binary",
59+
}
60+
61+
registry := NewDefaultToolsetRegistry()
62+
63+
runConfig := &config.RuntimeConfig{
64+
Config: config.Config{WorkingDir: t.TempDir()},
65+
EnvProviderForTests: environment.NewOsEnvProvider(),
66+
}
67+
68+
tool, err := registry.CreateTool(t.Context(), toolset, ".", runConfig, "test-agent")
69+
require.NoError(t, err)
70+
require.NotNil(t, tool)
71+
assert.Equal(t, "mcp(stdio cmd=some-nonexistent-mcp-binary)", tools.DescribeToolSet(tool))
72+
}

0 commit comments

Comments
 (0)