domon-mcp-server 0.1.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.
- domon_mcp_server-0.1.0/PKG-INFO +269 -0
- domon_mcp_server-0.1.0/README.md +244 -0
- domon_mcp_server-0.1.0/pyproject.toml +95 -0
- domon_mcp_server-0.1.0/pyproject.toml.orig +72 -0
- domon_mcp_server-0.1.0/src/icinga_mcp/__init__.py +10 -0
- domon_mcp_server-0.1.0/src/icinga_mcp/__main__.py +3 -0
- domon_mcp_server-0.1.0/src/icinga_mcp/cli.py +179 -0
- domon_mcp_server-0.1.0/src/icinga_mcp/clients/__init__.py +3 -0
- domon_mcp_server-0.1.0/src/icinga_mcp/clients/director.py +65 -0
- domon_mcp_server-0.1.0/src/icinga_mcp/clients/icinga_api.py +221 -0
- domon_mcp_server-0.1.0/src/icinga_mcp/clients/icingaweb.py +144 -0
- domon_mcp_server-0.1.0/src/icinga_mcp/config.py +191 -0
- domon_mcp_server-0.1.0/src/icinga_mcp/errors.py +31 -0
- domon_mcp_server-0.1.0/src/icinga_mcp/formatting.py +81 -0
- domon_mcp_server-0.1.0/src/icinga_mcp/history.py +251 -0
- domon_mcp_server-0.1.0/src/icinga_mcp/models.py +265 -0
- domon_mcp_server-0.1.0/src/icinga_mcp/permissions.py +38 -0
- domon_mcp_server-0.1.0/src/icinga_mcp/py.typed +0 -0
- domon_mcp_server-0.1.0/src/icinga_mcp/redaction.py +41 -0
- domon_mcp_server-0.1.0/src/icinga_mcp/server.py +93 -0
- domon_mcp_server-0.1.0/src/icinga_mcp/timeparse.py +42 -0
- domon_mcp_server-0.1.0/src/icinga_mcp/tools/__init__.py +95 -0
- domon_mcp_server-0.1.0/src/icinga_mcp/tools/acknowledgements.py +175 -0
- domon_mcp_server-0.1.0/src/icinga_mcp/tools/actions.py +227 -0
- domon_mcp_server-0.1.0/src/icinga_mcp/tools/base.py +71 -0
- domon_mcp_server-0.1.0/src/icinga_mcp/tools/comments.py +143 -0
- domon_mcp_server-0.1.0/src/icinga_mcp/tools/convert.py +132 -0
- domon_mcp_server-0.1.0/src/icinga_mcp/tools/director.py +146 -0
- domon_mcp_server-0.1.0/src/icinga_mcp/tools/downtimes.py +342 -0
- domon_mcp_server-0.1.0/src/icinga_mcp/tools/history.py +120 -0
- domon_mcp_server-0.1.0/src/icinga_mcp/tools/objects.py +148 -0
- domon_mcp_server-0.1.0/src/icinga_mcp/tools/problems.py +117 -0
- domon_mcp_server-0.1.0/src/icinga_mcp/tools/status.py +55 -0
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: domon-mcp-server
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: MCP server for analysing Icinga 2 monitoring: problems, history, acknowledgements, comments and downtimes.
|
|
5
|
+
Keywords: mcp,icinga,icinga2,monitoring,model-context-protocol
|
|
6
|
+
Author: Sebastian Wolschke
|
|
7
|
+
Author-email: Sebastian Wolschke <sebastian.wolschke@telekom.de>
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Intended Audience :: System Administrators
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
15
|
+
Classifier: Topic :: System :: Monitoring
|
|
16
|
+
Requires-Dist: anyio>=4.9
|
|
17
|
+
Requires-Dist: httpx2>=2.10
|
|
18
|
+
Requires-Dist: mcp>=2.3,<3
|
|
19
|
+
Requires-Dist: pydantic>=2.12
|
|
20
|
+
Requires-Dist: pydantic-settings>=2.16
|
|
21
|
+
Requires-Python: >=3.11
|
|
22
|
+
Project-URL: Source, https://github.com/telekom-mms/domon-mcp-server
|
|
23
|
+
Project-URL: Issues, https://github.com/telekom-mms/domon-mcp-server/issues
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# icinga-mcp
|
|
27
|
+
|
|
28
|
+
MCP server for analysing an [Icinga 2](https://icinga.com/) monitoring setup with an LLM.
|
|
29
|
+
Implements the [Model Context Protocol](https://modelcontextprotocol.io/) revision `2026-07-28`
|
|
30
|
+
(via the official Python SDK, which also falls back to `2025-11-25` for older clients).
|
|
31
|
+
|
|
32
|
+
> Status: early development. Not yet published on PyPI.
|
|
33
|
+
|
|
34
|
+
## Scope (v1)
|
|
35
|
+
|
|
36
|
+
- Read active problems, host/service details, comments and downtimes (Icinga 2 REST API)
|
|
37
|
+
- Acknowledge problems, add comments, schedule/remove downtimes (opt-in, every change is
|
|
38
|
+
confirmed by the user)
|
|
39
|
+
- Tools are grouped into toolsets that can be enabled/disabled individually; read-only by default
|
|
40
|
+
- Alert history via the IcingaDB Web module, optional (legacy `monitoring` module supported)
|
|
41
|
+
- Icinga Director configuration (read-only): hosts, templates, apply rules, commands, optional
|
|
42
|
+
|
|
43
|
+
Runs on Linux, macOS and Windows (Python 3.11+).
|
|
44
|
+
|
|
45
|
+
Creating, changing or deleting monitoring objects is intentionally out of scope.
|
|
46
|
+
|
|
47
|
+
## Installation
|
|
48
|
+
|
|
49
|
+
icinga-mcp is started by your MCP client via [uv](https://docs.astral.sh/uv/). Install uv once:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
# Linux / macOS
|
|
53
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
```powershell
|
|
57
|
+
# Windows (PowerShell)
|
|
58
|
+
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Quick start (VS Code)
|
|
62
|
+
|
|
63
|
+
Add the server to your MCP configuration. Recommended: the user configuration
|
|
64
|
+
(command palette: **MCP: Open User Configuration**), so the credentials stay outside of any
|
|
65
|
+
repository. A workspace file `.vscode/mcp.json` works too, but must not be committed.
|
|
66
|
+
|
|
67
|
+
```json
|
|
68
|
+
{
|
|
69
|
+
"servers": {
|
|
70
|
+
"icinga": {
|
|
71
|
+
"type": "stdio",
|
|
72
|
+
"command": "uvx",
|
|
73
|
+
"args": ["--from", "domon-mcp-server", "icinga-mcp"],
|
|
74
|
+
"env": {
|
|
75
|
+
"ICINGA_URL": "https://icinga-master.example.com:5665",
|
|
76
|
+
"ICINGA_USER": "icinga-mcp",
|
|
77
|
+
"ICINGA_PASSWORD": "change-me",
|
|
78
|
+
"ICINGAWEB_URL": "https://icinga.example.com",
|
|
79
|
+
"ICINGAWEB_USER": "jdoe",
|
|
80
|
+
"ICINGAWEB_PASSWORD": "change-me",
|
|
81
|
+
"ICINGA_MCP_READ_ONLY": "false",
|
|
82
|
+
"ICINGA_MCP_AUTHOR": "jdoe"
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
The `ICINGAWEB_*` lines enable the alert history and the Director tools (optional). Omit the last two lines to keep
|
|
90
|
+
icinga-mcp read-only. The password is stored in plain text in this file. Use a dedicated, minimally privileged
|
|
91
|
+
`ApiUser` (see [permissions](#icinga-2-api-permissions)) and protect the file accordingly.
|
|
92
|
+
|
|
93
|
+
Until `domon-mcp-server` is published on PyPI, run it from a local checkout instead of `uvx`:
|
|
94
|
+
|
|
95
|
+
```json
|
|
96
|
+
"command": "uv",
|
|
97
|
+
"args": ["run", "--directory", "/path/to/icinga-mcp", "icinga-mcp"],
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
On Windows use forward slashes or escaped backslashes in JSON paths, e.g.
|
|
101
|
+
`"C:/Users/me/icinga-mcp"`.
|
|
102
|
+
|
|
103
|
+
## Configuration
|
|
104
|
+
|
|
105
|
+
All settings are read from environment variables (the `env` block of the MCP configuration).
|
|
106
|
+
|
|
107
|
+
| Variable | Required | Description |
|
|
108
|
+
|---|---|---|
|
|
109
|
+
| `ICINGA_URL` | yes | Icinga 2 API base URL, e.g. `https://icinga-master:5665` |
|
|
110
|
+
| `ICINGA_USER` | yes | Icinga 2 `ApiUser` name |
|
|
111
|
+
| `ICINGA_PASSWORD` | yes | API password |
|
|
112
|
+
| `ICINGA_CA_CERT` | no | Path to the CA that signed the API certificate (e.g. the Icinga CA). Setting it enables TLS certificate verification |
|
|
113
|
+
| `ICINGA_TLS_SERVER_NAME` | no | Expected certificate host name if it differs from the URL host (used for SNI and verification), e.g. when the API sits behind a Kubernetes ingress |
|
|
114
|
+
| `ICINGA_VERIFY_TLS` | no | Force verification on (`true`, e.g. for publicly trusted certificates without `ICINGA_CA_CERT`) or off (`false`). Default: on if `ICINGA_CA_CERT` is set, otherwise off |
|
|
115
|
+
| `ICINGA_TIMEOUT` | no | Request timeout in seconds (default `30`) |
|
|
116
|
+
|
|
117
|
+
### Icinga Web: history and Director (optional)
|
|
118
|
+
|
|
119
|
+
The Icinga 2 API has no history and does not know the Director data model. `get_history`
|
|
120
|
+
reads alert history from Icinga Web 2's IcingaDB module by default, the
|
|
121
|
+
`director_*` tools read the configuration from the Icinga Director REST API. Both are only
|
|
122
|
+
available when these variables are set:
|
|
123
|
+
|
|
124
|
+
| Variable | Required | Description |
|
|
125
|
+
|---|---|---|
|
|
126
|
+
| `ICINGAWEB_URL` | yes | Icinga Web 2 root URL, e.g. `https://icinga.example.com` (or `.../icingaweb2`) |
|
|
127
|
+
| `ICINGAWEB_USER` | yes | Icinga Web user (needs IcingaDB module access for history by default; `monitoring` module for legacy history; Director API access for Director tools) |
|
|
128
|
+
| `ICINGAWEB_PASSWORD` | yes | Password (HTTP basic auth) |
|
|
129
|
+
| `ICINGAWEB_HISTORY_BACKEND` | no | History source: `icingadb` (default) or `monitoring` for legacy IDO installations |
|
|
130
|
+
| `ICINGAWEB_CA_CERT` | no | CA bundle if the web server certificate is not publicly trusted |
|
|
131
|
+
| `ICINGAWEB_VERIFY_TLS` | no | Default `true`; set `false` only for debugging |
|
|
132
|
+
| `ICINGAWEB_TIMEOUT` | no | Request timeout in seconds (default `60`) |
|
|
133
|
+
| `ICINGA_MCP_MAX_HISTORY` | no | Longest time window per query (default `31d`) |
|
|
134
|
+
|
|
135
|
+
### TLS certificate verification (optional)
|
|
136
|
+
|
|
137
|
+
Icinga 2 API certificates are usually signed by the internal Icinga CA, which no operating
|
|
138
|
+
system trusts. By default icinga-mcp therefore connects **without certificate verification**
|
|
139
|
+
and logs a warning. The API password is still sent encrypted, but the server identity is not
|
|
140
|
+
checked, so a man-in-the-middle could capture the credentials.
|
|
141
|
+
|
|
142
|
+
To enable verification, store the CA once per instance and add to the `env` block:
|
|
143
|
+
|
|
144
|
+
```json
|
|
145
|
+
"ICINGA_CA_CERT": "/home/me/.config/icinga-mcp/<instance>-ca.pem",
|
|
146
|
+
"ICINGA_TLS_SERVER_NAME": "<CN of the server certificate>"
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
`ICINGA_TLS_SERVER_NAME` is only needed if the certificate name differs from the URL host.
|
|
150
|
+
The CA is the last certificate printed by the following command (OpenSSL is included in
|
|
151
|
+
Linux, macOS and Git for Windows):
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
openssl s_client -connect <host>:5665 -showcerts </dev/null
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Compare the CA fingerprint (`openssl x509 -in <file> -noout -fingerprint -sha256`) with the
|
|
158
|
+
one provided by your Icinga administrators.
|
|
159
|
+
|
|
160
|
+
### Icinga 2 API permissions
|
|
161
|
+
|
|
162
|
+
Minimal `ApiUser` permissions:
|
|
163
|
+
|
|
164
|
+
```
|
|
165
|
+
object ApiUser "icinga-mcp" {
|
|
166
|
+
password = "..."
|
|
167
|
+
permissions = [
|
|
168
|
+
"status/query",
|
|
169
|
+
"objects/query/Host", "objects/query/Service",
|
|
170
|
+
"objects/query/HostGroup", "objects/query/ServiceGroup",
|
|
171
|
+
"objects/query/Comment", "objects/query/Downtime",
|
|
172
|
+
// only needed for write tools
|
|
173
|
+
"actions/acknowledge-problem", "actions/remove-acknowledgement",
|
|
174
|
+
"actions/add-comment", "actions/schedule-downtime", "actions/remove-downtime",
|
|
175
|
+
]
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## Tools
|
|
180
|
+
|
|
181
|
+
| Tool | Toolset | Mode | Description |
|
|
182
|
+
|---|---|---|---|
|
|
183
|
+
| `icinga_status` | `status` | read | Version, feature flags, host/service counts per state, unhandled problems |
|
|
184
|
+
| `list_problems` | `problems` | read | Current alerts (DOWN hosts, WARNING/CRITICAL/UNKNOWN services); filters for host/service patterns, host group, states, handled, hard states |
|
|
185
|
+
| `get_host` | `objects` | read | Host details incl. check output, perfdata, custom vars (redacted) and its services |
|
|
186
|
+
| `get_service` | `objects` | read | Service details incl. check output, perfdata, command and custom vars (redacted) |
|
|
187
|
+
| `list_hosts` | `objects` | read | Search hosts by name/address pattern or host group |
|
|
188
|
+
| `acknowledge_problem` | `acknowledgements` | write | Acknowledge problems (sticky, notify, expiry); OK or already acknowledged objects are skipped |
|
|
189
|
+
| `remove_acknowledgement` | `acknowledgements` | write | Remove acknowledgements |
|
|
190
|
+
| `list_comments` | `comments` | read | Comments and acknowledgement texts, newest first |
|
|
191
|
+
| `add_comment` | `comments` | write | Add a comment (note) to hosts/services |
|
|
192
|
+
| `list_downtimes` | `downtimes` | read | Scheduled downtimes and whether they are in effect |
|
|
193
|
+
| `director_list` | `director` | read | Search the Director configuration: hosts, host/service templates, service apply rules, commands, host groups, notification templates, time periods. Needs Icinga Web |
|
|
194
|
+
| `director_get` | `director` | read | One Director object with inherited properties (hosts/templates) and the objects that use a template or command. Needs Icinga Web |
|
|
195
|
+
| `get_history` | `history` | read | Alert history in a time window (`since` = `24h`, `7d` or ISO 8601): hard/soft state changes, notifications, acknowledgements, comments, downtimes, flapping; summary with the most active objects. Needs Icinga Web |
|
|
196
|
+
| `schedule_downtime` | `downtimes` | write | Fixed or flexible downtime (`start` = `now` or ISO 8601, `end` or `duration` like `2h`), optionally for all services of a host |
|
|
197
|
+
| `remove_downtime` | `downtimes` | write | Remove downtimes by name (from `list_downtimes`) |
|
|
198
|
+
|
|
199
|
+
Values below keys whose names look sensitive (`*pass*`, `*secret*`, `*token*`, `*basicauth*`,
|
|
200
|
+
...) are replaced by `***REDACTED***` in all tool results. Pure macro references such as
|
|
201
|
+
`$snmp_password$` (e.g. in command arguments) stay visible because they contain no secret.
|
|
202
|
+
|
|
203
|
+
### Enabling and disabling tools
|
|
204
|
+
|
|
205
|
+
| Variable | Default | Description |
|
|
206
|
+
|---|---|---|
|
|
207
|
+
| `ICINGA_MCP_TOOLSETS` | all | Comma-separated toolsets to enable, e.g. `status,problems,objects` |
|
|
208
|
+
| `ICINGA_MCP_DISABLED_TOOLS` | none | Comma-separated tool names to hide, e.g. `remove_downtime` |
|
|
209
|
+
| `ICINGA_MCP_READ_ONLY` | `true` | Hide all write tools. Set to `false` to enable them |
|
|
210
|
+
|
|
211
|
+
Disabled tools are not registered at all, so the model never sees them.
|
|
212
|
+
`icinga-mcp list-tools` shows the effective selection.
|
|
213
|
+
|
|
214
|
+
### Write tools and safety
|
|
215
|
+
|
|
216
|
+
Write tools are only available with `ICINGA_MCP_READ_ONLY=false` and need these settings:
|
|
217
|
+
|
|
218
|
+
| Variable | Default | Description |
|
|
219
|
+
|---|---|---|
|
|
220
|
+
| `ICINGA_MCP_AUTHOR` | (required) | Name recorded as author in Icinga, e.g. your user name |
|
|
221
|
+
| `ICINGA_MCP_MAX_TARGETS` | `20` | Maximum number of objects per call |
|
|
222
|
+
| `ICINGA_MCP_MAX_DOWNTIME` | `14d` | Maximum length of a downtime |
|
|
223
|
+
| `ICINGA_MCP_REQUIRE_ELICITATION` | `false` | Refuse changes from clients that cannot ask the user (see below) |
|
|
224
|
+
|
|
225
|
+
Safety measures:
|
|
226
|
+
|
|
227
|
+
- Targets are exact object names (`host` or `host!service`), never patterns or free filters.
|
|
228
|
+
All targets are looked up first; unknown names abort the call before anything is changed.
|
|
229
|
+
- **Every change is confirmed by the user.** If the MCP client supports
|
|
230
|
+
[elicitation](https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation)
|
|
231
|
+
(e.g. VS Code), the user gets a dialog listing the objects and options. Clients without
|
|
232
|
+
elicitation get a preview on the first call; only a second call with `confirm=true` applies
|
|
233
|
+
the change. In that mode the model is instructed to ask the user first, but technically it
|
|
234
|
+
could set `confirm=true` on its own; set `ICINGA_MCP_REQUIRE_ELICITATION=true` to rule that out.
|
|
235
|
+
- Results report per object whether Icinga applied the change.
|
|
236
|
+
|
|
237
|
+
## Command line
|
|
238
|
+
|
|
239
|
+
| Command | Description |
|
|
240
|
+
|---|---|
|
|
241
|
+
| `icinga-mcp` / `icinga-mcp serve` | Run the MCP server on stdio (started by the MCP client) |
|
|
242
|
+
| `icinga-mcp check` | Test connection, TLS, credentials, API permissions and (if configured) Icinga Web history access |
|
|
243
|
+
| `icinga-mcp list-tools` | Show all tools and which ones are enabled (no credentials needed) |
|
|
244
|
+
|
|
245
|
+
`check` reads the same environment variables as the server:
|
|
246
|
+
|
|
247
|
+
```bash
|
|
248
|
+
# Linux / macOS
|
|
249
|
+
ICINGA_URL=https://icinga-master:5665 ICINGA_USER=icinga-mcp ICINGA_PASSWORD='...' uvx --from domon-mcp-server icinga-mcp check
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
```powershell
|
|
253
|
+
# Windows (PowerShell)
|
|
254
|
+
$env:ICINGA_URL = "https://icinga-master:5665"; $env:ICINGA_USER = "icinga-mcp"; $env:ICINGA_PASSWORD = "..."
|
|
255
|
+
uvx --from domon-mcp-server icinga-mcp check
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
## Development
|
|
259
|
+
|
|
260
|
+
```bash
|
|
261
|
+
uv sync
|
|
262
|
+
uv run pytest # unit tests
|
|
263
|
+
uv run pytest -m integration # read-only tests against a real instance (needs ICINGA_* env)
|
|
264
|
+
uv run ruff check .
|
|
265
|
+
uv run ruff format --check .
|
|
266
|
+
uv run mypy
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
See [AGENTS.md](AGENTS.md) for architecture and conventions.
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
# icinga-mcp
|
|
2
|
+
|
|
3
|
+
MCP server for analysing an [Icinga 2](https://icinga.com/) monitoring setup with an LLM.
|
|
4
|
+
Implements the [Model Context Protocol](https://modelcontextprotocol.io/) revision `2026-07-28`
|
|
5
|
+
(via the official Python SDK, which also falls back to `2025-11-25` for older clients).
|
|
6
|
+
|
|
7
|
+
> Status: early development. Not yet published on PyPI.
|
|
8
|
+
|
|
9
|
+
## Scope (v1)
|
|
10
|
+
|
|
11
|
+
- Read active problems, host/service details, comments and downtimes (Icinga 2 REST API)
|
|
12
|
+
- Acknowledge problems, add comments, schedule/remove downtimes (opt-in, every change is
|
|
13
|
+
confirmed by the user)
|
|
14
|
+
- Tools are grouped into toolsets that can be enabled/disabled individually; read-only by default
|
|
15
|
+
- Alert history via the IcingaDB Web module, optional (legacy `monitoring` module supported)
|
|
16
|
+
- Icinga Director configuration (read-only): hosts, templates, apply rules, commands, optional
|
|
17
|
+
|
|
18
|
+
Runs on Linux, macOS and Windows (Python 3.11+).
|
|
19
|
+
|
|
20
|
+
Creating, changing or deleting monitoring objects is intentionally out of scope.
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
icinga-mcp is started by your MCP client via [uv](https://docs.astral.sh/uv/). Install uv once:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# Linux / macOS
|
|
28
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
```powershell
|
|
32
|
+
# Windows (PowerShell)
|
|
33
|
+
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Quick start (VS Code)
|
|
37
|
+
|
|
38
|
+
Add the server to your MCP configuration. Recommended: the user configuration
|
|
39
|
+
(command palette: **MCP: Open User Configuration**), so the credentials stay outside of any
|
|
40
|
+
repository. A workspace file `.vscode/mcp.json` works too, but must not be committed.
|
|
41
|
+
|
|
42
|
+
```json
|
|
43
|
+
{
|
|
44
|
+
"servers": {
|
|
45
|
+
"icinga": {
|
|
46
|
+
"type": "stdio",
|
|
47
|
+
"command": "uvx",
|
|
48
|
+
"args": ["--from", "domon-mcp-server", "icinga-mcp"],
|
|
49
|
+
"env": {
|
|
50
|
+
"ICINGA_URL": "https://icinga-master.example.com:5665",
|
|
51
|
+
"ICINGA_USER": "icinga-mcp",
|
|
52
|
+
"ICINGA_PASSWORD": "change-me",
|
|
53
|
+
"ICINGAWEB_URL": "https://icinga.example.com",
|
|
54
|
+
"ICINGAWEB_USER": "jdoe",
|
|
55
|
+
"ICINGAWEB_PASSWORD": "change-me",
|
|
56
|
+
"ICINGA_MCP_READ_ONLY": "false",
|
|
57
|
+
"ICINGA_MCP_AUTHOR": "jdoe"
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
The `ICINGAWEB_*` lines enable the alert history and the Director tools (optional). Omit the last two lines to keep
|
|
65
|
+
icinga-mcp read-only. The password is stored in plain text in this file. Use a dedicated, minimally privileged
|
|
66
|
+
`ApiUser` (see [permissions](#icinga-2-api-permissions)) and protect the file accordingly.
|
|
67
|
+
|
|
68
|
+
Until `domon-mcp-server` is published on PyPI, run it from a local checkout instead of `uvx`:
|
|
69
|
+
|
|
70
|
+
```json
|
|
71
|
+
"command": "uv",
|
|
72
|
+
"args": ["run", "--directory", "/path/to/icinga-mcp", "icinga-mcp"],
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
On Windows use forward slashes or escaped backslashes in JSON paths, e.g.
|
|
76
|
+
`"C:/Users/me/icinga-mcp"`.
|
|
77
|
+
|
|
78
|
+
## Configuration
|
|
79
|
+
|
|
80
|
+
All settings are read from environment variables (the `env` block of the MCP configuration).
|
|
81
|
+
|
|
82
|
+
| Variable | Required | Description |
|
|
83
|
+
|---|---|---|
|
|
84
|
+
| `ICINGA_URL` | yes | Icinga 2 API base URL, e.g. `https://icinga-master:5665` |
|
|
85
|
+
| `ICINGA_USER` | yes | Icinga 2 `ApiUser` name |
|
|
86
|
+
| `ICINGA_PASSWORD` | yes | API password |
|
|
87
|
+
| `ICINGA_CA_CERT` | no | Path to the CA that signed the API certificate (e.g. the Icinga CA). Setting it enables TLS certificate verification |
|
|
88
|
+
| `ICINGA_TLS_SERVER_NAME` | no | Expected certificate host name if it differs from the URL host (used for SNI and verification), e.g. when the API sits behind a Kubernetes ingress |
|
|
89
|
+
| `ICINGA_VERIFY_TLS` | no | Force verification on (`true`, e.g. for publicly trusted certificates without `ICINGA_CA_CERT`) or off (`false`). Default: on if `ICINGA_CA_CERT` is set, otherwise off |
|
|
90
|
+
| `ICINGA_TIMEOUT` | no | Request timeout in seconds (default `30`) |
|
|
91
|
+
|
|
92
|
+
### Icinga Web: history and Director (optional)
|
|
93
|
+
|
|
94
|
+
The Icinga 2 API has no history and does not know the Director data model. `get_history`
|
|
95
|
+
reads alert history from Icinga Web 2's IcingaDB module by default, the
|
|
96
|
+
`director_*` tools read the configuration from the Icinga Director REST API. Both are only
|
|
97
|
+
available when these variables are set:
|
|
98
|
+
|
|
99
|
+
| Variable | Required | Description |
|
|
100
|
+
|---|---|---|
|
|
101
|
+
| `ICINGAWEB_URL` | yes | Icinga Web 2 root URL, e.g. `https://icinga.example.com` (or `.../icingaweb2`) |
|
|
102
|
+
| `ICINGAWEB_USER` | yes | Icinga Web user (needs IcingaDB module access for history by default; `monitoring` module for legacy history; Director API access for Director tools) |
|
|
103
|
+
| `ICINGAWEB_PASSWORD` | yes | Password (HTTP basic auth) |
|
|
104
|
+
| `ICINGAWEB_HISTORY_BACKEND` | no | History source: `icingadb` (default) or `monitoring` for legacy IDO installations |
|
|
105
|
+
| `ICINGAWEB_CA_CERT` | no | CA bundle if the web server certificate is not publicly trusted |
|
|
106
|
+
| `ICINGAWEB_VERIFY_TLS` | no | Default `true`; set `false` only for debugging |
|
|
107
|
+
| `ICINGAWEB_TIMEOUT` | no | Request timeout in seconds (default `60`) |
|
|
108
|
+
| `ICINGA_MCP_MAX_HISTORY` | no | Longest time window per query (default `31d`) |
|
|
109
|
+
|
|
110
|
+
### TLS certificate verification (optional)
|
|
111
|
+
|
|
112
|
+
Icinga 2 API certificates are usually signed by the internal Icinga CA, which no operating
|
|
113
|
+
system trusts. By default icinga-mcp therefore connects **without certificate verification**
|
|
114
|
+
and logs a warning. The API password is still sent encrypted, but the server identity is not
|
|
115
|
+
checked, so a man-in-the-middle could capture the credentials.
|
|
116
|
+
|
|
117
|
+
To enable verification, store the CA once per instance and add to the `env` block:
|
|
118
|
+
|
|
119
|
+
```json
|
|
120
|
+
"ICINGA_CA_CERT": "/home/me/.config/icinga-mcp/<instance>-ca.pem",
|
|
121
|
+
"ICINGA_TLS_SERVER_NAME": "<CN of the server certificate>"
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
`ICINGA_TLS_SERVER_NAME` is only needed if the certificate name differs from the URL host.
|
|
125
|
+
The CA is the last certificate printed by the following command (OpenSSL is included in
|
|
126
|
+
Linux, macOS and Git for Windows):
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
openssl s_client -connect <host>:5665 -showcerts </dev/null
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Compare the CA fingerprint (`openssl x509 -in <file> -noout -fingerprint -sha256`) with the
|
|
133
|
+
one provided by your Icinga administrators.
|
|
134
|
+
|
|
135
|
+
### Icinga 2 API permissions
|
|
136
|
+
|
|
137
|
+
Minimal `ApiUser` permissions:
|
|
138
|
+
|
|
139
|
+
```
|
|
140
|
+
object ApiUser "icinga-mcp" {
|
|
141
|
+
password = "..."
|
|
142
|
+
permissions = [
|
|
143
|
+
"status/query",
|
|
144
|
+
"objects/query/Host", "objects/query/Service",
|
|
145
|
+
"objects/query/HostGroup", "objects/query/ServiceGroup",
|
|
146
|
+
"objects/query/Comment", "objects/query/Downtime",
|
|
147
|
+
// only needed for write tools
|
|
148
|
+
"actions/acknowledge-problem", "actions/remove-acknowledgement",
|
|
149
|
+
"actions/add-comment", "actions/schedule-downtime", "actions/remove-downtime",
|
|
150
|
+
]
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Tools
|
|
155
|
+
|
|
156
|
+
| Tool | Toolset | Mode | Description |
|
|
157
|
+
|---|---|---|---|
|
|
158
|
+
| `icinga_status` | `status` | read | Version, feature flags, host/service counts per state, unhandled problems |
|
|
159
|
+
| `list_problems` | `problems` | read | Current alerts (DOWN hosts, WARNING/CRITICAL/UNKNOWN services); filters for host/service patterns, host group, states, handled, hard states |
|
|
160
|
+
| `get_host` | `objects` | read | Host details incl. check output, perfdata, custom vars (redacted) and its services |
|
|
161
|
+
| `get_service` | `objects` | read | Service details incl. check output, perfdata, command and custom vars (redacted) |
|
|
162
|
+
| `list_hosts` | `objects` | read | Search hosts by name/address pattern or host group |
|
|
163
|
+
| `acknowledge_problem` | `acknowledgements` | write | Acknowledge problems (sticky, notify, expiry); OK or already acknowledged objects are skipped |
|
|
164
|
+
| `remove_acknowledgement` | `acknowledgements` | write | Remove acknowledgements |
|
|
165
|
+
| `list_comments` | `comments` | read | Comments and acknowledgement texts, newest first |
|
|
166
|
+
| `add_comment` | `comments` | write | Add a comment (note) to hosts/services |
|
|
167
|
+
| `list_downtimes` | `downtimes` | read | Scheduled downtimes and whether they are in effect |
|
|
168
|
+
| `director_list` | `director` | read | Search the Director configuration: hosts, host/service templates, service apply rules, commands, host groups, notification templates, time periods. Needs Icinga Web |
|
|
169
|
+
| `director_get` | `director` | read | One Director object with inherited properties (hosts/templates) and the objects that use a template or command. Needs Icinga Web |
|
|
170
|
+
| `get_history` | `history` | read | Alert history in a time window (`since` = `24h`, `7d` or ISO 8601): hard/soft state changes, notifications, acknowledgements, comments, downtimes, flapping; summary with the most active objects. Needs Icinga Web |
|
|
171
|
+
| `schedule_downtime` | `downtimes` | write | Fixed or flexible downtime (`start` = `now` or ISO 8601, `end` or `duration` like `2h`), optionally for all services of a host |
|
|
172
|
+
| `remove_downtime` | `downtimes` | write | Remove downtimes by name (from `list_downtimes`) |
|
|
173
|
+
|
|
174
|
+
Values below keys whose names look sensitive (`*pass*`, `*secret*`, `*token*`, `*basicauth*`,
|
|
175
|
+
...) are replaced by `***REDACTED***` in all tool results. Pure macro references such as
|
|
176
|
+
`$snmp_password$` (e.g. in command arguments) stay visible because they contain no secret.
|
|
177
|
+
|
|
178
|
+
### Enabling and disabling tools
|
|
179
|
+
|
|
180
|
+
| Variable | Default | Description |
|
|
181
|
+
|---|---|---|
|
|
182
|
+
| `ICINGA_MCP_TOOLSETS` | all | Comma-separated toolsets to enable, e.g. `status,problems,objects` |
|
|
183
|
+
| `ICINGA_MCP_DISABLED_TOOLS` | none | Comma-separated tool names to hide, e.g. `remove_downtime` |
|
|
184
|
+
| `ICINGA_MCP_READ_ONLY` | `true` | Hide all write tools. Set to `false` to enable them |
|
|
185
|
+
|
|
186
|
+
Disabled tools are not registered at all, so the model never sees them.
|
|
187
|
+
`icinga-mcp list-tools` shows the effective selection.
|
|
188
|
+
|
|
189
|
+
### Write tools and safety
|
|
190
|
+
|
|
191
|
+
Write tools are only available with `ICINGA_MCP_READ_ONLY=false` and need these settings:
|
|
192
|
+
|
|
193
|
+
| Variable | Default | Description |
|
|
194
|
+
|---|---|---|
|
|
195
|
+
| `ICINGA_MCP_AUTHOR` | (required) | Name recorded as author in Icinga, e.g. your user name |
|
|
196
|
+
| `ICINGA_MCP_MAX_TARGETS` | `20` | Maximum number of objects per call |
|
|
197
|
+
| `ICINGA_MCP_MAX_DOWNTIME` | `14d` | Maximum length of a downtime |
|
|
198
|
+
| `ICINGA_MCP_REQUIRE_ELICITATION` | `false` | Refuse changes from clients that cannot ask the user (see below) |
|
|
199
|
+
|
|
200
|
+
Safety measures:
|
|
201
|
+
|
|
202
|
+
- Targets are exact object names (`host` or `host!service`), never patterns or free filters.
|
|
203
|
+
All targets are looked up first; unknown names abort the call before anything is changed.
|
|
204
|
+
- **Every change is confirmed by the user.** If the MCP client supports
|
|
205
|
+
[elicitation](https://modelcontextprotocol.io/specification/2026-07-28/client/elicitation)
|
|
206
|
+
(e.g. VS Code), the user gets a dialog listing the objects and options. Clients without
|
|
207
|
+
elicitation get a preview on the first call; only a second call with `confirm=true` applies
|
|
208
|
+
the change. In that mode the model is instructed to ask the user first, but technically it
|
|
209
|
+
could set `confirm=true` on its own; set `ICINGA_MCP_REQUIRE_ELICITATION=true` to rule that out.
|
|
210
|
+
- Results report per object whether Icinga applied the change.
|
|
211
|
+
|
|
212
|
+
## Command line
|
|
213
|
+
|
|
214
|
+
| Command | Description |
|
|
215
|
+
|---|---|
|
|
216
|
+
| `icinga-mcp` / `icinga-mcp serve` | Run the MCP server on stdio (started by the MCP client) |
|
|
217
|
+
| `icinga-mcp check` | Test connection, TLS, credentials, API permissions and (if configured) Icinga Web history access |
|
|
218
|
+
| `icinga-mcp list-tools` | Show all tools and which ones are enabled (no credentials needed) |
|
|
219
|
+
|
|
220
|
+
`check` reads the same environment variables as the server:
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
# Linux / macOS
|
|
224
|
+
ICINGA_URL=https://icinga-master:5665 ICINGA_USER=icinga-mcp ICINGA_PASSWORD='...' uvx --from domon-mcp-server icinga-mcp check
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
```powershell
|
|
228
|
+
# Windows (PowerShell)
|
|
229
|
+
$env:ICINGA_URL = "https://icinga-master:5665"; $env:ICINGA_USER = "icinga-mcp"; $env:ICINGA_PASSWORD = "..."
|
|
230
|
+
uvx --from domon-mcp-server icinga-mcp check
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
## Development
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
uv sync
|
|
237
|
+
uv run pytest # unit tests
|
|
238
|
+
uv run pytest -m integration # read-only tests against a real instance (needs ICINGA_* env)
|
|
239
|
+
uv run ruff check .
|
|
240
|
+
uv run ruff format --check .
|
|
241
|
+
uv run mypy
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
See [AGENTS.md](AGENTS.md) for architecture and conventions.
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "domon-mcp-server"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "MCP server for analysing Icinga 2 monitoring: problems, history, acknowledgements, comments and downtimes."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.11"
|
|
7
|
+
keywords = [
|
|
8
|
+
"mcp",
|
|
9
|
+
"icinga",
|
|
10
|
+
"icinga2",
|
|
11
|
+
"monitoring",
|
|
12
|
+
"model-context-protocol",
|
|
13
|
+
]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 3 - Alpha",
|
|
16
|
+
"Intended Audience :: System Administrators",
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Programming Language :: Python :: 3.11",
|
|
19
|
+
"Programming Language :: Python :: 3.12",
|
|
20
|
+
"Programming Language :: Python :: 3.13",
|
|
21
|
+
"Programming Language :: Python :: 3.14",
|
|
22
|
+
"Topic :: System :: Monitoring",
|
|
23
|
+
]
|
|
24
|
+
dependencies = [
|
|
25
|
+
"anyio>=4.9",
|
|
26
|
+
"httpx2>=2.10",
|
|
27
|
+
"mcp>=2.3,<3",
|
|
28
|
+
"pydantic>=2.12",
|
|
29
|
+
"pydantic-settings>=2.16",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
[[project.authors]]
|
|
33
|
+
name = "Sebastian Wolschke"
|
|
34
|
+
email = "sebastian.wolschke@telekom.de"
|
|
35
|
+
|
|
36
|
+
[project.scripts]
|
|
37
|
+
icinga-mcp = "icinga_mcp.cli:main"
|
|
38
|
+
|
|
39
|
+
[project.urls]
|
|
40
|
+
Source = "https://github.com/telekom-mms/domon-mcp-server"
|
|
41
|
+
Issues = "https://github.com/telekom-mms/domon-mcp-server/issues"
|
|
42
|
+
|
|
43
|
+
[build-system]
|
|
44
|
+
requires = ["uv_build>=0.11.7,<0.12.0"]
|
|
45
|
+
build-backend = "uv_build"
|
|
46
|
+
|
|
47
|
+
[tool.uv.build-backend]
|
|
48
|
+
module-name = "icinga_mcp"
|
|
49
|
+
|
|
50
|
+
[tool.ruff]
|
|
51
|
+
line-length = 100
|
|
52
|
+
target-version = "py311"
|
|
53
|
+
|
|
54
|
+
[tool.ruff.lint]
|
|
55
|
+
select = [
|
|
56
|
+
"E",
|
|
57
|
+
"F",
|
|
58
|
+
"W",
|
|
59
|
+
"I",
|
|
60
|
+
"B",
|
|
61
|
+
"UP",
|
|
62
|
+
"S",
|
|
63
|
+
"SIM",
|
|
64
|
+
"RUF",
|
|
65
|
+
"ASYNC",
|
|
66
|
+
]
|
|
67
|
+
|
|
68
|
+
[tool.ruff.lint.per-file-ignores]
|
|
69
|
+
"tests/**" = [
|
|
70
|
+
"S101",
|
|
71
|
+
"S105",
|
|
72
|
+
"S106",
|
|
73
|
+
]
|
|
74
|
+
|
|
75
|
+
[tool.mypy]
|
|
76
|
+
strict = true
|
|
77
|
+
plugins = ["pydantic.mypy"]
|
|
78
|
+
python_version = "3.11"
|
|
79
|
+
files = [
|
|
80
|
+
"src",
|
|
81
|
+
"tests",
|
|
82
|
+
]
|
|
83
|
+
|
|
84
|
+
[tool.pytest.ini_options]
|
|
85
|
+
testpaths = ["tests"]
|
|
86
|
+
addopts = "-ra -m 'not integration'"
|
|
87
|
+
markers = ["integration: tests against a real Icinga 2 instance (requires ICINGA_* environment)"]
|
|
88
|
+
|
|
89
|
+
[dependency-groups]
|
|
90
|
+
dev = [
|
|
91
|
+
"anyio>=4.15.1",
|
|
92
|
+
"mypy>=2.4.0",
|
|
93
|
+
"pytest>=9.1.1",
|
|
94
|
+
"ruff>=0.17.0",
|
|
95
|
+
]
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "domon-mcp-server"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "MCP server for analysing Icinga 2 monitoring: problems, history, acknowledgements, comments and downtimes."
|
|
5
|
+
authors = [
|
|
6
|
+
{ name = "Sebastian Wolschke", email = "sebastian.wolschke@telekom.de" }
|
|
7
|
+
]
|
|
8
|
+
readme = "README.md"
|
|
9
|
+
requires-python = ">=3.11"
|
|
10
|
+
keywords = ["mcp", "icinga", "icinga2", "monitoring", "model-context-protocol"]
|
|
11
|
+
classifiers = [
|
|
12
|
+
"Development Status :: 3 - Alpha",
|
|
13
|
+
"Intended Audience :: System Administrators",
|
|
14
|
+
"Programming Language :: Python :: 3",
|
|
15
|
+
"Programming Language :: Python :: 3.11",
|
|
16
|
+
"Programming Language :: Python :: 3.12",
|
|
17
|
+
"Programming Language :: Python :: 3.13",
|
|
18
|
+
"Programming Language :: Python :: 3.14",
|
|
19
|
+
"Topic :: System :: Monitoring",
|
|
20
|
+
]
|
|
21
|
+
dependencies = [
|
|
22
|
+
"anyio>=4.9",
|
|
23
|
+
"httpx2>=2.10",
|
|
24
|
+
"mcp>=2.3,<3",
|
|
25
|
+
"pydantic>=2.12",
|
|
26
|
+
"pydantic-settings>=2.16",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
[project.scripts]
|
|
30
|
+
icinga-mcp = "icinga_mcp.cli:main"
|
|
31
|
+
|
|
32
|
+
[project.urls]
|
|
33
|
+
Source = "https://github.com/telekom-mms/domon-mcp-server"
|
|
34
|
+
Issues = "https://github.com/telekom-mms/domon-mcp-server/issues"
|
|
35
|
+
|
|
36
|
+
[build-system]
|
|
37
|
+
requires = ["uv_build>=0.11.7,<0.12.0"]
|
|
38
|
+
build-backend = "uv_build"
|
|
39
|
+
|
|
40
|
+
[tool.uv.build-backend]
|
|
41
|
+
module-name = "icinga_mcp"
|
|
42
|
+
|
|
43
|
+
[tool.ruff]
|
|
44
|
+
line-length = 100
|
|
45
|
+
target-version = "py311"
|
|
46
|
+
|
|
47
|
+
[tool.ruff.lint]
|
|
48
|
+
select = ["E", "F", "W", "I", "B", "UP", "S", "SIM", "RUF", "ASYNC"]
|
|
49
|
+
|
|
50
|
+
[tool.ruff.lint.per-file-ignores]
|
|
51
|
+
"tests/**" = ["S101", "S105", "S106"]
|
|
52
|
+
|
|
53
|
+
[tool.mypy]
|
|
54
|
+
strict = true
|
|
55
|
+
plugins = ["pydantic.mypy"]
|
|
56
|
+
python_version = "3.11"
|
|
57
|
+
files = ["src", "tests"]
|
|
58
|
+
|
|
59
|
+
[tool.pytest.ini_options]
|
|
60
|
+
testpaths = ["tests"]
|
|
61
|
+
addopts = "-ra -m 'not integration'"
|
|
62
|
+
markers = [
|
|
63
|
+
"integration: tests against a real Icinga 2 instance (requires ICINGA_* environment)",
|
|
64
|
+
]
|
|
65
|
+
|
|
66
|
+
[dependency-groups]
|
|
67
|
+
dev = [
|
|
68
|
+
"anyio>=4.15.1",
|
|
69
|
+
"mypy>=2.4.0",
|
|
70
|
+
"pytest>=9.1.1",
|
|
71
|
+
"ruff>=0.17.0",
|
|
72
|
+
]
|