Skip to content
Closed
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
14 changes: 14 additions & 0 deletions .changeset/patch-replace-awmg-with-gh-aw-mcpg.md

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

4 changes: 1 addition & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,6 @@ clean:
@echo "Cleaning build artifacts..."
@# Remove main binary and platform-specific binaries
rm -f $(BINARY_NAME) $(BINARY_NAME)-*
rm -f $(AWMG_BINARY_NAME) $(AWMG_BINARY_NAME)-*
@# Remove bundle-js binary
rm -f bundle-js
@# Remove coverage files
Expand Down Expand Up @@ -563,8 +562,7 @@ agent-finish: deps-dev fmt lint build test-all fix recompile dependabot generate
help:
@echo "Available targets:"
@echo " build - Build the binary for current platform"
@echo " build-awmg - Build the awmg (MCP gateway) binary for current platform"
@echo " build-all - Build binaries for all platforms (gh-aw and awmg)"
@echo " build-all - Build binaries for all platforms"
@echo " test - Run Go tests (unit + integration)"
@echo " test-unit - Run Go unit tests only (faster)"
@echo " test-security - Run security regression tests"
Expand Down
118 changes: 76 additions & 42 deletions actions/setup/sh/verify_mcp_gateway_health.sh
Original file line number Diff line number Diff line change
@@ -1,30 +1,32 @@
#!/usr/bin/env bash
# Verify MCP Gateway Health
# This script verifies that the MCP gateway is running and healthy
# Verify MCP Gateway (gh-aw-mcpg) Health
# This script verifies that the gh-aw-mcpg gateway is running and healthy

set -e

# Usage: verify_mcp_gateway_health.sh GATEWAY_URL MCP_CONFIG_PATH LOGS_FOLDER
# Usage: verify_mcp_gateway_health.sh GATEWAY_URL MCP_CONFIG_PATH LOGS_FOLDER [SESSION_TOKEN]
#
# Arguments:
# GATEWAY_URL : The HTTP URL of the MCP gateway (e.g., http://localhost:8080)
# GATEWAY_URL : The HTTP URL of the MCP gateway (e.g., http://localhost:80)
# MCP_CONFIG_PATH : Path to the MCP configuration file
# LOGS_FOLDER : Path to the gateway logs folder
# SESSION_TOKEN : Bearer token for MCP client auth (optional, defaults to awf-session)
#
# Exit codes:
# 0 - Gateway is healthy and ready
# 1 - Gateway failed to start or configuration is invalid

if [ "$#" -ne 3 ]; then
echo "Usage: $0 GATEWAY_URL MCP_CONFIG_PATH LOGS_FOLDER" >&2
if [ "$#" -lt 3 ]; then
echo "Usage: $0 GATEWAY_URL MCP_CONFIG_PATH LOGS_FOLDER [SESSION_TOKEN]" >&2
exit 1
fi

gateway_url="$1"
mcp_config_path="$2"
logs_folder="$3"
session_token="${4:-awf-session}"

echo 'Waiting for MCP Gateway to be ready...'
echo 'Verifying gh-aw-mcpg (MCP Gateway) health...'
echo ''
echo '=== File Locations ==='
echo "Gateway URL: $gateway_url"
Expand All @@ -37,14 +39,26 @@ echo ''
echo '=== Gateway Logs Check ==='
if [ -f "${logs_folder}/gateway.log" ]; then
echo "✓ Gateway log file exists at: ${logs_folder}/gateway.log"
echo "Log file size: $(stat -f%z "${logs_folder}/gateway.log" 2>/dev/null || stat -c%s "${logs_folder}/gateway.log" 2>/dev/null || echo 'unknown') bytes"
echo "Log file size: $(stat -c%s "${logs_folder}/gateway.log" 2>/dev/null || stat -f%z "${logs_folder}/gateway.log" 2>/dev/null || echo 'unknown') bytes"
echo "Last few lines of gateway log:"
tail -10 "${logs_folder}/gateway.log" 2>/dev/null || echo "Could not read log tail"
else
echo "⚠ Gateway log file NOT found at: ${logs_folder}/gateway.log"
fi
echo ''

# Check if gh-aw-mcpg container is running
echo '=== Docker Container Check ==='
if docker ps | grep -q gh-aw-mcpg; then
Copy link

Copilot AI Jan 6, 2026

Choose a reason for hiding this comment

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

The grep command on line 52 has a potential issue: it will match any container whose name contains "gh-aw-mcpg" anywhere in the output, not just the container name field. For example, it could match a container with an image name or other field containing that string.

Consider using docker ps with --filter "name=gh-aw-mcpg" directly in the condition instead of piping to grep, which would be more precise and avoid potential false positives. For example:

if docker ps --filter "name=gh-aw-mcpg" --format "{{.Names}}" | grep -q "^gh-aw-mcpg$"; then

This ensures an exact match on the container name.

Suggested change
if docker ps | grep -q gh-aw-mcpg; then
if docker ps --filter "name=gh-aw-mcpg" --format "{{.Names}}" | grep -q "^gh-aw-mcpg$"; then

Copilot uses AI. Check for mistakes.
echo "✓ gh-aw-mcpg container is running"
docker ps --filter "name=gh-aw-mcpg" --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
else
echo "⚠ gh-aw-mcpg container not found in running containers"
echo "Available containers:"
docker ps --format "table {{.Names}}\t{{.Status}}"
fi
echo ''

# Wait for gateway to be ready FIRST before checking config
echo '=== Testing Gateway Health ==='
max_retries=30
Expand All @@ -66,7 +80,10 @@ if [ "$gateway_ready" = false ]; then
echo "✗ Error: MCP Gateway failed to start after $max_retries attempts"
echo ''
echo '=== Gateway Logs (Full) ==='
cat "${logs_folder}/gateway.log" || echo 'No gateway logs found'
cat "${logs_folder}/gateway.log" 2>/dev/null || echo 'No gateway logs found'
echo ''
echo '=== Docker Logs ==='
docker logs gh-aw-mcpg 2>&1 || echo 'Could not get docker logs'
exit 1
fi
echo ''
Expand All @@ -75,8 +92,8 @@ echo ''
echo '=== MCP Configuration File ==='
if [ -f "$mcp_config_path" ]; then
echo "✓ Config file exists at: $mcp_config_path"
echo "File size: $(stat -f%z "$mcp_config_path" 2>/dev/null || stat -c%s "$mcp_config_path" 2>/dev/null || echo 'unknown') bytes"
echo "Last modified: $(stat -f%Sm "$mcp_config_path" 2>/dev/null || stat -c%y "$mcp_config_path" 2>/dev/null || echo 'unknown')"
echo "File size: $(stat -c%s "$mcp_config_path" 2>/dev/null || stat -f%z "$mcp_config_path" 2>/dev/null || echo 'unknown') bytes"
echo "Last modified: $(stat -c%y "$mcp_config_path" 2>/dev/null || stat -f%Sm "$mcp_config_path" 2>/dev/null || echo 'unknown')"
else
echo "✗ Config file NOT found at: $mcp_config_path"
exit 1
Expand All @@ -88,64 +105,79 @@ echo '=== MCP Configuration Content ==='
cat "$mcp_config_path" || { echo 'ERROR: Failed to read MCP config file'; exit 1; }
echo ''

# Verify safeinputs and safeoutputs are present in config
# Verify required servers are present in config (if applicable)
echo '=== Verifying Required Servers ==='
if ! grep -q '"safeinputs"' "$mcp_config_path"; then
echo '✗ ERROR: safeinputs server not found in MCP configuration'
exit 1
# Check for safeinputs and safeoutputs if they're expected
if grep -q '"safeinputs"' "$mcp_config_path" 2>/dev/null; then
echo '✓ safeinputs server found in configuration'
else
echo '⚠ safeinputs server not found (may not be required)'
fi
echo '✓ safeinputs server found in configuration'

if ! grep -q '"safeoutputs"' "$mcp_config_path"; then
echo '✗ ERROR: safeoutputs server not found in MCP configuration'
exit 1
if grep -q '"safeoutputs"' "$mcp_config_path" 2>/dev/null; then
echo '✓ safeoutputs server found in configuration'
else
echo '⚠ safeoutputs server not found (may not be required)'
fi
echo '✓ safeoutputs server found in configuration'
echo ''

