Skip to content

Add binary path detection for MCP server self-invocation#14140

Merged
pelikhan merged 9 commits intomainfrom
copilot/add-logic-for-gh-aw-binary
Feb 6, 2026
Merged

Add binary path detection for MCP server self-invocation#14140
pelikhan merged 9 commits intomainfrom
copilot/add-logic-for-gh-aw-binary

Conversation

Copy link
Contributor

Copilot AI commented Feb 6, 2026

Add Dynamic Binary Path Detection in MCP Server ✅

Implementation Complete

This PR implements dynamic binary path detection in the MCP server, addressing the requirement to determine the path to the gh-aw binary from the currently running Go binary.

Changes Made

  1. Added GetBinaryPath() function in pkg/cli/mcp_validation.go:

    • Uses os.Executable() to get current binary path
    • Resolves symlinks with filepath.EvalSymlinks() (important for gh extensions)
    • Returns absolute path (EvalSymlinks already returns absolute path)
    • Handles errors gracefully with warnings
  2. Added logAndValidateBinaryPath() helper in pkg/cli/mcp_validation.go:

    • Centralizes binary path validation logic
    • Logs the binary path for debugging
    • Checks if binary file exists at runtime
    • Displays appropriate errors/warnings with console formatting
    • Returns the detected path (string, error) so it can be used
    • Eliminates code duplication
    • Handles all logging internally (no duplicate logs)
  3. Updated runMCPServer() in pkg/cli/mcp_server.go:

    • Calls logAndValidateBinaryPath() at startup only when --cmd flag is not provided
    • Assigns detected path to cmdPath so createMCPServer uses the actual binary
    • When --cmd is provided, skips auto-detection (user explicitly specified path)
    • Added debug log when using detected path
  4. Updated validateMCPServerConfiguration() in pkg/cli/mcp_validation.go:

    • Calls logAndValidateBinaryPath() only when --cmd flag is not provided
    • Assigns detected path to cmdPath for validation
    • Consistent with runMCPServer() behavior
  5. Updated Dockerfile:

    • Removed --cmd gh-aw from CMD line
    • Now uses: CMD ["mcp-server"] (binary path auto-detected via os.Executable())
    • Comment explains automatic binary path detection
  6. Updated mcp_config_builtin.go:

    • Comment correctly reflects new Dockerfile CMD without --cmd argument
    • Clarifies that binary path is automatically detected via os.Executable()
  7. Comprehensive test coverage in pkg/cli/mcp_validation_test.go:

    • Tests binary path is non-empty
    • Tests path is absolute
    • Tests file exists at returned path
    • Tests path has valid base name
    • Tests symlinks are properly resolved
    • All tests pass

Critical Fix Applied

Previous Issue: Binary path was detected and logged but never actually used. The createMCPServer function would still fall back to calling "gh aw" via workflow.ExecGHContext(), which doesn't work in Docker containers where gh-aw isn't installed as a gh extension.

Fix: The detected binary path is now assigned to the cmdPath variable, ensuring createMCPServer receives and uses the actual binary path in subprocess invocations (exec.CommandContext(ctx, cmdPath, args...)).

Manual Testing

Without --cmd flag (auto-detection enabled and used):

ℹ gh-aw binary path: /home/runner/work/gh-aw/gh-aw/gh-aw
ℹ Current working directory: /home/runner/work/gh-aw/gh-aw
ℹ gh CLI: gh version 2.86.0 (2026-01-21)
✓ ✅ Configuration validated successfully

The detected path (/home/runner/work/gh-aw/gh-aw/gh-aw) is now used by createMCPServer.

With --cmd flag (auto-detection skipped):

ℹ Current working directory: /home/runner/work/gh-aw/gh-aw
ℹ gh CLI: gh version 2.86.0 (2026-01-21)
✓ ✅ Configuration validated successfully

Binary path detection is skipped, user-provided path is used.

Why These Changes

The MCP server needs to know where the gh-aw binary is located when launching itself with different arguments. This is particularly important for:

  • Docker container environments where the binary is mounted at specific paths
  • gh CLI extension installations where symlinks are involved
  • Debugging and troubleshooting MCP server issues

When the user provides --cmd, they explicitly specify the binary path, so automatic detection is unnecessary and should be skipped.

Code Quality

  • ✅ All unit tests pass
  • ✅ Linting passes (0 issues)
  • ✅ Formatting validated
  • ✅ Manual testing confirms correct behavior (with and without --cmd flag)
  • ✅ All code review feedback addressed
  • ✅ Critical issue fixed: detected path is now actually used
  • ✅ No code duplication
  • ✅ Clear, maintainable implementation

Ready for Merge

Original prompt

Add logic in MCP-server to determine the path to the gh-aw binary from the current running go binary (the MCP-server is launching itself with other args).

