Model Context Protocol (MCP) server exposing the Thruk monitoring REST API (Naemon / Nagios / Icinga / Shinken).
Project description
thruk-mcp
Model Context Protocol (MCP) server for Thruk — the unified web frontend for Naemon, Nagios, Icinga and Shinken.
Expose Thruk's REST API to MCP-compatible clients (Claude Desktop, Dust, LibreChat, OpenWebUI...) so that an LLM can query hosts/services, schedule downtimes, acknowledge problems, force rechecks and more in natural language.
Features
- Read: hosts, services, hostgroups, servicegroups, downtimes, comments, sites, aggregated stats, current problems
- Write: schedule/delete downtimes, acknowledge & remove acks, force rechecks
- Escape hatch:
thruk_querytool to call any Thruk REST endpoint - Multi-backend support (Thruk federated sites): pass
backends="prod,dr"to any tool - Two transports: stdio (default) or Streamable-HTTP (
--listen <port>) - Async httpx client with proper error handling and TLS verification
- Tested with
pytest+respx, linted withruff, packaged withhatchling
Quick start
1. Configure
cp .env.example .env
$EDITOR .env # set THRUK_BASE_URL and THRUK_API_KEY
An API key can be created from the Thruk user profile page (requires api_keys_enabled in thruk_local.conf) or via the REST API itself.
2a. Run with Docker
docker compose up -d
# MCP Streamable-HTTP endpoint: http://localhost:8001/mcp
2b. Run locally
pip install thruk-mcp # or: pipx install thruk-mcp
# stdio mode (for Claude Desktop, LibreChat, etc.)
thruk-mcp
# HTTP mode
thruk-mcp --listen 8001
For local development of the project itself, see CONTRIBUTING.md.
3. Wire it to an MCP client
Claude Desktop (~/.config/Claude/claude_desktop_config.json or macOS equivalent):
{
"mcpServers": {
"thruk": {
"command": "thruk-mcp",
"env": {
"THRUK_BASE_URL": "https://monitor.example.com/thruk",
"THRUK_API_KEY": "xxxxxxxx"
}
}
}
}
4. Use with the Docker MCP Gateway
The image at ghcr.io/k9fr4n/thruk-mcp:latest defaults to stdio transport, so it can be spawned natively by the gateway.
Option A — Private local catalog
# 1. Create your private catalog
docker mcp catalog create thruk-private
# 2. Register this server (catalog/server.yaml ships with the repo)
docker mcp catalog add thruk-private thruk-mcp ./catalog/server.yaml
# 3. Configure credentials & enable
docker mcp secret set thruk-mcp.api_key=YOUR_KEY
docker mcp config write thruk-mcp.base_url=https://monitor.example.com/thruk
docker mcp server enable thruk-mcp
# 4. Run the gateway with your catalog
docker mcp gateway run --catalog thruk-private
Then point any MCP client (Claude Desktop, VS Code, Cursor, ...) at the gateway as documented here.
Option B — Submit upstream
catalog/server.yaml, catalog/tools.json and catalog/readme.md follow the docker/mcp-registry schema and can be submitted to the official Docker MCP Catalog via PR.
What's exposed
29 MCP Tools
Read — state
thruk_list_hosts, thruk_get_host, thruk_list_services, thruk_get_service,
thruk_list_hostgroups, thruk_list_servicegroups, thruk_problems, thruk_stats,
thruk_sites.
Read — history & comments
thruk_list_logs, thruk_list_alerts, thruk_list_notifications, thruk_recent_events,
thruk_list_comments, thruk_list_downtimes, thruk_get_downtime.
Write — downtime management
thruk_schedule_downtime (host/service), thruk_schedule_host_services_downtime
(all services of a host), thruk_schedule_propagated_host_downtime (parent+children),
thruk_schedule_hostgroup_downtime, thruk_schedule_servicegroup_downtime,
thruk_delete_downtime, thruk_delete_active_downtimes,
thruk_delete_downtimes_by_filter.
Write — problem handling
thruk_acknowledge, thruk_remove_acknowledgement, thruk_recheck.
Escape hatches
thruk_query (raw call to any REST endpoint), thruk_run_background_query
(long-running endpoint via Thruk's ?background=1 mechanism with automatic
job polling).
All list-style tools share a consistent
limit/offset/sort/columnscontract. By default they return a tight subset of columns (~10 fields per row) to keep LLM token consumption low. Passcolumns=""to opt out and receive every column the Thruk row contains.
5 MCP Resources
URI templates that MCP clients with a resource browser (Claude Desktop, VS Code, ...) can "open" like files:
| URI | Content |
|---|---|
thruk://hosts/{name} |
Full host JSON |
thruk://services/{host}/{service} |
Full service JSON |
thruk://hostgroups/{name} |
Host group config + members |
thruk://problems |
Current unhandled problems (hosts + services) |
thruk://stats |
Aggregated host/service stats (cached) |
3 MCP Prompts
Pre-canned workflows the user can invoke as a slash-command in the MCP client UI:
| Prompt | Arguments | Purpose |
|---|---|---|
investigate_alert |
host, optional service |
7-step incident triage |
schedule_maintenance |
target, duration_minutes, kind |
Safe downtime workflow with confirmation |
diagnose_flapping |
host, service |
Root-cause a flapping service |
Robustness
- Connection retries —
httpx.AsyncHTTPTransport(retries=3)handles DNS failures, connection refusals, TLS handshakes. - HTTP retries with backoff — 5xx and 429 responses are retried up to 3 times with exponential backoff + jitter (cap 5 s).
- Opt-in TTL cache — slow-moving endpoints (
/sites,/processinfo,/hosts/stats,/services/stats,/contacts,/timeperiods, ...) are cached in-process for 15 s. Any tool can request caching viacache_ttl=on the underlying client. This absorbs the burst of identical calls an LLM agent typically issues across a multi-tool turn. - Pagination helper —
ThrukClient.get_all()is an async generator that iterates pages of 500 rows up to a configurable hard limit (default 50 000), so internal callers can scan entire backends without manual offset math. - Long-running queries — the
thruk_run_background_querytool wraps Thruk's?background=1flow and polls/thruk/jobs/<id>/outputuntil the job completes (5 min default timeout).
Environment variables
Connection
| Variable | Default | Description |
|---|---|---|
THRUK_BASE_URL |
http://localhost/thruk |
Thruk URL (no trailing slash) |
THRUK_API_KEY |
(required) | X-Thruk-Auth-Key header |
THRUK_AUTH_USER |
Impersonation user (superuser key only) | |
THRUK_VERIFY_SSL |
true |
Set false for self-signed certs |
THRUK_TIMEOUT |
30 |
HTTP timeout in seconds |
THRUK_DEFAULT_BACKENDS |
CSV of default backend names (federated Thruk) |
Security / multi-tenant (v0.6)
| Variable | Default | Description |
|---|---|---|
THRUK_READ_ONLY |
false |
Strip every write tool (ack, downtime, recheck, ...) |
THRUK_ENABLED_TOOLS |
Allowlist of tool names. CSV with fnmatch wildcards. Empty = all | |
THRUK_AUDIT_LOG |
true |
Emit one JSON audit line on stderr per write tool invocation |
THRUK_MAX_CONCURRENT |
0 |
Cap of concurrent in-flight HTTP requests. 0 = unlimited |
Security
-
Read-only mode — set
THRUK_READ_ONLY=trueto remove every write tool (thruk_acknowledge,thruk_schedule_*_downtime,thruk_recheck,thruk_delete_*,thruk_run_background_query) from the MCP server. The LLM literally cannot mutate monitoring state. Use this for general-purpose agents that should only observe. -
Tool allowlist —
THRUK_ENABLED_TOOLS=thruk_list_*,thruk_problems,thruk_statsrestricts the exposed surface to the listed tools (fnmatch wildcards supported). Useful when fronting multiple LLM clients with the same gateway but different scopes. -
Audit log — every write tool invocation emits one JSON line on
thruk_mcp.audit(stderr by default):{"ts":"2026-05-17T22:00:00+00:00","tool":"thruk_acknowledge","user":"alice", "args":{"host":"srv01","comment":"investigating"},"target":"srv01","status":"ok"}
Disable with
THRUK_AUDIT_LOG=false. Sensitive keys (api_key,password,token) are redacted as***before logging. -
Rate limit —
THRUK_MAX_CONCURRENT=8caps in-flight HTTP requests with anasyncio.Semaphore. Combined with the v0.3 TTL cache, this protects the Thruk core from an LLM that loops on tools or chains them aggressively.
Development
pip install -e ".[dev]"
pre-commit install # one-time setup of git hooks
ruff check src tests && ruff format src tests # lint + format
mypy src # type-check
pytest -v --cov=thruk_mcp --cov-fail-under=80 # tests with coverage gate
Conventions:
- Conventional Commits (
feat:,fix:,chore:,docs:,refactor:,test:). - No direct push to
main: branch → PR → squash merge. - Any new tool must come with a
respx-mocked unit test intests/test_tools.pyand an entry incatalog/tools.json(Docker MCP Registry contract). - CI gate:
ruff,ruff format --check,mypy,pytestwith 80 % coverage minimum.
References
- Thruk REST API: https://www.thruk.org/documentation/rest.html
- Thruk REST commands: https://www.thruk.org/documentation/rest_commands.html
- MCP spec: https://spec.modelcontextprotocol.io/
- Inspired by: https://github.com/lausser/omd-mcp (initial proof-of-concept)
Project docs
- CHANGELOG.md — what changed in each release.
- UPGRADING.md — per-version migration notes.
- SUPPORT.md — supported Python / Thruk / MCP-client versions, security policy, release cadence.
- CONTRIBUTING.md — dev setup, PR conventions, tool / env-var contribution checklists.
License
MIT — see LICENSE.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file thruk_mcp-1.0.2.tar.gz.
File metadata
- Download URL: thruk_mcp-1.0.2.tar.gz
- Upload date:
- Size: 41.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c1bda69e38d1de19aebf9ce25bdb6c1e53c8c371f22a909397cf09008328d4d9
|
|
| MD5 |
46554f99a45d8517e67ded0ea3d299f2
|
|
| BLAKE2b-256 |
aca6da1e882d61d032a338b78e808814479873fe4c61e3d3534a7d5c685b00f5
|
Provenance
The following attestation bundles were made for thruk_mcp-1.0.2.tar.gz:
Publisher:
pypi.yml on k9fr4n/thruk-mcp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
thruk_mcp-1.0.2.tar.gz -
Subject digest:
c1bda69e38d1de19aebf9ce25bdb6c1e53c8c371f22a909397cf09008328d4d9 - Sigstore transparency entry: 1564686436
- Sigstore integration time:
-
Permalink:
k9fr4n/thruk-mcp@6e4e19b2732f910a446467a912d03f7007c6ee88 -
Branch / Tag:
refs/tags/v1.0.2 - Owner: https://github.com/k9fr4n
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi.yml@6e4e19b2732f910a446467a912d03f7007c6ee88 -
Trigger Event:
release
-
Statement type:
File details
Details for the file thruk_mcp-1.0.2-py3-none-any.whl.
File metadata
- Download URL: thruk_mcp-1.0.2-py3-none-any.whl
- Upload date:
- Size: 23.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c302e1cc3e080fa35563e27d223cabb8e864c100b025ba48b316bca993558cb5
|
|
| MD5 |
18197a40afd9004ac72e0af82056c402
|
|
| BLAKE2b-256 |
ef19431ac1594de89874bc01b8bd7ed930f1e0eb876f1d8b0e74381071db65a8
|
Provenance
The following attestation bundles were made for thruk_mcp-1.0.2-py3-none-any.whl:
Publisher:
pypi.yml on k9fr4n/thruk-mcp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
thruk_mcp-1.0.2-py3-none-any.whl -
Subject digest:
c302e1cc3e080fa35563e27d223cabb8e864c100b025ba48b316bca993558cb5 - Sigstore transparency entry: 1564686545
- Sigstore integration time:
-
Permalink:
k9fr4n/thruk-mcp@6e4e19b2732f910a446467a912d03f7007c6ee88 -
Branch / Tag:
refs/tags/v1.0.2 - Owner: https://github.com/k9fr4n
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi.yml@6e4e19b2732f910a446467a912d03f7007c6ee88 -
Trigger Event:
release
-
Statement type: