Skip to content

Commit 2a64710

Browse files
committed
Extend helm to support port remap and extraFlags
1 parent 696bbd7 commit 2a64710

7 files changed

Lines changed: 71 additions & 14 deletions

File tree

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@ LABEL io.modelcontextprotocol.server.name="io.github.containers/kubernetes-mcp-s
1010
WORKDIR /app
1111
COPY --from=builder /app/kubernetes-mcp-server /app/kubernetes-mcp-server
1212
USER 65532:65532
13-
ENTRYPOINT ["/app/kubernetes-mcp-server", "--port", "8080"]
13+
ENTRYPOINT ["/app/kubernetes-mcp-server"]
1414

1515
EXPOSE 8080

charts/kubernetes-mcp-server/README.md

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
# kubernetes-mcp-server
22

3-
4-
5-
![Version: 0.1.0](https://img.shields.io/badge/Version-0.1.0-informational?style=flat-square) ![AppVersion: latest](https://img.shields.io/badge/AppVersion-latest-informational?style=flat-square)
3+
![Version: 0.1.0](https://img.shields.io/badge/Version-0.1.0-informational?style=flat-square) ![AppVersion: latest](https://img.shields.io/badge/AppVersion-latest-informational?style=flat-square)
64

75
Helm Chart for the Kubernetes MCP Server
86

@@ -15,15 +13,11 @@ Helm Chart for the Kubernetes MCP Server
1513
| Andrew Block | <[email protected]> | |
1614
| Marc Nuri | <[email protected]> | |
1715

18-
19-
20-
21-
2216
## Installing the Chart
2317

2418
The Chart can be installed quickly and easily to a Kubernetes cluster. Since an _Ingress_ is added as part of the default install of the Chart, the `ingress.host` Value must be specified.
2519

26-
Install the Chart using the following command from the root of this directory:
20+
Install the Chart using the following command from the root of this directory:
2721

2822
```shell
2923
helm upgrade -i -n kubernetes-mcp-server --create-namespace kubernetes-mcp-server oci://ghcr.io/containers/charts/kubernetes-mcp-server --set ingress.host=<hostname>
@@ -82,6 +76,7 @@ Each container accepts any valid Kubernetes container field including `image`, `
8276
| configFilePath | string | `"/etc/kubernetes-mcp-server/config.toml"` | |
8377
| defaultPodSecurityContext | object | `{"seccompProfile":{"type":"RuntimeDefault"}}` | Default Security Context for the Pod when one is not provided |
8478
| defaultSecurityContext | object | `{"allowPrivilegeEscalation":false,"capabilities":{"drop":["ALL"]},"runAsNonRoot":true}` | Default Security Context for the Container when one is not provided |
79+
| extraArgs | list | `[]` | Useful for passing TLS keys or other configuration options. |
8580
| extraContainers | list | `[]` | Each container is defined as a complete container spec. |
8681
| extraVolumeMounts | list | `[]` | Additional volumeMounts on the output Deployment definition. |
8782
| extraVolumes | list | `[]` | Additional volumes on the output Deployment definition. |
@@ -92,6 +87,24 @@ Each container accepts any valid Kubernetes container field including `image`, `
9287
| imagePullSecrets | list | `[]` | This is for the secrets for pulling an image from a private repository more information can be found here: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ |
9388
| ingress | object | `{"annotations":{},"className":"","enabled":true,"host":"","hosts":null,"path":"/","pathType":"ImplementationSpecific","termination":"edge","tls":null}` | This block is for setting up the ingress for more information can be found here: https://kubernetes.io/docs/concepts/services-networking/ingress/ |
9489
| livenessProbe | object | `{"httpGet":{"path":"/healthz","port":"http"}}` | Liveness and readiness probes for the container. |
90+
| metrics | object | `{"prometheusRule":{"additionalRules":[],"annotations":{},"defaultRules":{"enabled":true},"enabled":false,"labels":{}},"serviceMonitor":{"annotations":{},"enabled":false,"interval":"","labels":{},"metricRelabelings":[],"relabelings":[],"scheme":"","scrapeTimeout":"","tlsConfig":{}}}` | Metrics and monitoring configuration |
91+
| metrics.prometheusRule | object | `{"additionalRules":[],"annotations":{},"defaultRules":{"enabled":true},"enabled":false,"labels":{}}` | PrometheusRule configuration for recording rules Recording rules aggregate high-cardinality metrics for efficient querying and Telemeter compatibility |
92+
| metrics.prometheusRule.additionalRules | list | `[]` | Additional custom recording rules (appended to default rules if enabled) Example: additionalRules: - name: custom-mcp-rules rules: - record: my_custom_metric expr: sum(some_metric) |
93+
| metrics.prometheusRule.annotations | object | `{}` | Annotations for the PrometheusRule |
94+
| metrics.prometheusRule.defaultRules | object | `{"enabled":true}` | Default recording rules configuration |
95+
| metrics.prometheusRule.defaultRules.enabled | bool | `true` | Enable default recording rules that aggregate MCP metrics These rules create aggregates at two levels: Cluster-level (for Telemeter): - cluster:mcp_tool_calls:sum - Total tool calls across all tools - cluster:mcp_tool_errors:sum - Total tool errors across all tools - cluster:mcp_tool_error_rate:ratio - Error rate (errors/calls) - cluster:mcp_http_requests:sum - Total HTTP requests - cluster:mcp_http_requests_by_status:sum - HTTP requests by status class - cluster:mcp_server_info:count - Server instance count Namespace-level (for multi-tenant RBAC, grouped by k8s_namespace_name label): - namespace:mcp_tool_calls:sum - Tool calls by k8s_namespace_name - namespace:mcp_tool_errors:sum - Tool errors by k8s_namespace_name - namespace:mcp_tool_error_rate:ratio - Error rate by k8s_namespace_name - namespace:mcp_http_requests:sum - HTTP requests by k8s_namespace_name |
96+
| metrics.prometheusRule.enabled | bool | `false` | Enable PrometheusRule for recording rules |
97+
| metrics.prometheusRule.labels | object | `{}` | Additional labels for the PrometheusRule |
98+
| metrics.serviceMonitor | object | `{"annotations":{},"enabled":false,"interval":"","labels":{},"metricRelabelings":[],"relabelings":[],"scheme":"","scrapeTimeout":"","tlsConfig":{}}` | ServiceMonitor configuration for Prometheus Operator monitoring |
99+
| metrics.serviceMonitor.annotations | object | `{}` | Annotations for the ServiceMonitor |
100+
| metrics.serviceMonitor.enabled | bool | `false` | Enable ServiceMonitor for Prometheus scraping |
101+
| metrics.serviceMonitor.interval | string | `""` | Scrape interval (e.g., "30s", "1m") |
102+
| metrics.serviceMonitor.labels | object | `{}` | Additional labels for the ServiceMonitor (useful for prometheus-operator serviceMonitorSelector) |
103+
| metrics.serviceMonitor.metricRelabelings | list | `[]` | Metric relabeling rules |
104+
| metrics.serviceMonitor.relabelings | list | `[]` | Relabeling rules for metrics |
105+
| metrics.serviceMonitor.scheme | string | `""` | Scheme to use for scraping (http or https) |
106+
| metrics.serviceMonitor.scrapeTimeout | string | `""` | Scrape timeout (e.g., "10s") |
107+
| metrics.serviceMonitor.tlsConfig | object | `{}` | TLS configuration for scraping |
95108
| nameOverride | string | `""` | |
96109
| nodeSelector | object | `{}` | |
97110
| openshift | bool | `false` | Enable OpenShift specific features |
@@ -109,8 +122,10 @@ Each container accepts any valid Kubernetes container field including `image`, `
109122
| replicaCount | int | `1` | This will set the replicaset count more information can be found here: https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/ |
110123
| resources | object | `{"limits":{"cpu":"100m","memory":"128Mi"},"requests":{"cpu":"100m","memory":"128Mi"}}` | Resource requests and limits for the container. |
111124
| securityContext | object | `{}` | Define the Security Context for the Container |
112-
| service | object | `{"port":8080,"type":"ClusterIP"}` | This is for setting up a service more information can be found here: https://kubernetes.io/docs/concepts/services-networking/service/ |
125+
| service | object | `{"annotations":{},"port":8080,"targetPort":"http","type":"ClusterIP"}` | This is for setting up a service more information can be found here: https://kubernetes.io/docs/concepts/services-networking/service/ |
126+
| service.annotations | object | `{}` | Annotations to add to the service |
113127
| service.port | int | `8080` | This sets the ports more information can be found here: https://kubernetes.io/docs/concepts/services-networking/service/#field-spec-ports |
128+
| service.targetPort | string | `"http"` | Use this to remap the service port to a different container port. |
114129
| service.type | string | `"ClusterIP"` | This sets the service type more information can be found here: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types |
115130
| serviceAccount | object | `{"annotations":{},"create":true,"name":""}` | This section builds out the service account more information can be found here: https://kubernetes.io/docs/concepts/security/service-accounts/ |
116131
| serviceAccount.annotations | object | `{}` | Annotations to add to the service account |
@@ -120,7 +135,7 @@ Each container accepts any valid Kubernetes container field including `image`, `
120135

121136
## Updating the README
122137

123-
The contents of the README.md file is generated using [helm-docs](https://github.com/norwoodj/helm-docs). Whenever changes are introduced to the Chart and its _Values_, the documentation should be regenerated.
138+
The contents of the README.md file is generated using [helm-docs](https://github.com/norwoodj/helm-docs). Whenever changes are introduced to the Chart and its _Values_, the documentation should be regenerated.
124139

125140
Execute the following command to regenerate the documentation from within the Helm Chart directory.
126141

charts/kubernetes-mcp-server/templates/deployment.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ spec:
4343
args:
4444
- "--config"
4545
- "{{ .Values.configFilePath }}"
46+
{{- with .Values.extraArgs }}
47+
{{- toYaml . | nindent 12 }}
48+
{{- end }}
4649
env:
4750
- name: POD_NAMESPACE
4851
valueFrom:

charts/kubernetes-mcp-server/templates/service.yaml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,15 @@ metadata:
55
namespace: {{ .Release.Namespace }}
66
labels:
77
{{- include "kubernetes-mcp-server.labels" . | nindent 4 }}
8+
{{- with .Values.service.annotations }}
9+
annotations:
10+
{{- toYaml . | nindent 4 }}
11+
{{- end }}
812
spec:
913
type: {{ .Values.service.type }}
1014
ports:
1115
- port: {{ .Values.service.port }}
12-
targetPort: http
16+
targetPort: {{ .Values.service.targetPort | default "http" }}
1317
protocol: TCP
1418
name: http
1519
selector:

charts/kubernetes-mcp-server/values.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,11 @@ service:
118118
type: ClusterIP
119119
# -- This sets the ports more information can be found here: https://kubernetes.io/docs/concepts/services-networking/service/#field-spec-ports
120120
port: 8080
121+
# -- This sets the target port on the pod. Defaults to "http" (the container port name).
122+
# -- Use this to remap the service port to a different container port.
123+
targetPort: http
124+
# -- Annotations to add to the service
125+
annotations: {}
121126

122127
# -- This block is for setting up the ingress for more information can be found here: https://kubernetes.io/docs/concepts/services-networking/ingress/
123128
ingress:
@@ -164,6 +169,12 @@ extraVolumeMounts: []
164169
# mountPath: "/etc/foo"
165170
# readOnly: true
166171

172+
# -- Extra arguments to pass to the kubernetes-mcp-server command line.
173+
# -- Useful for passing TLS keys or other configuration options.
174+
extraArgs: []
175+
# - "--tls-cert=/etc/tls/tls.crt"
176+
# - "--tls-key=/etc/tls/tls.key"
177+
167178
# -- Additional containers to add to the pod (sidecars).
168179
# -- Each container is defined as a complete container spec.
169180
extraContainers: []

pkg/config/config_default.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ func Default() *StaticConfig {
1010
defaultConfig := StaticConfig{
1111
ListOutput: "table",
1212
Toolsets: []string{"core", "config", "helm"},
13+
Port: "8080",
1314
}
1415
overrides := defaultOverrides()
1516
mergedConfig := mergeConfig(defaultConfig, overrides)

pkg/http/http.go

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@ import (
44
"context"
55
"encoding/json"
66
"errors"
7+
"io"
8+
"log"
79
"net/http"
810
"os"
911
"os/signal"
12+
"strings"
1013
"syscall"
1114
"time"
1215

@@ -18,6 +21,21 @@ import (
1821
"github.com/containers/kubernetes-mcp-server/pkg/mcp"
1922
)
2023

24+
// tlsErrorFilterWriter filters out noisy TLS handshake errors from health checks
25+
type tlsErrorFilterWriter struct {
26+
underlying io.Writer
27+
}
28+
29+
func (w *tlsErrorFilterWriter) Write(p []byte) (n int, err error) {
30+
msg := string(p)
31+
// Filter out TLS handshake EOF errors - these are typically from
32+
// load balancer health checks that just do TCP connects
33+
if strings.Contains(msg, "TLS handshake error") && strings.Contains(msg, "EOF") {
34+
return len(p), nil // Silently discard
35+
}
36+
return w.underlying.Write(p)
37+
}
38+
2139
const (
2240
healthEndpoint = "/healthz"
2341
statsEndpoint = "/stats"
@@ -87,9 +105,14 @@ func Serve(ctx context.Context, mcpServer *mcp.Server, staticConfig *config.Stat
87105
// Wrap with metrics middleware
88106
instrumentedHandler := metricsMiddleware(wrappedMux, mcpServer)
89107

108+
// Use a custom error logger to filter out noisy TLS handshake errors
109+
// from load balancer health checks
110+
errorLog := log.New(&tlsErrorFilterWriter{underlying: os.Stderr}, "", 0)
111+
90112
httpServer := &http.Server{
91-
Addr: ":" + staticConfig.Port,
92-
Handler: instrumentedHandler,
113+
Addr: ":" + staticConfig.Port,
114+
Handler: instrumentedHandler,
115+
ErrorLog: errorLog,
93116
}
94117

95118
sseServer := mcpServer.ServeSse()

0 commit comments

Comments
 (0)