Skip to content

Support wildcard ["*"] in allowed-tools filtering #3443

@lpcox

Description

@lpcox

Problem

When the gh-aw compiler passes tools: ["*"] to the MCP gateway, the gateway treats "*" as a literal tool name rather than a wildcard. This causes all tools to be filtered out:

[allowed-tools] Filtered 6 tools from elastic-docs: keeping 0 of 6

This is because buildAllowedToolSets() in internal/server/unified.go:382-396 builds a map[string]bool from the Tools list, and the filtering logic in registerToolsFromBackend() (tool_registry.go:188-201) does a simple set membership check:

if allowedSet[tool.Name] {  // tool.Name is "search_code", set has "*" → false

No tool is literally named "*", so every tool fails the check and gets dropped.

Root Cause

Two layers are involved:

  1. Compiler side (gh-aw): The compiler emits tools: ["*"] in the lock file when the workflow frontmatter specifies a wildcard or "all tools" intent.
  2. Gateway side (mcpg): buildAllowedToolSets and isToolAllowed treat every entry in the Tools list as a literal tool name — there is no wildcard/glob handling.

Proposed Solution

Add wildcard detection in buildAllowedToolSets() so that if the Tools list contains "*", the server is treated as having no restriction (i.e., not added to the allowedToolSets map, same as when Tools is empty/nil).

Implementation

In internal/server/unified.go, modify buildAllowedToolSets:

func buildAllowedToolSets(cfg *config.Config) map[string]map[string]bool {
    sets := make(map[string]map[string]bool)
    if cfg == nil {
        return sets
    }
    for serverID, serverCfg := range cfg.Servers {
        if len(serverCfg.Tools) > 0 {
            // Treat ["*"] as "allow all" — skip adding to the filter map
            if len(serverCfg.Tools) == 1 && serverCfg.Tools[0] == "*" {
                continue
            }
            set := make(map[string]bool, len(serverCfg.Tools))
            for _, t := range serverCfg.Tools {
                set[t] = true
            }
            sets[serverID] = set
        }
    }
    return sets
}

Alternatively, check for "*" anywhere in the list (not just as a single element) for a more permissive approach.

Tests to Add

  1. TestBuildAllowedToolSets_WildcardStarTools: ["*"] should result in no entry in the sets map (all tools allowed)
  2. TestRegisterToolsFromBackend_WildcardAllowsAll — backend with Tools: ["*"] should have all tools registered
  3. TestIsToolAllowed_WildcardisToolAllowed returns true for any tool name when Tools: ["*"]
  4. TestAllowedTools_CallAllowed_Wildcard — integration test: tools/call succeeds with wildcard config

Acceptance Criteria

  • tools: ["*"] allows all tools through (same behavior as omitting the tools list)
  • Explicit tool lists (e.g., ["search_code", "create_issue"]) still filter correctly
  • Empty/nil tools list still allows all tools (no regression)
  • Unit and integration tests cover the wildcard case
  • Log message when wildcard is detected: [allowed-tools] Wildcard "*" configured for <serverID>: allowing all tools

References

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions