GitHub MCP Server on Amazon Bedrock AgentCore
by madlinux768
README.md
# GitHub MCP Server on Amazon Bedrock AgentCore
Private [GitHub MCP Server](https://github.com/github/github-mcp-server) hosted on Amazon Bedrock AgentCore Runtime, accessible via AWS Client VPN with Okta OAuth authentication.
## Overview
The official GitHub MCP Server runs as a managed container on AgentCore Runtime. AgentCore handles TLS termination, JWT authorization, and container lifecycle. Developers connect from any MCP-compatible IDE (Kiro, VS Code, Cursor) using `mcp-remote`, which handles OAuth login via Okta.
```
Developer Machine AWS
┌──────────────────┐ ┌──────────────────────────────────────┐
│ IDE (Kiro/etc) │ │ VPC Endpoint (PrivateLink) │
│ └─ mcp-remote │─── Client VPN ───▶│ └─ AgentCore Runtime (managed TLS) │
│ ├─ OAuth │ │ ├─ JWT Authorizer (Okta OIDC) │
│ │ discovery│ │ └─ Container │
│ ├─ Okta │ │ ├─ Supergateway (:8000) │
│ │ PKCE │ │ │ stateless Streamable HTTP│
│ └─ Bearer │ │ └─ github-mcp-server │
│ token │ │ (stdio subprocess) │
└──────────────────┘ └──────────────────────────────────────┘
```
### What AgentCore Replaces
- ECS Cluster, Service, Task Definition
- Application Load Balancer + self-signed certificate
- NAT Gateway + Internet Gateway + Public Subnet
- Custom JWT Proxy (Node.js sidecar)
## Prerequisites
- **AWS CLI** v2 configured with credentials
- **Terraform** >= 1.0
- **Docker** with Buildx (for ARM64 builds)
- **AWS Client VPN** connected to the target VPC
- **Okta** Native application (Authorization Code + PKCE) with client ID
- **GitHub Personal Access Token** with appropriate scopes
## Deployment
### 1. Bootstrap Terraform State
Create the S3 bucket and DynamoDB table for remote state (one-time setup):
```bash
aws s3api create-bucket \
--bucket github-mcp-agentcore-tfstate \
--region us-east-1
aws s3api put-bucket-versioning \
--bucket github-mcp-agentcore-tfstate \
--versioning-configuration Status=Enabled
aws s3api put-bucket-encryption \
--bucket github-mcp-agentcore-tfstate \
--server-side-encryption-configuration \
'{"Rules":[{"ApplyServerSideEncryptionByDefault":{"SSEAlgorithm":"AES256"}}]}'
aws s3api put-public-access-block \
--bucket github-mcp-agentcore-tfstate \
--public-access-block-configuration \
BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true
aws dynamodb create-table \
--table-name github-mcp-agentcore-tflock \
--attribute-definitions AttributeName=LockID,AttributeType=S \
--key-schema AttributeName=LockID,KeyType=HASH \
--billing-mode PAY_PER_REQUEST \
--region us-east-1
```
### 2. Configure Variables
```bash
cd terraform
cp terraform.tfvars.example terraform.tfvars
# Edit terraform.tfvars with your values
```
Store the GitHub PAT separately (this file is gitignored):
```bash
cat > secrets.auto.tfvars <<EOF
github_pat = "github_pat_XXXXXXXXXXXX"
EOF
```
### 3. Deploy Infrastructure
```bash
terraform init
terraform plan
terraform apply
```
### 4. Build and Push Container
```bash
# Get ECR repository URL from Terraform output
ECR_URL=$(terraform output -raw ecr_repository_url)
# Authenticate to ECR
aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin "$ECR_URL"
# Build ARM64 image and push
docker buildx build --platform linux/arm64 -f docker/Dockerfile -t "$ECR_URL:latest" --push .
```
On subsequent pushes, the GitHub Actions workflow (`.github/workflows/docker-build.yml`) handles builds automatically when `docker/` files change on the main branch.
## Client Configuration
See [docs/client-config.md](docs/client-config.md) for IDE-specific setup instructions (Kiro, VS Code, Cursor).
Quick example — add to your MCP config and connect to VPN:
```json
{
"mcpServers": {
"github": {
"command": "npx",
"args": [
"mcp-remote",
"https://<AGENTCORE_ENDPOINT>",
"--static-oauth-client-info",
"{\"client_id\":\"<OKTA_CLIENT_ID>\"}"
]
}
}
}
```
No `NODE_TLS_REJECT_UNAUTHORIZED=0` needed — AgentCore uses AWS-managed TLS.
## Operations
### Logs
Application logs are delivered to CloudWatch via vended log delivery:
```bash
# Get log group name from Terraform output
LOG_GROUP=$(terraform -chdir=terraform output -raw log_group_name)
# Tail logs
aws logs tail "$LOG_GROUP" --since 30m --follow
```
### Health Check
From a machine connected to the VPN:
```bash
curl -s https://<AGENTCORE_ENDPOINT>/healthz
```
### X-Ray Traces
Traces are delivered to X-Ray automatically. View them in the AWS Console under CloudWatch > X-Ray traces.
## CI/CD
Two GitHub Actions workflows handle automation:
- **`terraform.yml`** — Runs `terraform fmt`, `validate`, and `plan` on PRs. Applies on merge to main with environment protection rules.
- **`docker-build.yml`** — Builds ARM64 Docker image and pushes to ECR on changes to `docker/` on main.
Both workflows use OIDC federation for AWS authentication (no stored credentials).
## Project Structure
```
├── .github/workflows/
│ ├── terraform.yml # Terraform plan/apply CI/CD
│ └── docker-build.yml # ARM64 Docker build + ECR push
├── docker/
│ ├── Dockerfile # Supergateway + github-mcp-server (ARM64)
│ └── start.sh # Fetch secret, start Supergateway
├── terraform/
│ ├── main.tf # AgentCore runtime resource
│ ├── vpc-endpoint.tf # PrivateLink VPC endpoint + security group
│ ├── iam.tf # Agent execution role, GitHub Actions OIDC role
│ ├── ecr.tf # ECR repository + lifecycle policy
│ ├── secrets.tf # Secrets Manager for GitHub PAT
│ ├── observability.tf # CloudWatch vended logs + X-Ray traces
│ ├── backend.tf # S3 remote state configuration
│ ├── variables.tf # Input variables
│ ├── outputs.tf # Output values
│ ├── versions.tf # Provider version constraints
│ └── terraform.tfvars.example
├── docs/
│ └── client-config.md # IDE configuration examples
├── tests/ # Property-based and unit tests
├── .gitignore
└── README.md
```