Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions charts/github-mcp-server/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ The default deployment starts the server in HTTP mode on port `8082`, read-only
The chart is stateless by default.
If persistence is enabled and the Deployment is scaled above one replica, use `ReadWriteMany` storage or disable persistence to avoid sharing one `ReadWriteOnce` PVC across pods.

Ingress class rendering is optional. Set `ingress.ingressClassName: ""` to omit `spec.ingressClassName`.
When `networkPolicy.enabled=true`, ingress is restricted to the configured peers.
Setting `networkPolicy.extraEgress` also enables egress isolation with built-in DNS and HTTPS allowances, then appends the supplied proxy or API-server rules.

## Token Configuration

Use a Kubernetes Secret for production:
Expand Down
46 changes: 36 additions & 10 deletions charts/github-mcp-server/templates/NOTES.txt
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
{{/* SPDX-License-Identifier: Apache-2.0 */}}
GitHub MCP Server has been deployed.
1. Release

Access:
GitHub MCP Server has been deployed as release {{ .Release.Name }} in namespace {{ .Release.Namespace }}.

- Service: http://{{ include "github-mcp-server.fullname" . }}.{{ .Release.Namespace }}.svc:{{ .Values.service.port }}
- Port-forward: kubectl port-forward svc/{{ include "github-mcp-server.fullname" . }} 8082:{{ .Values.service.port }} -n {{ .Release.Namespace }}
2. Access

- Service DNS: http://{{ include "github-mcp-server.fullname" . }}.{{ .Release.Namespace }}.svc:{{ .Values.service.port }}
- Port-forward:
kubectl port-forward svc/{{ include "github-mcp-server.fullname" . }} 8082:{{ .Values.service.port }} -n {{ .Release.Namespace }}
- Local MCP URL: http://127.0.0.1:8082

GitHub runtime:
3. GitHub Runtime

- Read-only mode: {{ .Values.github.readOnly }}
- Toolsets: {{ .Values.github.toolsets }}
Expand All @@ -23,18 +26,41 @@ GitHub runtime:
- No GitHub token is configured; set github.existingSecret for production.
{{- end }}

Security:
4. Security

- Keep this service internal or protect Ingress/Gateway with external authentication.
- Keep github.readOnly=true unless write tools are explicitly required.
- Restrict token scopes to the enabled toolsets.
- When NetworkPolicy is enabled, use networkPolicy.extraEgress for required private proxies or GitHub Enterprise endpoints.
- Enable networkPolicy.enabled and set networkPolicy.ingressFrom for restricted clients.

5. Scaling

- Current replicas: {{ .Values.replicaCount }}
- If persistence.enabled=true and replicaCount > 1, persistence.accessModes must include ReadWriteMany.
- Prefer stateless replicas with persistence.enabled=false for horizontal scaling.

6. Networking

{{- if .Values.ingress.enabled }}
- Ingress is enabled.
{{- else }}
- Ingress is disabled.
{{- end }}
{{- if .Values.gateway.enabled }}
- Gateway API HTTPRoute is enabled.
{{- else }}
- Gateway API HTTPRoute is disabled.
{{- end }}

Troubleshooting:
7. Troubleshooting

- kubectl get pod -l app.kubernetes.io/instance={{ .Release.Name }} -n {{ .Release.Namespace }}
- kubectl logs deploy/{{ include "github-mcp-server.fullname" . }} -n {{ .Release.Namespace }}
- Pods:
kubectl get pod -l app.kubernetes.io/instance={{ .Release.Name }} -n {{ .Release.Namespace }}
- Logs:
kubectl logs deploy/{{ include "github-mcp-server.fullname" . }} -n {{ .Release.Namespace }}

Resources:
8. Resources

- Chart documentation: https://helmforge.dev/docs/charts/github-mcp-server
- Upstream: https://github.com/github/github-mcp-server
Expand Down
15 changes: 15 additions & 0 deletions charts/github-mcp-server/templates/_helpers.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,18 @@ app.kubernetes.io/part-of: helmforge
{{- end -}}
{{- end -}}
{{- end -}}

