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
16 changes: 12 additions & 4 deletions .github/workflows/smoke-codex.lock.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 4 additions & 10 deletions pkg/workflow/claude_mcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,11 @@ func (e *ClaudeEngine) RenderMCPConfig(yaml *strings.Builder, tools map[string]a
claudeMCPLog.Printf("Rendering MCP config for Claude: tool_count=%d, mcp_tool_count=%d", len(tools), len(mcpTools))

// Claude uses JSON format without Copilot-specific fields and multi-line args
createRenderer := buildMCPRendererFactory(workflowData, "json", false, false)

// Build gateway configuration for MCP config
// Per MCP Gateway Specification v1.0.0 section 4.1.3, the gateway section is required
return RenderJSONMCPConfig(yaml, tools, mcpTools, workflowData, JSONMCPConfigOptions{
ConfigPath: "/tmp/gh-aw/mcp-config/mcp-servers.json",
GatewayConfig: buildMCPGatewayConfig(workflowData),
Renderers: buildStandardJSONMCPRenderers(workflowData, createRenderer, false, func(yaml *strings.Builder, toolName string, toolConfig map[string]any, isLast bool) error {
return renderStandardJSONMCPConfig(yaml, tools, mcpTools, workflowData,
"/tmp/gh-aw/mcp-config/mcp-servers.json", false, false, false,
func(yaml *strings.Builder, toolName string, toolConfig map[string]any, isLast bool) error {
return e.renderClaudeMCPConfigWithContext(yaml, toolName, toolConfig, isLast, workflowData)
}),
})
}, nil)
}

// renderClaudeMCPConfigWithContext generates custom MCP server configuration for a single tool in Claude workflow mcp-servers.json
Expand Down
16 changes: 4 additions & 12 deletions pkg/workflow/codex_mcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,20 +103,12 @@ func (e *CodexEngine) RenderMCPConfig(yaml *strings.Builder, tools map[string]an
yaml.WriteString(" \n")
yaml.WriteString(" # Generate JSON config for MCP gateway\n")

// Build gateway configuration
gatewayConfig := buildMCPGatewayConfig(workflowData)

// Use shared JSON renderer for gateway input
// Gateway uses JSON format without Copilot-specific fields and multi-line args
createJSONRenderer := buildMCPRendererFactory(workflowData, "json", false, false)

return RenderJSONMCPConfig(yaml, tools, mcpTools, workflowData, JSONMCPConfigOptions{
ConfigPath: "/tmp/gh-aw/mcp-config/mcp-servers.json",
GatewayConfig: gatewayConfig,
Renderers: buildStandardJSONMCPRenderers(workflowData, createJSONRenderer, false, func(yaml *strings.Builder, toolName string, toolConfig map[string]any, isLast bool) error {
return renderStandardJSONMCPConfig(yaml, tools, mcpTools, workflowData,
"/tmp/gh-aw/mcp-config/mcp-servers.json", false, false, false,
func(yaml *strings.Builder, toolName string, toolConfig map[string]any, isLast bool) error {
return e.renderCodexJSONMCPConfigWithContext(yaml, toolName, toolConfig, isLast, workflowData)
}),
})
}, nil)
}

