Skip to content

Commit 2839780

Browse files
committed
feat Adding a helm chart to instally the MCP server in k8s and updated the docs
Signed-off-by: S3B4SZ17 <[email protected]>
1 parent 7c11d2e commit 2839780

File tree

15 files changed

+616
-5
lines changed

15 files changed

+616
-5
lines changed

README.md

Lines changed: 77 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,26 @@
11
# MCP Server
22

3+
## Table of contents
4+
5+
- [MCP Server](#mcp-server)
6+
- [Table of contents](#table-of-contents)
7+
- [Description](#description)
8+
- [Available Tools](#available-tools)
9+
- [Requirements](#requirements)
10+
- [UV Setup](#uv-setup)
11+
- [Configuration](#configuration)
12+
- [`app_config.yaml`](#app_configyaml)
13+
- [Environment Variables](#environment-variables)
14+
- [Running the Server](#running-the-server)
15+
- [Docker](#docker)
16+
- [K8s Deployment](#k8s-deployment)
17+
- [UV](#uv)
18+
- [Client Configuration](#client-configuration)
19+
- [Authentication](#authentication)
20+
- [URL](#url)
21+
- [Claude Desktop App](#claude-desktop-app)
22+
- [MCP Inspector](#mcp-inspector)
23+
324
## Description
425

526
This is an implementation of an [MCP (Model Context Protocol) Server](https://modelcontextprotocol.io/quickstart/server) to allow different LLMs to query information from Sysdig Secure platform. **It is still in early development and not yet ready for production use.** New endpoints and functionalities will be added over time. The goal is to provide a simple and easy-to-use interface for querying information from Sysdig Secure platform using LLMs.
@@ -73,10 +94,6 @@ source .venv/bin/activate
7394

7495
This will create a virtual environment using `uv` and install the required dependencies.
7596

76-
### Sysdig SDK
77-
78-
You will need the Sysdig-SDK. You can find it in the `build` directory as a `.tar.gz` file that will be used by UV to install the package.
79-
8097
## Configuration
8198

8299
The application can be configured via the `app_config.yaml` file and environment variables.
@@ -105,9 +122,11 @@ You can set these variables in your shell or in a `.env` file.
105122

106123
You can also use `MCP_TRANSPORT` to override the transport protocol set in `app_config.yaml`.
107124

125+
> All of this env variables have precedence over the fields configured in the app_config.yaml.
126+
108127
## Running the Server
109128

110-
You can run the MCP server using either Docker or `uv`.
129+
You can run the MCP server using either Docker, `uv` or install it in your K8s cluster with helm.
111130

112131
### Docker
113132

@@ -129,6 +148,51 @@ By default, the server will run using the `stdio` transport. To use the `streama
129148
docker run -e MCP_TRANSPORT=streamable-http -e SYSDIG_HOST=<your_sysdig_host> -e SYSDIG_SECURE_API_TOKEN=<your_sysdig_secure_api_token> -p 8080:8080 sysdig-mcp-server
130149
```
131150

151+
### K8s Deployment
152+
153+
If you want to run the Sysdig MCP server in a K8s cluster you can use the helm chart provided in the `charts/sysdig-mcp` path
154+
155+
Modify the `values.yaml`
156+
157+
```yaml
158+
# Example values.yaml
159+
---
160+
sysdig:
161+
secrets:
162+
create: true
163+
# If enabled, the secrets will be mounted as environment variables
164+
secureAPIToken: "<your_sysdig_secure_api_token>"
165+
mcp:
166+
transport: "streamable-http"
167+
# You can set the Sysdig Tenant URL at this level or below in the app_config configmap
168+
host: "https://us2.app.sysdig.com" # <your_sysdig_host> "https://eu1.app.sysdig.com"
169+
170+
configMap:
171+
enabled: true
172+
app_config: |
173+
# Sysdig MCP Server Configuration
174+
# This file is used to configure the Sysdig MCP server.
175+
# You can add your custom configuration here.
176+
app:
177+
host: "0.0.0.0"
178+
port: 8080
179+
log_level: "error"
180+
181+
sysdig:
182+
host: "https://us2.app.sysdig.com" # <your_sysdig_host> "https://eu1.app.sysdig.com"
183+
184+
mcp:
185+
transport: streamable-http
186+
host: "0.0.0.0"
187+
port: 8080
188+
```
189+
190+
Install the chart
191+
192+
```bash,copy
193+
helm upgrade --install sysdig-mcp ./charts/sysdig-mcp/ -n sysdig-mcp -f charts/sysdig-mcp/values.yaml
194+
```
195+
132196
### UV
133197

134198
To run the server using `uv`, first set up the environment as described in the [UV Setup](#uv-setup) section. Then, run the `main.py` script:
@@ -204,3 +268,11 @@ For the Claude Desktop app, you can manually configure the MCP server by editing
204268
- Replace `<path_to_your_sysdig_mcp_server_directory>` with the absolute path to the `sysdig-mcp-server` directory.
205269

206270
4. **Save the file** and restart the Claude Desktop app for the changes to take effect.
271+
272+
### MCP Inspector
273+
274+
1. Run the [MCP Inspector](https://modelcontextprotocol.io/docs/tools/inspector) locally
275+
2. Select the transport type and have the Sysdig MCP server running accordingly.
276+
3. Pass the Authorization header if using "streamable-http" or the SYSDIG_SECURE_API_TOKEN env var if using "stdio"
277+
278+
![mcp-inspector](./docs/assets/mcp-inspector.png)

charts/sysdig-mcp/.helmignore

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Patterns to ignore when building packages.
2+
# This supports shell glob matching, relative path matching, and
3+
# negation (prefixed with !). Only one pattern per line.
4+
.DS_Store
5+
# Common VCS dirs
6+
.git/
7+
.gitignore
8+
.bzr/
9+
.bzrignore
10+
.hg/
11+
.hgignore
12+
.svn/
13+
# Common backup files
14+
*.swp
15+
*.bak
16+
*.tmp
17+
*.orig
18+
*~
19+
# Various IDEs
20+
.project
21+
.idea/
22+
*.tmproj
23+
.vscode/

charts/sysdig-mcp/Chart.yaml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
apiVersion: v2
2+
name: sysdig-mcp
3+
description: A Helm chart to deploy the Sysdig MCP server
4+
5+
# A chart can be either an 'application' or a 'library' chart.
6+
#
7+
# Application charts are a collection of templates that can be packaged into versioned archives
8+
# to be deployed.
9+
#
10+
# Library charts provide useful utilities or functions for the chart developer. They're included as
11+
# a dependency of application charts to inject those utilities and functions into the rendering
12+
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
13+
type: application
14+
15+
# This is the chart version. This version number should be incremented each time you make changes
16+
# to the chart and its templates, including the app version.
17+
# Versions are expected to follow Semantic Versioning (https://semver.org/)
18+
version: 0.1.1
19+
20+
# This is the version number of the application being deployed. This version number should be
21+
# incremented each time you make changes to the application. Versions are not expected to
22+
# follow Semantic Versioning. They should reflect the version the application is using.
23+
# It is recommended to use it with quotes.
24+
appVersion: "0.1.1"

charts/sysdig-mcp/templates/NOTES.txt

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
1. Get the application URL by running these commands:
2+
{{- if .Values.ingress.enabled }}
3+
{{- range $host := .Values.ingress.hosts }}
4+
{{- range .paths }}
5+
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }}
6+
{{- end }}
7+
{{- end }}
8+
{{- else if contains "NodePort" .Values.service.type }}
9+
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "sysdig-mcp.fullname" . }})
10+
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
11+
echo http://$NODE_IP:$NODE_PORT
12+
{{- else if contains "LoadBalancer" .Values.service.type }}
13+
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
14+
You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "sysdig-mcp.fullname" . }}'
15+
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "sysdig-mcp.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
16+
echo http://$SERVICE_IP:{{ .Values.service.port }}
17+
{{- else if contains "ClusterIP" .Values.service.type }}
18+
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "sysdig-mcp.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
19+
export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
20+
echo "Visit http://127.0.0.1:8080 to use your application"
21+
kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT
22+
{{- end }}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
{{/*
2+
Expand the name of the chart.
3+
*/}}
4+
{{- define "sysdig-mcp.name" -}}
5+
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
6+
{{- end }}
7+
8+
{{/*
9+
Create a default fully qualified app name.
10+
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
11+
If release name contains chart name it will be used as a full name.
12+
*/}}
13+
{{- define "sysdig-mcp.fullname" -}}
14+
{{- if .Values.fullnameOverride }}
15+
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
16+
{{- else }}
17+
{{- $name := default .Chart.Name .Values.nameOverride }}
18+
{{- if contains $name .Release.Name }}
19+
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
20+
{{- else }}
21+
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
22+
{{- end }}
23+
{{- end }}
24+
{{- end }}
25+
26+
{{/*
27+
Create chart name and version as used by the chart label.
28+
*/}}
29+
{{- define "sysdig-mcp.chart" -}}
30+
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
31+
{{- end }}
32+
33+
{{/*
34+
Common labels
35+
*/}}
36+
{{- define "sysdig-mcp.labels" -}}
37+
helm.sh/chart: {{ include "sysdig-mcp.chart" . }}
38+
{{ include "sysdig-mcp.selectorLabels" . }}
39+
{{- if .Chart.AppVersion }}
40+
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
41+
{{- end }}
42+
app.kubernetes.io/managed-by: {{ .Release.Service }}
43+
{{- end }}
44+
45+
{{/*
46+
Selector labels
47+
*/}}
48+
{{- define "sysdig-mcp.selectorLabels" -}}
49+
app.kubernetes.io/name: {{ include "sysdig-mcp.name" . }}
50+
app.kubernetes.io/instance: {{ .Release.Name }}
51+
{{- end }}
52+
53+
{{/*
54+
Create the name of the service account to use
55+
*/}}
56+
{{- define "sysdig-mcp.serviceAccountName" -}}
57+
{{- if .Values.serviceAccount.create }}
58+
{{- default (include "sysdig-mcp.fullname" .) .Values.serviceAccount.name }}
59+
{{- else }}
60+
{{- default "default" .Values.serviceAccount.name }}
61+
{{- end }}
62+
{{- end }}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
{{- if .Values.configMap.enabled -}}
3+
apiVersion: v1
4+
kind: ConfigMap
5+
metadata:
6+
name: {{ include "sysdig-mcp.fullname" . }}-config
7+
data:
8+
app_config.yaml: |
9+
{{- (tpl .Values.configMap.app_config $) | nindent 4 }}
10+
{{- end }}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
apiVersion: apps/v1
2+
kind: Deployment
3+
metadata:
4+
name: {{ include "sysdig-mcp.fullname" . }}
5+
labels:
6+
{{- include "sysdig-mcp.labels" . | nindent 4 }}
7+
spec:
8+
{{- if not .Values.autoscaling.enabled }}
9+
replicas: {{ .Values.replicaCount }}
10+
{{- end }}
11+
selector:
12+
matchLabels:
13+
{{- include "sysdig-mcp.selectorLabels" . | nindent 6 }}
14+
template:
15+
metadata:
16+
{{- with .Values.podAnnotations }}
17+
annotations:
18+
{{- toYaml . | nindent 8 }}
19+
{{- end }}
20+
labels:
21+
{{- include "sysdig-mcp.labels" . | nindent 8 }}
22+
{{- with .Values.podLabels }}
23+
{{- toYaml . | nindent 8 }}
24+
{{- end }}
25+
spec:
26+
{{- with .Values.imagePullSecrets }}
27+
imagePullSecrets:
28+
{{- toYaml . | nindent 8 }}
29+
{{- end }}
30+
serviceAccountName: {{ include "sysdig-mcp.serviceAccountName" . }}
31+
securityContext:
32+
{{- toYaml .Values.podSecurityContext | nindent 8 }}
33+
containers:
34+
- name: {{ .Chart.Name }}
35+
securityContext:
36+
{{- toYaml .Values.securityContext | nindent 12 }}
37+
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
38+
imagePullPolicy: {{ .Values.image.pullPolicy }}
39+
env:
40+
- name: SYSDIG_HOST
41+
value: {{ .Values.sysdig.host | quote }}
42+
{{- if .Values.sysdig.secrets.create }}
43+
- name: SYSDIG_SECURE_API_TOKEN
44+
valueFrom:
45+
secretKeyRef:
46+
name: "{{ include "sysdig-mcp.fullname" . }}-sysdig-secrets"
47+
key: SYSDIG_SECURE_API_TOKEN
48+
{{- end }}
49+
{{- if .Values.oauth.secrets.create }}
50+
- name: MCP_OAUTH_OAUTH_CLIENT_ID
51+
valueFrom:
52+
secretKeyRef:
53+
name: "{{ include "sysdig-mcp.fullname" . }}-oauth-secrets"
54+
key: clientId
55+
- name: MCP_OAUTH_OAUTH_CLIENT_SECRET
56+
valueFrom:
57+
secretKeyRef:
58+
name: "{{ include "sysdig-mcp.fullname" . }}-oauth-secrets"
59+
key: clientSecret
60+
{{- end }}
61+
- name: MCP_TRANSPORT
62+
value: {{ .Values.sysdig.mcp.transport | quote }}
63+
ports:
64+
- name: http
65+
containerPort: {{ .Values.service.port }}
66+
protocol: TCP
67+
livenessProbe:
68+
httpGet:
69+
path: /healthz
70+
port: http
71+
periodSeconds: 60
72+
readinessProbe:
73+
httpGet:
74+
path: /healthz
75+
port: http
76+
periodSeconds: 60
77+
resources:
78+
{{- toYaml .Values.resources | nindent 12 }}
79+
volumeMounts:
80+
- name: config
81+
mountPath: "/app/app_config.yaml"
82+
subPath: "app_config.yaml"
83+
{{- with .Values.volumeMounts }}
84+
{{- toYaml . | nindent 12 }}
85+
{{- end }}
86+
volumes:
87+
- name: config
88+
configMap:
89+
# Provide the name of the ConfigMap you want to mount.
90+
name: {{ include "sysdig-mcp.fullname" . }}-config
91+
{{- with .Values.volumes }}
92+
{{- toYaml . | nindent 8 }}
93+
{{- end }}
94+
{{- with .Values.nodeSelector }}
95+
nodeSelector:
96+
{{- toYaml . | nindent 8 }}
97+
{{- end }}
98+
{{- with .Values.affinity }}
99+
affinity:
100+
{{- toYaml . | nindent 8 }}
101+
{{- end }}
102+
{{- with .Values.tolerations }}
103+
tolerations:
104+
{{- toYaml . | nindent 8 }}
105+
{{- end }}

charts/sysdig-mcp/templates/hpa.yaml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{{- if .Values.autoscaling.enabled }}
2+
apiVersion: autoscaling/v2
3+
kind: HorizontalPodAutoscaler
4+
metadata:
5+
name: {{ include "sysdig-mcp.fullname" . }}
6+
labels:
7+
{{- include "sysdig-mcp.labels" . | nindent 4 }}
8+
spec:
9+
scaleTargetRef:
10+
apiVersion: apps/v1
11+
kind: Deployment
12+
name: {{ include "sysdig-mcp.fullname" . }}
13+
minReplicas: {{ .Values.autoscaling.minReplicas }}
14+
maxReplicas: {{ .Values.autoscaling.maxReplicas }}
15+
metrics:
16+
{{- if .Values.autoscaling.targetCPUUtilizationPercentage }}
17+
- type: Resource
18+
resource:
19+
name: cpu
20+
target:
21+
type: Utilization
22+
averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
23+
{{- end }}
24+
{{- if .Values.autoscaling.targetMemoryUtilizationPercentage }}
25+
- type: Resource
26+
resource:
27+
name: memory
28+
target:
29+
type: Utilization
30+
averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }}
31+
{{- end }}
32+
{{- end }}

0 commit comments

Comments
 (0)