thruk-mcp 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. thruk_mcp-1.0.0/.env.example +34 -0
  2. thruk_mcp-1.0.0/.github/workflows/ci.yml +45 -0
  3. thruk_mcp-1.0.0/.github/workflows/integration.yml +59 -0
  4. thruk_mcp-1.0.0/.github/workflows/pypi.yml +50 -0
  5. thruk_mcp-1.0.0/.github/workflows/release.yml +46 -0
  6. thruk_mcp-1.0.0/.gitignore +24 -0
  7. thruk_mcp-1.0.0/.pre-commit-config.yaml +27 -0
  8. thruk_mcp-1.0.0/CHANGELOG.md +208 -0
  9. thruk_mcp-1.0.0/CONTRIBUTING.md +86 -0
  10. thruk_mcp-1.0.0/Dockerfile +20 -0
  11. thruk_mcp-1.0.0/LICENSE +21 -0
  12. thruk_mcp-1.0.0/PKG-INFO +292 -0
  13. thruk_mcp-1.0.0/README.md +262 -0
  14. thruk_mcp-1.0.0/SUPPORT.md +66 -0
  15. thruk_mcp-1.0.0/UPGRADING.md +67 -0
  16. thruk_mcp-1.0.0/catalog/readme.md +6 -0
  17. thruk_mcp-1.0.0/catalog/server.yaml +100 -0
  18. thruk_mcp-1.0.0/catalog/tools.json +31 -0
  19. thruk_mcp-1.0.0/compose.test.yml +23 -0
  20. thruk_mcp-1.0.0/compose.yml +12 -0
  21. thruk_mcp-1.0.0/pyproject.toml +91 -0
  22. thruk_mcp-1.0.0/scripts/get-test-api-key.sh +17 -0
  23. thruk_mcp-1.0.0/src/thruk_mcp/__init__.py +3 -0
  24. thruk_mcp-1.0.0/src/thruk_mcp/__main__.py +49 -0
  25. thruk_mcp-1.0.0/src/thruk_mcp/audit.py +102 -0
  26. thruk_mcp-1.0.0/src/thruk_mcp/cache.py +46 -0
  27. thruk_mcp-1.0.0/src/thruk_mcp/client.py +253 -0
  28. thruk_mcp-1.0.0/src/thruk_mcp/config.py +72 -0
  29. thruk_mcp-1.0.0/src/thruk_mcp/server.py +990 -0
  30. thruk_mcp-1.0.0/tests/__init__.py +0 -0
  31. thruk_mcp-1.0.0/tests/conftest.py +34 -0
  32. thruk_mcp-1.0.0/tests/integration/__init__.py +0 -0
  33. thruk_mcp-1.0.0/tests/integration/test_live.py +58 -0
  34. thruk_mcp-1.0.0/tests/test_cache.py +41 -0
  35. thruk_mcp-1.0.0/tests/test_client.py +43 -0
  36. thruk_mcp-1.0.0/tests/test_config.py +39 -0
  37. thruk_mcp-1.0.0/tests/test_list_params.py +36 -0
  38. thruk_mcp-1.0.0/tests/test_pagination_retry.py +67 -0
  39. thruk_mcp-1.0.0/tests/test_prompts.py +59 -0
  40. thruk_mcp-1.0.0/tests/test_resources.py +56 -0
  41. thruk_mcp-1.0.0/tests/test_run_background.py +49 -0
  42. thruk_mcp-1.0.0/tests/test_security.py +160 -0
  43. thruk_mcp-1.0.0/tests/test_tools.py +355 -0