Log value, add runtime check file exists in startup path.


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.


Changeset

  • Type: patch
  • Description: Treat 404s from add_comment as warnings instead of retrying the request as a discussion when the target is gone.

Generated by Changeset Generator

Copilot AI and others added 5 commits February 6, 2026 13:42
- 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>
- Changed assert.NoError to require.NoError for error assertions
- Complies with testifylint requirements

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
- 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>
- 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>
- 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>
Copilot AI changed the title [WIP] Add logic to determine path to gh-aw binary Add binary path detection for MCP server self-invocation Feb 6, 2026
Copilot AI requested a review from pelikhan February 6, 2026 13:58
@pelikhan
Copy link
Contributor

pelikhan commented Feb 6, 2026

@copilot

  • skip this detection if --cmd is provided

  • remove --cmd args from arguments to setup agentic-woriflows tool MCP server configuration

- 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>
Copy link
Contributor Author

Copilot AI commented Feb 6, 2026

@copilot

  • skip this detection if --cmd is provided...

Done in commit 56eb2d4:

  1. Skip detection when --cmd provided: Binary path detection now only runs when cmdPath is empty. When --cmd is provided, auto-detection is skipped in both runMCPServer() and validateMCPServerConfiguration().

  2. Removed --cmd from Dockerfile: Updated CMD ["mcp-server"] (removed "--cmd", "gh-aw"). Binary path is now automatically detected via os.Executable().

Behavior:

  • Without --cmd: Binary path logged twice (startup + validation)
  • With --cmd: Binary path not logged (user explicitly specified path)

@pelikhan pelikhan added the smoke label Feb 6, 2026
@pelikhan pelikhan marked this pull request as ready for review February 6, 2026 14:15
Copilot AI review requested due to automatic review settings February 6, 2026 14:15
@github-actions
Copy link
Contributor

github-actions bot commented Feb 6, 2026

📰 BREAKING: Smoke Copilot is now investigating this pull request. Sources say the story is developing...

@github-actions
Copy link
Contributor

github-actions bot commented Feb 6, 2026

🌑 The shadows whisper... Smoke Codex failed. The oracle requires further meditation...

@github-actions
Copy link
Contributor

github-actions bot commented Feb 6, 2026

Changeset Generator failed. Please review the logs for details.

@github-actions
Copy link
Contributor

github-actions bot commented Feb 6, 2026

🎬 THE ENDSmoke Claude MISSION: ACCOMPLISHED! The hero saves the day! ✨

@github-actions
Copy link
Contributor

github-actions bot commented Feb 6, 2026

Agent Container Tool Check

Tool Status Version
bash 5.2.21
sh available
git 2.52.0
jq 1.7
yq 4.50.1
curl 8.5.0
gh 2.86.0
node 20.20.0
python3 3.12.3
go 1.24.12
java not found
dotnet not found

Result: 10/12 tools available ❌

Missing tools:

  • java - Java runtime not available
  • dotnet - .NET runtime not available

AI generated by Agent Container Smoke Test

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This pull request adds binary path detection for the MCP server to support Docker container mounts and gh CLI extension symlinks. However, there is a critical implementation issue: while the binary path is successfully detected and logged, it is never actually used to invoke subprocesses, rendering the feature non-functional.

