FastMCP Server
Deploy FastMCP Server on Kubernetes as a streamable HTTP MCP server.
The chart runs the official docker.io/helmforge/fastmcp-server image and loads tools, resources, prompts, and knowledge
from inline ConfigMaps, S3-compatible object storage, or Git repositories.
Key Features
- Inline, S3, and Git sources — combine local ConfigMaps with external source stores.
- Documented merge precedence — inline content overrides S3, and S3 overrides Git.
- Bearer and JWT auth — use an existing Kubernetes secret for bearer tokens or configure JWT issuer, audience, and JWKS URI.
- Read-only inline mounts — tools, resources, prompts, and knowledge are mounted as separate ConfigMaps.
- Optional init sync — run source synchronization before the main container starts.
- Web UI and metrics —
/uiis enabled by default;/metricsand ServiceMonitor are opt-in. - Gateway API and Ingress — expose the MCP endpoint through an existing Gateway or a classic Ingress.
- Restricted pod defaults — non-root UID/GID
1000, dropped capabilities, RuntimeDefault seccomp, and no service account token automount. - Runtime controls — rate limiting, result caching, sandbox output limits, HPA, PDB, persistence, and JSON logs.
Installation
HTTPS Repository
helm repo add helmforge https://repo.helmforge.dev
helm repo update
helm install fastmcp-server helmforge/fastmcp-server
OCI Registry
helm install fastmcp-server oci://ghcr.io/helmforgedev/helm/fastmcp-server
Architecture
The chart renders one Deployment and one Service by default. The server listens on server.port and serves the MCP
endpoint at server.path.
| Area | Default | Notes |
|---|---|---|
| Workload | Deployment with replicaCount: 1 |
autoscaling.enabled=true delegates replicas to HPA. |
| Strategy | Recreate |
Avoids overlapping writers when a ReadWriteOnce workspace PVC is used. |
| Workspace | emptyDir at /app/workspace |
Set persistence.enabled=true for a PVC. |
| UI | enabled at /ui |
Disable with ui.enabled=false. |
| Auth | none |
Use bearer or JWT before exposing outside a trusted network. |
| Service | ClusterIP on port 8000 |
Dual-stack fields are opt-in. |
Inline source ConfigMaps are mounted read-only at:
| Values key | Mount path |
|---|---|
sources.inline.tools |
/app/inline/tools |
sources.inline.resources |
/app/inline/resources |
sources.inline.prompts |
/app/inline/prompts |
sources.inline.knowledge |
/app/inline/knowledge |
Operational Boundaries
The chart owns the FastMCP Deployment, Service, inline ConfigMaps, optionally generated Secrets, and enabled routing, storage, policy, autoscaling, disruption, and monitoring resources. The platform remains responsible for DNS, TLS, controllers, storage classes, external Secrets, source-system availability, log collection, and alerting.
Python tools, Git content, and packages execute inside the server process. Treat them as trusted code: the chart’s memory and output limits are application controls, not a container sandbox. A ready pod proves that the health endpoint responds, but it does not prove that every tool, remote source, or downstream API works.
Examples
Inline Tools
sources:
inline:
tools:
greet.py: |
def greet(name: str) -> str:
"""Greet someone by name."""
return f"Hello, {name}!"
knowledge:
overview.md: |
# Product Overview
Context document for MCP clients.
S3-Compatible Source
sources:
s3:
enabled: true
endpoint: 'https://minio.example.com'
bucket: mcp-tools
region: us-east-1
prefix: production
existingSecret: mcp-s3-credentials
The secret should contain the configured key names:
apiVersion: v1
kind: Secret
metadata:
name: mcp-s3-credentials
stringData:
access-key: replace-me
secret-key: replace-me
Git Source
sources:
git:
enabled: true
repository: 'https://github.com/your-org/mcp-tools.git'
branch: main
path: tools
existingSecret: mcp-git-token
Production Profile
server:
name: production-mcp
logLevel: WARNING
logFormat: json
strictLoading: true
auth:
type: bearer
bearer:
existingSecret: mcp-auth-token
sources:
s3:
enabled: true
bucket: mcp-production
region: us-east-1
existingSecret: mcp-s3-credentials
initSync:
enabled: true
persistence:
enabled: true
size: 5Gi
metrics:
enabled: true
serviceMonitor:
enabled: true
ingress:
enabled: true
ingressClassName: nginx
hosts:
- host: mcp.example.com
paths:
- path: /
pathType: Prefix
tls:
- hosts:
- mcp.example.com
secretName: mcp-tls
networkPolicy:
enabled: true
extraEgress:
- to:
- ipBlock:
cidr: 10.0.0.0/8
ports:
- protocol: TCP
port: 443
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
Authentication
Bearer auth creates or references a Kubernetes secret:
auth:
type: bearer
bearer:
existingSecret: mcp-auth-token
existingSecretKey: token
JWT auth is configured through issuer metadata:
auth:
type: jwt
jwt:
issuer: 'https://auth.example.com'
audience: 'mcp-server'
jwksUri: 'https://auth.example.com/.well-known/jwks.json'
When using JWT with NetworkPolicy or cluster egress controls, allow the JWKS endpoint.
Network Policy
networkPolicy.enabled=true restricts inbound traffic to the MCP service port. With an empty
networkPolicy.extraEgress, egress remains unrestricted. Supplying any egress rule enables the Egress policy type and
allows that traffic from the chart’s policy. The effective Kubernetes allow set is the union of all NetworkPolicies
that select the pods. Include DNS plus every Git, S3, JWKS, package-index, and downstream-tool destination unless
another matching policy allows it. External policy mechanisms may still deny traffic.
networkPolicy:
enabled: true
extraEgress:
- to:
- ipBlock:
cidr: 10.0.0.0/8
ports:
- protocol: TCP
port: 443
Gateway API
Gateway API renders only an HTTPRoute; the Gateway itself is owned by the platform.
gatewayAPI:
enabled: true
parentRefs:
- name: public-gateway
namespace: gateway-system
sectionName: https
hostnames:
- mcp.example.com
paths:
- type: PathPrefix
value: /mcp
Operations
Enable JSON logs and metrics for production observability:
server:
logFormat: json
metrics:
enabled: true
serviceMonitor:
enabled: true
The chart renders a ServiceMonitor only when both metrics flags are enabled. The ServiceMonitor CRD and a Prometheus Operator that selects the resource must already exist in the cluster.
Use port-forwarding for local checks:
RELEASE=fastmcp-server
NAMESPACE=default
SERVICE=$(kubectl get service -n "$NAMESPACE" \
-l "app.kubernetes.io/instance=$RELEASE,app.kubernetes.io/name=fastmcp-server" \
-o jsonpath='{.items[0].metadata.name}')
SERVICE_PORT="${SERVICE_PORT:-8000}" # Match service.port.
MCP_PATH="${MCP_PATH:-/mcp}" # Match server.path.
kubectl port-forward service/"$SERVICE" \
"$SERVICE_PORT:$SERVICE_PORT" -n "$NAMESPACE"
curl "http://127.0.0.1:$SERVICE_PORT/healthz"
# A bare GET is expected to return HTTP 406 without an Accept:
# text/event-stream header; that response confirms the route is reachable.
curl -i "http://127.0.0.1:$SERVICE_PORT$MCP_PATH"
Key Values
| Key | Default | Description |
|---|---|---|
image.repository |
docker.io/helmforge/fastmcp-server |
Container image. |
image.tag |
0.11.2 |
Image tag. |
server.name |
fastmcp-server |
Server name announced in MCP responses. |
server.port |
8000 |
HTTP port. |
server.path |
/mcp |
MCP endpoint path. |
server.logLevel |
INFO |
Log level. |
server.logFormat |
text |
Log format. |
server.strictLoading |
false |
Fail on boot if source loading has errors. |
ui.enabled |
true |
Enable Web UI at /ui. |
metrics.enabled |
false |
Enable Prometheus metrics at /metrics. |
metrics.serviceMonitor.enabled |
false |
Render a ServiceMonitor. |
auth.type |
none |
Authentication mode: none, bearer, or jwt. |
sources.inline.tools |
{} |
Inline Python tool files. |
sources.inline.resources |
{} |
Inline Python resource files. |
sources.inline.prompts |
{} |
Inline Python prompt files. |
sources.inline.knowledge |
{} |
Inline knowledge files. |
sources.s3.enabled |
false |
Enable S3-compatible source loading. |
sources.s3.existingSecret |
"" |
Existing S3 credential secret. |
sources.git.enabled |
false |
Enable Git source loading. |
sources.git.existingSecret |
"" |
Existing Git token secret. |
extraPipPackages |
[] |
Extra pip packages installed at startup. |
initSync.enabled |
false |
Run source sync in an init container. |
persistence.enabled |
false |
Use a PVC for /app/workspace. |
serviceAccount.automountServiceAccountToken |
false |
Mount the Kubernetes API token. |
service.ipFamilyPolicy |
"" |
Optional Service IP family policy. |
gatewayAPI.enabled |
false |
Render an HTTPRoute. |
ingress.enabled |
false |
Render an Ingress. |
networkPolicy.enabled |
false |
Render a NetworkPolicy for the MCP port. |
networkPolicy.extraEgress |
[] |
Additional NetworkPolicy egress rules. |
autoscaling.enabled |
false |
Render an HPA. |
pdb.enabled |
false |
Render a PodDisruptionBudget. |