diff --git a/.github/workflows/archie.lock.yml b/.github/workflows/archie.lock.yml index 374c889b955..b88d79f9b10 100644 --- a/.github/workflows/archie.lock.yml +++ b/.github/workflows/archie.lock.yml @@ -472,7 +472,7 @@ jobs: }, "serena": { "type": "http", - "url": "http://localhost:9121" + "url": "http://host.docker.internal:9121" } }, "gateway": { diff --git a/.github/workflows/cloclo.lock.yml b/.github/workflows/cloclo.lock.yml index 687f69b9c03..f6cafa6558e 100644 --- a/.github/workflows/cloclo.lock.yml +++ b/.github/workflows/cloclo.lock.yml @@ -599,7 +599,7 @@ jobs: } }, "serena": { - "url": "http://localhost:9121" + "url": "http://host.docker.internal:9121" } }, "gateway": { diff --git a/.github/workflows/daily-file-diet.lock.yml b/.github/workflows/daily-file-diet.lock.yml index 6c75554cdf0..c18e31c79e9 100644 --- a/.github/workflows/daily-file-diet.lock.yml +++ b/.github/workflows/daily-file-diet.lock.yml @@ -470,7 +470,7 @@ jobs: }, "serena": { "type": "http", - "url": "http://localhost:9121" + "url": "http://host.docker.internal:9121" } }, "gateway": { diff --git a/.github/workflows/developer-docs-consolidator.lock.yml b/.github/workflows/developer-docs-consolidator.lock.yml index 53546f3604a..141cb77b520 100644 --- a/.github/workflows/developer-docs-consolidator.lock.yml +++ b/.github/workflows/developer-docs-consolidator.lock.yml @@ -513,7 +513,7 @@ jobs: } }, "serena": { - "url": "http://localhost:9121" + "url": "http://host.docker.internal:9121" } }, "gateway": { diff --git a/.github/workflows/duplicate-code-detector.lock.yml b/.github/workflows/duplicate-code-detector.lock.yml index 423edbc18f4..82a54e65942 100644 --- a/.github/workflows/duplicate-code-detector.lock.yml +++ b/.github/workflows/duplicate-code-detector.lock.yml @@ -445,7 +445,7 @@ jobs: env_vars = ["GH_AW_MCP_LOG_DIR", "GH_AW_SAFE_OUTPUTS", "GH_AW_SAFE_OUTPUTS_CONFIG_PATH", "GH_AW_SAFE_OUTPUTS_TOOLS_PATH", "GH_AW_ASSETS_BRANCH", "GH_AW_ASSETS_MAX_SIZE_KB", "GH_AW_ASSETS_ALLOWED_EXTS", "GITHUB_REPOSITORY", "GITHUB_SERVER_URL", "GITHUB_SHA", "GITHUB_WORKSPACE", "DEFAULT_BRANCH"] [mcp_servers.serena] - url = "http://localhost:9121" + url = "http://host.docker.internal:9121" EOF # Generate JSON config for MCP gateway @@ -482,7 +482,7 @@ jobs: } }, "serena": { - "url": "http://localhost:9121" + "url": "http://host.docker.internal:9121" } }, "gateway": { diff --git a/.github/workflows/glossary-maintainer.lock.yml b/.github/workflows/glossary-maintainer.lock.yml index 6e67d32bc2d..3f3cb4ccf62 100644 --- a/.github/workflows/glossary-maintainer.lock.yml +++ b/.github/workflows/glossary-maintainer.lock.yml @@ -469,7 +469,7 @@ jobs: }, "serena": { "type": "http", - "url": "http://localhost:9121" + "url": "http://host.docker.internal:9121" } }, "gateway": { diff --git a/.github/workflows/go-fan.lock.yml b/.github/workflows/go-fan.lock.yml index de8a398d2b5..81dd77f5212 100644 --- a/.github/workflows/go-fan.lock.yml +++ b/.github/workflows/go-fan.lock.yml @@ -449,7 +449,7 @@ jobs: } }, "serena": { - "url": "http://localhost:9121" + "url": "http://host.docker.internal:9121" } }, "gateway": { diff --git a/.github/workflows/jsweep.lock.yml b/.github/workflows/jsweep.lock.yml index b60db5a2cbd..ddc1c0fd58a 100644 --- a/.github/workflows/jsweep.lock.yml +++ b/.github/workflows/jsweep.lock.yml @@ -470,7 +470,7 @@ jobs: }, "serena": { "type": "http", - "url": "http://localhost:9121" + "url": "http://host.docker.internal:9121" } }, "gateway": { diff --git a/.github/workflows/mcp-inspector.lock.yml b/.github/workflows/mcp-inspector.lock.yml index 70b94395543..59b8b854166 100644 --- a/.github/workflows/mcp-inspector.lock.yml +++ b/.github/workflows/mcp-inspector.lock.yml @@ -761,7 +761,7 @@ jobs: }, "serena": { "type": "http", - "url": "http://localhost:9121" + "url": "http://host.docker.internal:9121" }, "tavily": { "type": "http", diff --git a/.github/workflows/q.lock.yml b/.github/workflows/q.lock.yml index c00427aa87b..0e9138ff724 100644 --- a/.github/workflows/q.lock.yml +++ b/.github/workflows/q.lock.yml @@ -586,7 +586,7 @@ jobs: }, "serena": { "type": "http", - "url": "http://localhost:9121" + "url": "http://host.docker.internal:9121" }, "tavily": { "type": "http", diff --git a/.github/workflows/repository-quality-improver.lock.yml b/.github/workflows/repository-quality-improver.lock.yml index 77b2f0073f1..e47b9daec25 100644 --- a/.github/workflows/repository-quality-improver.lock.yml +++ b/.github/workflows/repository-quality-improver.lock.yml @@ -460,7 +460,7 @@ jobs: }, "serena": { "type": "http", - "url": "http://localhost:9121" + "url": "http://host.docker.internal:9121" } }, "gateway": { diff --git a/.github/workflows/smoke-claude.lock.yml b/.github/workflows/smoke-claude.lock.yml index b157c7c59a8..8fe18650ea5 100644 --- a/.github/workflows/smoke-claude.lock.yml +++ b/.github/workflows/smoke-claude.lock.yml @@ -698,7 +698,7 @@ jobs: } }, "serena": { - "url": "http://localhost:9121" + "url": "http://host.docker.internal:9121" }, "tavily": { "type": "http", diff --git a/.github/workflows/smoke-codex.lock.yml b/.github/workflows/smoke-codex.lock.yml index 6de1b324a25..a30243631fb 100644 --- a/.github/workflows/smoke-codex.lock.yml +++ b/.github/workflows/smoke-codex.lock.yml @@ -714,7 +714,7 @@ jobs: env_vars = ["GH_AW_MCP_LOG_DIR", "GH_AW_SAFE_OUTPUTS", "GH_AW_SAFE_OUTPUTS_CONFIG_PATH", "GH_AW_SAFE_OUTPUTS_TOOLS_PATH", "GH_AW_ASSETS_BRANCH", "GH_AW_ASSETS_MAX_SIZE_KB", "GH_AW_ASSETS_ALLOWED_EXTS", "GITHUB_REPOSITORY", "GITHUB_SERVER_URL", "GITHUB_SHA", "GITHUB_WORKSPACE", "DEFAULT_BRANCH"] [mcp_servers.serena] - url = "http://localhost:9121" + url = "http://host.docker.internal:9121" [mcp_servers.tavily] url = "https://mcp.tavily.com/mcp/" @@ -779,7 +779,7 @@ jobs: } }, "serena": { - "url": "http://localhost:9121" + "url": "http://host.docker.internal:9121" }, "tavily": { "type": "http", diff --git a/.github/workflows/smoke-copilot.lock.yml b/.github/workflows/smoke-copilot.lock.yml index c53808edc37..0dd374c97ff 100644 --- a/.github/workflows/smoke-copilot.lock.yml +++ b/.github/workflows/smoke-copilot.lock.yml @@ -581,7 +581,7 @@ jobs: }, "serena": { "type": "http", - "url": "http://localhost:9121" + "url": "http://host.docker.internal:9121" } }, "gateway": { diff --git a/.github/workflows/terminal-stylist.lock.yml b/.github/workflows/terminal-stylist.lock.yml index 24022f4fcd0..db0ffb1230b 100644 --- a/.github/workflows/terminal-stylist.lock.yml +++ b/.github/workflows/terminal-stylist.lock.yml @@ -438,7 +438,7 @@ jobs: }, "serena": { "type": "http", - "url": "http://localhost:9121" + "url": "http://host.docker.internal:9121" } }, "gateway": { diff --git a/.github/workflows/typist.lock.yml b/.github/workflows/typist.lock.yml index a9196d96bee..0b7b8a9c5a2 100644 --- a/.github/workflows/typist.lock.yml +++ b/.github/workflows/typist.lock.yml @@ -436,7 +436,7 @@ jobs: } }, "serena": { - "url": "http://localhost:9121" + "url": "http://host.docker.internal:9121" } }, "gateway": { diff --git a/pkg/workflow/importable_tools_test.go b/pkg/workflow/importable_tools_test.go index c82ecd2eb89..932fe922f0a 100644 --- a/pkg/workflow/importable_tools_test.go +++ b/pkg/workflow/importable_tools_test.go @@ -160,8 +160,8 @@ Uses imported serena tool. if !strings.Contains(workflowData, "uvx --from git+https://github.com/oraios/serena") { t.Error("Expected compiled workflow to use uvx to start Serena") } - if !strings.Contains(workflowData, "http://localhost:9121") { - t.Error("Expected compiled workflow to contain Serena HTTP URL") + if !strings.Contains(workflowData, "http://host.docker.internal:9121") { + t.Error("Expected compiled workflow to contain Serena HTTP URL with host.docker.internal") } // Verify that language service setup steps ARE present @@ -324,8 +324,8 @@ Uses all imported tools. if !strings.Contains(workflowData, "mcr.microsoft.com/playwright/mcp") { t.Error("Expected compiled workflow to contain playwright Docker image") } - if !strings.Contains(workflowData, "http://localhost:9121") { - t.Error("Expected compiled workflow to contain Serena HTTP URL") + if !strings.Contains(workflowData, "http://host.docker.internal:9121") { + t.Error("Expected compiled workflow to contain Serena HTTP URL with host.docker.internal") } if !strings.Contains(workflowData, "example.com") { t.Error("Expected compiled workflow to contain example.com domain for playwright") diff --git a/pkg/workflow/mcp-config.go b/pkg/workflow/mcp-config.go index 792826b06ad..cf81b5c8d8e 100644 --- a/pkg/workflow/mcp-config.go +++ b/pkg/workflow/mcp-config.go @@ -147,7 +147,8 @@ func renderPlaywrightMCPConfigWithOptions(yaml *strings.Builder, playwrightTool // renderSerenaMCPConfigWithOptions generates the Serena MCP server configuration with engine-specific options // Serena now runs using uvx with HTTP transport in the agent job (not containerized) -// The HTTP server is started in a background step and accessed via http://localhost:9121 +// The HTTP server is started in a background step and accessed via http://host.docker.internal:9121 +// Note: host.docker.internal is used because the MCP gateway runs in a container and needs to reach the host func renderSerenaMCPConfigWithOptions(yaml *strings.Builder, serenaTool any, isLast bool, includeCopilotFields bool, inlineArgs bool) { yaml.WriteString(" \"serena\": {\n") @@ -157,7 +158,8 @@ func renderSerenaMCPConfigWithOptions(yaml *strings.Builder, serenaTool any, isL } // HTTP URL for Serena MCP server running on host - yaml.WriteString(" \"url\": \"http://localhost:9121\"\n") + // Use host.docker.internal so the gateway container can reach the host + yaml.WriteString(" \"url\": \"http://host.docker.internal:9121\"\n") // Note: tools field is NOT included here - the converter script adds it back // for Copilot. This keeps the gateway config compatible with the schema. diff --git a/pkg/workflow/mcp_config_comprehensive_test.go b/pkg/workflow/mcp_config_comprehensive_test.go index e896758fb5d..4dba3060fd0 100644 --- a/pkg/workflow/mcp_config_comprehensive_test.go +++ b/pkg/workflow/mcp_config_comprehensive_test.go @@ -574,7 +574,7 @@ func TestRenderSerenaMCPConfigWithOptions(t *testing.T) { inlineArgs: false, expectedContent: []string{ `"serena": {`, - `"url": "http://localhost:9121"`, + `"url": "http://host.docker.internal:9121"`, ` },`, }, unexpectedContent: []string{ @@ -593,7 +593,7 @@ func TestRenderSerenaMCPConfigWithOptions(t *testing.T) { inlineArgs: false, expectedContent: []string{ `"serena": {`, - `"url": "http://localhost:9121"`, + `"url": "http://host.docker.internal:9121"`, ` }`, }, unexpectedContent: []string{ @@ -612,7 +612,7 @@ func TestRenderSerenaMCPConfigWithOptions(t *testing.T) { expectedContent: []string{ `"serena": {`, `"type": "http"`, - `"url": "http://localhost:9121"`, + `"url": "http://host.docker.internal:9121"`, }, unexpectedContent: []string{ `"container"`, @@ -627,7 +627,7 @@ func TestRenderSerenaMCPConfigWithOptions(t *testing.T) { expectedContent: []string{ `"serena": {`, `"type": "http"`, - `"url": "http://localhost:9121"`, + `"url": "http://host.docker.internal:9121"`, }, unexpectedContent: []string{ `"container"`, @@ -644,7 +644,7 @@ func TestRenderSerenaMCPConfigWithOptions(t *testing.T) { inlineArgs: false, expectedContent: []string{ `"serena": {`, - `"url": "http://localhost:9121"`, + `"url": "http://host.docker.internal:9121"`, }, unexpectedContent: []string{ `"container"`, diff --git a/pkg/workflow/mcp_renderer.go b/pkg/workflow/mcp_renderer.go index 2cce44fb0e0..d3d6663654a 100644 --- a/pkg/workflow/mcp_renderer.go +++ b/pkg/workflow/mcp_renderer.go @@ -186,11 +186,12 @@ func (r *MCPConfigRendererUnified) RenderSerenaMCP(yaml *strings.Builder, serena // renderSerenaTOML generates Serena MCP configuration in TOML format // Serena now runs using uvx with HTTP transport in the agent job (not containerized) -// The HTTP server is started in a background step and accessed via http://localhost:9121 +// The HTTP server is started in a background step and accessed via http://host.docker.internal:9121 +// Note: host.docker.internal is used because the MCP gateway runs in a container and needs to reach the host func (r *MCPConfigRendererUnified) renderSerenaTOML(yaml *strings.Builder, serenaTool any) { yaml.WriteString(" \n") yaml.WriteString(" [mcp_servers.serena]\n") - yaml.WriteString(" url = \"http://localhost:9121\"\n") + yaml.WriteString(" url = \"http://host.docker.internal:9121\"\n") } // RenderSafeOutputsMCP generates the Safe Outputs MCP server configuration