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
41 changes: 0 additions & 41 deletions pkg/workflow/mcp_benchmark_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,50 +3,9 @@
package workflow

import (
"strings"
"testing"
)

// BenchmarkRenderPlaywrightMCPConfig benchmarks Playwright MCP config generation
func BenchmarkRenderPlaywrightMCPConfig(b *testing.B) {
playwrightTool := map[string]any{
"container": "mcr.microsoft.com/playwright:v1.41.0",
"args": []any{"--debug"},
}
playwrightConfig := parsePlaywrightTool(playwrightTool)

for b.Loop() {
var yaml strings.Builder
renderPlaywrightMCPConfig(&yaml, playwrightConfig, true)
}
}

// BenchmarkGeneratePlaywrightDockerArgs benchmarks Playwright args generation
func BenchmarkGeneratePlaywrightDockerArgs(b *testing.B) {
playwrightTool := map[string]any{
"container": "mcr.microsoft.com/playwright:v1.41.0",
}
playwrightConfig := parsePlaywrightTool(playwrightTool)

for b.Loop() {
_ = generatePlaywrightDockerArgs(playwrightConfig)
}
}

// BenchmarkRenderPlaywrightMCPConfig_Complex benchmarks complex Playwright config
func BenchmarkRenderPlaywrightMCPConfig_Complex(b *testing.B) {
playwrightTool := map[string]any{
"container": "mcr.microsoft.com/playwright:v1.41.0",
"args": []any{"--debug", "--timeout", "30000"},
}
playwrightConfig := parsePlaywrightTool(playwrightTool)

for b.Loop() {
var yaml strings.Builder
renderPlaywrightMCPConfig(&yaml, playwrightConfig, true)
}
}