{{- define "github-mcp-server.validate" -}}
{{- if and .Values.github.requireToken (not (or .Values.github.personalAccessToken .Values.github.existingSecret)) -}}
{{- fail "github.requireToken=true requires github.personalAccessToken or github.existingSecret" -}}
{{- end -}}
{{- if and (gt (int .Values.replicaCount) 1) .Values.persistence.enabled (not .Values.persistence.existingClaim) (not (has "ReadWriteMany" .Values.persistence.accessModes)) -}}
{{- fail "replicaCount > 1 with persistence.enabled requires persistence.accessModes to include ReadWriteMany or persistence.enabled=false" -}}
{{- end -}}
{{- $podLabels := .Values.podLabels | default dict -}}
{{- range $key := (list "app.kubernetes.io/name" "app.kubernetes.io/instance") -}}
{{- if hasKey $podLabels $key -}}
{{- fail (printf "podLabels must not override the selector label %s" $key) -}}
{{- end -}}
{{- end -}}
{{- end -}}
2 changes: 1 addition & 1 deletion charts/github-mcp-server/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ spec:
template:
metadata:
labels:
{{- include "github-mcp-server.labels" . | nindent 8 }}
{{- include "github-mcp-server.selectorLabels" . | nindent 8 }}
{{- with .Values.podLabels }}
{{- toYaml . | nindent 8 }}
{{- end }}
Expand Down
4 changes: 3 additions & 1 deletion charts/github-mcp-server/templates/ingress.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ metadata:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
ingressClassName: {{ .Values.ingress.ingressClassName | quote }}
{{- with .Values.ingress.ingressClassName }}
ingressClassName: {{ . | quote }}
{{- end }}
{{- with .Values.ingress.tls }}
tls:
{{- toYaml . | nindent 4 }}
Expand Down
25 changes: 25 additions & 0 deletions charts/github-mcp-server/templates/networkpolicy.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{{/* SPDX-License-Identifier: Apache-2.0 */}}
{{- if .Values.networkPolicy.enabled }}
{{- $extraEgress := .Values.networkPolicy.extraEgress | default list }}
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
Expand All @@ -12,6 +13,9 @@ spec:
{{- include "github-mcp-server.selectorLabels" . | nindent 6 }}
policyTypes:
- Ingress
{{- if $extraEgress }}
- Egress
{{- end }}
ingress:
- from:
{{- if .Values.networkPolicy.ingressFrom }}
Expand All @@ -22,4 +26,25 @@ spec:
ports:
- protocol: TCP
port: http
{{- if $extraEgress }}
egress:
- to:
- namespaceSelector: {}
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
- to:
- ipBlock:
cidr: 0.0.0.0/0
- ipBlock:
cidr: ::/0
ports:
- protocol: TCP
port: 443
{{- with $extraEgress }}
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}
{{- end }}
9 changes: 2 additions & 7 deletions charts/github-mcp-server/templates/validate.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,2 @@
{{/* SPDX-License-Identifier: Apache-2.0 */}}
{{- if and .Values.github.requireToken (not (or .Values.github.personalAccessToken .Values.github.existingSecret)) -}}
{{- fail "github.requireToken=true requires github.personalAccessToken or github.existingSecret" -}}
{{- end -}}
{{- if and (gt (int .Values.replicaCount) 1) .Values.persistence.enabled (not (has "ReadWriteMany" .Values.persistence.accessModes)) -}}
{{- fail "replicaCount > 1 with persistence.enabled requires persistence.accessModes to include ReadWriteMany or persistence.enabled=false" -}}
{{- end -}}
# SPDX-License-Identifier: Apache-2.0
{{- include "github-mcp-server.validate" . -}}
26 changes: 26 additions & 0 deletions charts/github-mcp-server/tests/networkpolicy_test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,29 @@ tests:
content:
protocol: TCP
port: http

- it: appends extra egress rules
set:
networkPolicy:
enabled: true
extraEgress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
ports:
- protocol: UDP
port: 53
asserts:
- contains:
path: spec.policyTypes
content: Egress
- equal:
path: spec.egress[0].ports[0].port
value: 53
- equal:
path: spec.egress[1].ports[0].port
value: 443
- equal:
path: spec.egress[2].ports[0].port
value: 53
13 changes: 13 additions & 0 deletions charts/github-mcp-server/tests/templates_test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,19 @@ tests:
- equal:
path: metadata.annotations["cert-manager.io/cluster-issuer"]
value: letsencrypt
- it: omits ingressClassName when empty
template: templates/ingress.yaml
set:
ingress.enabled: true
ingress.ingressClassName: ""
ingress.hosts:
- host: github-mcp-server.example.com
paths:
- path: /
pathType: Prefix
asserts:
- notExists:
path: spec.ingressClassName
- it: renders HTTPRoute hostnames
template: templates/httproute.yaml
set:
Expand Down
22 changes: 22 additions & 0 deletions charts/github-mcp-server/tests/validation_test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,25 @@ tests:
asserts:
- failedTemplate:
errorMessage: "replicaCount > 1 with persistence.enabled requires persistence.accessModes to include ReadWriteMany or persistence.enabled=false"
- it: fails when podLabels override selector instance
set:
podLabels:
app.kubernetes.io/instance: custom
asserts:
- failedTemplate:
errorMessage: "podLabels must not override the selector label app.kubernetes.io/instance"
- it: allows scaling with an existing persistence claim
set:
replicaCount: 2
persistence.enabled: true
persistence.existingClaim: github-mcp-data-rwx
persistence.accessModes[0]: ReadWriteOnce
asserts:
- notFailedTemplate: {}
- it: fails when podLabels override selector labels
set:
podLabels:
app.kubernetes.io/name: custom
asserts:
- failedTemplate:
errorMessage: "podLabels must not override the selector label app.kubernetes.io/name"
7 changes: 6 additions & 1 deletion charts/github-mcp-server/values.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,12 @@
"type": "object",
"properties": {
"enabled": { "type": "boolean", "default": false },
"ingressFrom": { "type": "array", "items": { "type": "object" } }
"ingressFrom": { "type": "array", "items": { "type": "object" } },
"extraEgress": {
"type": "array",
"description": "Additional egress rules appended after the built-in DNS and HTTPS allowances",
"items": { "type": "object" }
}
}
},
"probes": { "$ref": "#/definitions/probes" },
Expand Down
2 changes: 2 additions & 0 deletions charts/github-mcp-server/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ networkPolicy:
enabled: false
# -- Ingress peers allowed to reach the MCP server. Empty allows all namespaces when policy is enabled.
ingressFrom: []
# -- Additional egress rules appended after the built-in DNS and HTTPS allowances.
extraEgress: []

probes:
startup: { enabled: true, initialDelaySeconds: 5, periodSeconds: 10, timeoutSeconds: 3, failureThreshold: 60 }
Expand Down