Skip to content

Commit ee0a440

Browse files
committed
make insiders mode metadata stripping generic
1 parent adc1053 commit ee0a440

File tree

2 files changed

+85
-4
lines changed

2 files changed

+85
-4
lines changed

internal/ghmcp/server.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ func NewMCPServer(cfg MCPServerConfig) (*mcp.Server, error) {
181181
WithToolsets(enabledToolsets).
182182
WithTools(cfg.EnabledTools).
183183
WithFeatureChecker(featureChecker).
184+
WithInsidersMode(cfg.InsidersMode).
184185
WithServerInstructions()
185186

186187
// Apply token scope filtering if scopes are known (for PAT filtering)

pkg/inventory/builder.go

Lines changed: 84 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ type Builder struct {
4141
featureChecker FeatureFlagChecker
4242
filters []ToolFilter // filters to apply to all tools
4343
generateInstructions bool
44+
insidersMode bool
4445
}
4546

4647
// NewBuilder creates a new Builder.
@@ -135,6 +136,15 @@ func (b *Builder) WithFilter(filter ToolFilter) *Builder {
135136
return b
136137
}
137138

139+
// WithInsidersMode enables or disables insiders mode features.
140+
// When insiders mode is disabled (default), UI metadata is removed from tools
141+
// so clients won't attempt to load UI resources.
142+
// Returns self for chaining.
143+
func (b *Builder) WithInsidersMode(enabled bool) *Builder {
144+
b.insidersMode = enabled
145+
return b
146+
}
147+
138148
// cleanTools trims whitespace and removes duplicates from tool names.
139149
// Empty strings after trimming are excluded.
140150
func cleanTools(tools []string) []string {
@@ -162,8 +172,14 @@ func cleanTools(tools []string) []string {
162172
// (i.e., they don't exist in the tool set and are not deprecated aliases).
163173
// This ensures invalid tool configurations fail fast at build time.
164174
func (b *Builder) Build() (*Inventory, error) {
175+
// When insiders mode is disabled, strip insiders-only features from tools
176+
tools := b.tools
177+
if !b.insidersMode {
178+
tools = stripInsidersFeatures(b.tools)
179+
}
180+
165181
r := &Inventory{
166-
tools: b.tools,
182+
tools: tools,
167183
resourceTemplates: b.resourceTemplates,
168184
prompts: b.prompts,
169185
deprecatedAliases: b.deprecatedAliases,
@@ -176,9 +192,9 @@ func (b *Builder) Build() (*Inventory, error) {
176192
r.enabledToolsets, r.unrecognizedToolsets, r.toolsetIDs, r.toolsetIDSet, r.defaultToolsetIDs, r.toolsetDescriptions = b.processToolsets()
177193

178194
// Build set of valid tool names for validation
179-
validToolNames := make(map[string]bool, len(b.tools))
180-
for i := range b.tools {
181-
validToolNames[b.tools[i].Tool.Name] = true
195+
validToolNames := make(map[string]bool, len(tools))
196+
for i := range tools {
197+
validToolNames[tools[i].Tool.Name] = true
182198
}
183199

184200
// Process additional tools (clean, resolve aliases, and track unrecognized)
@@ -326,3 +342,67 @@ func (b *Builder) processToolsets() (map[ToolsetID]bool, []string, []ToolsetID,
326342
}
327343
return enabledToolsets, unrecognized, allToolsetIDs, validIDs, defaultToolsetIDList, descriptions
328344
}
345+
346+
// insidersOnlyMetaKeys lists the Meta keys that are only available in insiders mode.
347+
// Add new experimental feature keys here to have them automatically stripped
348+
// when insiders mode is disabled.
349+
var insidersOnlyMetaKeys = []string{
350+
"ui", // MCP Apps UI metadata
351+
}
352+
353+
// stripInsidersFeatures removes insiders-only features from tools.
354+
// This includes Meta keys listed in insidersOnlyMetaKeys.
355+
func stripInsidersFeatures(tools []ServerTool) []ServerTool {
356+
result := make([]ServerTool, len(tools))
357+
for i, tool := range tools {
358+
if stripped := stripInsidersMetaFromTool(tool); stripped != nil {
359+
result[i] = *stripped
360+
} else {
361+
result[i] = tool
362+
}
363+
}
364+
return result
365+
}
366+
367+
// stripInsidersMetaFromTool removes insiders-only Meta keys from a single tool.
368+
// Returns a modified copy if changes were made, nil otherwise.
369+
func stripInsidersMetaFromTool(tool ServerTool) *ServerTool {
370+
if tool.Tool.Meta == nil {
371+
return nil
372+
}
373+
374+
// Check if any insiders-only keys exist
375+
hasInsidersKeys := false
376+
for _, key := range insidersOnlyMetaKeys {
377+
if tool.Tool.Meta[key] != nil {
378+
hasInsidersKeys = true
379+
break
380+
}
381+
}
382+
if !hasInsidersKeys {
383+
return nil
384+
}
385+
386+
// Make a shallow copy and remove insiders-only keys
387+
toolCopy := tool
388+
newMeta := make(map[string]any, len(tool.Tool.Meta))
389+
for k, v := range tool.Tool.Meta {
390+
isInsidersKey := false
391+
for _, insidersKey := range insidersOnlyMetaKeys {
392+
if k == insidersKey {
393+
isInsidersKey = true
394+
break
395+
}
396+
}
397+
if !isInsidersKey {
398+
newMeta[k] = v
399+
}
400+
}
401+
402+
if len(newMeta) == 0 {
403+
toolCopy.Tool.Meta = nil
404+
} else {
405+
toolCopy.Tool.Meta = newMeta
406+
}
407+
return &toolCopy
408+
}

0 commit comments

Comments
 (0)