Remote Deployment
Deploy Clinical Terminology MCP servers as remote HTTP services.
Overview
Clinical Terminology MCP servers support two transport modes:
- stdio (default): Local process communication via stdin/stdout
- http: Remote HTTP transport using the Streamable HTTP protocol
Remote deployment enables:
- Centralized terminology services for teams
- Horizontal scaling with load balancers
- Integration with container orchestration (Kubernetes, Docker Swarm)
- API key authentication for access control
Quick Start
Run as HTTP Server
# Start snomed-mcp on port 8080
MCP_TRANSPORT=http MCP_HTTP_ADDR=:8080 ./snomed-mcp
Test the Server
# Health check
curl http://localhost:8080/health
# Initialize MCP session
curl -X POST http://localhost:8080/mcp \
-H "Content-Type: application/json" \
-H "MCP-Protocol-Version: 2025-03-26" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}'
Configuration
Environment Variables
| Variable | Default | Description |
|---|---|---|
MCP_TRANSPORT | stdio | Transport mode: stdio or http |
MCP_HTTP_ADDR | :8080 | HTTP listen address |
MCP_HTTP_PATH | /mcp | MCP endpoint path |
MCP_API_KEY | API key for authentication | |
MCP_ALLOWED_ORIGINS | Comma-separated allowed origins | |
MCP_TLS_CERT | TLS certificate file | |
MCP_TLS_KEY | TLS private key file | |
MCP_STATELESS | false | Disable session tracking |
MCP_LOG_LEVEL | info | Log level: debug, info, warn, error |
MCP_LOG_FORMAT | text | Log format: text, json |
OpenTelemetry (Optional)
| Variable | Default | Description |
|---|---|---|
OTEL_ENABLED | false | Enable OpenTelemetry |
OTEL_SERVICE_NAME | clinical-terminology-mcp | Service name |
OTEL_EXPORTER_OTLP_ENDPOINT | localhost:4317 | OTLP endpoint |
OTEL_EXPORTER_TYPE | none | Exporter: otlp, stdout, none |
Docker Deployment
Single Server
# Build the image
docker build -f snomed-mcp/Dockerfile -t snomed-mcp .
# Run the container
docker run -p 8080:8080 \
-e MCP_TRANSPORT=http \
snomed-mcp
All Servers with Docker Compose
# Start all servers
docker-compose up -d
# Check status
docker-compose ps
# View logs
docker-compose logs -f snomed
Servers are available at:
- snomed: http://localhost:8080
- rxnorm: http://localhost:8081
- icd10: http://localhost:8082
- icd11: http://localhost:8083
- loinc: http://localhost:8084
- umls: http://localhost:8085
- ucum: http://localhost:8086
With Nginx Reverse Proxy
# Start with nginx proxy profile
docker-compose --profile with-proxy up -d
Access all servers through nginx at https://localhost:443:
- https://localhost/snomed/mcp
- https://localhost/rxnorm/mcp
- etc.
Kubernetes Deployment
Using Manifests
# Apply manifests
kubectl apply -f deploy/k8s/
# Check deployment
kubectl -n clinical-terminology get pods
# Port-forward for testing
kubectl -n clinical-terminology port-forward svc/snomed-mcp 8080:8080
Using Helm
# Install chart
helm install clinical-terminology ./deploy/helm/clinical-terminology-mcp \
--namespace clinical-terminology \
--create-namespace
# With custom values
helm install clinical-terminology ./deploy/helm/clinical-terminology-mcp \
--set servers.snomed.replicas=3 \
--set ingress.enabled=true \
--set ingress.host=mcp.example.com
# Upgrade
helm upgrade clinical-terminology ./deploy/helm/clinical-terminology-mcp \
--set auth.apiKey.enabled=true \
--set auth.apiKey.existingSecret=mcp-api-key
Helm Values
# values.yaml
global:
image:
registry: ghcr.io/aktagon
tag: latest
servers:
snomed:
enabled: true
replicas: 2
resources:
requests:
memory: "64Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "500m"
ingress:
enabled: true
className: nginx
host: mcp.example.com
tls:
enabled: true
secretName: mcp-tls
auth:
apiKey:
enabled: true
existingSecret: mcp-api-key
Security
TLS Configuration
# Generate self-signed certificate (development only)
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes \
-subj "/CN=localhost"
# Start with TLS
MCP_TRANSPORT=http \
MCP_TLS_CERT=cert.pem \
MCP_TLS_KEY=key.pem \
./snomed-mcp
API Key Authentication
# Set API key
export MCP_API_KEY=$(openssl rand -hex 32)
# Start server
MCP_TRANSPORT=http MCP_API_KEY=$MCP_API_KEY ./snomed-mcp
# Client request with auth
curl -H "Authorization: Bearer $MCP_API_KEY" \
http://localhost:8080/health
Origin Validation
# Allow specific origins
MCP_ALLOWED_ORIGINS=https://claude.ai,https://app.example.com ./snomed-mcp
Localhost origins are always allowed for development.
Health Checks
Three health endpoints are available:
| Endpoint | Purpose | Use Case |
|---|---|---|
/health | Combined health | General health check |
/health/live | Liveness probe | K8s liveness probe |
/health/ready | Readiness probe | K8s readiness probe |
# Check readiness
curl http://localhost:8080/health/ready
# {"status":"ok"}
Monitoring
Structured Logging
# JSON logs for log aggregators
MCP_LOG_FORMAT=json MCP_LOG_LEVEL=info ./snomed-mcp
Example log output:
{"time":"2024-01-15T10:30:00Z","level":"INFO","msg":"request completed","method":"POST","path":"/mcp","status":200,"duration":"45ms","trace_id":"abc123","span_id":"def456"}
OpenTelemetry
# Enable OTLP export
OTEL_ENABLED=true \
OTEL_EXPORTER_TYPE=otlp \
OTEL_EXPORTER_OTLP_ENDPOINT=otel-collector:4317 \
./snomed-mcp
Metrics exported:
http.server.request.total- Request counthttp.server.request.duration- Request latency histogramhttp.server.active_requests- Active request gauge
Client Configuration
Claude Desktop
Add to claude_desktop_config.json:
{
"mcpServers": {
"snomed": {
"url": "https://mcp.example.com/snomed/mcp",
"transport": "streamable-http",
"headers": {
"Authorization": "Bearer your-api-key"
}
}
}
}
Claude Code
Create .mcp.json in project root:
{
"mcpServers": {
"snomed": {
"url": "https://mcp.example.com/snomed/mcp",
"transport": "streamable-http",
"headers": {
"Authorization": "Bearer ${MCP_API_KEY}"
}
}
}
}
Troubleshooting
Connection Refused
# Verify server is running
curl http://localhost:8080/health
# Check if port is in use
lsof -i :8080
Authentication Errors
# Test with API key
curl -v -H "Authorization: Bearer $MCP_API_KEY" \
http://localhost:8080/health
CORS Errors
Ensure the client origin is in MCP_ALLOWED_ORIGINS:
MCP_ALLOWED_ORIGINS=https://your-app.com ./snomed-mcp
Session Timeout
Sessions expire after 1 hour of inactivity. Clients should handle reconnection by sending a new initialize request.
For stateless deployments (load-balanced):
MCP_STATELESS=true ./snomed-mcp