Skip to content

Commit fa6c9d7

Browse files
committed
Adding new Sysdig MCP helm chart and updated release workflows
Signed-off-by: S3B4SZ17 <sebastian.zumbado@sysdig.com>
1 parent ae08b12 commit fa6c9d7

19 files changed

+738
-8
lines changed

.github/workflows/publish.yaml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ on:
66
- main
77
paths:
88
- pyproject.toml
9+
- Dockerfile
10+
- *.py
11+
- tests/**
12+
- tools/**
13+
- utils/**
914
workflow_dispatch:
1015
inputs:
1116
version:
@@ -15,13 +20,24 @@ on:
1520
type: string
1621

1722
jobs:
23+
tests:
24+
permissions:
25+
checks: write
26+
pull-requests: write
27+
contents: write
28+
uses: ./.github/workflows/test.yaml
29+
secrets: inherit
1830
push_to_registry:
1931
name: Push Docker image to GitHub Packages
2032
runs-on: ubuntu-latest
33+
needs: tests
2134
permissions:
2235
contents: read # required for actions/checkout
2336
packages: write # required for pushing to ghcr.io
2437
id-token: write # required for signing with cosign
38+
outputs:
39+
version: ${{ steps.extract_version.outputs.VERSION }}
40+
tag: ${{ steps.extract_version.outputs.TAG }}
2541
steps:
2642
- name: Check out the repo
2743
uses: actions/checkout@v4
@@ -31,6 +47,8 @@ jobs:
3147
run: |
3248
VERSION=$(grep 'version =' pyproject.toml | sed -e 's/version = "\(.*\)"/\1/')-$(echo $GITHUB_SHA | cut -c1-7)
3349
echo "VERSION=$VERSION" >> "$GITHUB_OUTPUT"
50+
TAG=v$(grep 'version =' pyproject.toml | sed -e 's/version = "\(.*\)"/\1/')
51+
echo "TAG=$TAG" >> "$GITHUB_OUTPUT"
3452
3553
- name: Log in to GitHub Container Registry
3654
uses: docker/login-action@v3
@@ -61,3 +79,29 @@ jobs:
6179
ghcr.io/sysdiglabs/sysdig-mcp-server:v${{ steps.extract_version.outputs.VERSION }}
6280
DIGEST: ${{ steps.build-and-push.outputs.digest }}
6381
run: echo "${TAGS}" | xargs -I {} cosign sign --yes {}@${DIGEST}
82+
83+
tag_release:
84+
name: Tag Release
85+
runs-on: ubuntu-latest
86+
needs: push_to_registry
87+
steps:
88+
- name: Check out the repo
89+
uses: actions/checkout@v4
90+
91+
- name: Get tag version
92+
id: semantic_release
93+
uses: anothrNick/github-tag-action@1.73.0
94+
env:
95+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
96+
DEFAULT_BUMP: "patch"
97+
TAG_CONTEXT: ${{ (github.base_ref != 'main') && 'branch' || 'repo' }}
98+
PRERELEASE_SUFFIX: "beta"
99+
PRERELEASE: ${{ (github.base_ref != 'main') && 'true' || 'false' }}
100+
DRY_RUN: false
101+
INITIAL_VERSION: ${{ needs.push_to_registry.outputs.tag }}
102+
103+
- name: Summary
104+
run: |
105+
echo "## Release Summary
106+
- Tag: ${{ steps.semantic_release.outputs.tag }}
107+
- Docker Image: ghcr.io/sysdiglabs/sysdig-mcp-server:v${{ needs.push_to_registry.outputs.version }}" >> $GITHUB_STEP_SUMMARY

.github/workflows/test.yaml

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,26 @@ on:
44
push:
55
branches:
66
- main
7+
- develop
8+
- feature/**
9+
- release/**
10+
- hotfix/**
11+
paths:
12+
- pyproject.toml
13+
- Dockerfile
14+
- *.py
15+
- tests/**
16+
- tools/**
17+
- utils/**
718
pull_request:
19+
paths:
20+
- pyproject.toml
21+
- Dockerfile
22+
- *.py
23+
- tests/**
24+
- tools/**
25+
- utils/**
26+
workflow_call:
827

928
jobs:
1029
test:
@@ -34,3 +53,52 @@ jobs:
3453

3554
- name: Run Unit Tests
3655
run: make test
56+
57+
pre_release:
58+
name: Tag Release
59+
runs-on: ubuntu-latest
60+
needs: test
61+
permissions:
62+
contents: write # required for creating a tag
63+
steps:
64+
- name: Check out the repo
65+
uses: actions/checkout@v4
66+
with:
67+
ref: ${{ github.head_ref }} # checkout the correct branch name
68+
fetch-depth: 0
69+
70+
- name: Extract current version
71+
id: pyproject_version
72+
run: |
73+
TAG=v$(grep 'version =' pyproject.toml | sed -e 's/version = "\(.*\)"/\1/')
74+
echo "TAG=$TAG" >> "$GITHUB_OUTPUT"
75+
76+
- name: Get tag version
77+
id: semantic_release
78+
uses: anothrNick/github-tag-action@1.73.0
79+
env:
80+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
81+
DEFAULT_BUMP: "patch"
82+
TAG_CONTEXT: ${{ (github.base_ref != 'main') && 'branch' || 'repo' }}
83+
PRERELEASE_SUFFIX: "beta"
84+
PRERELEASE: ${{ (github.base_ref != 'main') && 'true' || 'false' }}
85+
DRY_RUN: true
86+
INITIAL_VERSION: ${{ steps.pyproject_version.outputs.TAG }}
87+
88+
- name: Compare versions
89+
run: |
90+
echo "Current version: ${{ steps.pyproject_version.outputs.TAG }}"
91+
echo "New version: ${{ steps.semantic_release.outputs.tag }}"
92+
if [ "${{ steps.pyproject_version.outputs.TAG }}" != "${{ steps.semantic_release.outputs.tag }}" ]; then
93+
echo "### Version mismatch detected! :warning:
94+
Current pyproject version: ${{ steps.pyproject_version.outputs.TAG }}
95+
New Tag version: **${{ steps.semantic_release.outputs.tag }}**
96+
Current Tag: ${{ steps.semantic_release.outputs.old_tag }}
97+
Please update the version in pyproject.toml." >> $GITHUB_STEP_SUMMARY
98+
exit 1
99+
else
100+
echo "### Version match confirmed! :rocket:
101+
Current pyproject version: ${{ steps.pyproject_version.outputs.TAG }}
102+
New Tag version: **${{ steps.semantic_release.outputs.tag }}**
103+
The version is up-to-date." >> $GITHUB_STEP_SUMMARY
104+
fi

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_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:
@@ -233,3 +297,11 @@ For the Claude Desktop app, you can manually configure the MCP server by editing
233297
- Replace `<path_to_your_sysdig_mcp_server_directory>` with the absolute path to the `sysdig-mcp-server` directory.
234298

235299
4. **Save the file** and restart the Claude Desktop app for the changes to take effect.
300+
301+
### MCP Inspector
302+
303+
1. Run the [MCP Inspector](https://modelcontextprotocol.io/docs/tools/inspector) locally
304+
2. Select the transport type and have the Sysdig MCP server running accordingly.
305+
3. Pass the Authorization header if using "streamable-http" or the SYSDIG_SECURE_API_TOKEN env var if using "stdio"
306+
307+
![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 }}

0 commit comments

Comments
 (0)