name: http_mcp_headers description: Implement secret-safe HTTP headers for MCP transport in gh-aw.
HTTP MCP Header Secret Support - Implementation Summary
Use this reference for HTTP MCP header secret support in the copilot engine.
Problem Statement
When HTTP MCP headers include GitHub Actions secrets, mcp-config.json must:
- Extract secrets from headers (e.g.,
${{ secrets.DD_API_KEY }}) - Declare those env variables in the execution step
- Configure the MCP config's "env" section to passthrough those variables
- Use the passed variables in the headers section
Example Workflow
on:
workflow_dispatch:
permissions:
contents: read
engine: copilot
mcp-servers:
datadog:
type: http
url: "https://mcp.datadoghq.com/api/unstable/mcp-server/mcp"
headers:
DD_API_KEY: "${{ secrets.DD_API_KEY }}"
DD_APPLICATION_KEY: "${{ secrets.DD_APPLICATION_KEY }}"
DD_SITE: "${{ secrets.DD_SITE || 'datadoghq.com' }}"
allowed:
- search_datadog_dashboards
- search_datadog_slos
- search_datadog_metrics
- get_datadog_metric
# Datadog Dashboard Search
Search for Datadog dashboards and provide a summary.
Generated Output
1. MCP Config (mcp-config.json)
{
"mcpServers": {
"datadog": {
"type": "http",
"url": "https://mcp.datadoghq.com/api/unstable/mcp-server/mcp",
"headers": {
"DD_API_KEY": "${DD_API_KEY}",
"DD_APPLICATION_KEY": "${DD_APPLICATION_KEY}",
"DD_SITE": "${DD_SITE}"
},
"tools": [
"search_datadog_dashboards",
"search_datadog_slos",
"search_datadog_metrics",
"get_datadog_metric"
],
"env": {
"DD_API_KEY": "\\${DD_API_KEY}",
"DD_APPLICATION_KEY": "\\${DD_APPLICATION_KEY}",
"DD_SITE": "\\${DD_SITE}"
}
}
}
}
2. Execution Step Environment Variables
env:
DD_API_KEY: ${{ secrets.DD_API_KEY }}
DD_APPLICATION_KEY: ${{ secrets.DD_APPLICATION_KEY }}
DD_SITE: ${{ secrets.DD_SITE || 'datadoghq.com' }}
COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
# ... other env vars
GH_AW_MCP_CONFIG is intentionally NOT in the YAML env: block — it is exported from the run script (export GH_AW_MCP_CONFIG="$HOME/.copilot/mcp-config.json") so $HOME is resolved at runtime. GitHub Actions does not shell-expand env: values, so the path must be set via export to work on self-hosted/containerized runners where HOME is not /home/runner.
Implementation Details
Key Functions
extractSecretsFromValue(value string) - Extracts secret expressions from a string
- Parses
${{ secrets.VAR_NAME }}patterns - Handles default values:
${{ secrets.VAR || 'default' }} - Returns map of variable names to full expressions
- Parses
extractSecretsFromHeaders(headers map[string]string) - Extracts all secrets from HTTP headers
- Iterates through all header values
- Collects all unique secret expressions
- Returns consolidated map of secrets
replaceSecretsWithEnvVars(value string, secrets map[string]string) - Replaces secret expressions with env var references
- Transforms
${{ secrets.DD_API_KEY }}to${DD_API_KEY} - Used in MCP config headers rendering
- Transforms
collectHTTPMCPHeaderSecrets(tools map[string]any) - Collects secrets from all HTTP MCP tools
- Scans all tools for HTTP MCP configurations
- Extracts secrets from each tool's headers
- Returns consolidated map for execution step env
Rendering Logic
In renderSharedMCPConfig (mcp-config.go):
- Extract secrets when rendering HTTP MCP configs for copilot engine
- Add env section to property order when secrets are found
- Render headers with env var references instead of secret expressions
- Render env with passthrough syntax (
\${VAR_NAME})
In GetExecutionSteps (copilot_engine.go):
- Collect all HTTP MCP header secrets from workflow tools
- Add to execution step env map with secret expressions
Security Benefits
- Secrets never appear in MCP config - Only env var references
- Proper GitHub Actions secret handling - Uses
${{ secrets.* }}syntax - Environment isolation - Each MCP server receives only its required secrets
- Consistent pattern - Matches existing GitHub remote MCP server implementation
Test Coverage
Unit Tests (mcp_http_headers_test.go)
- extractSecretsFromValue
- extractSecretsFromHeaders
- replaceSecretsWithEnvVars
- collectHTTPMCPHeaderSecrets
- renderSharedMCPConfig with HTTP headers
Integration Tests (copilot_mcp_http_integration_test.go)
- Single HTTP MCP tool with secrets
- Multiple HTTP MCP tools
- HTTP MCP without secrets
- Property ordering
- Env variable sorting
All tests pass ✓