Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions forge-core/validate/mcp_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,15 @@ import (
// ≤31 chars.
var mcpServerNamePattern = regexp.MustCompile(`^[a-z][a-z0-9-]{0,30}$`)

// MCP tool name format. Allowed in Tools.Allow / Tools.Deny. Names
// containing "__" are reserved for the namespaced runtime form
// "<server>__<tool>"; here we only validate the bare tool name.
var mcpToolNamePattern = regexp.MustCompile(`^[a-zA-Z0-9_]{1,64}$`)
// MCP tool name format. Allowed in Tools.Allow / Tools.Deny. Matches the
// MCP spec's SHOULD pattern for tool names (`^[a-zA-Z0-9_-]{1,128}$`) —
// real servers expose hyphenated names (Calendly's users-get_current_user,
// event_types-list_event_types, …), and rejecting the hyphen bricked any
// agent at startup whose allow-list carried the server's genuine tool
// names. Names containing "__" are reserved for the namespaced runtime
// form "<server>__<tool>" and rejected by a separate check; single "-"
// or "_" pose no conflict with that separator.
var mcpToolNamePattern = regexp.MustCompile(`^[a-zA-Z0-9_-]{1,128}$`)

// knownMCPTransports is the closed set of accepted transport values.
// Phase 1: HTTP only. Stdio is on the roadmap.
Expand Down
22 changes: 19 additions & 3 deletions forge-core/validate/mcp_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,12 +234,28 @@ func TestValidateMCPConfig(t *testing.T) {
wantErrs: []string{"invalid tool name"},
},
{
name: "deny tool name with hyphen rejected",
// Hyphenated names are the MCP-ecosystem norm (Calendly:
// users-get_current_user, event_types-list_event_types, …)
// and match the spec's SHOULD pattern. Rejecting them bricked
// agents at startup whose allow-lists carried the server's
// real tool names.
name: "tool names with hyphens accepted",
cfg: types.MCPConfig{Servers: []types.MCPServer{{
Name: "x", Transport: "http", URL: "http://x",
Tools: types.MCPToolFilter{Allow: []string{"good"}, Deny: []string{"bad-tool"}},
Tools: types.MCPToolFilter{
Allow: []string{"users-get_current_user", "scheduling_links-create_single_use_scheduling_link"},
Deny: []string{"meetings-cancel_event"},
},
}}},
wantErrs: []string{"invalid tool name"},
wantErrs: nil,
},
{
name: "tool name with double underscore still rejected",
cfg: types.MCPConfig{Servers: []types.MCPServer{{
Name: "x", Transport: "http", URL: "http://x",
Tools: types.MCPToolFilter{Allow: []string{"foo__bar"}},
}}},
wantErrs: []string{"reserved for MCP namespacing"},
},
{
name: "tool in both allow and deny",
Expand Down
Loading