mirror of
https://github.com/shadoll/redmine-mcp.git
synced 2026-08-28 11:33:28 +00:00
Add Helm chart and Kubernetes deployment configuration for Redmine MCP
This commit is contained in:
@@ -9,12 +9,18 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: write
|
||||||
packages: write
|
packages: write
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
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
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v3
|
uses: docker/setup-qemu-action@v3
|
||||||
@@ -36,6 +42,28 @@ jobs:
|
|||||||
file: container/Containerfile
|
file: container/Containerfile
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
push: true
|
push: true
|
||||||
tags: ghcr.io/${{ github.repository }}:latest
|
tags: ghcr.io/${{ github.repository }}:${{ steps.tag.outputs.value }}
|
||||||
cache-from: type=gha
|
cache-from: type=gha
|
||||||
cache-to: type=gha,mode=max
|
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
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ Exposes Redmine REST API as tools for Claude Code via MCP (Model Context Protoco
|
|||||||
|
|
||||||
## Available tools
|
## Available tools
|
||||||
|
|
||||||
| Tool | Description |
|
|
||||||
|------|-------------|
|
|
||||||
**Issues**
|
**Issues**
|
||||||
|
|
||||||
| Tool | Description |
|
| Tool | Description |
|
||||||
@@ -87,6 +85,74 @@ Verify it was added:
|
|||||||
claude mcp list
|
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
|
## Usage examples
|
||||||
|
|
||||||
Once registered, just ask Claude naturally in any project:
|
Once registered, just ask Claude naturally in any project:
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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 }}
|
||||||
@@ -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 }}
|
||||||
@@ -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 }}
|
||||||
@@ -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
|
||||||
@@ -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: {}
|
||||||
Reference in New Issue
Block a user