From 0ee5325e10624bf0232c7ac326aabc8532997e1b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 6 Feb 2026 13:35:10 +0000 Subject: [PATCH 1/9] Initial plan From 0f2a9467154163c770a47f6d374742ed2841f6b5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 6 Feb 2026 13:42:57 +0000 Subject: [PATCH 2/9] Add dynamic binary path detection with logging and validation - Added GetBinaryPath() helper to determine gh-aw binary path using os.Executable() - Added runtime file existence check in startup path - Added logging of binary path in runMCPServer() and validateMCPServerConfiguration() - Added comprehensive tests for binary path detection - Binary path is now logged at MCP server startup for debugging Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- pkg/cli/mcp_server.go | 22 ++++++++++++++ pkg/cli/mcp_validation.go | 55 ++++++++++++++++++++++++++++++++++ pkg/cli/mcp_validation_test.go | 49 ++++++++++++++++++++++++++++++ 3 files changed, 126 insertions(+) create mode 100644 pkg/cli/mcp_validation_test.go diff --git a/pkg/cli/mcp_server.go b/pkg/cli/mcp_server.go index fc954e7a46..2069324978 100644 --- a/pkg/cli/mcp_server.go +++ b/pkg/cli/mcp_server.go @@ -108,6 +108,28 @@ func runMCPServer(port int, cmdPath string) error { mcpLog.Print("Starting MCP server with stdio transport") } + // Determine and log the binary path + binaryPath, err := GetBinaryPath() + if err != nil { + mcpLog.Printf("Warning: failed to get binary path: %v", err) + fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("Warning: failed to get binary path: %v", err))) + } else { + // Check if the binary file exists + if _, err := os.Stat(binaryPath); err != nil { + if os.IsNotExist(err) { + mcpLog.Printf("ERROR: binary file does not exist at path: %s", binaryPath) + fmt.Fprintln(os.Stderr, console.FormatErrorMessage(fmt.Sprintf("ERROR: binary file does not exist at path: %s", binaryPath))) + } else { + mcpLog.Printf("Warning: failed to stat binary file at %s: %v", binaryPath, err) + fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("Warning: failed to stat binary file at %s: %v", binaryPath, err))) + } + } else { + // Log the binary path for debugging + mcpLog.Printf("gh-aw binary path: %s", binaryPath) + fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("gh-aw binary path: %s", binaryPath))) + } + } + // Log current working directory if cwd, err := os.Getwd(); err == nil { mcpLog.Printf("Current working directory: %s", cwd) diff --git a/pkg/cli/mcp_validation.go b/pkg/cli/mcp_validation.go index aacad6d0a2..81eee0841c 100644 --- a/pkg/cli/mcp_validation.go +++ b/pkg/cli/mcp_validation.go @@ -8,6 +8,7 @@ import ( "fmt" "os" "os/exec" + "path/filepath" "strings" "time" @@ -19,6 +20,38 @@ import ( var mcpValidationLog = logger.New("cli:mcp_validation") +// GetBinaryPath returns the path to the currently running gh-aw binary. +// This is used by the MCP server to determine where the gh-aw binary is located +// when launching itself with different arguments. +// +// Returns the absolute path to the binary, or an error if the path cannot be determined. +func GetBinaryPath() (string, error) { + // Get the path to the currently running executable + exePath, err := os.Executable() + if err != nil { + return "", fmt.Errorf("failed to get executable path: %w", err) + } + + // Resolve any symlinks to get the actual binary path + // This is important because gh extensions are typically symlinked + resolvedPath, err := filepath.EvalSymlinks(exePath) + if err != nil { + // If we can't resolve symlinks, use the original path + mcpValidationLog.Printf("Warning: failed to resolve symlinks for %s: %v", exePath, err) + return exePath, nil + } + + // Get absolute path + absPath, err := filepath.Abs(resolvedPath) + if err != nil { + // If we can't get absolute path, use the resolved path + mcpValidationLog.Printf("Warning: failed to get absolute path for %s: %v", resolvedPath, err) + return resolvedPath, nil + } + + return absPath, nil +} + // validateServerSecrets checks if required environment variables/secrets are available func validateServerSecrets(config parser.MCPServerConfig, verbose bool, useActionsSecrets bool) error { mcpValidationLog.Printf("Validating server secrets: server=%s, type=%s, useActionsSecrets=%v", config.Name, config.Type, useActionsSecrets) @@ -169,6 +202,28 @@ func validateServerSecrets(config parser.MCPServerConfig, verbose bool, useActio func validateMCPServerConfiguration(cmdPath string) error { mcpValidationLog.Printf("Validating MCP server configuration: cmdPath=%s", cmdPath) + // Determine and log the binary path + binaryPath, err := GetBinaryPath() + if err != nil { + mcpValidationLog.Printf("Warning: failed to get binary path: %v", err) + fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("Warning: failed to get binary path: %v", err))) + } else { + // Check if the binary file exists + if _, err := os.Stat(binaryPath); err != nil { + if os.IsNotExist(err) { + mcpValidationLog.Printf("ERROR: binary file does not exist at path: %s", binaryPath) + fmt.Fprintln(os.Stderr, console.FormatErrorMessage(fmt.Sprintf("ERROR: binary file does not exist at path: %s", binaryPath))) + return fmt.Errorf("binary file does not exist at path: %s", binaryPath) + } + mcpValidationLog.Printf("Warning: failed to stat binary file at %s: %v", binaryPath, err) + fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("Warning: failed to stat binary file at %s: %v", binaryPath, err))) + } else { + // Log the binary path for debugging + mcpValidationLog.Printf("gh-aw binary path: %s", binaryPath) + fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("gh-aw binary path: %s", binaryPath))) + } + } + // Try to run the status command to verify CLI is working ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() diff --git a/pkg/cli/mcp_validation_test.go b/pkg/cli/mcp_validation_test.go new file mode 100644 index 0000000000..8cca4565bb --- /dev/null +++ b/pkg/cli/mcp_validation_test.go @@ -0,0 +1,49 @@ +//go:build !integration + +package cli + +import ( + "os" + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestGetBinaryPath(t *testing.T) { + t.Run("returns non-empty path", func(t *testing.T) { + path, err := GetBinaryPath() + require.NoError(t, err, "Should get binary path without error") + assert.NotEmpty(t, path, "Binary path should not be empty") + }) + + t.Run("returns absolute path", func(t *testing.T) { + path, err := GetBinaryPath() + require.NoError(t, err, "Should get binary path without error") + assert.True(t, filepath.IsAbs(path), "Binary path should be absolute") + }) + + t.Run("returned path exists", func(t *testing.T) { + path, err := GetBinaryPath() + require.NoError(t, err, "Should get binary path without error") + + // Check if the file exists + info, err := os.Stat(path) + assert.NoError(t, err, "Binary file should exist at the returned path") + if err == nil { + assert.False(t, info.IsDir(), "Binary path should not be a directory") + } + }) + + t.Run("path ends with executable name", func(t *testing.T) { + path, err := GetBinaryPath() + require.NoError(t, err, "Should get binary path without error") + + // The path should end with a reasonable executable name + // During tests, it might be a test binary name + base := filepath.Base(path) + assert.NotEmpty(t, base, "Binary path should have a base name") + // Don't check for specific name as it could be the test binary + }) +} From 3631c9f738e5d8fb82ba3314cb5c8c0397d957ec Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 6 Feb 2026 13:45:29 +0000 Subject: [PATCH 3/9] Fix linter error in mcp_validation_test.go - Changed assert.NoError to require.NoError for error assertions - Complies with testifylint requirements Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- pkg/cli/mcp_validation_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/cli/mcp_validation_test.go b/pkg/cli/mcp_validation_test.go index 8cca4565bb..d52ab40528 100644 --- a/pkg/cli/mcp_validation_test.go +++ b/pkg/cli/mcp_validation_test.go @@ -30,7 +30,7 @@ func TestGetBinaryPath(t *testing.T) { // Check if the file exists info, err := os.Stat(path) - assert.NoError(t, err, "Binary file should exist at the returned path") + require.NoError(t, err, "Binary file should exist at the returned path") if err == nil { assert.False(t, info.IsDir(), "Binary path should not be a directory") } From 2ab7b399581f7f3002bad64d66d65fd06142e6a3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 6 Feb 2026 13:52:29 +0000 Subject: [PATCH 4/9] Add symlink resolution test for GetBinaryPath - Added test to verify symlinks are properly resolved - Documents behavior for gh CLI extension symlinks Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- pkg/cli/mcp_validation_test.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/pkg/cli/mcp_validation_test.go b/pkg/cli/mcp_validation_test.go index d52ab40528..628aed653f 100644 --- a/pkg/cli/mcp_validation_test.go +++ b/pkg/cli/mcp_validation_test.go @@ -46,4 +46,19 @@ func TestGetBinaryPath(t *testing.T) { assert.NotEmpty(t, base, "Binary path should have a base name") // Don't check for specific name as it could be the test binary }) + + t.Run("resolves symlinks", func(t *testing.T) { + path, err := GetBinaryPath() + require.NoError(t, err, "Should get binary path without error") + + // The path should be the resolved path, not a symlink + // We can verify this by checking that EvalSymlinks returns the same path + resolved, err := filepath.EvalSymlinks(path) + if err == nil { + // If we can resolve symlinks, the path should already be resolved + assert.Equal(t, path, resolved, "Path should already be resolved (no symlinks)") + } + // If EvalSymlinks fails, that's OK - the original path is still valid + }) } + From d6aa49969da10fae62a872bee274b3d946aaca4a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 6 Feb 2026 13:55:22 +0000 Subject: [PATCH 5/9] Address code review feedback - Removed redundant error check in test (require.NoError already ensures no error) - Extracted binary path validation logic into logAndValidateBinaryPath() helper - Eliminates code duplication between runMCPServer and validateMCPServerConfiguration - Improves maintainability with single source of truth for validation logic Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- pkg/cli/mcp_server.go | 24 +++------------ pkg/cli/mcp_validation.go | 53 +++++++++++++++++++++------------- pkg/cli/mcp_validation_test.go | 5 +--- 3 files changed, 38 insertions(+), 44 deletions(-) diff --git a/pkg/cli/mcp_server.go b/pkg/cli/mcp_server.go index 2069324978..6f5cd17462 100644 --- a/pkg/cli/mcp_server.go +++ b/pkg/cli/mcp_server.go @@ -108,26 +108,10 @@ func runMCPServer(port int, cmdPath string) error { mcpLog.Print("Starting MCP server with stdio transport") } - // Determine and log the binary path - binaryPath, err := GetBinaryPath() - if err != nil { - mcpLog.Printf("Warning: failed to get binary path: %v", err) - fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("Warning: failed to get binary path: %v", err))) - } else { - // Check if the binary file exists - if _, err := os.Stat(binaryPath); err != nil { - if os.IsNotExist(err) { - mcpLog.Printf("ERROR: binary file does not exist at path: %s", binaryPath) - fmt.Fprintln(os.Stderr, console.FormatErrorMessage(fmt.Sprintf("ERROR: binary file does not exist at path: %s", binaryPath))) - } else { - mcpLog.Printf("Warning: failed to stat binary file at %s: %v", binaryPath, err) - fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("Warning: failed to stat binary file at %s: %v", binaryPath, err))) - } - } else { - // Log the binary path for debugging - mcpLog.Printf("gh-aw binary path: %s", binaryPath) - fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("gh-aw binary path: %s", binaryPath))) - } + // Determine, log, and validate the binary path + if err := logAndValidateBinaryPath(); err != nil { + // Log error but don't fail - server can still start + mcpLog.Printf("Binary path validation warning: %v", err) } // Log current working directory diff --git a/pkg/cli/mcp_validation.go b/pkg/cli/mcp_validation.go index 81eee0841c..0945d8a681 100644 --- a/pkg/cli/mcp_validation.go +++ b/pkg/cli/mcp_validation.go @@ -52,6 +52,35 @@ func GetBinaryPath() (string, error) { return absPath, nil } +// logAndValidateBinaryPath determines the binary path, logs it, and validates it exists. +// Returns an error if the binary path cannot be determined or if the file doesn't exist. +// This is a helper used by both runMCPServer and validateMCPServerConfiguration. +func logAndValidateBinaryPath() error { + binaryPath, err := GetBinaryPath() + if err != nil { + mcpValidationLog.Printf("Warning: failed to get binary path: %v", err) + fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("Warning: failed to get binary path: %v", err))) + return err + } + + // Check if the binary file exists + if _, err := os.Stat(binaryPath); err != nil { + if os.IsNotExist(err) { + mcpValidationLog.Printf("ERROR: binary file does not exist at path: %s", binaryPath) + fmt.Fprintln(os.Stderr, console.FormatErrorMessage(fmt.Sprintf("ERROR: binary file does not exist at path: %s", binaryPath))) + return fmt.Errorf("binary file does not exist at path: %s", binaryPath) + } + mcpValidationLog.Printf("Warning: failed to stat binary file at %s: %v", binaryPath, err) + fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("Warning: failed to stat binary file at %s: %v", binaryPath, err))) + return err + } + + // Log the binary path for debugging + mcpValidationLog.Printf("gh-aw binary path: %s", binaryPath) + fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("gh-aw binary path: %s", binaryPath))) + return nil +} + // validateServerSecrets checks if required environment variables/secrets are available func validateServerSecrets(config parser.MCPServerConfig, verbose bool, useActionsSecrets bool) error { mcpValidationLog.Printf("Validating server secrets: server=%s, type=%s, useActionsSecrets=%v", config.Name, config.Type, useActionsSecrets) @@ -202,26 +231,10 @@ func validateServerSecrets(config parser.MCPServerConfig, verbose bool, useActio func validateMCPServerConfiguration(cmdPath string) error { mcpValidationLog.Printf("Validating MCP server configuration: cmdPath=%s", cmdPath) - // Determine and log the binary path - binaryPath, err := GetBinaryPath() - if err != nil { - mcpValidationLog.Printf("Warning: failed to get binary path: %v", err) - fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("Warning: failed to get binary path: %v", err))) - } else { - // Check if the binary file exists - if _, err := os.Stat(binaryPath); err != nil { - if os.IsNotExist(err) { - mcpValidationLog.Printf("ERROR: binary file does not exist at path: %s", binaryPath) - fmt.Fprintln(os.Stderr, console.FormatErrorMessage(fmt.Sprintf("ERROR: binary file does not exist at path: %s", binaryPath))) - return fmt.Errorf("binary file does not exist at path: %s", binaryPath) - } - mcpValidationLog.Printf("Warning: failed to stat binary file at %s: %v", binaryPath, err) - fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("Warning: failed to stat binary file at %s: %v", binaryPath, err))) - } else { - // Log the binary path for debugging - mcpValidationLog.Printf("gh-aw binary path: %s", binaryPath) - fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("gh-aw binary path: %s", binaryPath))) - } + // Determine, log, and validate the binary path + if err := logAndValidateBinaryPath(); err != nil { + // Log error but don't fail - continue with validation + mcpValidationLog.Printf("Binary path validation warning: %v", err) } // Try to run the status command to verify CLI is working diff --git a/pkg/cli/mcp_validation_test.go b/pkg/cli/mcp_validation_test.go index 628aed653f..e30daf724b 100644 --- a/pkg/cli/mcp_validation_test.go +++ b/pkg/cli/mcp_validation_test.go @@ -31,9 +31,7 @@ func TestGetBinaryPath(t *testing.T) { // Check if the file exists info, err := os.Stat(path) require.NoError(t, err, "Binary file should exist at the returned path") - if err == nil { - assert.False(t, info.IsDir(), "Binary path should not be a directory") - } + assert.False(t, info.IsDir(), "Binary path should not be a directory") }) t.Run("path ends with executable name", func(t *testing.T) { @@ -61,4 +59,3 @@ func TestGetBinaryPath(t *testing.T) { // If EvalSymlinks fails, that's OK - the original path is still valid }) } - From 8c2360f53fb5baa0649d3c2a8b08186796dd5363 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 6 Feb 2026 13:57:45 +0000 Subject: [PATCH 6/9] Final code review improvements - Removed redundant filepath.Abs() call (EvalSymlinks already returns absolute path) - Removed duplicate error logging (logAndValidateBinaryPath handles all logging internally) - Improved code clarity with better comments - All tests pass, linting passes Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- pkg/cli/mcp_server.go | 6 ++---- pkg/cli/mcp_validation.go | 17 ++++------------- 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/pkg/cli/mcp_server.go b/pkg/cli/mcp_server.go index 6f5cd17462..0403ff3774 100644 --- a/pkg/cli/mcp_server.go +++ b/pkg/cli/mcp_server.go @@ -109,10 +109,8 @@ func runMCPServer(port int, cmdPath string) error { } // Determine, log, and validate the binary path - if err := logAndValidateBinaryPath(); err != nil { - // Log error but don't fail - server can still start - mcpLog.Printf("Binary path validation warning: %v", err) - } + // Note: logAndValidateBinaryPath handles all logging internally + _ = logAndValidateBinaryPath() // Log current working directory if cwd, err := os.Getwd(); err == nil { diff --git a/pkg/cli/mcp_validation.go b/pkg/cli/mcp_validation.go index 0945d8a681..0efb9e0663 100644 --- a/pkg/cli/mcp_validation.go +++ b/pkg/cli/mcp_validation.go @@ -34,6 +34,7 @@ func GetBinaryPath() (string, error) { // Resolve any symlinks to get the actual binary path // This is important because gh extensions are typically symlinked + // Note: EvalSymlinks already returns an absolute path resolvedPath, err := filepath.EvalSymlinks(exePath) if err != nil { // If we can't resolve symlinks, use the original path @@ -41,15 +42,7 @@ func GetBinaryPath() (string, error) { return exePath, nil } - // Get absolute path - absPath, err := filepath.Abs(resolvedPath) - if err != nil { - // If we can't get absolute path, use the resolved path - mcpValidationLog.Printf("Warning: failed to get absolute path for %s: %v", resolvedPath, err) - return resolvedPath, nil - } - - return absPath, nil + return resolvedPath, nil } // logAndValidateBinaryPath determines the binary path, logs it, and validates it exists. @@ -232,10 +225,8 @@ func validateMCPServerConfiguration(cmdPath string) error { mcpValidationLog.Printf("Validating MCP server configuration: cmdPath=%s", cmdPath) // Determine, log, and validate the binary path - if err := logAndValidateBinaryPath(); err != nil { - // Log error but don't fail - continue with validation - mcpValidationLog.Printf("Binary path validation warning: %v", err) - } + // Note: logAndValidateBinaryPath handles all logging internally + _ = logAndValidateBinaryPath() // Try to run the status command to verify CLI is working ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) From 56eb2d46cad7397c0a690e76759721f8fbfb9985 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 6 Feb 2026 14:12:23 +0000 Subject: [PATCH 7/9] Skip binary path detection when --cmd flag is provided - Only call logAndValidateBinaryPath() when cmdPath is empty (not provided by user) - Updated both runMCPServer() and validateMCPServerConfiguration() to skip detection - Removed --cmd gh-aw from Dockerfile CMD line (binary path now auto-detected) - Updated comment in mcp_config_builtin.go to reflect new CMD without --cmd arg - When --cmd is provided, user explicitly specifies binary path, so auto-detection is unnecessary Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- Dockerfile | 3 ++- pkg/cli/mcp_server.go | 9 ++++++--- pkg/cli/mcp_validation.go | 9 ++++++--- pkg/workflow/mcp_config_builtin.go | 3 ++- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/Dockerfile b/Dockerfile index 14bd3f16b0..8eeccbd37d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -32,7 +32,8 @@ WORKDIR /workspace ENTRYPOINT ["gh-aw"] # Default command runs MCP server -CMD ["mcp-server", "--cmd", "gh-aw"] +# Note: Binary path detection is automatic via os.Executable() +CMD ["mcp-server"] # Metadata labels LABEL org.opencontainers.image.source="https://github.com/github/gh-aw" diff --git a/pkg/cli/mcp_server.go b/pkg/cli/mcp_server.go index 0403ff3774..5a9daa42cd 100644 --- a/pkg/cli/mcp_server.go +++ b/pkg/cli/mcp_server.go @@ -108,9 +108,12 @@ func runMCPServer(port int, cmdPath string) error { mcpLog.Print("Starting MCP server with stdio transport") } - // Determine, log, and validate the binary path - // Note: logAndValidateBinaryPath handles all logging internally - _ = logAndValidateBinaryPath() + // Determine, log, and validate the binary path only if --cmd flag is not provided + // When --cmd is provided, the user explicitly specified the binary path to use + if cmdPath == "" { + // Note: logAndValidateBinaryPath handles all logging internally + _ = logAndValidateBinaryPath() + } // Log current working directory if cwd, err := os.Getwd(); err == nil { diff --git a/pkg/cli/mcp_validation.go b/pkg/cli/mcp_validation.go index 0efb9e0663..772c6f49ec 100644 --- a/pkg/cli/mcp_validation.go +++ b/pkg/cli/mcp_validation.go @@ -224,9 +224,12 @@ func validateServerSecrets(config parser.MCPServerConfig, verbose bool, useActio func validateMCPServerConfiguration(cmdPath string) error { mcpValidationLog.Printf("Validating MCP server configuration: cmdPath=%s", cmdPath) - // Determine, log, and validate the binary path - // Note: logAndValidateBinaryPath handles all logging internally - _ = logAndValidateBinaryPath() + // Determine, log, and validate the binary path only if --cmd flag is not provided + // When --cmd is provided, the user explicitly specified the binary path to use + if cmdPath == "" { + // Note: logAndValidateBinaryPath handles all logging internally + _ = logAndValidateBinaryPath() + } // Try to run the status command to verify CLI is working ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) diff --git a/pkg/workflow/mcp_config_builtin.go b/pkg/workflow/mcp_config_builtin.go index 88749737ab..10753adee7 100644 --- a/pkg/workflow/mcp_config_builtin.go +++ b/pkg/workflow/mcp_config_builtin.go @@ -185,7 +185,8 @@ func renderAgenticWorkflowsMCPConfigWithOptions(yaml *strings.Builder, isLast bo if actionMode.IsDev() { // Dev mode: Use locally built Docker image which includes gh-aw binary and gh CLI - // The Dockerfile sets ENTRYPOINT ["gh-aw"] and CMD ["mcp-server", "--cmd", "gh-aw"] + // The Dockerfile sets ENTRYPOINT ["gh-aw"] and CMD ["mcp-server"] + // Binary path is automatically detected via os.Executable() // So we don't need to specify entrypoint or entrypointArgs containerImage = constants.DevModeGhAwImage entrypoint = "" // Use container's default entrypoint From 35b8e5c8e75ce256da5c9b5e7fc774b00f96aa45 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 6 Feb 2026 14:31:17 +0000 Subject: [PATCH 8/9] Fix critical issue: actually use detected binary path - Changed logAndValidateBinaryPath() to return (string, error) instead of error - Assign detected binary path to cmdPath variable when detection succeeds - This ensures createMCPServer receives the actual binary path instead of falling back to "gh aw" - Updated both runMCPServer() and validateMCPServerConfiguration() to use returned path - Added debug log when using detected path - Fixes the issue where binary path was logged but never actually used in subprocess invocations Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- pkg/cli/mcp_server.go | 9 +++++++-- pkg/cli/mcp_validation.go | 20 ++++++++++++-------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/pkg/cli/mcp_server.go b/pkg/cli/mcp_server.go index 5a9daa42cd..a29ea9782a 100644 --- a/pkg/cli/mcp_server.go +++ b/pkg/cli/mcp_server.go @@ -111,8 +111,13 @@ func runMCPServer(port int, cmdPath string) error { // Determine, log, and validate the binary path only if --cmd flag is not provided // When --cmd is provided, the user explicitly specified the binary path to use if cmdPath == "" { - // Note: logAndValidateBinaryPath handles all logging internally - _ = logAndValidateBinaryPath() + // Attempt to detect the binary path and assign it to cmdPath + // This ensures createMCPServer receives the actual binary path instead of falling back to "gh aw" + detectedPath, err := logAndValidateBinaryPath() + if err == nil && detectedPath != "" { + cmdPath = detectedPath + mcpLog.Printf("Using detected binary path: %s", cmdPath) + } } // Log current working directory diff --git a/pkg/cli/mcp_validation.go b/pkg/cli/mcp_validation.go index 772c6f49ec..9aeeacad0f 100644 --- a/pkg/cli/mcp_validation.go +++ b/pkg/cli/mcp_validation.go @@ -46,14 +46,14 @@ func GetBinaryPath() (string, error) { } // logAndValidateBinaryPath determines the binary path, logs it, and validates it exists. -// Returns an error if the binary path cannot be determined or if the file doesn't exist. +// Returns the detected binary path and an error if the path cannot be determined or if the file doesn't exist. // This is a helper used by both runMCPServer and validateMCPServerConfiguration. -func logAndValidateBinaryPath() error { +func logAndValidateBinaryPath() (string, error) { binaryPath, err := GetBinaryPath() if err != nil { mcpValidationLog.Printf("Warning: failed to get binary path: %v", err) fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("Warning: failed to get binary path: %v", err))) - return err + return "", err } // Check if the binary file exists @@ -61,17 +61,17 @@ func logAndValidateBinaryPath() error { if os.IsNotExist(err) { mcpValidationLog.Printf("ERROR: binary file does not exist at path: %s", binaryPath) fmt.Fprintln(os.Stderr, console.FormatErrorMessage(fmt.Sprintf("ERROR: binary file does not exist at path: %s", binaryPath))) - return fmt.Errorf("binary file does not exist at path: %s", binaryPath) + return "", fmt.Errorf("binary file does not exist at path: %s", binaryPath) } mcpValidationLog.Printf("Warning: failed to stat binary file at %s: %v", binaryPath, err) fmt.Fprintln(os.Stderr, console.FormatWarningMessage(fmt.Sprintf("Warning: failed to stat binary file at %s: %v", binaryPath, err))) - return err + return "", err } // Log the binary path for debugging mcpValidationLog.Printf("gh-aw binary path: %s", binaryPath) fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("gh-aw binary path: %s", binaryPath))) - return nil + return binaryPath, nil } // validateServerSecrets checks if required environment variables/secrets are available @@ -227,8 +227,12 @@ func validateMCPServerConfiguration(cmdPath string) error { // Determine, log, and validate the binary path only if --cmd flag is not provided // When --cmd is provided, the user explicitly specified the binary path to use if cmdPath == "" { - // Note: logAndValidateBinaryPath handles all logging internally - _ = logAndValidateBinaryPath() + // Attempt to detect the binary path and assign it to cmdPath + // This ensures the validation uses the actual binary path instead of falling back to "gh aw" + detectedPath, err := logAndValidateBinaryPath() + if err == nil && detectedPath != "" { + cmdPath = detectedPath + } } // Try to run the status command to verify CLI is working From 56d50f0200f75a6bb0c9a54861174baf90e8980a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 6 Feb 2026 14:36:00 +0000 Subject: [PATCH 9/9] Add changeset [skip-ci] --- .changeset/patch-stop-404-discussion-retries.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/patch-stop-404-discussion-retries.md diff --git a/.changeset/patch-stop-404-discussion-retries.md b/.changeset/patch-stop-404-discussion-retries.md new file mode 100644 index 0000000000..e879009549 --- /dev/null +++ b/.changeset/patch-stop-404-discussion-retries.md @@ -0,0 +1,5 @@ +--- +"gh-aw": patch +--- + +Handle 404s from `add_comment` by warning instead of retrying the request as a discussion so deleted targets are skipped cleanly.