summaryrefslogtreecommitdiff
path: root/internal/executor/container.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/executor/container.go')
-rw-r--r--internal/executor/container.go42
1 files changed, 39 insertions, 3 deletions
diff --git a/internal/executor/container.go b/internal/executor/container.go
index 78c3ed7..4f8fa06 100644
--- a/internal/executor/container.go
+++ b/internal/executor/container.go
@@ -306,16 +306,22 @@ func (r *ContainerRunner) runContainer(ctx context.Context, t *task.Task, e *sto
}
// Per-task MCP back-channel: mint a scoped token bound to this run's channel
- // and write an mcp-config pointing the agent at the host agent MCP server.
+ // and point the agent at the host agent MCP server. Claude reads an
+ // --mcp-config file; the gemini CLI auto-discovers servers from its
+ // ~/.gemini/settings.json (agentHome is the container's $HOME).
mcpEnabled := false
- if r.Registry != nil && t.Agent.Type != "gemini" {
+ if r.Registry != nil {
token, mintErr := r.Registry.Mint(ch)
if mintErr != nil {
return fmt.Errorf("minting agent mcp token: %w", mintErr)
}
defer r.Registry.Revoke(token)
mcpURL := strings.TrimRight(strings.ReplaceAll(r.APIURL, "localhost", "host.docker.internal"), "/") + "/mcp"
- if err := writeMCPConfig(workspace, mcpURL, token); err != nil {
+ if t.Agent.Type == "gemini" {
+ if err := writeGeminiMCPSettings(agentHome, mcpURL, token); err != nil {
+ return fmt.Errorf("writing gemini mcp settings: %w", err)
+ }
+ } else if err := writeMCPConfig(workspace, mcpURL, token); err != nil {
return fmt.Errorf("writing mcp config: %w", err)
}
mcpEnabled = true
@@ -534,6 +540,36 @@ func writeMCPConfig(workspace, mcpURL, token string) error {
return os.WriteFile(filepath.Join(workspace, ".claudomator-mcp.json"), data, 0600)
}
+// writeGeminiMCPSettings registers the per-task agent MCP server in the gemini
+// CLI's user settings (agentHome/.gemini/settings.json, which is $HOME/.gemini
+// in-container). The gemini CLI discovers MCP servers from this file rather than
+// a command-line flag; httpUrl selects the streamable-HTTP transport and headers
+// carry the bearer token.
+//
+// NOTE: the on-disk schema follows the gemini-cli mcpServers format, but whether
+// the CLI actually invokes these tools in non-interactive (-p) mode has not been
+// verified against a live gemini binary — confirm with a spike before relying on
+// gemini tool-use in production.
+func writeGeminiMCPSettings(agentHome, mcpURL, token string) error {
+ cfg := map[string]any{
+ "mcpServers": map[string]any{
+ "claudomator": map[string]any{
+ "httpUrl": mcpURL,
+ "headers": map[string]string{"Authorization": "Bearer " + token},
+ },
+ },
+ }
+ data, err := json.Marshal(cfg)
+ if err != nil {
+ return err
+ }
+ dir := filepath.Join(agentHome, ".gemini")
+ if err := os.MkdirAll(dir, 0755); err != nil {
+ return err
+ }
+ return os.WriteFile(filepath.Join(dir, "settings.json"), data, 0600)
+}
+
func (r *ContainerRunner) buildInnerCmd(t *task.Task, e *storage.Execution, isResume, mcpEnabled bool) []string {
// Claude CLI uses -p for prompt text. To pass a file, we use a shell to cat it.
// We use a shell variable to capture the expansion to avoid quoting issues with instructions contents.