Deploy to Azure Container Apps
Deploy Clinical Terminology MCP servers to Azure Container Apps.
Deploy MCP servers to Azure Container Apps for serverless container hosting with built-in scaling.
Prerequisites
- Azure CLI installed and logged in
- Docker installed locally
- Azure subscription with appropriate permissions
Set Up Resources
# Set variables
export RESOURCE_GROUP=clinical-terminology-mcp
export LOCATION=eastus
export ENVIRONMENT=mcp-env
export ACR_NAME=clinicalterminologymcp
# Create resource group
az group create \
--name $RESOURCE_GROUP \
--location $LOCATION
# Create Container Registry
az acr create \
--resource-group $RESOURCE_GROUP \
--name $ACR_NAME \
--sku Basic \
--admin-enabled true
Build and Push Image
# Login to ACR
az acr login --name $ACR_NAME
# Build and push (using ACR Tasks)
az acr build \
--registry $ACR_NAME \
--image snomed-mcp:latest \
--file snomed-mcp/Dockerfile \
.
# Or push locally built image
docker build -t snomed-mcp -f snomed-mcp/Dockerfile .
docker tag snomed-mcp $ACR_NAME.azurecr.io/snomed-mcp:latest
docker push $ACR_NAME.azurecr.io/snomed-mcp:latest
Store Secrets in Key Vault
# Create Key Vault
az keyvault create \
--name mcp-secrets \
--resource-group $RESOURCE_GROUP \
--location $LOCATION
# Store ICD-11 credentials
az keyvault secret set \
--vault-name mcp-secrets \
--name icd11-client-id \
--value "your-client-id"
az keyvault secret set \
--vault-name mcp-secrets \
--name icd11-client-secret \
--value "your-client-secret"
# Store UMLS API key
az keyvault secret set \
--vault-name mcp-secrets \
--name umls-api-key \
--value "your-api-key"
# Store LOINC credentials
az keyvault secret set \
--vault-name mcp-secrets \
--name loinc-username \
--value "your-username"
az keyvault secret set \
--vault-name mcp-secrets \
--name loinc-password \
--value "your-password"
Create Container Apps Environment
az containerapp env create \
--name $ENVIRONMENT \
--resource-group $RESOURCE_GROUP \
--location $LOCATION
Create Managed Identity
# Create user-assigned managed identity
az identity create \
--name mcp-identity \
--resource-group $RESOURCE_GROUP
# Get identity details
IDENTITY_ID=$(az identity show \
--name mcp-identity \
--resource-group $RESOURCE_GROUP \
--query id -o tsv)
IDENTITY_CLIENT_ID=$(az identity show \
--name mcp-identity \
--resource-group $RESOURCE_GROUP \
--query clientId -o tsv)
IDENTITY_PRINCIPAL_ID=$(az identity show \
--name mcp-identity \
--resource-group $RESOURCE_GROUP \
--query principalId -o tsv)
# Grant ACR pull permission
ACR_ID=$(az acr show --name $ACR_NAME --query id -o tsv)
az role assignment create \
--assignee $IDENTITY_PRINCIPAL_ID \
--role AcrPull \
--scope $ACR_ID
# Grant Key Vault access
az keyvault set-policy \
--name mcp-secrets \
--object-id $IDENTITY_PRINCIPAL_ID \
--secret-permissions get
Deploy Container App
Basic Server (no secrets)
az containerapp create \
--name snomed-mcp \
--resource-group $RESOURCE_GROUP \
--environment $ENVIRONMENT \
--image $ACR_NAME.azurecr.io/snomed-mcp:latest \
--registry-server $ACR_NAME.azurecr.io \
--user-assigned $IDENTITY_ID \
--registry-identity $IDENTITY_ID \
--target-port 8080 \
--ingress external \
--min-replicas 0 \
--max-replicas 10 \
--cpu 0.5 \
--memory 1Gi \
--env-vars \
MCP_TRANSPORT=http \
MCP_HTTP_ADDR=:8080 \
MCP_LOG_FORMAT=json \
MCP_METRICS_ENABLED=true
Server with Secrets (e.g., ICD-11)
# Get Key Vault URI
KEYVAULT_URI=$(az keyvault show --name mcp-secrets --query properties.vaultUri -o tsv)
az containerapp create \
--name icd11-mcp \
--resource-group $RESOURCE_GROUP \
--environment $ENVIRONMENT \
--image $ACR_NAME.azurecr.io/icd11-mcp:latest \
--registry-server $ACR_NAME.azurecr.io \
--user-assigned $IDENTITY_ID \
--registry-identity $IDENTITY_ID \
--target-port 8080 \
--ingress external \
--min-replicas 0 \
--max-replicas 10 \
--cpu 0.5 \
--memory 1Gi \
--env-vars \
MCP_TRANSPORT=http \
MCP_HTTP_ADDR=:8080 \
MCP_LOG_FORMAT=json \
--secrets \
icd11-client-id=keyvaultref:${KEYVAULT_URI}secrets/icd11-client-id,identityref:$IDENTITY_ID \
icd11-client-secret=keyvaultref:${KEYVAULT_URI}secrets/icd11-client-secret,identityref:$IDENTITY_ID \
--env-vars \
ICD11_CLIENT_ID=secretref:icd11-client-id \
ICD11_CLIENT_SECRET=secretref:icd11-client-secret
Configure Health Probes
Update the container app with health probes:
az containerapp update \
--name snomed-mcp \
--resource-group $RESOURCE_GROUP \
--set-env-vars "MCP_TRANSPORT=http" \
--yaml - << 'EOF'
properties:
template:
containers:
- name: snomed-mcp
probes:
- type: liveness
httpGet:
path: /health/live
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
- type: readiness
httpGet:
path: /health/ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
EOF
Configure Custom Domain
# Add custom domain
az containerapp hostname add \
--name snomed-mcp \
--resource-group $RESOURCE_GROUP \
--hostname mcp.yourdomain.com
# Bind certificate (managed)
az containerapp hostname bind \
--name snomed-mcp \
--resource-group $RESOURCE_GROUP \
--hostname mcp.yourdomain.com \
--environment $ENVIRONMENT \
--validation-method CNAME
Verify Deployment
# Get app URL
APP_URL=$(az containerapp show \
--name snomed-mcp \
--resource-group $RESOURCE_GROUP \
--query properties.configuration.ingress.fqdn -o tsv)
# Test health
curl https://$APP_URL/health
# Test MCP endpoint
curl -X POST https://$APP_URL/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"initialize","params":{},"id":1}'
Scaling Rules
Configure auto-scaling based on HTTP requests:
az containerapp update \
--name snomed-mcp \
--resource-group $RESOURCE_GROUP \
--scale-rule-name http-rule \
--scale-rule-type http \
--scale-rule-http-concurrency 50
Deploy All Servers
Script to deploy all servers:
#!/bin/bash
SERVERS="snomed-mcp rxnorm-mcp icd10-mcp ucum-mcp"
for server in $SERVERS; do
az containerapp create \
--name $server \
--resource-group $RESOURCE_GROUP \
--environment $ENVIRONMENT \
--image $ACR_NAME.azurecr.io/$server:latest \
--registry-server $ACR_NAME.azurecr.io \
--user-assigned $IDENTITY_ID \
--registry-identity $IDENTITY_ID \
--target-port 8080 \
--ingress external \
--min-replicas 0 \
--max-replicas 10 \
--env-vars \
MCP_TRANSPORT=http \
MCP_HTTP_ADDR=:8080 \
MCP_LOG_FORMAT=json \
MCP_METRICS_ENABLED=true
done
Monitoring
Container Apps integrates with Azure Monitor. View metrics in the Azure Portal:
- Requests and response times
- Replica count
- CPU and memory usage
Enable Log Analytics for application logs:
az containerapp logs show \
--name snomed-mcp \
--resource-group $RESOURCE_GROUP \
--follow