@@ -0,0 +1,34 @@
1
+ # Thruk REST API endpoint (no trailing slash). Example: https://monitor.example.com/thruk
2
+ THRUK_BASE_URL=http://localhost/thruk
3
+
4
+ # API key generated from the Thruk user profile page (X-Thruk-Auth-Key).
5
+ # A super-user/system key can be combined with THRUK_AUTH_USER to impersonate.
6
+ THRUK_API_KEY=changeme
7
+
8
+ # Optional: user to impersonate (only effective with a superuser API key)
9
+ THRUK_AUTH_USER=
10
+
11
+ # Verify TLS certificate (set to false only for dev / self-signed)
12
+ THRUK_VERIFY_SSL=true
13
+
14
+ # Default request timeout in seconds
15
+ THRUK_TIMEOUT=30
16
+
17
+ # Optional: default backend(s) to query, comma-separated site names. Empty = all.
18
+ THRUK_DEFAULT_BACKENDS=
19
+
20
+ # ----------------- v0.6 security / multi-tenant knobs -----------------------
21
+ # When true, all WRITE tools (acknowledge, schedule_*_downtime, recheck,
22
+ # delete_*, run_background_query) are stripped from the MCP server. Use this
23
+ # for agents that should only OBSERVE the monitoring state.
24
+ THRUK_READ_ONLY=false
25
+
26
+ # Optional allowlist of tool names (comma-separated, fnmatch wildcards
27
+ # accepted). Empty = no filter. Example: "thruk_list_*,thruk_problems,thruk_stats"
28
+ THRUK_ENABLED_TOOLS=
29
+
30
+ # Emit a JSON audit line on stderr for every WRITE tool invocation.
31
+ THRUK_AUDIT_LOG=true
32
+
33
+ # Cap the number of concurrent in-flight HTTP requests to Thruk. 0 = unlimited.
34
+ THRUK_MAX_CONCURRENT=0
@@ -0,0 +1,45 @@
1
+ name: CI
2
+ on:
3
+ push:
4
+ branches: [main]
5
+ pull_request:
6
+ concurrency:
7
+ group: ci-${{ github.ref }}
8
+ cancel-in-progress: true
9
+
10
+ jobs:
11
+ lint-test:
12
+ runs-on: ubuntu-latest
13
+ strategy:
14
+ fail-fast: false
15
+ matrix:
16
+ python: ["3.10", "3.11", "3.12"]
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+ - uses: actions/setup-python@v5
20
+ with:
21
+ python-version: ${{ matrix.python }}
22
+ cache: pip
23
+ - run: pip install -e ".[dev]"
24
+ - run: ruff check src tests
25
+ - run: ruff format --check src tests
26
+ - run: mypy src
27
+ - name: pytest with coverage
28
+ run: pytest -v --cov=thruk_mcp --cov-report=term --cov-report=xml --cov-fail-under=80
29
+ - name: Upload coverage to Codecov
30
+ if: matrix.python == '3.12'
31
+ uses: codecov/codecov-action@v5
32
+ with:
33
+ token: ${{ secrets.CODECOV_TOKEN }}
34
+ files: ./coverage.xml
35
+ flags: unittests
36
+ name: thruk-mcp-py3.12
37
+ fail_ci_if_error: true
38
+
39
+ docker:
40
+ needs: lint-test
41
+ runs-on: ubuntu-latest
42
+ steps:
43
+ - uses: actions/checkout@v4
44
+ - uses: docker/setup-buildx-action@v3
45
+ - run: docker build -t thruk-mcp:ci .
@@ -0,0 +1,59 @@
1
+ name: Integration tests (live Thruk)
2
+
3
+ on:
4
+ schedule:
5
+ - cron: "0 3 * * *" # 03:00 UTC nightly
6
+ workflow_dispatch:
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ jobs:
12
+ live:
13
+ runs-on: ubuntu-latest
14
+ # Don't fail the badge while the OMD demo image upstream is in flux;
15
+ # we treat live failures as warnings until v1.1.
16
+ continue-on-error: true
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+ - uses: actions/setup-python@v5
20
+ with:
21
+ python-version: "3.12"
22
+ cache: pip
23
+ - run: pip install -e ".[dev]"
24
+
25
+ - name: Start OMD demo
26
+ run: docker compose -f compose.test.yml up -d
27
+
28
+ - name: Wait for OMD to boot
29
+ run: |
30
+ for i in $(seq 1 60); do
31
+ if curl -fsS -o /dev/null "http://localhost:8080/demo/thruk/cgi-bin/login.cgi"; then
32
+ echo "OMD ready after ${i}0s"; exit 0
33
+ fi
34
+ sleep 10
35
+ done
36
+ docker compose -f compose.test.yml logs --tail=200
37
+ exit 1
38
+
39
+ - name: Generate Thruk API key
40
+ id: apikey
41
+ run: |
42
+ key=$(./scripts/get-test-api-key.sh)
43
+ echo "::add-mask::$key"
44
+ echo "key=$key" >> "$GITHUB_OUTPUT"
45
+
46
+ - name: Run live integration tests
47
+ env:
48
+ THRUK_BASE_URL: http://localhost:8080/demo
49
+ THRUK_API_KEY: ${{ steps.apikey.outputs.key }}
50
+ THRUK_VERIFY_SSL: "false"
51
+ run: pytest -v -m integration
52
+
53
+ - name: Dump OMD logs on failure
54
+ if: failure()
55
+ run: docker compose -f compose.test.yml logs --tail=400
56
+
57
+ - name: Tear down
58
+ if: always()
59
+ run: docker compose -f compose.test.yml down -v
@@ -0,0 +1,50 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+ workflow_dispatch:
7
+
8
+ permissions:
9
+ contents: read
10
+ id-token: write # required for PyPI trusted publishing
11
+
12
+ jobs:
13
+ build:
14
+ name: Build wheel + sdist
15
+ runs-on: ubuntu-latest
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+ - uses: actions/setup-python@v5
19
+ with:
20
+ python-version: "3.12"
21
+ - run: pip install --upgrade build
22
+ - run: python -m build
23
+ - uses: actions/upload-artifact@v4
24
+ with:
25
+ name: dist
26
+ path: dist/
27
+
28
+ publish:
29
+ name: Publish to PyPI (trusted publisher)
30
+ needs: build
31
+ runs-on: ubuntu-latest
32
+ environment:
33
+ name: pypi
34
+ url: https://pypi.org/p/thruk-mcp
35
+ steps:
36
+ - uses: actions/download-artifact@v4
37
+ with:
38
+ name: dist
39
+ path: dist/
40
+ - uses: pypa/gh-action-pypi-publish@release/v1
41
+ with:
42
+ # OIDC trusted publishing - no token needed once the pending
43
+ # publisher is configured on pypi.org (Account Settings -> Publishing).
44
+ # Required values for that pending publisher:
45
+ # PyPI project name: thruk-mcp
46
+ # Repository owner: k9fr4n
47
+ # Repository name: thruk-mcp
48
+ # Workflow name: pypi.yml
49
+ # Environment: pypi
50
+ attestations: true
@@ -0,0 +1,46 @@
1
+ name: Release image
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ tags: ["v*"]
7
+ workflow_dispatch:
8
+
9
+ permissions:
10
+ contents: read
11
+ packages: write
12
+
13
+ jobs:
14
+ image:
15
+ runs-on: ubuntu-latest
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+
19
+ - uses: docker/setup-qemu-action@v3
20
+ - uses: docker/setup-buildx-action@v3
21
+
22
+ - uses: docker/login-action@v3
23
+ with:
24
+ registry: ghcr.io
25
+ username: ${{ github.actor }}
26
+ password: ${{ secrets.GITHUB_TOKEN }}
27
+
28
+ - id: meta
29
+ uses: docker/metadata-action@v5
30
+ with:
31
+ images: ghcr.io/${{ github.repository_owner }}/thruk-mcp
32
+ tags: |
33
+ type=ref,event=branch
34
+ type=semver,pattern={{version}}
35
+ type=semver,pattern={{major}}.{{minor}}
36
+ type=raw,value=latest,enable={{is_default_branch}}
37
+
38
+ - uses: docker/build-push-action@v6
39
+ with:
40
+ context: .
41
+ platforms: linux/amd64,linux/arm64
42
+ push: true
43
+ tags: ${{ steps.meta.outputs.tags }}
44
+ labels: ${{ steps.meta.outputs.labels }}
45
+ provenance: true
46
+ sbom: true
@@ -0,0 +1,24 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ .eggs/
6
+ build/
7
+ dist/
8
+ .venv/
9
+ venv/
10
+ .env
11
+ .env.local
12
+
13
+ # Testing / tooling
14
+ .pytest_cache/
15
+ .ruff_cache/
16
+ .mypy_cache/
17
+ .coverage
18
+ htmlcov/
19
+
20
+ # IDE
21
+ .idea/
22
+ .vscode/
23
+ *.swp
24
+ .DS_Store
@@ -0,0 +1,27 @@
1
+ repos:
2
+ - repo: https://github.com/pre-commit/pre-commit-hooks
3
+ rev: v5.0.0
4
+ hooks:
5
+ - id: trailing-whitespace
6
+ - id: end-of-file-fixer
7
+ - id: check-yaml
8
+ - id: check-json
9
+ - id: check-added-large-files
10
+ - id: check-merge-conflict
11
+
12
+ - repo: https://github.com/astral-sh/ruff-pre-commit
13
+ rev: v0.8.0
14
+ hooks:
15
+ - id: ruff
16
+ args: [--fix]
17
+ - id: ruff-format
18
+
19
+ - repo: https://github.com/pre-commit/mirrors-mypy
20
+ rev: v1.13.0
21
+ hooks:
22
+ - id: mypy
23
+ files: ^src/
24
+ additional_dependencies:
25
+ - httpx>=0.27
26
+ - pydantic>=2.5
27
+ - mcp[cli]>=1.2.0
@@ -0,0 +1,208 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this project
5
+ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [1.0.0] - 2026-05-17
10
+
11
+ First stable release. The API surface (29 tools, 5 resources, 3 prompts,
12
+ 14 env vars) is now committed to semantic versioning: future MAJOR bumps
13
+ will be announced and documented ahead of time.
14
+
15
+ ### Added
16
+
17
+ - `SUPPORT.md`: explicit Python / Thruk / MCP-client support matrix,
18
+ security reporting channel, release cadence.
19
+ - `CONTRIBUTING.md`: development setup, PR conventions, tool/env-var
20
+ contribution checklists, release process for maintainers.
21
+ - `UPGRADING.md`: per-MINOR migration notes covering 0.2.0 \u2192 1.0.0.
22
+ - `.github/workflows/pypi.yml`: PyPI publish via trusted OIDC publisher
23
+ on every published GitHub release (no token required once the pending
24
+ publisher is configured on pypi.org).
25
+ - `.github/workflows/integration.yml`: nightly live-Thruk integration
26
+ workflow that boots an OMD demo container, generates an API key, and
27
+ runs `pytest -m integration` against it. `continue-on-error: true`
28
+ for now so the badge stays green while the upstream demo image is in
29
+ flux.
30
+ - `compose.test.yml`: docker-compose definition for the OMD demo
31
+ Thruk used by the integration workflow and by local maintainers.
32
+ - `scripts/get-test-api-key.sh`: helper to mint a superuser API key
33
+ inside the running OMD container.
34
+ - `tests/integration/test_live.py`: three smoke tests
35
+ (`/processinfo`, `/hosts`, `/hosts/stats`) gated on
36
+ `pytest.mark.integration` and skipped by default unless
37
+ `THRUK_API_KEY` is set.
38
+
39
+ ### Changed
40
+
41
+ - `pytest` default invocation now passes `-m 'not integration'` so the
42
+ standard `pytest` command stays fast and offline; the integration
43
+ workflow overrides with `-m integration`.
44
+
45
+ ## [0.5.0] - 2026-05-17
46
+
47
+ ### Added
48
+
49
+ - **Security & multi-tenant knobs**:
50
+ - `THRUK_READ_ONLY=true` strips every write tool from the server
51
+ (acknowledge, schedule_*_downtime, recheck, delete_*,
52
+ run_background_query). Read tools remain available.
53
+ - `THRUK_ENABLED_TOOLS=thruk_list_*,thruk_problems` restricts the
54
+ exposed tool surface via fnmatch wildcards. Empty = no filter.
55
+ - `THRUK_AUDIT_LOG=true` (default) emits one JSON line per write
56
+ tool invocation on the `thruk_mcp.audit` logger (stderr). Sensitive
57
+ keys (`api_key`, `password`, `token`) redacted as `***`. Payload:
58
+ `ts`, `tool`, `user`, `args`, `target`, `status`, `error`.
59
+ - `THRUK_MAX_CONCURRENT=N` caps in-flight HTTP requests with an
60
+ `asyncio.Semaphore` to protect the Thruk core from a looping LLM.
61
+ - New module `src/thruk_mcp/audit.py`: `configure()`, `audited()`
62
+ decorator, `_redact()` helper.
63
+ - 9 new security tests; coverage now **84.02 %** (was 82.10 %).
64
+ - Codecov badge, Python versions badge and ghcr.io badge in README.
65
+ - `catalog/server.yaml` declares the 4 new env vars in `config.env`
66
+ and `config.parameters` so the Docker MCP Toolkit UI renders them.
67
+ - Strict Codecov upload in CI (`fail_ci_if_error: true`, scoped token,
68
+ `flags: unittests`).
69
+
70
+ ### Fixed
71
+
72
+ - README and CHANGELOG: 6 literal `\u2014` / `\u2192` escape sequences
73
+ left over from earlier heredoc commits replaced with real Unicode
74
+ characters (em-dash, right-arrow).
75
+
76
+ ## [0.4.0] - 2026-05-17
77
+
78
+ ### Added
79
+
80
+ - Comprehensive test suite: **63 passing tests, 82 % coverage**
81
+ (was 15 tests, ~50 %).
82
+ - `tests/test_tools.py` covers the 29 MCP tools (URL / method /
83
+ key params for each), including a regression test for the v0.2
84
+ acknowledge payload-key bug.
85
+ - `tests/test_resources.py` covers the 5 MCP resources.
86
+ - `tests/test_prompts.py` covers the 3 MCP prompts.
87
+ - `tests/test_config.py` covers `ThrukConfig.from_env()`.
88
+ - `tests/test_run_background.py` covers the 302 → 200 polling cycle
89
+ and the pass-through fallback.
90
+ - `mypy` type-checking baseline (`warn_redundant_casts`,
91
+ `warn_unused_ignores`, `warn_unreachable`, `no_implicit_optional`,
92
+ `check_untyped_defs`). 0 errors on `src/`.
93
+ - `ruff format` integrated alongside `ruff check`.
94
+ - `.pre-commit-config.yaml` (ruff + ruff-format + mypy + standard
95
+ pre-commit hooks).
96
+ - Coverage gate in CI: `pytest --cov-fail-under=80`.
97
+ - Codecov upload on Python 3.12 CI matrix entry.
98
+ - `[tool.coverage.*]` configuration with branch coverage and sensible
99
+ excludes. `integration` pytest marker registered for future live
100
+ tests.
101
+
102
+ ### Changed
103
+
104
+ - **API cleanup** (small breaking change): `thruk_query` and
105
+ `thruk_run_background_query` arguments are now `params: dict` and
106
+ `data: dict` instead of `params_json: str` / `data_json: str`. The
107
+ previous JSON-string parameters were impossible to call through
108
+ FastMCP because pydantic auto-decodes JSON-looking strings before
109
+ reaching the function. Migration: pass a dict literal instead of a
110
+ JSON string.
111
+
112
+ ## [0.3.0] - 2026-05-17
113
+
114
+ ### Added
115
+
116
+ - **Connection retries** via `httpx.AsyncHTTPTransport(retries=3)` for
117
+ DNS / TCP / TLS handshake failures.
118
+ - **HTTP retries with exponential backoff + jitter** for 429 and 5xx
119
+ responses (cap 5 s, configurable). 4xx are not retried.
120
+ - **Async-safe TTL cache** (`thruk_mcp.cache.TTLCache`, default 15 s)
121
+ wired to slow-moving endpoints: `/sites`, `/processinfo`,
122
+ `/*/stats`, `/*/totals`, `/contacts`, `/contactgroups`,
123
+ `/timeperiods`, `/commands`. Per-call override via `cache_ttl=`.
124
+ - **`ThrukClient.get_all()`** — async paginator over a list endpoint
125
+ using `limit`/`offset`, with `hard_limit` safety net (default 50k).
126
+ - **`ThrukClient.run_background()`** + new tool
127
+ `thruk_run_background_query` — wrap Thruk's `?background=1` flow
128
+ and poll `/thruk/jobs/<id>/output` (302 vs. 200) until completion.
129
+ - **5 MCP Resources** — `thruk://hosts/{name}`,
130
+ `thruk://services/{host}/{service}`, `thruk://hostgroups/{name}`,
131
+ `thruk://problems`, `thruk://stats`. Clients with a resource browser
132
+ (Claude Desktop, VS Code, ...) can open Thruk objects like files.
133
+ - **3 MCP Prompts** — `investigate_alert(host, service?)`,
134
+ `schedule_maintenance(target, duration_minutes, kind)`,
135
+ `diagnose_flapping(host, service)`. Pre-canned slash-commands for
136
+ the most common ops workflows.
137
+ - 12 new tests (cache TTL semantics, get_all pagination, retry on
138
+ 503/4xx, cache hit). Suite now 15 passing.
139
+
140
+ ### Changed
141
+
142
+ - README rewritten: \"What is exposed\" section (29 tools / 5 resources /
143
+ 3 prompts) and \"Robustness\" section. The stale v0.1 tools table was
144
+ removed.
145
+
146
+ ## [0.2.0] - 2026-05-17
147
+
148
+ ### Added
149
+
150
+ - **Log / history tools** for incident investigation:
151
+ `thruk_list_logs`, `thruk_list_alerts`, `thruk_list_notifications`,
152
+ `thruk_recent_events`, `thruk_get_downtime`.
153
+ - **Comprehensive downtime management**:
154
+ `thruk_schedule_host_services_downtime` (all services of a host),
155
+ `thruk_schedule_propagated_host_downtime` (parent + child hosts, optionally
156
+ triggered), `thruk_schedule_hostgroup_downtime`,
157
+ `thruk_schedule_servicegroup_downtime`,
158
+ `thruk_delete_active_downtimes`, `thruk_delete_downtimes_by_filter`
159
+ (bulk delete via `del_downtime_by_{host_name,hostgroup_name,start_time_comment}`).
160
+ - **Pagination, sort and tight default columns** on every list-style tool:
161
+ new `offset`, `sort`, `columns` arguments. Module-level
162
+ `DEFAULT_*_COLUMNS` constants document the curated subsets. Pass
163
+ `columns=""` to opt out and get every column (v0.1 behaviour).
164
+ - Unit tests for `_list_params` (8 passing tests total).
165
+
166
+ ### Changed
167
+
168
+ - All list tools (`thruk_list_hosts`, `thruk_list_services`,
169
+ `thruk_list_hostgroups`, `thruk_list_servicegroups`, `thruk_problems`,
170
+ `thruk_list_downtimes`, `thruk_list_comments`, plus the 4 log-family
171
+ tools) now return a tight default subset of columns to dramatically
172
+ reduce LLM token consumption. **Breaking** for callers that relied on
173
+ every field being returned: pass `columns=""` to restore.
174
+ - `limit` is now clamped to `1..1000` on every list tool.
175
+
176
+ ### Fixed
177
+
178
+ - `thruk_acknowledge` payload keys corrected to match the Thruk REST
179
+ contract (`sticky_ack`, `send_notification`, `persistent_comment`).
180
+ The previous keys (`sticky`, `notify`, `persistent`) were silently
181
+ ignored by the core, meaning the `notify=False` flag never actually
182
+ suppressed notifications.
183
+
184
+ ## [0.1.0] - 2026-05-17
185
+
186
+ ### Added
187
+
188
+ - Initial release.
189
+ - 17 MCP tools for the Thruk REST API: hosts, services, groups,
190
+ downtimes (schedule/delete), comments, sites, stats, problems,
191
+ acknowledge / remove ack, force recheck, plus a `thruk_query`
192
+ escape hatch for any other endpoint.
193
+ - Async `httpx` client with native multi-backend (federated Thruk
194
+ sites) support.
195
+ - Two transports: stdio (default) and Streamable-HTTP (`--listen PORT`).
196
+ - Multi-stage Dockerfile, non-root user, ghcr.io publishing on tag.
197
+ - Docker MCP Gateway compatibility (`catalog/server.yaml`,
198
+ `catalog/tools.json`, stdio default).
199
+ - GitHub Actions CI (ruff + pytest matrix on 3.10/3.11/3.12 + Docker
200
+ build) and release workflow (multi-arch image with provenance + SBOM).
201
+
202
+ [Unreleased]: https://github.com/k9fr4n/thruk-mcp/compare/v1.0.0...HEAD
203
+ [1.0.0]: https://github.com/k9fr4n/thruk-mcp/compare/v0.5.0...v1.0.0
204
+ [0.5.0]: https://github.com/k9fr4n/thruk-mcp/compare/v0.4.0...v0.5.0
205
+ [0.4.0]: https://github.com/k9fr4n/thruk-mcp/compare/v0.3.0...v0.4.0
206
+ [0.3.0]: https://github.com/k9fr4n/thruk-mcp/compare/v0.2.0...v0.3.0
207
+ [0.2.0]: https://github.com/k9fr4n/thruk-mcp/compare/v0.1.0...v0.2.0
208
+ [0.1.0]: https://github.com/k9fr4n/thruk-mcp/releases/tag/v0.1.0
@@ -0,0 +1,86 @@
1
+ # Contributing
2
+
3
+ Thanks for considering a contribution! This project is small enough that the
4
+ rules can fit on one page.
5
+
6
+ ## Quick setup
7
+
8
+ ```bash
9
+ git clone https://github.com/k9fr4n/thruk-mcp.git
10
+ cd thruk-mcp
11
+ python -m venv .venv && . .venv/bin/activate
12
+ pip install -e ".[dev]"
13
+ pre-commit install
14
+ ```
15
+
16
+ Run the full checks the way CI does:
17
+
18
+ ```bash
19
+ ruff check src tests
20
+ ruff format --check src tests
21
+ mypy src
22
+ pytest -v --cov=thruk_mcp --cov-fail-under=80
23
+ ```
24
+
25
+ ## Branching and PR flow
26
+
27
+ - **No direct push to `main`.** All changes go through a PR.
28
+ - Branch prefixes: `feat/`, `fix/`, `chore/`, `docs/`, `refactor/`, `test/`.
29
+ - We squash-merge. Make your commit message look like the final PR title.
30
+ - PR titles follow [Conventional Commits](https://www.conventionalcommits.org/):
31
+ `feat(server): ...`, `fix(client): ...`, `chore(ci): ...`, etc.
32
+
33
+ ## Adding a new MCP tool
34
+
35
+ 1. Define the tool in `src/thruk_mcp/server.py` inside `build_server()`.
36
+ - Use `snake_case` and the `thruk_` prefix.
37
+ - Type every parameter; no `**kwargs`.
38
+ - Docstring is LLM-facing — keep it concise and unambiguous.
39
+ - Surface `ThrukError` messages verbatim; never swallow them.
40
+ 2. **List tools must** accept `limit`, `offset`, `sort`, `columns` and use
41
+ `_list_params()` + a `DEFAULT_*_COLUMNS` constant.
42
+ 3. **Write tools must** be added to `WRITE_TOOLS` in `server.py` so that
43
+ `THRUK_READ_ONLY` and the audit log apply to them.
44
+ 4. Add an entry in `catalog/tools.json` (one line per tool).
45
+ 5. Add a `respx`-mocked routing test in `tests/test_tools.py` asserting the
46
+ method, URL path and key params.
47
+ 6. Run the checks listed above. Coverage gate is **80 %**.
48
+
49
+ ## Adding a new env var
50
+
51
+ Any new `THRUK_*` env var must appear in three places (the CI does not enforce
52
+ this but reviewers will):
53
+
54
+ - `src/thruk_mcp/config.py` — added as a field on `ThrukConfig` and parsed in
55
+ `from_env()`.
56
+ - `.env.example` — with a comment describing it.
57
+ - `catalog/server.yaml` — in `config.env` *and* `config.parameters` so the
58
+ Docker MCP Toolkit UI can render it.
59
+
60
+ ## Releasing (maintainers)
61
+
62
+ 1. Open a `chore/release-X.Y.Z` branch.
63
+ 2. Bump `version` in `pyproject.toml` and `__version__` in
64
+ `src/thruk_mcp/__init__.py`.
65
+ 3. Add a `CHANGELOG.md` section dated to release day, plus a new compare
66
+ link at the bottom.
67
+ 4. Note any breaking change in `UPGRADING.md`.
68
+ 5. PR → review → squash merge.
69
+ 6. From `main`: `git tag -a vX.Y.Z -m '...'` then `git push origin vX.Y.Z`.
70
+ 7. `gh release create vX.Y.Z --title '...' --notes '...'`.
71
+
72
+ The tag triggers `.github/workflows/release.yml` which builds and pushes
73
+ `ghcr.io/k9fr4n/thruk-mcp:{X.Y.Z,X.Y,latest}` (multi-arch, provenance, SBOM).
74
+
75
+ ## Reporting bugs
76
+
77
+ Open an issue with:
78
+
79
+ - Thruk version (`/thruk/r/processinfo`)
80
+ - `thruk-mcp --help` (covers version + transport mode)
81
+ - The exact tool call that misbehaved and the error message
82
+ - Whether the same call works with `curl` against Thruk
83
+
84
+ ## Code of conduct
85
+
86
+ Be respectful. Disagreements are fine, personal attacks are not.
@@ -0,0 +1,20 @@
1
+ # syntax=docker/dockerfile:1.7
2
+ FROM python:3.12-slim AS build
3
+ WORKDIR /src
4
+ RUN pip install --no-cache-dir build
5
+ COPY pyproject.toml README.md ./
6
+ COPY src ./src
7
+ RUN python -m build --wheel --outdir /dist
8
+
9
+ FROM python:3.12-slim
10
+ RUN useradd -r -u 1001 -m thruk
11
+ WORKDIR /app
12
+ COPY --from=build /dist/*.whl /tmp/
13
+ RUN pip install --no-cache-dir /tmp/*.whl && rm -f /tmp/*.whl
14
+ USER thruk
15
+ ENV PYTHONUNBUFFERED=1
16
+ # Default = stdio transport (Docker MCP Gateway / Claude Desktop / LibreChat).
17
+ # For HTTP/Streamable-HTTP, override CMD: ["--listen", "8001"]
18
+ EXPOSE 8001
19
+ ENTRYPOINT ["thruk-mcp"]
20
+ CMD []
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Franck SALLET
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.