From 1053d223e596288fa47a30ac426be09704e3de8a Mon Sep 17 00:00:00 2001 From: Lukasz Raczylo Date: Fri, 12 Jun 2026 01:32:21 +0100 Subject: [PATCH] fixup! fix(apply): propagate read errors, auto-open repo, dedupe adapter base (#6) --- internal/adapter/common/io.go | 2 ++ internal/adapter/common/io_fs_test.go | 2 ++ internal/adapter/common/mcp.go | 9 +++++++++ internal/adapter/common/mcp_test.go | 14 ++++++++++++-- internal/canonical/types.go | 1 + 5 files changed, 26 insertions(+), 2 deletions(-) diff --git a/internal/adapter/common/io.go b/internal/adapter/common/io.go index 1bd6a92..ace3bae 100644 --- a/internal/adapter/common/io.go +++ b/internal/adapter/common/io.go @@ -168,6 +168,7 @@ func parseMCPEntry(name string, raw json.RawMessage) (canonical.MCPServer, bool) Cmd json.RawMessage `json:"cmd"` Args []string `json:"args"` URL string `json:"url"` + Headers map[string]string `json:"headers"` Env map[string]string `json:"env"` Environment map[string]string `json:"environment"` } @@ -198,6 +199,7 @@ func parseMCPEntry(name string, raw json.RawMessage) (canonical.MCPServer, bool) Args: args, URL: e.URL, Transport: transport, + Headers: e.Headers, Env: env, }, true } diff --git a/internal/adapter/common/io_fs_test.go b/internal/adapter/common/io_fs_test.go index 9e3c109..8bc39b4 100644 --- a/internal/adapter/common/io_fs_test.go +++ b/internal/adapter/common/io_fs_test.go @@ -42,6 +42,7 @@ func TestImportMCPFromJSONFileFSExtractsServers(t *testing.T) { "myserver": { "command": "/usr/bin/mytool", "args": ["--flag"], + "headers": {"Authorization": "Bearer ${MCP_TOKEN}"}, "type": "stdio" } } @@ -55,6 +56,7 @@ func TestImportMCPFromJSONFileFSExtractsServers(t *testing.T) { assert.Equal(t, "/usr/bin/mytool", servers[0].Command) assert.Equal(t, []string{"--flag"}, servers[0].Args) assert.Equal(t, "stdio", servers[0].Transport) + assert.Equal(t, map[string]string{"Authorization": "Bearer ${MCP_TOKEN}"}, servers[0].Headers) } func TestImportMCPFromJSONFileFSReadOnlyFS(t *testing.T) { diff --git a/internal/adapter/common/mcp.go b/internal/adapter/common/mcp.go index 8568236..ab0a751 100644 --- a/internal/adapter/common/mcp.go +++ b/internal/adapter/common/mcp.go @@ -39,6 +39,9 @@ func mcpEntry(s canonical.MCPServer, style MCPStyle) map[string]any { } e["type"] = t e["url"] = s.URL + if len(s.Headers) > 0 { + e["headers"] = s.Headers + } } else { // Claude honours Transport field; Crush always uses "stdio". t := "stdio" @@ -60,6 +63,9 @@ func mcpEntry(s canonical.MCPServer, style MCPStyle) map[string]any { if s.URL != "" { e["type"] = "remote" e["url"] = s.URL + if len(s.Headers) > 0 { + e["headers"] = s.Headers + } } else { e["type"] = "local" cmd := []string{} @@ -79,6 +85,9 @@ func mcpEntry(s canonical.MCPServer, style MCPStyle) map[string]any { // fail all of them. Omitting "enabled" defaults to true. if s.URL != "" { e["url"] = s.URL + if len(s.Headers) > 0 { + e["headers"] = s.Headers + } } else { if s.Command != "" { e["command"] = s.Command diff --git a/internal/adapter/common/mcp_test.go b/internal/adapter/common/mcp_test.go index f05df48..8844bfd 100644 --- a/internal/adapter/common/mcp_test.go +++ b/internal/adapter/common/mcp_test.go @@ -26,11 +26,16 @@ func TestBuildMCPMapStyledClaudeStyle(t *testing.T) { } func TestBuildMCPMapStyledClaudeStyleURL(t *testing.T) { - r := reg(canonical.MCPServer{Name: "remote", URL: "https://example.com"}) + r := reg(canonical.MCPServer{ + Name: "remote", + URL: "https://example.com", + Headers: map[string]string{"Authorization": "Bearer ${MCP_TOKEN}"}, + }) out := BuildMCPMapStyled(r, MCPClaudeStyle) e := out["remote"].(map[string]any) assert.Equal(t, "https://example.com", e["url"]) assert.Equal(t, "http", e["type"]) + assert.Equal(t, map[string]string{"Authorization": "Bearer ${MCP_TOKEN}"}, e["headers"]) } func TestBuildMCPMapStyledCrushStdio(t *testing.T) { @@ -70,12 +75,17 @@ func TestBuildMCPMapStyledOpencodeLocal(t *testing.T) { } func TestBuildMCPMapStyledOpencodeRemote(t *testing.T) { - r := reg(canonical.MCPServer{Name: "r", URL: "https://example.com"}) + r := reg(canonical.MCPServer{ + Name: "r", + URL: "https://example.com", + Headers: map[string]string{"X-Tenant": "tenant-a"}, + }) out := BuildMCPMapStyled(r, MCPOpencodeStyle) e := out["r"].(map[string]any) assert.Equal(t, "remote", e["type"]) assert.Equal(t, true, e["enabled"]) assert.Equal(t, "https://example.com", e["url"]) + assert.Equal(t, map[string]string{"X-Tenant": "tenant-a"}, e["headers"]) } func TestBuildMCPMapStyledOpencodeEnv(t *testing.T) { diff --git a/internal/canonical/types.go b/internal/canonical/types.go index e3dd18a..d557e9d 100644 --- a/internal/canonical/types.go +++ b/internal/canonical/types.go @@ -43,6 +43,7 @@ type MCPRegistry struct { type MCPServer struct { Env map[string]string `yaml:"env,omitempty"` + Headers map[string]string `yaml:"headers,omitempty"` Name string `yaml:"name"` Command string `yaml:"command,omitempty"` URL string `yaml:"url,omitempty"`