Deploy to AWS ECS
Deploy Clinical Terminology MCP servers to AWS ECS with Fargate.
Deploy MCP servers to AWS Elastic Container Service using Fargate for serverless container execution.
Prerequisites
- AWS CLI configured with appropriate credentials
- Docker installed locally
- AWS account with permissions for ECR, ECS, IAM, and Secrets Manager
Create ECR Repository
# Create repository
aws ecr create-repository \
--repository-name clinical-terminology-mcp/snomed-mcp \
--region us-east-1
# Get login token
aws ecr get-login-password --region us-east-1 | \
docker login --username AWS --password-stdin \
<account-id>.dkr.ecr.us-east-1.amazonaws.com
# Build and push
docker build -t snomed-mcp -f snomed-mcp/Dockerfile .
docker tag snomed-mcp:latest \
<account-id>.dkr.ecr.us-east-1.amazonaws.com/clinical-terminology-mcp/snomed-mcp:latest
docker push \
<account-id>.dkr.ecr.us-east-1.amazonaws.com/clinical-terminology-mcp/snomed-mcp:latest
Store Secrets
For servers requiring credentials (ICD-11, LOINC, UMLS), store them in Secrets Manager:
# ICD-11 credentials
aws secretsmanager create-secret \
--name clinical-terminology-mcp/icd11 \
--secret-string '{"ICD11_CLIENT_ID":"your-id","ICD11_CLIENT_SECRET":"your-secret"}'
# UMLS API key
aws secretsmanager create-secret \
--name clinical-terminology-mcp/umls \
--secret-string '{"UMLS_API_KEY":"your-key"}'
# LOINC credentials
aws secretsmanager create-secret \
--name clinical-terminology-mcp/loinc \
--secret-string '{"LOINC_USERNAME":"your-user","LOINC_PASSWORD":"your-pass"}'
Create ECS Cluster
aws ecs create-cluster \
--cluster-name clinical-terminology-mcp \
--capacity-providers FARGATE FARGATE_SPOT \
--default-capacity-provider-strategy \
capacityProvider=FARGATE,weight=1 \
capacityProvider=FARGATE_SPOT,weight=3
Create Task Execution Role
# Create trust policy
cat > trust-policy.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {"Service": "ecs-tasks.amazonaws.com"},
"Action": "sts:AssumeRole"
}]
}
EOF
# Create role
aws iam create-role \
--role-name ecsTaskExecutionRole \
--assume-role-policy-document file://trust-policy.json
# Attach policies
aws iam attach-role-policy \
--role-name ecsTaskExecutionRole \
--policy-arn arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
# Add Secrets Manager access
cat > secrets-policy.json << 'EOF'
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": ["secretsmanager:GetSecretValue"],
"Resource": "arn:aws:secretsmanager:us-east-1:<account-id>:secret:clinical-terminology-mcp/*"
}]
}
EOF
aws iam put-role-policy \
--role-name ecsTaskExecutionRole \
--policy-name SecretsManagerAccess \
--policy-document file://secrets-policy.json
Create Task Definition
cat > task-definition.json << 'EOF'
{
"family": "snomed-mcp",
"networkMode": "awsvpc",
"requiresCompatibilities": ["FARGATE"],
"cpu": "256",
"memory": "512",
"executionRoleArn": "arn:aws:iam::<account-id>:role/ecsTaskExecutionRole",
"containerDefinitions": [{
"name": "snomed-mcp",
"image": "<account-id>.dkr.ecr.us-east-1.amazonaws.com/clinical-terminology-mcp/snomed-mcp:latest",
"portMappings": [{
"containerPort": 8080,
"protocol": "tcp"
}],
"environment": [
{"name": "MCP_TRANSPORT", "value": "http"},
{"name": "MCP_HTTP_ADDR", "value": ":8080"},
{"name": "MCP_LOG_FORMAT", "value": "json"},
{"name": "MCP_METRICS_ENABLED", "value": "true"}
],
"healthCheck": {
"command": ["CMD-SHELL", "wget -q --spider http://localhost:8080/health/live || exit 1"],
"interval": 30,
"timeout": 5,
"retries": 3,
"startPeriod": 10
},
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/clinical-terminology-mcp",
"awslogs-region": "us-east-1",
"awslogs-stream-prefix": "snomed-mcp"
}
}
}]
}
EOF
aws ecs register-task-definition --cli-input-json file://task-definition.json
For servers with secrets (e.g., ICD-11), add secrets to the container definition:
"secrets": [
{
"name": "ICD11_CLIENT_ID",
"valueFrom": "arn:aws:secretsmanager:us-east-1:<account-id>:secret:clinical-terminology-mcp/icd11:ICD11_CLIENT_ID::"
},
{
"name": "ICD11_CLIENT_SECRET",
"valueFrom": "arn:aws:secretsmanager:us-east-1:<account-id>:secret:clinical-terminology-mcp/icd11:ICD11_CLIENT_SECRET::"
}
]
Create Application Load Balancer
# Create ALB
aws elbv2 create-load-balancer \
--name clinical-terminology-mcp-alb \
--subnets subnet-xxx subnet-yyy \
--security-groups sg-xxx \
--scheme internet-facing \
--type application
# Create target group
aws elbv2 create-target-group \
--name snomed-mcp-tg \
--protocol HTTP \
--port 8080 \
--vpc-id vpc-xxx \
--target-type ip \
--health-check-path /health/ready \
--health-check-interval-seconds 30
# Create listener
aws elbv2 create-listener \
--load-balancer-arn arn:aws:elasticloadbalancing:us-east-1:<account-id>:loadbalancer/app/clinical-terminology-mcp-alb/xxx \
--protocol HTTPS \
--port 443 \
--certificates CertificateArn=arn:aws:acm:us-east-1:<account-id>:certificate/xxx \
--default-actions Type=forward,TargetGroupArn=arn:aws:elasticloadbalancing:us-east-1:<account-id>:targetgroup/snomed-mcp-tg/xxx
Create ECS Service
aws ecs create-service \
--cluster clinical-terminology-mcp \
--service-name snomed-mcp \
--task-definition snomed-mcp \
--desired-count 2 \
--launch-type FARGATE \
--network-configuration "awsvpcConfiguration={subnets=[subnet-xxx,subnet-yyy],securityGroups=[sg-xxx],assignPublicIp=ENABLED}" \
--load-balancers "targetGroupArn=arn:aws:elasticloadbalancing:us-east-1:<account-id>:targetgroup/snomed-mcp-tg/xxx,containerName=snomed-mcp,containerPort=8080" \
--health-check-grace-period-seconds 60
Verify Deployment
# Check service status
aws ecs describe-services \
--cluster clinical-terminology-mcp \
--services snomed-mcp
# Test health endpoint
curl https://your-alb-domain.com/health
# Test MCP endpoint
curl -X POST https://your-alb-domain.com/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"initialize","params":{},"id":1}'
Auto Scaling (Optional)
# Register scalable target
aws application-autoscaling register-scalable-target \
--service-namespace ecs \
--resource-id service/clinical-terminology-mcp/snomed-mcp \
--scalable-dimension ecs:service:DesiredCount \
--min-capacity 1 \
--max-capacity 10
# Create scaling policy
aws application-autoscaling put-scaling-policy \
--service-namespace ecs \
--resource-id service/clinical-terminology-mcp/snomed-mcp \
--scalable-dimension ecs:service:DesiredCount \
--policy-name cpu-scaling \
--policy-type TargetTrackingScaling \
--target-tracking-scaling-policy-configuration '{
"TargetValue": 70.0,
"PredefinedMetricSpecification": {
"PredefinedMetricType": "ECSServiceAverageCPUUtilization"
},
"ScaleOutCooldown": 60,
"ScaleInCooldown": 60
}'