Changes:

  • Added GetBinaryPath() function to detect the currently running binary path with symlink resolution
  • Added logAndValidateBinaryPath() helper for validation and logging
  • Integrated binary path detection into runMCPServer() and validateMCPServerConfiguration()
  • Removed --cmd gh-aw from Dockerfile CMD to rely on automatic detection
  • Added comprehensive unit tests for GetBinaryPath()

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
pkg/cli/mcp_validation.go Implements GetBinaryPath() and logAndValidateBinaryPath() functions, but doesn't return the detected path for use
pkg/cli/mcp_validation_test.go Comprehensive unit tests for GetBinaryPath() covering symlink resolution, absolute paths, and file existence
pkg/cli/mcp_server.go Calls logAndValidateBinaryPath() when cmdPath is empty but doesn't assign the detected path to cmdPath
Dockerfile Removes --cmd flag from CMD, expecting automatic detection (but detection isn't actually used)
pkg/workflow/mcp_config_builtin.go Updates comment claiming automatic detection works (but it doesn't)
Comments suppressed due to low confidence (1)

pkg/cli/mcp_validation.go:75

  • The function should return the binary path in addition to the error, so that callers can actually use the detected path. Currently, the function only logs and validates the path but doesn't return it, making it impossible for callers to use the detected value.

Consider changing the function signature to:

func logAndValidateBinaryPath() (string, error)

And updating the implementation to:

return binaryPath, nil  // at the end instead of return 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
}

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


// 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 == "" {
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

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

The binary path is determined and logged, but never actually used. When cmdPath is empty, createMCPServer(cmdPath) receives an empty string and falls back to calling "gh aw" via workflow.ExecGHContext(), which won't work in Docker containers where gh-aw isn't installed as a gh extension.

The detected binary path should be assigned to cmdPath when it's empty. Consider modifying the code to:

if cmdPath == "" {
    detectedPath, err := GetBinaryPath()
    if err == nil {
        cmdPath = detectedPath
    }
    // Note: logAndValidateBinaryPath handles all logging internally
    _ = logAndValidateBinaryPath()
}

This would ensure that createMCPServer(cmdPath) receives the actual binary path and uses it in exec.CommandContext(ctx, cmdPath, args...) instead of falling back to "gh aw".

Suggested change
if cmdPath == "" {
if cmdPath == "" {
// Attempt to detect the binary path and assign it to cmdPath
if detectedPath, err := GetBinaryPath(); err == nil && detectedPath != "" {
cmdPath = detectedPath
}

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed in commit 35b8e5c. The detected binary path is now assigned to cmdPath when detection succeeds, ensuring createMCPServer receives and uses the actual binary path instead of falling back to "gh aw".

Comment on lines 230 to 231
// Note: logAndValidateBinaryPath handles all logging internally
_ = logAndValidateBinaryPath()
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

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

Similar to the issue in runMCPServer, the binary path is logged but never used. When cmdPath is empty, the validateMCPServerConfiguration function should use the detected binary path for validation instead of falling back to "gh aw" which won't work in environments where gh-aw isn't installed as a gh extension.

Consider returning the detected path from logAndValidateBinaryPath() and using it:

if cmdPath == "" {
    detectedPath, err := logAndValidateBinaryPath()
    if err == nil {
        cmdPath = detectedPath
    }
}

Then update the function signature:

func logAndValidateBinaryPath() (string, error)
Suggested change
// Note: logAndValidateBinaryPath handles all logging internally
_ = logAndValidateBinaryPath()
// Note: logAndValidateBinaryPath handles all logging internally and returns the detected path
detectedPath, err := logAndValidateBinaryPath()
if err == nil && detectedPath != "" {
cmdPath = detectedPath
}

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed in commit 35b8e5c. Updated logAndValidateBinaryPath() to return (string, error) and assign the detected path to cmdPath for validation.

Comment on lines +189 to 190
// Binary path is automatically detected via os.Executable()
// So we don't need to specify entrypoint or entrypointArgs
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

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

This comment is misleading because the binary path is currently only logged but not actually used. The MCP server still falls back to calling "gh aw" when cmdPath is empty (see createMCPServer function in mcp_server.go line 159-160), which means the automatic detection doesn't actually work as described.

The comment should be updated to reflect the actual behavior once the binary path detection is properly wired up to be used by the MCP server.

Suggested change
// Binary path is automatically detected via os.Executable()
// So we don't need to specify entrypoint or entrypointArgs
// Note: while the gh-aw binary path may be detected (e.g., via os.Executable()),
// it is currently only logged and not used to override the MCP server command.
// In dev mode we rely on the container's default ENTRYPOINT and CMD instead.

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed in commit 35b8e5c. The comment is now accurate - the binary path is actually used by the MCP server via the cmdPath variable passed to createMCPServer.

Comment on lines +35 to +36
# Note: Binary path detection is automatic via os.Executable()
CMD ["mcp-server"]
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

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

This comment is misleading for the same reason as the comment in mcp_config_builtin.go - the binary path is only logged but not actually used. The MCP server still needs the --cmd flag to be explicitly set, or it will fall back to calling "gh aw" which won't work in Docker.

The comment should be updated once the binary path detection is properly implemented to actually use the detected path.

See below for a potential fix:

# Default command runs MCP server. Note: the MCP server still requires an explicit
# --cmd flag to be set; otherwise it falls back to calling "gh aw", which will not
# work correctly inside this Docker image. Update this comment once binary path
# detection is fully wired to use the detected path.

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed in commit 35b8e5c. The comment is now accurate - the binary path detection is fully wired up to use the detected path via the cmdPath variable.

@github-actions
Copy link
Contributor

github-actions bot commented Feb 6, 2026

🎭 The smoke test agent was here! 🎭

Testing, testing... 1, 2, 3! 🎤 Just your friendly neighborhood automation bot stopping by to make sure all the MCP servers are playing nicely together. Everything's looking good from my corner of the digital universe! ✨

Beep boop 🤖 Back to the testing mines I go!

AI generated by Smoke Copilot

@github-actions
Copy link
Contributor

github-actions bot commented Feb 6, 2026

Smoke Test Results

PR #14150: [WIP] Remove .github/aw/github-agentic-workflows.md from init command
PR #14149: [WIP] Add flags for binding agent execution to engine front matter

✅ GitHub MCP Testing
✅ Safe Inputs GH CLI Testing
✅ Serena MCP Testing
✅ Playwright Testing
✅ File Writing Testing
✅ Bash Tool Testing
✅ Discussion Interaction Testing
✅ Build gh-aw
✅ Workflow Dispatch Testing

Overall Status: PASS

cc @pelikhan @Copilot

AI generated by Smoke Copilot

@github-actions
Copy link
Contributor

github-actions bot commented Feb 6, 2026

📰 VERDICT: Smoke Copilot has concluded. All systems operational. This is a developing story. 🎤

@github-actions
Copy link
Contributor

github-actions bot commented Feb 6, 2026

Smoke Test: Claude - PASS ✅

Test Status
✅ GitHub MCP Last 2 merged PRs: #14147, #14139
✅ Safe Inputs GH CLI Queried 2 PRs: #14150, #14149
✅ Serena MCP Activated project, found 186 symbols
✅ Make Build Built gh-aw v56eb2d46
✅ Playwright Navigated to GitHub.com
✅ Tavily Search Found 5 results for "GitHub Agentic Workflows"
✅ File Writing Created smoke test file
✅ Bash Tool Verified file creation
✅ Discussion Comment Added comment to #14148
✅ Agentic Workflows MCP Queried smoke-claude status

Overall: PASS

Run §21753638108

AI generated by Smoke Claude

@pelikhan
Copy link
Contributor

pelikhan commented Feb 6, 2026

@copilot review comments carefully and fix code

- 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>
Copy link
Contributor Author

Copilot AI commented Feb 6, 2026

@copilot review comments carefully and fix code

All review comments addressed in commit 35b8e5c. The critical issue has been fixed - the detected binary path is now actually used instead of just being logged.

@github-actions
Copy link
Contributor

github-actions bot commented Feb 6, 2026

🎬 THE ENDSmoke Claude MISSION: ACCOMPLISHED! The hero saves the day! ✨

@github-actions
Copy link
Contributor

github-actions bot commented Feb 6, 2026

Changeset Generator completed successfully!

@github-actions
Copy link
Contributor

github-actions bot commented Feb 6, 2026

🌑 The shadows whisper... Smoke Codex failed. The oracle requires further meditation...

@github-actions
Copy link
Contributor

github-actions bot commented Feb 6, 2026

📰 BREAKING: Smoke Copilot is now investigating this pull request. Sources say the story is developing...

@github-actions
Copy link
Contributor

github-actions bot commented Feb 6, 2026

Agent Container Tool Check

Tool Status Version
bash 5.2.21
sh available
git 2.52.0
jq 1.7
yq 4.52.2
curl 8.5.0
gh 2.86.0
node 20.20.0
python3 3.12.3
go 1.24.12
java CRITICAL: System-level execution issue
dotnet CRITICAL: System-level execution issue

Result: 10/12 tools available ⚠️

Critical Issues Found

Java and .NET runtimes are experiencing severe system-level execution failures:

  • Both java and dotnet ELF binaries execute as bash instead of their actual programs
  • Issue persists even when:
    • Using absolute paths (/opt/hostedtoolcache/.../java, /usr/share/dotnet/dotnet)
    • Invoking via dynamic linker directly (/lib64/ld-linux-x86-64.so.2)
    • Running in new shell contexts (sh -c)
    • Using env to bypass shell configuration
  • ELF magic bytes and file types are correct
  • Dynamic linker dependencies are intact
  • No shell aliases or functions are interfering

This suggests a fundamental system-level process execution problem, possibly:

  • Compromised kernel execution paths
  • Container runtime issue
  • Corrupted process execution handlers
  • Security policy interfering with exec syscalls

Recommendation: This requires immediate investigation of the container image and runner environment. The 10 working tools demonstrate the container is functional, but Java and .NET execution paths are critically broken.

AI generated by Agent Container Smoke Test

@github-actions
Copy link
Contributor

github-actions bot commented Feb 6, 2026

Smoke Test PASS - Run 21754229163

PRs Tested: #14154, #14151
✅ GitHub MCP
✅ Safe Inputs GH CLI
✅ Serena MCP
✅ Playwright
✅ File Write/Read
✅ Discussion Comment
✅ Build gh-aw
✅ Haiku Dispatch

@pelikhan All tests passed!

AI generated by Smoke Copilot

@github-actions github-actions bot removed the smoke label Feb 6, 2026
@github-actions
Copy link
Contributor

github-actions bot commented Feb 6, 2026

📰 VERDICT: Smoke Copilot has concluded. All systems operational. This is a developing story. 🎤

@pelikhan pelikhan merged commit 384756b into main Feb 6, 2026
1 check passed
@pelikhan pelikhan deleted the copilot/add-logic-for-gh-aw-binary branch February 6, 2026 14:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants