How the MCP Gateway Routes Model Context Protocol Server Calls in GitHub Actions Workflows
The MCP Gateway is a container-based proxy that unifies all MCP server endpoints behind a single HTTP interface, routing requests to HTTP, stdio, or remote servers based on a JSON configuration generated during workflow compilation.
The github/gh-aw repository implements this gateway to centralize authentication and network isolation for Model Context Protocol (MCP) integrations. When an agentic workflow runs, the gateway receives a single JSON payload containing all server definitions and exposes a unified endpoint that translates incoming HTTP requests to the appropriate backend protocol.
Gateway Configuration and Rendering
The routing configuration begins in pkg/workflow/mcp_renderer.go, where the unified renderer injects a top-level gateway object into the MCP JSON configuration. This object defines the port, domain, API key, and optional payload directory that the gateway container will use to listen for incoming requests.
// From pkg/workflow/mcp_renderer.go
gatewayConfig := map[string]interface{}{
"port": "$MCP_GATEWAY_PORT",
"domain": "host.docker.internal",
"apiKey": "$MCP_GATEWAY_API_KEY",
"payloadDir": "/tmp/gh-aw/mcp-payload",
}
The rendered JSON is then piped to the startup script, where the gateway parses this configuration to determine how to route each tool request.
Default Runtime Settings
If the workflow definition does not specify gateway parameters, pkg/workflow/mcp_gateway_config.go ensures sensible defaults through the ensureDefaultMCPGatewayConfig function. This guarantees that every workflow has a valid routing target even without explicit configuration.
// From pkg/workflow/mcp_gateway_config.go
if workflowData.SandboxConfig.MCP == nil {
workflowData.SandboxConfig.MCP = &MCPGatewayRuntimeConfig{
Container: constants.DefaultMCPGatewayContainer, // "github/gh-aw-mcpg"
Version: string(constants.DefaultMCPGatewayVersion), // "v0.0.12"
Port: int(DefaultMCPGatewayPort), // 80
}
}
These defaults include the container image reference, version tag, and network port that the gateway will bind to inside the Docker environment.
Environment Preparation and Secret Handling
Before the gateway starts, pkg/workflow/mcp_setup_generator.go constructs the workflow step that exports environment variables and builds the Docker command. This step masks sensitive values and ensures the gateway receives all necessary authentication tokens.
// From pkg/workflow/mcp_setup_generator.go
yaml.WriteString(fmt.Sprintf(" export MCP_GATEWAY_PORT=\"%d\"\n", port))
yaml.WriteString(fmt.Sprintf(" export MCP_GATEWAY_DOMAIN=\"%s\"\n", domain))
yaml.WriteString(" MCP_GATEWAY_API_KEY=$(openssl rand -base64 45 | tr -d '/+=')\n")
yaml.WriteString(" echo \"::add-mask::${MCP_GATEWAY_API_KEY}\"\n")
The collectMCPEnvironmentVariables function in pkg/workflow/mcp_environment.go gathers secrets for specific servers—such as GITHUB_MCP_SERVER_TOKEN for the GitHub MCP server and HTTP header secrets for custom endpoints—and injects them into the gateway's environment.
Container Startup and Health Checks
The actions/setup/sh/start_mcp_gateway.sh script handles the actual container orchestration. It reads the JSON configuration from stdin, validates the presence of required fields, and executes the Docker run command with appropriate volume mounts and port bindings.
# From actions/setup/sh/start_mcp_gateway.sh
docker run -d \
--name gh-aw-mcp-gateway \
-p "${MCP_GATEWAY_PORT}:${MCP_GATEWAY_PORT}" \
-e "MCP_GATEWAY_API_KEY=${MCP_GATEWAY_API_KEY}" \
-v "${MCP_GATEWAY_PAYLOAD_DIR}:${MCP_GATEWAY_PAYLOAD_DIR}" \
"${MCP_GATEWAY_CONTAINER}:${MCP_GATEWAY_VERSION}"
After launching the container, the script polls the /health endpoint until the gateway reports healthy status, ensuring that subsequent workflow steps only proceed once the routing layer is fully operational.
Request Routing Logic
Once running, the MCP Gateway parses the JSON configuration to route incoming requests. Each tool entry in the configuration includes a type field that determines the routing strategy:
- HTTP servers: The gateway forwards requests to the URL specified in the tool's
urlfield. - stdio servers: The gateway launches the specified container and streams stdin/stdout over HTTP transport.
- Remote servers: The gateway proxies to remote MCP services, such as GitHub's hosted server.
Because the gateway receives a single JSON payload containing every MCP server definition, it can resolve the target server for each request using the toolsets and mode information supplied by the renderer in pkg/workflow/mcp_renderer.go.
Summary
- The MCP Gateway in
github/gh-awacts as a unified HTTP proxy for all Model Context Protocol servers, routing requests based on a JSON configuration generated during workflow compilation. - Configuration defaults are enforced by
pkg/workflow/mcp_gateway_config.go, ensuring the gateway container (github/gh-aw-mcpg:v0.0.12) starts with valid port, domain, and authentication settings. - Environment variables and secrets are collected by
pkg/workflow/mcp_environment.goand exported bypkg/workflow/mcp_setup_generator.go, with the API key masked using::add-mask::. - The
actions/setup/sh/start_mcp_gateway.shscript launches the container, validates the configuration, and performs health checks before allowing the workflow to proceed. - Routing logic inside the gateway distinguishes between HTTP, stdio, and remote server types, forwarding requests to the appropriate backend based on the
typefield in the MCP configuration.
Frequently Asked Questions
How does the MCP Gateway handle authentication for different MCP servers?
The gateway receives all necessary credentials through environment variables collected by collectMCPEnvironmentVariables in pkg/workflow/mcp_environment.go. This function gathers tokens such as GITHUB_MCP_SERVER_TOKEN for GitHub integrations and extracts secrets from HTTP header configurations for custom endpoints. These values are injected into the gateway container at startup, allowing the gateway to authenticate with each backend server without exposing secrets in workflow logs.
What happens if the MCP Gateway fails to start?
The actions/setup/sh/start_mcp_gateway.sh script includes a health check mechanism that polls the gateway's /health endpoint after launching the Docker container. If the endpoint does not return a healthy status within the timeout period, the script exits with an error code, halting the workflow execution. This ensures that subsequent steps attempting to use MCP tools only run when the routing layer is fully operational and ready to accept requests.
Can I configure custom HTTP MCP servers through the gateway?
Yes, the gateway supports custom HTTP MCP servers through the configuration generated by pkg/workflow/mcp_renderer.go. When defining an HTTP server, you specify the type as http and provide a url field pointing to your server endpoint. The collectMCPEnvironmentVariables function in pkg/workflow/mcp_environment.go also extracts any secrets defined in the headers section of your HTTP configuration, injecting them as environment variables so the gateway can authenticate with your custom server.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →