summaryrefslogtreecommitdiff
path: root/internal/executor/container_test.go
diff options
context:
space:
mode:
authorClaude <noreply@anthropic.com>2026-05-25 19:02:19 +0000
committerClaude <noreply@anthropic.com>2026-05-25 19:02:19 +0000
commit65cd7ea65d9c6fe0fad39bb2c5cac70d61153444 (patch)
tree693dc265879bc39872e490989ece62ef07aef9eb /internal/executor/container_test.go
parentc0fabf5a2f4ca371403571b82e29c5073bed24fb (diff)
feat(executor): wire the agent MCP back-channel for gemini containers (Phase 4)
ContainerRunner previously skipped the MCP back-channel for gemini agents, so they ran tool-less. It now mints a per-task token for gemini too and registers the agent MCP server in the gemini CLI's user settings (agentHome/.gemini/settings.json → $HOME/.gemini in-container) using the gemini-cli mcpServers/httpUrl schema with a bearer header. With MCP enabled, gemini also receives the planning preamble that points at the ask_user/ report_summary/spawn_subtask/record_progress tools. Config generation is unit-tested (TestWriteGeminiMCPSettings) and the write is in the run setup path. CAVEAT: whether the gemini CLI actually invokes these tools in non-interactive (-p) mode — and how it handles tool auto-approval — is NOT verified against a live gemini binary in this environment; this lands the plumbing for a follow-up spike. No regression risk for gemini runs: a config issue degrades to the prior tool-less behavior. https://claude.ai/code/session_01SESwn7kQ7oP62trWw6pc39
Diffstat (limited to 'internal/executor/container_test.go')
-rw-r--r--internal/executor/container_test.go30
1 files changed, 30 insertions, 0 deletions
diff --git a/internal/executor/container_test.go b/internal/executor/container_test.go
index 3d0887c..521e1cb 100644
--- a/internal/executor/container_test.go
+++ b/internal/executor/container_test.go
@@ -107,6 +107,36 @@ func TestWriteMCPConfig(t *testing.T) {
}
}
+func TestWriteGeminiMCPSettings(t *testing.T) {
+ agentHome := t.TempDir()
+ if err := writeGeminiMCPSettings(agentHome, "http://host.docker.internal:8484/mcp", "tok-xyz"); err != nil {
+ t.Fatalf("writeGeminiMCPSettings: %v", err)
+ }
+ data, err := os.ReadFile(filepath.Join(agentHome, ".gemini", "settings.json"))
+ if err != nil {
+ t.Fatalf("read settings: %v", err)
+ }
+ var parsed struct {
+ MCPServers map[string]struct {
+ HTTPURL string `json:"httpUrl"`
+ Headers map[string]string `json:"headers"`
+ } `json:"mcpServers"`
+ }
+ if err := json.Unmarshal(data, &parsed); err != nil {
+ t.Fatalf("settings is not valid JSON: %v", err)
+ }
+ srv, ok := parsed.MCPServers["claudomator"]
+ if !ok {
+ t.Fatal("expected claudomator server entry")
+ }
+ if srv.HTTPURL != "http://host.docker.internal:8484/mcp" {
+ t.Errorf("unexpected httpUrl: %q", srv.HTTPURL)
+ }
+ if srv.Headers["Authorization"] != "Bearer tok-xyz" {
+ t.Errorf("expected bearer header, got %q", srv.Headers["Authorization"])
+ }
+}
+
func TestContainerRunner_BuildInnerCmd(t *testing.T) {
runner := &ContainerRunner{}