Clinical Terminology MCP

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

VariableDefaultDescription
MCP_TRANSPORTstdioTransport mode: stdio or http
MCP_HTTP_ADDR:8080HTTP listen address
MCP_HTTP_PATH/mcpMCP endpoint path
MCP_API_KEYAPI key for authentication
MCP_ALLOWED_ORIGINSComma-separated allowed origins
MCP_TLS_CERTTLS certificate file
MCP_TLS_KEYTLS private key file
MCP_STATELESSfalseDisable session tracking
MCP_LOG_LEVELinfoLog level: debug, info, warn, error
MCP_LOG_FORMATtextLog format: text, json

OpenTelemetry (Optional)

VariableDefaultDescription
OTEL_ENABLEDfalseEnable OpenTelemetry
OTEL_SERVICE_NAMEclinical-terminology-mcpService name
OTEL_EXPORTER_OTLP_ENDPOINTlocalhost:4317OTLP endpoint
OTEL_EXPORTER_TYPEnoneExporter: 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:

EndpointPurposeUse Case
/healthCombined healthGeneral health check
/health/liveLiveness probeK8s liveness probe
/health/readyReadiness probeK8s 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 count
  • http.server.request.duration - Request latency histogram
  • http.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