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.
- thruk_mcp-1.0.0/.env.example +34 -0
- thruk_mcp-1.0.0/.github/workflows/ci.yml +45 -0
- thruk_mcp-1.0.0/.github/workflows/integration.yml +59 -0
- thruk_mcp-1.0.0/.github/workflows/pypi.yml +50 -0
- thruk_mcp-1.0.0/.github/workflows/release.yml +46 -0
- thruk_mcp-1.0.0/.gitignore +24 -0
- thruk_mcp-1.0.0/.pre-commit-config.yaml +27 -0
- thruk_mcp-1.0.0/CHANGELOG.md +208 -0
- thruk_mcp-1.0.0/CONTRIBUTING.md +86 -0
- thruk_mcp-1.0.0/Dockerfile +20 -0
- thruk_mcp-1.0.0/LICENSE +21 -0
- thruk_mcp-1.0.0/PKG-INFO +292 -0
- thruk_mcp-1.0.0/README.md +262 -0
- thruk_mcp-1.0.0/SUPPORT.md +66 -0
- thruk_mcp-1.0.0/UPGRADING.md +67 -0
- thruk_mcp-1.0.0/catalog/readme.md +6 -0
- thruk_mcp-1.0.0/catalog/server.yaml +100 -0
- thruk_mcp-1.0.0/catalog/tools.json +31 -0
- thruk_mcp-1.0.0/compose.test.yml +23 -0
- thruk_mcp-1.0.0/compose.yml +12 -0
- thruk_mcp-1.0.0/pyproject.toml +91 -0
- thruk_mcp-1.0.0/scripts/get-test-api-key.sh +17 -0
- thruk_mcp-1.0.0/src/thruk_mcp/__init__.py +3 -0
- thruk_mcp-1.0.0/src/thruk_mcp/__main__.py +49 -0
- thruk_mcp-1.0.0/src/thruk_mcp/audit.py +102 -0
- thruk_mcp-1.0.0/src/thruk_mcp/cache.py +46 -0
- thruk_mcp-1.0.0/src/thruk_mcp/client.py +253 -0
- thruk_mcp-1.0.0/src/thruk_mcp/config.py +72 -0
- thruk_mcp-1.0.0/src/thruk_mcp/server.py +990 -0
- thruk_mcp-1.0.0/tests/__init__.py +0 -0
- thruk_mcp-1.0.0/tests/conftest.py +34 -0
- thruk_mcp-1.0.0/tests/integration/__init__.py +0 -0
- thruk_mcp-1.0.0/tests/integration/test_live.py +58 -0
- thruk_mcp-1.0.0/tests/test_cache.py +41 -0
- thruk_mcp-1.0.0/tests/test_client.py +43 -0
- thruk_mcp-1.0.0/tests/test_config.py +39 -0
- thruk_mcp-1.0.0/tests/test_list_params.py +36 -0
- thruk_mcp-1.0.0/tests/test_pagination_retry.py +67 -0
- thruk_mcp-1.0.0/tests/test_prompts.py +59 -0
- thruk_mcp-1.0.0/tests/test_resources.py +56 -0
- thruk_mcp-1.0.0/tests/test_run_background.py +49 -0
- thruk_mcp-1.0.0/tests/test_security.py +160 -0
- 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 []
|
thruk_mcp-1.0.0/LICENSE
ADDED
|
@@ -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.
|