# Fetch and display gateway servers list
echo '=== Gateway Servers List ==='
echo "Fetching servers from: ${gateway_url}/servers"
curl -s "${gateway_url}/servers" || echo "✗ Could not fetch servers list"
# List registered MCP servers via sys endpoint
echo '=== Gateway MCP System Info ==='
echo "Querying: ${gateway_url}/mcp/sys"
sys_response=$(curl -sf "${gateway_url}/mcp/sys" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${session_token}" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"list_servers","arguments":{}}}' 2>/dev/null) || true

if [ -n "$sys_response" ]; then
echo "Response:"
echo "$sys_response" | jq -r '.result.content[0].text' 2>/dev/null || echo "$sys_response"
else
echo "⚠ Could not query sys endpoint (this may be expected if sys server is not configured)"
fi
echo ''

# Test MCP server connectivity through gateway
echo '=== Testing MCP Server Connectivity ==='

# Extract first external MCP server name from config (excluding safeinputs/safeoutputs)
mcp_server=$(jq -r '.mcpServers | to_entries[] | select(.key != "safeinputs" and .key != "safeoutputs") | .key' "$mcp_config_path" | head -n 1)
# Extract first MCP server name from config (excluding safeinputs/safeoutputs)
mcp_server=$(jq -r '.mcpServers | to_entries[] | select(.key != "safeinputs" and .key != "safeoutputs") | .key' "$mcp_config_path" 2>/dev/null | head -n 1) || true

if [ -n "$mcp_server" ]; then
echo "Testing connectivity to MCP server: $mcp_server"
mcp_url="${gateway_url}/mcp/${mcp_server}"
echo "MCP URL: $mcp_url"
echo ''

# Check if server was rewritten in config
echo "Checking if '$mcp_server' was rewritten to use gateway..."
server_config=$(jq -r ".mcpServers.\"$mcp_server\"" "$mcp_config_path")
echo "Server config for '$mcp_server':"
echo "$server_config" | jq '.' 2>/dev/null || echo "$server_config"

if echo "$server_config" | grep -q "gateway"; then
echo "✓ Server appears to be configured for gateway"
else
echo "⚠ Server may not be configured for gateway (no 'gateway' field found)"

# Check if server config uses HTTP transport (gateway-proxied)
echo "Checking '$mcp_server' configuration..."
server_config=$(jq -r ".mcpServers.\"$mcp_server\"" "$mcp_config_path" 2>/dev/null) || true
if [ -n "$server_config" ]; then
echo "Server config:"
echo "$server_config" | jq '.' 2>/dev/null || echo "$server_config"

if echo "$server_config" | grep -q '"type": "http"' 2>/dev/null; then
echo "✓ Server is configured for HTTP transport (gateway-proxied)"
else
echo "⚠ Server may use local transport (not gateway-proxied)"
fi
fi
echo ''

# Test with MCP initialize call
echo "Sending MCP initialize request..."
response=$(curl -s -w "\n%{http_code}" -X POST "$mcp_url" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0.0"}}}')

-H "Authorization: Bearer ${session_token}" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0.0"}}}' 2>/dev/null) || true

http_code=$(echo "$response" | tail -n 1)
body=$(echo "$response" | head -n -1)

echo "HTTP Status: $http_code"
echo "Response: $body"
echo ''

if [ "$http_code" = "200" ]; then
echo "✓ MCP server connectivity test passed"
else
Expand All @@ -158,4 +190,6 @@ else
echo "No external MCP servers configured for testing"
fi

echo ''
echo '=== Health Check Complete ==='
exit 0
10 changes: 10 additions & 0 deletions pkg/workflow/claude_engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,13 +235,23 @@ func (e *ClaudeEngine) GetExecutionSteps(workflowData *WorkflowData, logFile str
// Check if safe-inputs is enabled to include host.docker.internal in allowed domains
hasSafeInputs := IsSafeInputsEnabled(workflowData.SafeInputs, workflowData)

// Check if MCP gateway is enabled
hasMCPGateway := IsMCPGatewayEnabled(workflowData)

// Get allowed domains (Claude defaults + network permissions + host.docker.internal if safe-inputs enabled)
allowedDomains := GetClaudeAllowedDomainsWithSafeInputs(workflowData.NetworkPermissions, hasSafeInputs)

// Build AWF arguments: mount points + standard flags + custom args from config
var awfArgs []string
awfArgs = append(awfArgs, "--env-all")

// Add --enable-host-access when MCP gateway is enabled
// This allows AWF containers to reach gh-aw-mcpg running on the host
if hasMCPGateway {
awfArgs = append(awfArgs, "--enable-host-access")
claudeLog.Print("Added --enable-host-access for MCP gateway access")
}

// TTY is required for Claude Code CLI
awfArgs = append(awfArgs, "--tty")

Expand Down
10 changes: 10 additions & 0 deletions pkg/workflow/codex_engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,10 +156,20 @@ func (e *CodexEngine) GetExecutionSteps(workflowData *WorkflowData, logFile stri
// Get allowed domains (Codex defaults + network permissions)
allowedDomains := GetCodexAllowedDomains(workflowData.NetworkPermissions)

// Check if MCP gateway is enabled
hasMCPGateway := IsMCPGatewayEnabled(workflowData)

// Build AWF arguments: mount points + standard flags + custom args from config
var awfArgs []string
awfArgs = append(awfArgs, "--env-all")

// Add --enable-host-access when MCP gateway is enabled
// This allows AWF containers to reach gh-aw-mcpg running on the host
if hasMCPGateway {
awfArgs = append(awfArgs, "--enable-host-access")
codexEngineLog.Print("Added --enable-host-access for MCP gateway access")
}

// Set container working directory to match GITHUB_WORKSPACE
awfArgs = append(awfArgs, "--container-workdir", "\"${GITHUB_WORKSPACE}\"")
codexEngineLog.Print("Set container working directory to GITHUB_WORKSPACE")
Expand Down
10 changes: 10 additions & 0 deletions pkg/workflow/copilot_engine_execution.go
Original file line number Diff line number Diff line change
Expand Up @@ -225,13 +225,23 @@ func (e *CopilotEngine) GetExecutionSteps(workflowData *WorkflowData, logFile st
// Check if safe-inputs is enabled to include host.docker.internal in allowed domains
hasSafeInputs := IsSafeInputsEnabled(workflowData.SafeInputs, workflowData)

// Check if MCP gateway is enabled
hasMCPGateway := IsMCPGatewayEnabled(workflowData)

// Get allowed domains (copilot defaults + network permissions + host.docker.internal if safe-inputs enabled)
allowedDomains := GetCopilotAllowedDomainsWithSafeInputs(workflowData.NetworkPermissions, hasSafeInputs)

// Build AWF arguments: mount points + standard flags + custom args from config
var awfArgs []string
awfArgs = append(awfArgs, "--env-all")

// Add --enable-host-access when MCP gateway is enabled
// This allows AWF containers to reach gh-aw-mcpg running on the host
if hasMCPGateway {
awfArgs = append(awfArgs, "--enable-host-access")
copilotExecLog.Print("Added --enable-host-access for MCP gateway access")
}
Comment on lines 225 to +243
Copy link

Copilot AI Jan 6, 2026

Choose a reason for hiding this comment

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

There's an inconsistency in how MCP gateway access is enabled for different engines. The Copilot and Claude engines check hasMCPGateway to add --enable-host-access (lines 228-243 in copilot_engine_execution.go and 238-253 in claude_engine.go), but the allowed domains calculation still relies only on hasSafeInputs parameter via GetCopilotAllowedDomainsWithSafeInputs/GetClaudeAllowedDomainsWithSafeInputs.

While host.docker.internal is now in the default domains, the logic should be consistent: if we're checking hasMCPGateway for --enable-host-access, we should also consider it when calculating domains or document why the MCP gateway check is separate from domain configuration.

Copilot uses AI. Check for mistakes.

// Set container working directory to match GITHUB_WORKSPACE
// This ensures pwd inside the container matches what the prompt tells the AI
awfArgs = append(awfArgs, "--container-workdir", "\"${GITHUB_WORKSPACE}\"")
Expand Down
1 change: 1 addition & 0 deletions pkg/workflow/domains.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ var CopilotDefaultDomains = []string{
// CodexDefaultDomains are the minimal default domains required for Codex CLI operation
var CodexDefaultDomains = []string{
"api.openai.com",
"host.docker.internal",
"openai.com",
}

Expand Down
Loading