Back to Home

Deploy MCP Servers in Kubernetes: Architecture and JWT

The article describes the migration of MCP servers from local launch to centralized infrastructure in Kubernetes. It covers sidecar proxying patterns, JWT authentication setup via Envoy and secrets management using Vault.

How to Deploy MCP Servers in Kubernetes for the Entire Team
Advertisement 728x90

# Centralized Deployment of MCP Servers in Kubernetes: Architecture, Authentication, and Secret Management

Running MCP servers locally via package managers or containers quickly becomes a bottleneck when scaling AI infrastructure across a team. Fragmented runtimes, uncontrolled spread of credentials, and lack of a single entry point hinder secure integration of language models into the enterprise environment. This article outlines a practical migration path from isolated instances to a centralized Kubernetes architecture using sidecar proxying, JWT validation, and secret orchestration.

Architecture Evolution: From Local Processes to Containerization

At the initial stage of Model Context Protocol adoption, using ready-made remote endpoints from vendors is sufficient. Configuration simply involves specifying a URL in the client app, with the provider handling authentication and scaling. However, integrating internal systems (Kubernetes, Grafana, databases) requires running servers independently.

The standard approach with local npx, uvx calls, or compiled binaries creates dependency management headaches. Each integration needs its own runtime, leading to version conflicts and complicating onboarding for new team members. Storing production access tokens in local config files also violates core information security principles.

Google AdInline article slot

Containerization addresses environment isolation. Running each MCP server in its own container with environment variable passthrough standardizes deployment at the workstation level. Example config for isolated launch:

{
  "mcpServers": {
    "grafana": {
      "command": "docker",
      "args": [
        "run", "--rm", "-i",
        "-e", "GRAFANA_URL",
        "-e", "GRAFANA_SERVICE_ACCOUNT_TOKEN",
        "grafana/mcp-grafana",
        "-t", "stdio"
      ],
      "env": {
        "GRAFANA_URL": "https://grafana.example.com",
        "GRAFANA_SERVICE_ACCOUNT_TOKEN": "<token>"
      }
    }
  }
}

Despite better isolation, local Docker doesn't enable shared access. Automated pipelines, CI/CD systems, and non-technical users can't effectively work with scattered containers. This creates a need to migrate MCP servers to shared infrastructure with centralized lifecycle management.

Orchestration in Kubernetes: Proxying and Universal Deployment

Migrating MCP servers to a cluster requires bridging architectural mismatches: most servers use stdio, while Kubernetes networking relies on HTTP/HTTPS. The sidecar pattern with MCP Gateway fills this gap. The proxy container handles incoming HTTP requests (Streamable HTTP or SSE), forwards them to the target process's stdin, and relays responses back over the network.

Google AdInline article slot

Since MCP servers in Streamable HTTP mode are stateless services, they're perfect for horizontal scaling via HPA. To avoid duplicating manifests per integration, use a universal Helm chart supporting two modes:

  • proxy — sidecar container launch for HTTP-to-stdio translation.
  • native — direct exposure of services already supporting HTTP transport.

Deployment config via values.yaml offers flexible control over networking, secret injection, and routing:

mode: proxy
proxy:
  image:
    repository: node
    tag: "20-bookworm"
    pullPolicy: IfNotPresent
  gateway:
    package: "@michlyn/mcpgateway"
    stdioCommand: "npx -y @digitalocean/mcp --services apps,droplets,doks,networking"
    outputTransport: streamable-http
    port: 8080
    httpPath: /mcp
vault:
  enabled: true
  role: "mcp"
  path: "kubernetes_dev-fra1-01"
env:
  - name: DIGITALOCEAN_API_TOKEN
    value: vault:devops/data/ai/mcp/digitalocean#token
ingress:
  enabled: true
  className: "internal"
  annotations:
    nginx.ingress.kubernetes.io/proxy-buffering: "off"
    nginx.ingress.kubernetes.io/proxy-http-version: "1.1"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"

Integration with HashiCorp Vault or External Secrets Operator keeps credentials out of version control. Ingress controllers or Gateway API manage routing, while disabling buffering and extending timeouts ensure proper support for long-lived connections and streaming data.

Google AdInline article slot

Security and Authentication: JWT, Envoy, and Access Management

MCP protocol lacks built-in authentication, so protection must be implemented at the infrastructure gateway. Basic auth falls short for enterprise security, making JWT validation via Envoy Gateway the best option. The gateway checks token signature, issuer, and audience before requests hit the MCP server pod.

Key and token generation uses standard crypto tools. The public key is packaged as JWKS in a ConfigMap for Envoy to load and verify:

# Generate RSA keys and form JWT
openssl genrsa -out mcp-jwt-private.pem 4096
openssl rsa -in mcp-jwt-private.pem -pubout -out mcp-jwt-public.pem
KID=$(openssl rand -hex 16)
HEADER=$(echo -n '{"alg":"RS256","typ":"JWT","kid":"${KID}"}' | base64 -w0 | tr '+/' '-_' | tr -d '=')
PAYLOAD=$(echo -n '{"sub":"claude-desktop","aud":"mcp-servers","iss":"https://your-domain.com","iat":$(date +%s),"exp":$(( $(date +%s) + 31536000 ))}' | base64 -w0 | tr '+/' '-_' | tr -d '=')
SIGNATURE=$(echo -n "${HEADER}.${PAYLOAD}" | openssl dgst -sha256 -sign mcp-jwt-private.pem | base64 -w0 | tr '+/' '-_' | tr -d '=')
echo "${HEADER}.${PAYLOAD}.${SIGNATURE}"

At this stage of protocol maturity, architectural limitations persist. Target system access uses shared service accounts—fine for reads, risky for writes. No end-user context transmission blocks per-user authorization and detailed tool call auditing. Envoy logging captures only network metadata, not specific MCP method parameters.

Key Takeaways

  • Local MCP server launches don't scale team-wide due to runtime conflicts and credential leak risks.
  • Sidecar pattern with MCP Gateway bridges stdio transport and Kubernetes networking protocols.
  • Stateless Streamable HTTP architecture supports standard HPA for auto horizontal scaling.
  • Offload JWT validation and routing to API Gateway, as the protocol has no native auth.
  • No user context in MCP limits granular authorization and end-to-end auditing for now.

— Editorial Team

Advertisement 728x90

Read Next