// BenchmarkExtractExpressionsFromPlaywrightArgs benchmarks expression extraction
func BenchmarkExtractExpressionsFromPlaywrightArgs(b *testing.B) {
customArgs := []string{"--debug", "--timeout", "${{ github.event.inputs.timeout }}"}
Expand Down
7 changes: 0 additions & 7 deletions pkg/workflow/mcp_config_builtin.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,13 +108,6 @@ import (

var mcpBuiltinLog = logger.New("workflow:mcp-config-builtin")

// renderSafeOutputsMCPConfig generates the Safe Outputs MCP server configuration
// This is a shared function used by both Claude and Custom engines
func renderSafeOutputsMCPConfig(yaml *strings.Builder, isLast bool, workflowData *WorkflowData) {
mcpBuiltinLog.Print("Rendering Safe Outputs MCP configuration")
renderSafeOutputsMCPConfigWithOptions(yaml, isLast, false, workflowData)
}

// renderSafeOutputsMCPConfigWithOptions generates the Safe Outputs MCP server configuration with engine-specific options
// Now uses HTTP transport instead of stdio, similar to safe-inputs
// The server is started in a separate step before the agent job
Expand Down
26 changes: 0 additions & 26 deletions pkg/workflow/mcp_config_custom.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,32 +16,6 @@ import (

var mcpCustomLog = logger.New("workflow:mcp-config-custom")

// renderCustomMCPConfigWrapper generates custom MCP server configuration wrapper
// This is a shared function used by both Claude and Custom engines
func renderCustomMCPConfigWrapper(yaml *strings.Builder, toolName string, toolConfig map[string]any, isLast bool) error {
mcpCustomLog.Printf("Rendering custom MCP config wrapper for tool: %s", toolName)
fmt.Fprintf(yaml, " \"%s\": {\n", toolName)

// Use the shared MCP config renderer with JSON format
renderer := MCPConfigRenderer{
IndentLevel: " ",
Format: "json",
}

err := renderSharedMCPConfig(yaml, toolName, toolConfig, renderer)
if err != nil {
return err
}

if isLast {
yaml.WriteString(" }\n")
} else {
yaml.WriteString(" },\n")
}

return nil
}

// renderCustomMCPConfigWrapperWithContext generates custom MCP server configuration wrapper with workflow context
// This version includes workflowData to determine if localhost URLs should be rewritten
func renderCustomMCPConfigWrapperWithContext(yaml *strings.Builder, toolName string, toolConfig map[string]any, isLast bool, workflowData *WorkflowData) error {
Expand Down
8 changes: 0 additions & 8 deletions pkg/workflow/mcp_config_playwright_renderer.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,6 @@ import (

var mcpPlaywrightLog = logger.New("workflow:mcp_config_playwright_renderer")

// renderPlaywrightMCPConfig generates the Playwright MCP server configuration
// Uses Docker container to launch Playwright MCP for consistent browser environment
// This is a shared function used by both Claude and Custom engines
func renderPlaywrightMCPConfig(yaml *strings.Builder, playwrightConfig *PlaywrightToolConfig, isLast bool) {
mcpPlaywrightLog.Print("Rendering Playwright MCP configuration")
renderPlaywrightMCPConfigWithOptions(yaml, playwrightConfig, isLast, false, false)
}

// renderPlaywrightMCPConfigWithOptions generates the Playwright MCP server configuration with engine-specific options
// Per MCP Gateway Specification v1.0.0 section 3.2.1, stdio-based MCP servers MUST be containerized.
// Uses MCP Gateway spec format: container, entrypointArgs, mounts, and args fields.
Expand Down
138 changes: 0 additions & 138 deletions pkg/workflow/mcp_config_shared_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,144 +7,6 @@ import (
"testing"
)

// TestRenderSafeOutputsMCPConfigShared tests the shared renderSafeOutputsMCPConfig function
func TestRenderSafeOutputsMCPConfigShared(t *testing.T) {
tests := []struct {
name string
isLast bool
wantContains []string
wantEnding string
}{
{
name: "safe outputs config not last",
isLast: false,
wantContains: []string{
`"safeoutputs": {`,
`"type": "http"`,
`"url": "http://host.docker.internal:$GH_AW_SAFE_OUTPUTS_PORT"`,
`"headers": {`,
`"Authorization": "$GH_AW_SAFE_OUTPUTS_API_KEY"`,
},
wantEnding: "},\n",
},
{
name: "safe outputs config is last",
isLast: true,
wantContains: []string{
`"safeoutputs": {`,
`"type": "http"`,
`"url": "http://host.docker.internal:$GH_AW_SAFE_OUTPUTS_PORT"`,
},
wantEnding: "}\n",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var yaml strings.Builder
renderSafeOutputsMCPConfig(&yaml, tt.isLast, nil)

result := yaml.String()

// Check all required strings are present
for _, want := range tt.wantContains {
if !strings.Contains(result, want) {
t.Errorf("renderSafeOutputsMCPConfig() result missing %q\nGot:\n%s", want, result)
}
}

// Check correct ending
if !strings.HasSuffix(result, tt.wantEnding) {
// Show last part of result for debugging, but handle short strings
endSnippet := result
if len(result) > 10 {
endSnippet = result[len(result)-10:]
}
t.Errorf("renderSafeOutputsMCPConfig() ending = %q, want suffix %q", endSnippet, tt.wantEnding)
}
})
}
}

// TestRenderCustomMCPConfigWrapperShared tests the shared renderCustomMCPConfigWrapper function
func TestRenderCustomMCPConfigWrapperShared(t *testing.T) {
tests := []struct {
name string
toolName string
toolConfig map[string]any
isLast bool
wantContains []string
wantEnding string
wantError bool
}{
{
name: "custom MCP config not last",
toolName: "my-tool",
toolConfig: map[string]any{
"command": "node",
"args": []string{"server.js"},
},
isLast: false,
wantContains: []string{
`"my-tool": {`,
`"command": "node"`,
},
wantEnding: "},\n",
wantError: false,
},
{
name: "custom MCP config is last",
toolName: "another-tool",
toolConfig: map[string]any{
"command": "python",
"args": []string{"-m", "server"},
},
isLast: true,
wantContains: []string{
`"another-tool": {`,
`"command": "python"`,
},
wantEnding: "}\n",
wantError: false,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var yaml strings.Builder
err := renderCustomMCPConfigWrapper(&yaml, tt.toolName, tt.toolConfig, tt.isLast)

if (err != nil) != tt.wantError {
t.Errorf("renderCustomMCPConfigWrapper() error = %v, wantError %v", err, tt.wantError)
return
}

if tt.wantError {
return
}

result := yaml.String()

// Check all required strings are present
for _, want := range tt.wantContains {
if !strings.Contains(result, want) {
t.Errorf("renderCustomMCPConfigWrapper() result missing %q\nGot:\n%s", want, result)
}
}

// Check correct ending
if !strings.HasSuffix(result, tt.wantEnding) {
// Show last part of result for debugging, but handle short strings
endSnippet := result
if len(result) > 10 {
endSnippet = result[len(result)-10:]
}
t.Errorf("renderCustomMCPConfigWrapper() ending = %q, want suffix %q", endSnippet, tt.wantEnding)
}
})
}
}

// TestEngineMethodsDelegateToShared ensures engine methods properly delegate to shared functions
func TestEngineMethodsDelegateToShared(t *testing.T) {
t.Run("Claude engine Playwright delegation via unified renderer", func(t *testing.T) {
Expand Down
107 changes: 0 additions & 107 deletions pkg/workflow/mcp_config_utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,113 +7,6 @@ import (
"testing"
)

func TestGetTypeString(t *testing.T) {
tests := []struct {
name string
value any
want string
}{
{
name: "nil value",
value: nil,
want: "null",
},
{
name: "int value",
value: 42,
want: "number",
},
{
name: "int64 value",
value: int64(100),
want: "number",
},
{
name: "float64 value",
value: 3.14,
want: "number",
},
{
name: "float32 value",
value: float32(2.71),
want: "number",
},
{
name: "boolean true",
value: true,
want: "boolean",
},
{
name: "boolean false",
value: false,
want: "boolean",
},
{
name: "string value",
value: "hello world",
want: "string",
},
{
name: "empty string",
value: "",
want: "string",
},
{
name: "object (map[string]any)",
value: map[string]any{
"key": "value",
},
want: "object",
},
{
name: "empty object",
value: map[string]any{},
want: "object",
},
{
name: "array of strings",
value: []string{"a", "b", "c"},
want: "array",
},
{
name: "array of ints",
value: []int{1, 2, 3},
want: "array",
},
{
name: "array of any",
value: []any{"mixed", 123, true},
want: "array",
},
{
name: "empty array",
value: []string{},
want: "array",
},
{
name: "array of objects",
value: []map[string]any{{"key": "value"}},
want: "array",
},
{
name: "unknown type (struct)",
value: struct {
Name string
}{Name: "test"},
want: "unknown",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := getTypeString(tt.value)
if got != tt.want {
t.Errorf("getTypeString(%v) = %v, want %v", tt.value, got, tt.want)
}
})
}
}

func TestWriteArgsToYAMLInline(t *testing.T) {
tests := []struct {
name string
Expand Down
Loading
Loading