Add Helm chart and Kubernetes deployment configuration for Redmine MCP

This commit is contained in:
sha
2026-03-20 16:40:23 +02:00
parent 315992c37a
commit 2ad020761e
8 changed files with 254 additions and 4 deletions
+30 -2
View File
@@ -9,12 +9,18 @@ jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
contents: write
packages: write
steps:
- name: Checkout
uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Set image tag
id: tag
run: echo "value=sha-$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
@@ -36,6 +42,28 @@ jobs:
file: container/Containerfile
platforms: linux/amd64,linux/arm64
push: true
tags: ghcr.io/${{ github.repository }}:latest
tags: ghcr.io/${{ github.repository }}:${{ steps.tag.outputs.value }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Bump chart version and set appVersion
id: chart
run: |
CURRENT=$(grep '^version:' helm/Chart.yaml | awk '{print $2}')
MAJOR=$(echo $CURRENT | cut -d. -f1)
MINOR=$(echo $CURRENT | cut -d. -f2)
PATCH=$(echo $CURRENT | cut -d. -f3)
NEW_VERSION="$MAJOR.$MINOR.$((PATCH + 1))"
sed -i "s/^version: .*/version: $NEW_VERSION/" helm/Chart.yaml
sed -i "s/^appVersion: .*/appVersion: \"${{ steps.tag.outputs.value }}\"/" helm/Chart.yaml
echo "version=$NEW_VERSION" >> $GITHUB_OUTPUT
- name: Commit and push chart update
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add helm/Chart.yaml
git commit -m "chore: chart ${{ steps.chart.outputs.version }}, appVersion ${{ steps.tag.outputs.value }} [skip ci]"
git push
+68 -2
View File
@@ -4,8 +4,6 @@ Exposes Redmine REST API as tools for Claude Code via MCP (Model Context Protoco
## Available tools
| Tool | Description |
|------|-------------|
**Issues**
| Tool | Description |
@@ -87,6 +85,74 @@ Verify it was added:
claude mcp list
```
## Kubernetes / k3s
### Quick start
**1. Install Helm** (if not already installed):
```bash
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
```
**2. Install the chart:**
```bash
helm install redmine-mcp ./helm \
--set redmine.url=https://your.redmine.com \
--set redmine.apiKey=your_api_key
```
**3. Register with Claude Code** (using port-forward):
```bash
kubectl port-forward svc/redmine-mcp 8000:8000
claude mcp add --scope user --transport http redmine http://localhost:8000/mcp
```
---
### Expose via NodePort (access without port-forward)
```bash
helm install redmine-mcp ./helm \
--set redmine.url=https://your.redmine.com \
--set redmine.apiKey=your_api_key \
--set service.type=NodePort
```
Then find the assigned port:
```bash
kubectl get svc redmine-mcp
```
Register:
```bash
claude mcp add --scope user --transport http redmine http://<node-ip>:<node-port>/mcp
```
---
### Use an existing Kubernetes Secret
```bash
kubectl create secret generic redmine-credentials \
--from-literal=REDMINE_URL=https://your.redmine.com \
--from-literal=REDMINE_API_KEY=your_api_key
helm install redmine-mcp ./helm \
--set redmine.existingSecret=redmine-credentials
```
---
### Upgrade / uninstall
```bash
# Upgrade
helm upgrade redmine-mcp ./helm --reuse-values
# Uninstall
helm uninstall redmine-mcp
```
## Usage examples
Once registered, just ask Claude naturally in any project:
+6
View File
@@ -0,0 +1,6 @@
apiVersion: v2
name: redmine-mcp
description: Redmine MCP Server — exposes Redmine REST API as MCP tools for Claude Code
type: application
version: 0.1.0
appVersion: "0.0.0" # updated automatically by CI
+36
View File
@@ -0,0 +1,36 @@
{{/*
Expand the name of the chart.
*/}}
{{- define "redmine-mcp.name" -}}
{{- .Chart.Name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Common labels
*/}}
{{- define "redmine-mcp.labels" -}}
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }}
app.kubernetes.io/name: {{ include "redmine-mcp.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
Selector labels
*/}}
{{- define "redmine-mcp.selectorLabels" -}}
app.kubernetes.io/name: {{ include "redmine-mcp.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
Name of the secret containing Redmine credentials
*/}}
{{- define "redmine-mcp.secretName" -}}
{{- if .Values.redmine.existingSecret -}}
{{ .Values.redmine.existingSecret }}
{{- else -}}
{{ include "redmine-mcp.name" . }}-credentials
{{- end }}
{{- end }}
+58
View File
@@ -0,0 +1,58 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "redmine-mcp.name" . }}
labels:
{{- include "redmine-mcp.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
{{- include "redmine-mcp.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "redmine-mcp.labels" . | nindent 8 }}
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: 8000
protocol: TCP
envFrom:
- secretRef:
name: {{ include "redmine-mcp.secretName" . }}
env:
- name: MCP_TRANSPORT
value: http
- name: MCP_HOST
value: "0.0.0.0"
- name: MCP_PORT
value: "8000"
livenessProbe:
tcpSocket:
port: http
initialDelaySeconds: 5
periodSeconds: 10
readinessProbe:
tcpSocket:
port: http
initialDelaySeconds: 3
periodSeconds: 5
resources:
{{- toYaml .Values.resources | nindent 12 }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
+12
View File
@@ -0,0 +1,12 @@
{{- if not .Values.redmine.existingSecret }}
apiVersion: v1
kind: Secret
metadata:
name: {{ include "redmine-mcp.name" . }}-credentials
labels:
{{- include "redmine-mcp.labels" . | nindent 4 }}
type: Opaque
stringData:
REDMINE_URL: {{ .Values.redmine.url | required "redmine.url is required" | quote }}
REDMINE_API_KEY: {{ .Values.redmine.apiKey | required "redmine.apiKey is required" | quote }}
{{- end }}
+15
View File
@@ -0,0 +1,15 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "redmine-mcp.name" . }}
labels:
{{- include "redmine-mcp.labels" . | nindent 4 }}
spec:
type: {{ .Values.service.type }}
selector:
{{- include "redmine-mcp.selectorLabels" . | nindent 4 }}
ports:
- name: http
port: {{ .Values.service.port }}
targetPort: http
protocol: TCP
+29
View File
@@ -0,0 +1,29 @@
replicaCount: 1
image:
repository: ghcr.io/shadoll/redmine-mcp
tag: "" # defaults to Chart.appVersion when empty
pullPolicy: Always
redmine:
# Inline credentials (will be stored in a Secret)
url: ""
apiKey: ""
# -- Or reference an existing Secret with keys REDMINE_URL and REDMINE_API_KEY
existingSecret: ""
service:
type: ClusterIP
port: 8000
resources: {}
# limits:
# cpu: 200m
# memory: 128Mi
# requests:
# cpu: 100m
# memory: 64Mi
nodeSelector: {}
tolerations: []
affinity: {}