- name
- gh-aw-mcp-gateway
- description
- Expert knowledge in GitHub Agentic Workflows MCP Gateway - Model Context Protocol routing, configuration, Docker integration, security, and production deployment patterns
- license
- MIT
- version
- 2.0.0
- last_updated
- 2026-04-02T00:00:00.000Z
- tags
- ["github-agentic-workflows","mcp","model-context-protocol","mcp-gateway","docker","json-rpc","security"]
# 🌐 GitHub Agentic Workflows - MCP Gateway Skill
## 🔴 AI FIRST Quality Principle
> **Apply the AI FIRST principle: never accept first-pass quality. Minimum 2 iterations. Read all output, improve every section. No shortcuts.**
## 📋 Purpose
Master the **MCP Gateway** for GitHub Agentic Workflows - the foundational infrastructure component that enables AI agents to access Model Context Protocol (MCP) servers safely and efficiently. This skill provides comprehensive expertise in configuring, deploying, and operating the MCP Gateway for production AI automation.
## 🎯 Core Concept
### What Is the MCP Gateway?
The **MCP Gateway** is a proxy server that routes Model Context Protocol (MCP) requests from AI agents to backend MCP servers. It provides centralized configuration, Docker container management, and secure access to multiple MCP servers through a unified HTTP API.
**Key Principles:**
- 🔒 **Secure Routing**: Proxies MCP requests with authentication and validation
- 🐳 **Docker Integration**: Launches MCP servers as isolated Docker containers
- 📡 **Protocol Translation**: Handles stdio ↔ HTTP transport for MCP servers
- 🔌 **Multi-Server**: Routes to multiple backend MCP servers (GitHub, Serena, custom)
- 📊 **Observable**: Comprehensive logging and per-server log files
- 🛡️ **Containerized**: Runs in GitHub Actions with security enforcement
**Architecture:**
```
┌──────────────────────────────────────────────────────────┐
│ GitHub Actions Workflow │
│ │
│ ┌───────────────────────────────────────────────────┐ │
│ │ AI Agent │ │
│ │ - Reads: MCP tools (GitHub, Serena, etc.) │ │
│ │ - Calls: tools/list, tools/call │ │
│ │ - HTTP requests to MCP Gateway │ │
│ └──────────────┬────────────────────────────────────┘ │
│ │ │
│ ▼ HTTP (JSON-RPC) │
│ ┌──────────────────────────────────────────────────┐ │
│ │ MCP Gateway (awmg) │ │
│ │ - Routes: /mcp/{serverID} (routed mode) │ │
│ │ - Auth: API key validation (MCP 7.1) │ │
│ │ - Spawns: Docker containers │ │
│ │ - Logs: Per-server + unified logs │ │
│ └──┬───────────┬────────────────┬──────────────────┘ │
│ │ stdio │ stdio │ stdio │
│ ▼ ▼ ▼ │
│ ┌─────┐ ┌─────────┐ ┌──────────────┐ │
│ │GitHub│ │ Serena │ │ Custom MCP │ │
│ │ MCP │ │ MCP │ │ Server │ │
│ └─────┘ └─────────┘ └──────────────┘ │
│ (Container) (Container) (Container) │
└──────────────────────────────────────────────────────────┘
```
#### 🏗️ MCP Gateway Core
A gateway for Model Context Protocol (MCP) servers.
This gateway is used with [GitHub Agentic Workflows](https://github.com/github/gh-aw) via the `sandbox.mcp` configuration to provide MCP server access to AI agents running in sandboxed environments.
📖 **[Full Configuration Specification](https://github.com/github/gh-aw/blob/main/docs/src/content/docs/reference/mcp-gateway.md)** - Complete reference for all configuration options and validation rules.
#### Session timeout (gh-aw v0.71.3+)
> ⚠️ **DO NOT SET `engine.mcp.session-timeout`** — MCP Gateway v0.3.1 rejects this field with `additionalProperties 'sessionTimeout' not allowed` ([#29353](https://github.com/github/gh-aw/issues/29353)). The field was added in gh-aw v0.71.3 but is incompatible with the current gateway version. The `sandbox.mcp.keepalive-interval` setting is also no longer needed — the gateway default keepalive is sufficient for 60-min jobs.
The gateway manages session lifetimes internally. The PR deadline for news workflows is governed by Timer A (job `timeout-minutes: 60`) and Timer B (Copilot API session ~60 min).
#### Features
- **Configuration Modes**: Supports both TOML files and JSON stdin configuration
- **Spec-Compliant Validation**: Fail-fast validation with detailed error messages
- **Variable Expansion**: Environment variable substitution with `${VAR_NAME}` syntax
- **Type Normalization**: Automatic conversion of legacy `"local"` type to `"stdio"`
- **Schema Normalization**: Automatic fixing of malformed JSON schemas from backend MCP servers
- Adds missing `properties` field to object schemas
- Prevents downstream validation errors
- Transparent to both backends and clients
- **Routing Modes**:
- **Routed**: Each backend server accessible at `/mcp/{serverID}`
- **Unified**: Single endpoint `/mcp` that routes to configured servers
- **Docker Support**: Launch backend MCP servers as Docker containers
- **Stdio Transport**: JSON-RPC 2.0 over stdin/stdout for MCP communication
- **Container Detection**: Automatic detection of containerized environments with security warnings
- **Enhanced Debugging**: Detailed error context and troubleshooting suggestions for command failures
- **Per-ServerID Logs**: Separate log files for each backend MCP server (`{serverID}.log`) for easier troubleshooting
#### Getting Started
For detailed setup instructions, building from source, and local development, see [CONTRIBUTING.md](CONTRIBUTING.md).
#### Quick Start with Docker
1. **Pull the Docker image** (when available):
```bash
docker pull ghcr.io/github/gh-aw-mcpg:latest
```
2. **Create a configuration file** (`config.json`):
```json
{
"mcpServers": {
"github": {
"type": "stdio",
"container": "ghcr.io/github/github-mcp-server:latest",
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": ""
}
}
}
}
```
3. **Run the container**:
```bash
docker run --rm -i \
-e MCP_GATEWAY_PORT=8000 \
-e MCP_GATEWAY_DOMAIN=localhost \
-e MCP_GATEWAY_API_KEY=your-secret-key \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /path/to/logs:/tmp/gh-aw/mcp-logs \
-p 8000:8000 \
ghcr.io/github/gh-aw-mcpg:latest < config.json
```
**Required flags:**
- `-i`: Enables stdin for passing JSON configuration
- `-e MCP_GATEWAY_*`: Required environment variables
- `-v /var/run/docker.sock`: Required for spawning backend MCP servers
- `-v /path/to/logs:/tmp/gh-aw/mcp-logs`: Mount for persistent gateway logs (or use `-e MCP_GATEWAY_LOG_DIR=/custom/path` with matching volume mount)
- `mcp-gateway.log`: Unified log with all messages
- `{serverID}.log`: Per-server logs for easier troubleshooting
- `gateway.md`: Markdown-formatted logs for GitHub workflow previews
- `rpc-messages.jsonl`: Machine-readable RPC message logs
- `tools.json`: Available tools from all backend MCP servers
- `-p 8000:8000`: Port mapping must match `MCP_GATEWAY_PORT`
MCPG will start in routed mode on `http://0.0.0.0:8000` (using `MCP_GATEWAY_PORT`), proxying MCP requests to your configured backend servers.
#### Configuration
MCP Gateway supports two configuration formats:
1. **TOML format** - Use with `--config` flag for file-based configuration
2. **JSON stdin format** - Use with `--config-stdin` flag for dynamic configuration
#### TOML Format (`config.toml`)
TOML configuration uses `command` and `args` fields directly for maximum flexibility:
```toml
[servers]
[servers.github]
command = "docker"
args = ["run", "--rm", "-e", "GITHUB_PERSONAL_ACCESS_TOKEN", "-i", "ghcr.io/github/github-mcp-server:latest"]
[servers.filesystem]
command = "node"
args = ["/path/to/filesystem-server.js"]
```
**Note**: In TOML format, you specify the `command` and `args` directly. This allows you to use any command (docker, node, python, etc.).
#### JSON Stdin Format
For the complete JSON configuration specification with all validation rules, see the **[MCP Gateway Configuration Reference](https://github.com/github/gh-aw/blob/main/docs/src/content/docs/reference/mcp-gateway.md)**.
```json
{
"mcpServers": {
"github": {
"type": "stdio",
"container": "ghcr.io/github/github-mcp-server:latest",
"entrypoint": "/custom/entrypoint.sh",
"entrypointArgs": ["--verbose"],
"mounts": [
"/host/config:/app/config:ro",
"/host/data:/app/data:rw"
],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "",
"EXPANDED_VAR": "${MY_HOME}/config"
}
}
},
"gateway": {
"port": 8080,
"apiKey": "your-api-key",
"domain": "localhost",
"startupTimeout": 30,
"toolTimeout": 60,
"payloadDir": "/tmp/jq-payloads"
}
}
```
#### Server Configuration Fields
- **`type`** (optional): Server transport type
- `"stdio"` - Standard input/output transport (default)
- `"http"` - HTTP transport (fully supported)
- `"local"` - Alias for `"stdio"` (backward compatibility)
- **`container`** (required for stdio in JSON format): Docker container image (e.g., `"ghcr.io/github/github-mcp-server:latest"`)
- Automatically wraps as `docker run --rm -i <container>`
- **Note**: The `command` field is NOT supported in JSON stdin format (stdio servers must use `container` instead)
- **TOML format uses `command` and `args` fields directly**
- **`entrypoint`** (optional): Custom entrypoint for the container
- Overrides the default container entrypoint
- Applied as `--entrypoint` flag to Docker
- **`entrypointArgs`** (optional): Arguments passed to container entrypoint
- Array of strings passed after the container image
- **`mounts`** (optional): Volume mounts for the container
- Array of strings in format `"source:dest:mode"`
- `source` - Host path to mount (can use environment variables with `${VAR}` syntax)
- `dest` - Container path where the volume is mounted
- `mode` - Either `"ro"` (read-only) or `"rw"` (read-write)
- Example: `["/host/config:/app/config:ro", "/host/data:/app/data:rw"]`
- **`env`** (optional): Environment variables
- Set to `""` (empty string) for passthrough from host environment
- Set to `"value"` for explicit value
- Use `"${VAR_NAME}"` for environment variable expansion (fails if undefined)
- **`url`** (required for http): HTTP endpoint URL for `type: "http"` servers
**Validation Rules:**
- **JSON stdin format**:
- **Stdio servers** must specify `container` (required)
- **HTTP servers** must specify `url` (required)
- **The `command` field is not supported** - stdio servers must use `container`
- **TOML format**:
- Uses `command` and `args` fields directly (e.g., `command = "docker"`)
- **Common rules** (both formats):
- Empty/"local" type automatically normalized to "stdio"
- Variable expansion with `${VAR_NAME}` fails fast on undefined variables
- All validation errors include JSONPath and helpful suggestions
- **Mount specifications** must follow `"source:dest:mode"` format
- `mode` must be either `"ro"` or `"rw"`
- Both source and destination paths are required (cannot be empty)
See **[Configuration Specification](https://github.com/github/gh-aw/blob/main/docs/src/content/docs/reference/mcp-gateway.md)** for complete validation rules.
#### Gateway Configuration Fields (Reserved)
- **`port`** (optional): Gateway HTTP port (default: from `--listen` flag)
- Valid range: 1-65535
- **`apiKey`** (optional): API key for authentication
- **`domain`** (optional): Domain name for the gateway
- Allowed values: `"localhost"`, `"host.docker.internal"`
- **`startupTimeout`** (optional): Seconds to wait for backend startup (default: 60)
- Must be positive integer
- **`toolTimeout`** (optional): Seconds to wait for tool execution (default: 120)
- Must be positive integer
- **`payloadDir`** (optional): Directory for storing large payload files (default: `/tmp/jq-payloads`)
- Payloads are organized by session: `{payloadDir}/{sessionID}/{queryID}/payload.json`
**Note**: Gateway configuration fields are validated and parsed but not yet fully implemented.
**Configuration Alternatives**:
- **`payloadSizeThreshold`** is not supported in JSON stdin format. Use:
- CLI flag: `--payload-size-threshold <bytes>` (default: 10240)
- Environment variable: `MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD=<bytes>`
- Payloads **larger** than this threshold are stored to disk and return metadata
- Payloads **smaller than or equal** to this threshold are returned inline
**Environment Variable Features**:
- **Passthrough**: Set value to empty string (`""`) to pass through from host
- **Expansion**: Use `${VAR_NAME}` syntax for dynamic substitution (fails if undefined)
#### Configuration Validation and Error Handling
MCP Gateway provides detailed error messages and validation to help catch configuration issues early:
#### Parse Errors with Precise Location
When there's a syntax error in your TOML configuration, the gateway reports the exact line and column:
```bash
$ awmg --config config.toml
Error: failed to parse TOML at line 2, column 6: expected '.' or '=', but got '3' instead
```
This helps you quickly identify and fix syntax issues.
#### Unknown Key Detection (Typo Detection)
The gateway detects and warns about unknown configuration keys, helping catch typos and deprecated options:
```toml
[gateway]
prot = 3000 # Typo: should be 'port'
startup_timout = 30 # Typo: should be 'startup_timeout'
```
When you run the gateway with these typos, you'll see warnings in the log file:
```
[2026-02-07T17:46:51Z] [WARN] [config] Unknown configuration key 'gateway.prot' - check for typos or deprecated options
[2026-02-07T17:46:51Z] [WARN] [config] Unknown configuration key 'gateway.startup_timout' - check for typos or deprecated options
```
The gateway will use default values for unrecognized keys, so it will still start, but the warnings help you identify and fix configuration issues.
#### Memory-Efficient Parsing
The gateway uses streaming parsing for configuration files, making it efficient even with large configuration files containing many servers.
#### Best Practices
1. **Check logs for warnings**: After starting the gateway, check the log file for any warnings about unknown keys
2. **Use precise error messages**: When you see a parse error, the line and column numbers point exactly to the problem
3. **Validate configuration**: Test your configuration changes by running the gateway and checking for warnings
4. **Keep configuration clean**: Remove any deprecated or unused configuration options
Voir sur GitHub