Skip to main content
Glama
README.md
# Production MCP on AWS (Bedrock + EKS/GitOps)

A production-oriented Model Context Protocol (MCP) platform: an MCP server
exposing tools, resources, and prompts over Streamable HTTP, secured with JWT
authentication and per-tool RBAC, consumed by an Amazon Bedrock (Claude) client,
and packaged for delivery on Amazon EKS via Helm, ArgoCD (GitOps), and GitLab CI/CD.

## Architecture

```
Developer push -> GitLab CI/CD (test -> build image -> push to ECR -> bump tag in Git)
                                                                |
                                                                v
                                          ArgoCD (GitOps: watches Git, syncs to EKS)
                                                                |
                                                                v
   Bedrock Claude client --(JWT over HTTPS)--> ALB Ingress -> Service -> MCP server pods (HPA)
                                                                          |  IRSA
                                                                          v
                                                    AWS Secrets Manager (JWT key) + Bedrock
```

- **Authentication**: JWT (signing key from AWS Secrets Manager), verified in middleware.
- **Authorization**: per-tool RBAC (admin/user/guest), deny-by-default.
- **Transport**: Streamable HTTP (remote MCP).
- **Scaling**: multiple stateless pods behind a Service/ALB, autoscaled by HPA.
- **Security**: no static keys — IRSA for pods, Secrets Manager for the signing key.

## Repository layout

```
server/            MCP server + auth (JWT + RBAC)
client/            Bedrock Claude MCP client
scaling/           Round-robin load balancer (demonstrates LB internals)
deploy/Dockerfile  Container image
deploy/helm/       Helm chart (Deployment, Service, Ingress/ALB, HPA, IRSA SA)
deploy/argocd/     ArgoCD Application (GitOps)
.gitlab-ci.yml     CI/CD pipeline
```

## Status: implemented vs design

**Implemented and run locally**
- MCP server with tools, resources, and prompts (`server/mcp_server.py`)
- JWT auth + per-tool RBAC with 401/403 handling (`server/auth.py`)
- JWT signing key sourced from AWS Secrets Manager
- Bedrock Claude client with tool discovery + tool-use execution (`client/bedrock_client.py`)
- Round-robin load balancer with health checks (`scaling/load_balancer.py`)
- Container image (`deploy/Dockerfile`) built and run locally

**Delivered as config-as-code (validated with `helm lint` / YAML checks; deploy on a real EKS cluster)**
- Helm chart: Deployment, Service, ALB Ingress, HPA, IRSA ServiceAccount
- ArgoCD Application (automated sync, prune, self-heal)
- GitLab CI/CD (test -> build/push to ECR -> update image tag in Git)

## Prerequisites

- Python 3.12, an MCP-compatible environment (`pip install -r requirements.txt`)
- AWS account with Bedrock (Claude) access
- A secret in AWS Secrets Manager named `mcp/jwt-signing-key`
- For deployment: an EKS cluster, ECR repo, AWS Load Balancer Controller, ArgoCD

## Run locally

Create the JWT signing secret (one time):

```
aws secretsmanager create-secret \
  --name "mcp/jwt-signing-key" \
  --secret-string "$(python3 -c 'import secrets; print(secrets.token_urlsafe(48))')" \
  --region us-east-1
```

Start the server:

```
cd server
uvicorn mcp_server:app --host 0.0.0.0 --port 8000
```

Run the Bedrock client (role is optional: user | admin | guest):

```
cd client
python bedrock_client.py "What is 5 plus 59?" user
python bedrock_client.py "reset the counter" admin
```

`/health` is public (for probes); all MCP requests require a valid JWT, and
tool calls are authorized per role.

## Notes

- Model ID and region are read from env (`BEDROCK_MODEL_ID`, `BEDROCK_REGION`)
  to avoid hardcoding a model that may be retired.
- Secrets are never committed or baked into the image; they are fetched at
  runtime (Secrets Manager) and, in EKS, accessed via IRSA.