diff --git a/pkg/agent/agent_mcp.go b/pkg/agent/agent_mcp.go index d04a0fdf3..3d569b2bd 100644 --- a/pkg/agent/agent_mcp.go +++ b/pkg/agent/agent_mcp.go @@ -317,8 +317,16 @@ func filterMCPConfigServers( filtered := mcpCfg filtered.Servers = make(map[string]config.MCPServerConfig) + normalizedAllowed := make(map[string]struct{}, len(allowed)) + for serverName := range allowed { + name := normalizeMCPServerName(serverName) + if name == "" { + continue + } + normalizedAllowed[name] = struct{}{} + } for serverName, serverCfg := range mcpCfg.Servers { - if _, ok := allowed[serverName]; ok { + if _, ok := normalizedAllowed[normalizeMCPServerName(serverName)]; ok { filtered.Servers[serverName] = serverCfg } } diff --git a/pkg/agent/agent_mcp_test.go b/pkg/agent/agent_mcp_test.go index 5c3f67445..7c8a4cd28 100644 --- a/pkg/agent/agent_mcp_test.go +++ b/pkg/agent/agent_mcp_test.go @@ -172,6 +172,38 @@ func TestToolRegistryIncludesReportsOnlyRegisteredTools(t *testing.T) { } } +func TestFilterMCPConfigServersCaseInsensitivePreservesOriginalKeys(t *testing.T) { + mcpCfg := config.MCPConfig{ + Servers: map[string]config.MCPServerConfig{ + "GitHub": {Enabled: true}, + "filesystem": {Enabled: true}, + "Slack": {Enabled: true}, + }, + } + allowed := map[string]struct{}{ + "github": {}, + "FILESYSTEM": {}, + } + + filtered := filterMCPConfigServers(mcpCfg, allowed) + + if len(filtered.Servers) != 2 { + t.Fatalf("filtered.Servers = %v, want 2 entries", filtered.Servers) + } + if _, ok := filtered.Servers["GitHub"]; !ok { + t.Fatal("expected original GitHub config key to be preserved") + } + if _, ok := filtered.Servers["filesystem"]; !ok { + t.Fatal("expected filesystem config key to be preserved") + } + if _, ok := filtered.Servers["github"]; ok { + t.Fatal("did not expect normalized github key to replace original config key") + } + if _, ok := filtered.Servers["Slack"]; ok { + t.Fatal("did not expect unallowed Slack server") + } +} + func TestEnsureMCPInitialized_LoadFailureSetsInitErr(t *testing.T) { al, cfg, _, _, cleanup := newTestAgentLoop(t) defer cleanup() diff --git a/pkg/agent/tool_allowlist.go b/pkg/agent/tool_allowlist.go index 87ae2ee4c..7a020c82c 100644 --- a/pkg/agent/tool_allowlist.go +++ b/pkg/agent/tool_allowlist.go @@ -11,6 +11,24 @@ import ( const dynamicMCPToolPrefix = "mcp_" +func normalizeMCPServerName(name string) string { + return strings.ToLower(strings.TrimSpace(name)) +} + +func normalizedMCPServerNameSet( + servers map[string]config.MCPServerConfig, +) map[string]struct{} { + normalized := make(map[string]struct{}, len(servers)) + for serverName := range servers { + name := normalizeMCPServerName(serverName) + if name == "" { + continue + } + normalized[name] = struct{}{} + } + return normalized +} + func warnOnUnknownAgentToolDeclarations( agentID, workspace string, definition AgentContextDefinition, @@ -93,13 +111,14 @@ func unknownAgentMCPServerNames(cfg *config.Config, definition AgentContextDefin return nil } + knownServers := normalizedMCPServerNameSet(cfg.Tools.MCP.Servers) unknown := make(map[string]struct{}) for _, raw := range definition.Agent.Frontmatter.MCPServers { - name := strings.ToLower(strings.TrimSpace(raw)) + name := normalizeMCPServerName(raw) if name == "" { continue } - if _, ok := cfg.Tools.MCP.Servers[name]; ok { + if _, ok := knownServers[name]; ok { continue } unknown[name] = struct{}{} diff --git a/pkg/agent/tool_allowlist_test.go b/pkg/agent/tool_allowlist_test.go index 46bbac2bc..4851dcaa8 100644 --- a/pkg/agent/tool_allowlist_test.go +++ b/pkg/agent/tool_allowlist_test.go @@ -93,3 +93,30 @@ mcpServers: [github, githb] t.Fatalf("unknownAgentMCPServerNames() = %v, want [githb]", unknown) } } + +func TestUnknownAgentMCPServerNamesMatchesConfigCaseInsensitively(t *testing.T) { + workspace := setupWorkspace(t, map[string]string{ + "AGENT.md": `--- +mcpServers: [github, FileSystem, slak] +--- +# Agent +`, + }) + defer cleanupWorkspace(t, workspace) + + cfg := &config.Config{ + Tools: config.ToolsConfig{ + MCP: config.MCPConfig{ + Servers: map[string]config.MCPServerConfig{ + "GitHub": {Enabled: true}, + "filesystem": {Enabled: true}, + }, + }, + }, + } + + unknown := unknownAgentMCPServerNames(cfg, loadAgentDefinition(workspace)) + if len(unknown) != 1 || unknown[0] != "slak" { + t.Fatalf("unknownAgentMCPServerNames() = %v, want [slak]", unknown) + } +}