Skip to content

Commit 209f851

Browse files
fix: register all tools from all toolsets when skills are enabled
When skills handle progressive disclosure, the server should expose all tools via tools/list regardless of toolset configuration. The client decides tool visibility through skill allowedTools, not the server. This replaces the previous filtering approach — now inv.AllTools() registers every tool with the MCP server, and skills reference the full tool surface. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent eb1865f commit 209f851

3 files changed

Lines changed: 8 additions & 92 deletions

File tree

pkg/github/server.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -125,13 +125,13 @@ func NewMCPServer(ctx context.Context, cfg *MCPServerConfig, deps ToolDependenci
125125
}
126126

127127
// Register skill resources for MCP clients that support skills-based discovery.
128-
// Filter allowedTools against actually-registered tools so skills only reference
129-
// tools that exist for the current toolset configuration.
130-
availableTools := make(map[string]struct{})
128+
// When skills are present, register ALL tools from all toolsets so that skills
129+
// can progressively reveal the full tool surface. The skills handle disclosure;
130+
// the server exposes everything.
131131
for _, tool := range inv.AllTools() {
132-
availableTools[tool.Tool.Name] = struct{}{}
132+
tool.RegisterFunc(ghServer, deps)
133133
}
134-
RegisterSkillResources(ghServer, availableTools)
134+
RegisterSkillResources(ghServer)
135135

136136
return ghServer, nil
137137
}

pkg/github/skill_resources.go

Lines changed: 1 addition & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -508,18 +508,8 @@ func buildSkillContent(skill skillDefinition) string {
508508
// RegisterSkillResources registers all skill resources with the MCP server.
509509
// Each skill is a static resource with a skill:// URI that can be discovered
510510
// by MCP clients supporting the skills pattern.
511-
// The availableTools set filters each skill's allowedTools to only include
512-
// tools that are actually registered, ensuring skills work correctly
513-
// regardless of which toolsets are enabled.
514-
func RegisterSkillResources(s *mcp.Server, availableTools map[string]struct{}) {
511+
func RegisterSkillResources(s *mcp.Server) {
515512
for _, skill := range allSkills() {
516-
// Filter allowedTools to only include tools that are actually registered
517-
filtered := filterAvailableTools(skill.allowedTools, availableTools)
518-
if len(filtered) == 0 {
519-
continue // Skip skills with no available tools
520-
}
521-
skill.allowedTools = filtered
522-
523513
content := buildSkillContent(skill)
524514
uri := fmt.Sprintf("skill://github/%s/SKILL.md", skill.name)
525515

@@ -546,18 +536,3 @@ func RegisterSkillResources(s *mcp.Server, availableTools map[string]struct{}) {
546536
)
547537
}
548538
}
549-
550-
// filterAvailableTools returns only the tool names that exist in the available set.
551-
// If availableTools is nil, all tools are returned (no filtering).
552-
func filterAvailableTools(tools []string, availableTools map[string]struct{}) []string {
553-
if availableTools == nil {
554-
return tools
555-
}
556-
var filtered []string
557-
for _, t := range tools {
558-
if _, ok := availableTools[t]; ok {
559-
filtered = append(filtered, t)
560-
}
561-
}
562-
return filtered
563-
}

pkg/github/skill_resources_test.go

Lines changed: 2 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -75,69 +75,10 @@ func TestRegisterSkillResources(t *testing.T) {
7575
Version: "0.0.1",
7676
}, nil)
7777

78-
// Should not panic with nil (no filtering)
79-
RegisterSkillResources(server, nil)
78+
// Should not panic
79+
RegisterSkillResources(server)
8080

8181
// Verify the expected number of skills were registered by counting definitions
8282
skills := allSkills()
8383
assert.Equal(t, 27, len(skills), "expected 27 workflow-oriented skills")
8484
}
85-
86-
func TestFilterAvailableTools(t *testing.T) {
87-
tests := []struct {
88-
name string
89-
tools []string
90-
available map[string]struct{}
91-
expected []string
92-
}{
93-
{
94-
name: "nil available returns all tools",
95-
tools: []string{"a", "b", "c"},
96-
available: nil,
97-
expected: []string{"a", "b", "c"},
98-
},
99-
{
100-
name: "filters to only available tools",
101-
tools: []string{"a", "b", "c"},
102-
available: map[string]struct{}{"a": {}, "c": {}},
103-
expected: []string{"a", "c"},
104-
},
105-
{
106-
name: "returns nil when no tools match",
107-
tools: []string{"a", "b"},
108-
available: map[string]struct{}{"x": {}},
109-
expected: nil,
110-
},
111-
{
112-
name: "empty available set filters everything",
113-
tools: []string{"a", "b"},
114-
available: map[string]struct{}{},
115-
expected: nil,
116-
},
117-
}
118-
119-
for _, tc := range tests {
120-
t.Run(tc.name, func(t *testing.T) {
121-
result := filterAvailableTools(tc.tools, tc.available)
122-
assert.Equal(t, tc.expected, result)
123-
})
124-
}
125-
}
126-
127-
func TestRegisterSkillResourcesFiltering(t *testing.T) {
128-
t.Parallel()
129-
// Only make get_me available — skills that have no overlap should be skipped
130-
available := map[string]struct{}{"get_me": {}}
131-
132-
server := mcp.NewServer(&mcp.Implementation{
133-
Name: "test-server",
134-
Version: "0.0.1",
135-
}, nil)
136-
137-
RegisterSkillResources(server, available)
138-
139-
// get-context skill includes get_me, so it should be registered.
140-
// Skills with zero available tools should be skipped entirely.
141-
// We can't easily count resources on mcp.Server, but we verify no panic
142-
// and the logic is correct via TestFilterAvailableTools above.
143-
}

0 commit comments

Comments
 (0)