// renderCodexMCPConfigWithContext generates custom MCP server configuration for a single tool in codex workflow config.toml
Expand Down
29 changes: 12 additions & 17 deletions pkg/workflow/copilot_mcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ import (

var copilotMCPLog = logger.New("workflow:copilot_mcp")

// copilotMCPToolFilter returns true for MCP tools that should be included in the Copilot MCP config.
// Cache-memory is excluded because it is handled as a simple file share, not an MCP server.
func copilotMCPToolFilter(toolName string) bool {
return toolName != "cache-memory"
}

// RenderMCPConfig generates MCP server configuration for Copilot CLI
func (e *CopilotEngine) RenderMCPConfig(yaml *strings.Builder, tools map[string]any, mcpTools []string, workflowData *WorkflowData) error {
copilotMCPLog.Printf("Rendering MCP config for Copilot engine: mcpTools=%d", len(mcpTools))
Expand All @@ -16,25 +22,14 @@ func (e *CopilotEngine) RenderMCPConfig(yaml *strings.Builder, tools map[string]
yaml.WriteString(" mkdir -p /home/runner/.copilot\n")

// Copilot uses JSON format with type and tools fields, and inline args
createRenderer := buildMCPRendererFactory(workflowData, "json", true, true)

// Build gateway configuration for MCP config
// Per MCP Gateway Specification v1.0.0 section 4.1.3, the gateway section is required
options := JSONMCPConfigOptions{
ConfigPath: "/home/runner/.copilot/mcp-config.json",
GatewayConfig: buildMCPGatewayConfig(workflowData),
// webFetchIncludeTools=true: Copilot requires a tools field in the web-fetch server config
Renderers: buildStandardJSONMCPRenderers(workflowData, createRenderer, true, func(yaml *strings.Builder, toolName string, toolConfig map[string]any, isLast bool) error {
// webFetchIncludeTools=true: Copilot requires a tools field in the web-fetch server config
return renderStandardJSONMCPConfig(yaml, tools, mcpTools, workflowData,
"/home/runner/.copilot/mcp-config.json", true, true, true,
func(yaml *strings.Builder, toolName string, toolConfig map[string]any, isLast bool) error {
return e.renderCopilotMCPConfigWithContext(yaml, toolName, toolConfig, isLast, workflowData)
}),
FilterTool: func(toolName string) bool {
// Filter out cache-memory for Copilot
// Cache-memory is handled as a simple file share, not an MCP server
return toolName != "cache-memory"
},
}

return RenderJSONMCPConfig(yaml, tools, mcpTools, workflowData, options)
copilotMCPToolFilter,
)
}

// renderCopilotMCPConfigWithContext generates custom MCP server configuration for Copilot CLI
Expand Down
13 changes: 4 additions & 9 deletions pkg/workflow/gemini_mcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,9 @@ func (e *GeminiEngine) RenderMCPConfig(yaml *strings.Builder, tools map[string]a
geminiMCPLog.Printf("Rendering MCP config for Gemini: tool_count=%d, mcp_tool_count=%d", len(tools), len(mcpTools))

// Gemini uses JSON format without Copilot-specific fields and multi-line args
createRenderer := buildMCPRendererFactory(workflowData, "json", false, false)

// Use shared JSON MCP config renderer
return RenderJSONMCPConfig(yaml, tools, mcpTools, workflowData, JSONMCPConfigOptions{
ConfigPath: "/tmp/gh-aw/mcp-config/mcp-servers.json",
GatewayConfig: buildMCPGatewayConfig(workflowData),
Renderers: buildStandardJSONMCPRenderers(workflowData, createRenderer, false, func(yaml *strings.Builder, toolName string, toolConfig map[string]any, isLast bool) error {
return renderStandardJSONMCPConfig(yaml, tools, mcpTools, workflowData,
"/tmp/gh-aw/mcp-config/mcp-servers.json", false, false, false,
func(yaml *strings.Builder, toolName string, toolConfig map[string]any, isLast bool) error {
return renderCustomMCPConfigWrapperWithContext(yaml, toolName, toolConfig, isLast, workflowData)
}),
})
}, nil)
}
36 changes: 36 additions & 0 deletions pkg/workflow/mcp_renderer_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,42 @@ package workflow

import "strings"

// renderStandardJSONMCPConfig is a shared helper for JSON MCP config rendering used by
// Claude, Gemini, Copilot, and Codex engines. It consolidates the repeated sequence of:
// buildMCPRendererFactory → buildMCPGatewayConfig → buildStandardJSONMCPRenderers → RenderJSONMCPConfig.
//
// Parameters:
// - yaml: output builder
// - tools: tool configurations from frontmatter
// - mcpTools: list of enabled MCP tool names
// - workflowData: compiled workflow context
// - configPath: engine-specific MCP config file path
// - includeCopilotFields: whether to include "type" and "tools" fields (true for Copilot)
// - inlineArgs: whether to render args inline (true for Copilot) vs multi-line
// - webFetchIncludeTools: whether the web-fetch server includes a tools field (true for Copilot)
// - renderCustom: engine-specific handler for custom MCP tool entries
// - filterTool: optional tool filter function; nil to include all tools
func renderStandardJSONMCPConfig(
yaml *strings.Builder,
tools map[string]any,
mcpTools []string,
workflowData *WorkflowData,
configPath string,
includeCopilotFields bool,
inlineArgs bool,
webFetchIncludeTools bool,
renderCustom RenderCustomMCPToolConfigHandler,
filterTool func(string) bool,
Comment on lines +20 to +30
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

renderStandardJSONMCPConfig takes several positional boolean parameters (includeCopilotFields, inlineArgs, webFetchIncludeTools). At the call sites this results in false, false, false argument sequences, which are easy to mis-order and hard to review. Consider replacing these booleans with a small options struct (or a single renderFlags struct) so callers can set named fields, improving readability and reducing the risk of flag mixups during future edits.

Copilot uses AI. Check for mistakes.
) error {
createRenderer := buildMCPRendererFactory(workflowData, "json", includeCopilotFields, inlineArgs)
return RenderJSONMCPConfig(yaml, tools, mcpTools, workflowData, JSONMCPConfigOptions{
ConfigPath: configPath,
GatewayConfig: buildMCPGatewayConfig(workflowData),
Renderers: buildStandardJSONMCPRenderers(workflowData, createRenderer, webFetchIncludeTools, renderCustom),
FilterTool: filterTool,
})
}

// buildMCPRendererFactory creates a factory function for MCPConfigRendererUnified instances.
// The returned function accepts isLast as a parameter and creates a renderer with engine-specific
// options derived from the provided parameters and workflowData at call time.
Expand Down
Loading