Are you the author? Sign in to claim
Design-time KNX/ETS assistant as an MCP server: validate (naming·DPT·status·Secure·Matter), repair (propose fixes), deco
A design-time KNX / ETS6 assistant exposed as an MCP server.
Four things you can do with it — all without ever touching the live KNX bus:
basic/comfort preset per slot) assemble a new, validated project → an allocation manifest + ETS GA XML/CSV + a device BOM proposal. Dry-run, new projects only (R1).Under the hood: a device library that expands each actuator into its real communication objects — from generic recipes up to the exact vendor object model parsed straight from ETS application programs.
🇷🇺 Русская версия: README.ru.md
New — a whole demo house.
examples/demo-homeships a synthetic 239-GA / 47-Function project, the tool's generated report + Home Assistant config + ETS export, and a full smart-home “brain” — circadian lighting, an 8-factor climate setpoint, a presence/season/time state machine and statistics — driving a 5-view dashboard. See it all on the live site ↗.
Real screenshots from a live Home Assistant running the demo house. They show the tool's assembled entities at work: RGBW / RGB / CCT colour lights, six floor-heating climate zones (target, mode and valve %), a circadian lighting curve and a computed climate setpoint — not set by hand.
▶ Explore it interactively on the live site → · config in examples/demo-home/ha-brain
This is a public beta. The full pipeline passes an end-to-end smoke test on a synthetic project and has been validated against real multi-thousand-GA ETS5/ETS6 projects (anonymised) — but real ETS projects are wonderfully messy and diverse, and more field reports make it better.
👉 If you have an ETS5/ETS6 project, please try it and tell us what happens. Open a Real-project test report issue. The tool is read-only and never connects to a bus, so testing is safe (see Safety model). See CONTRIBUTING.md for details.
💬 Join the discussion → — say hi, ask anything, or share what the tool found on your project.
Recent reviews from practising KNX integrators (in Discussions) are steering what comes next:
check_device_parameters) — flag the one device whose ETS parameter settings differ from its N identical siblings: a thermostat with a different setpoint/hysteresis, a presence detector with a different detection time. Extracts per-device parameters straight from the .knxproj and finds the odd one out on real 42–275-device projects — read-only, no ETS, no bus — and correctly reports nothing on a clean project (no false positives across a different vendor / integrator school).check_policy) — validate a project against your own agreed rules (naming, GA taxonomy, command/status exemptions) instead of one universal "professional standard", since conventions differ per integrator; with no profile it validates against the taxonomy inferred from the project itself.compose_rooms + validate_room_template: new projects, dry-run, allocation manifest + ETS XML/CSV + device BOM). R2 planned: docking into an existing project + exact device selection.Have a project to test, a workflow that breaks, or a feature to shape? → Discussions.
As of mid-2026 there is no off-the-shelf ETS6 ↔ Claude / MCP tool. The KNX community has been explicitly asking for an integration that can inspect and help modify projects (adding / renaming devices and group addresses) through an AI/CLI workflow. This package fills exactly the design-time layer — the missing one.
The recommended full setup is four layers; only one needs to be built from scratch:
| Layer | Purpose | What to use | Build it? |
|---|---|---|---|
| 1. Live | states, control, debugging a running house | official Home Assistant MCP Server + KNX (XKNX) integration | No, already exists |
| 2. Design-time | parse .knxproj, validate DPT/naming/status + GA-intent de-noise, generate HA YAML (colour lights + climate assembled) & ETS XML/CSV | nickol-knx-mcp (this package) | YES — this is the gap |
| 3. Files + Git | YAML/CSV/XML, versioning the address schema | standard filesystem + git MCP servers | No, already exists |
| 4. Skill | design rules (GA structure, naming, DPT, scenes) + ops discipline | CLAUDE.md + skills/ (ha-git-backup ops companion) | No, included |
Safety by design: layer 2 (this server) physically cannot connect to a bus. It has no network/bus dependency at all — it only reads
.knxprojand writes files into a confined workspace. The "never write to a live bus" requirement is enforced structurally, not by promise. Any real interaction with the house goes only through layer 1 (Home Assistant).
Turn a project specification (equipment schedules, cable journals, a device list) into a complete, validated group-address structure — and the full document set to implement it:
decompose_device): a dimmer channel is on/off + status + relative dim (3.007) +
absolute value (5.001) + brightness status — not "one GA"; a floor-heating zone is 8 objects; a
pulse meter is 6.Full methodology: docs/spec-to-structure.md. Field-checked by
reconstructing a real as-built ETS project (3,600+ group addresses) from its specification alone:
~92 % structural match (taxonomy, domains, automation logic, DPT distribution) at zero
validation errors — the remaining delta is the integrator's per-device parameterisation, which no
spec encodes.
.knxproj via
xknxproject; classifies every GA by category
(lighting / shutter / hvac / sensor / scene / energy / diagnostics) and kind (command / status /
sensor) from the DPT + multilingual (EN/DE/RU) name keywords. GA purpose tagging
(functional / reserve / logic / scratch) keeps intentional placeholders out of the error
lists, so the report doesn't cry wolf (on a real 685-GA project: false errors 29 → 6).analyze_all runs everything): naming & structure · missing status objects
(ETS-Function roles first, then name-token pairing, positional pairing — parallel status middles with 1:1 names — and self-reporting R+T objects) · missing/inconsistent DPTs +
sub-DPT sanity (a "temperature" GA carrying 5.001 gets flagged) · relative-only dimmers ·
KNX Secure posture (secured vs plaintext, mixed groups, keyring checklist — key material is
never read) · Matter-readiness · energy-domain coverage.suggest_repairs): infer a DPT from the name, correct a suspect
sub-DPT, synthesise a missing status GA in a free address slot, add an absolute-brightness GA.
Suggestions only — a human reviews, accepted GAs feed the ETS export. On a real 3,646-GA
project: 145 concrete proposals (32 DPT inferences, 112 synthesised status GAs).grade_completeness (bare skeleton → as-built score), suggest_names,
diff_projects (semantic diff of two .knxproj revisions: added / removed / DPT-changed /
renamed / secure-changed), then regenerate the report, handover pack and test protocol.state_address wherever the device can report — HA reads real state, never assumes.review list with an explanation (including actuator-dependent cover
flags like invert_position / travel times, which no .knxproj encodes).expose block for date/time broadcast (DPT 19.001), Matter-readiness lint,
KNX IoT (Turtle/RDF) semantic export.skills/ha-git-backup — the life of your config
after deploy: a real git history of /config (deploy key + pre-commit secret scanner) plus
encrypted offsite backups in GitHub Releases, with a monthly restore drill.basic / comfort preset per slot (a house
can mix comfort climate with basic lighting), and compose_rooms assembles a new project.manifest (main = domain, middle = role, sub sequential), ETS-importable
GA XML/CSV via the existing generators, and a device BOM proposal from the device library..knxproj is re-read through the standard load_project
— the same path used for third-party projects — and passes all four linters (naming / missing-status /
DPT / policy) with 0 errors / 0 warnings.room_templates/SCHEMA.md):
identity is a locale-neutral slot_id, never a human name.parse_devices_from_project extracts exact vendor object models — including ref-level (ComObjectRef) publishers like HDL/Ekinex — from the manufacturer
application programs inside any .knxproj / .knxprod: object numbers, names, sizes, DPTs,
C/R/W/T/U flags, per-channel block strides — deterministically, and PII-safe (vendor catalog
data only; the client project part of the file is never read).NICKOL_KNX_CATALOG at your catalog and decompose_device answers with the exact
model (catalog-exact) instead of a generic recipe — the catalog grows on demand, from the
projects and product databases you feed it.unverified — never guessed.All writes go only into the workspace directory (NICKOL_KNX_WORKSPACE, default ./knx-workspace);
writes outside it are rejected.
Requires Python 3.10+.
git clone https://github.com/NickoScope/nickol-knx-mcp.git
cd nickol-knx-mcp
python3 -m venv .venv && source .venv/bin/activate
pip install -e .
Dependencies: mcp>=1.10, xknxproject>=3.8, PyYAML>=6.0.
On Debian/Ubuntu, if pip complains about an externally-managed environment, use a venv (as above) or
pip install -e . --break-system-packages. IfPyJWTconflicts, runpip install mcp --ignore-installed PyJWTfirst.
Verify:
python tests/test_pipeline.py # synthetic 16-GA project, end-to-end smoke test
nickol-knx-mcp # start the MCP server (stdio)
examples/claude_desktop_config.json wires up nickol-knx + filesystem + git + home-assistant.
Minimal fragment (macOS config path: ~/Library/Application Support/Claude/claude_desktop_config.json):
{
"mcpServers": {
"nickol-knx": {
"command": "nickol-knx-mcp",
"env": { "NICKOL_KNX_WORKSPACE": "/path/to/your/knx-workspace" }
}
}
}
claude mcp add nickol-knx \
-e NICKOL_KNX_WORKSPACE="$HOME/knx-workspace" \
-- /absolute/path/to/.venv/bin/nickol-knx-mcp
Then drop CLAUDE.md into your project root — it acts as an ETS Assistant skill (design rules,
safety rules, 3-level GA structure, command/status pairing, DPT discipline, naming, KNX Secure
keyring handling, and the recommended workflow).
Read
| Tool | Purpose |
|---|---|
load_project(path, password?, language?) | parse a .knxproj (read-only) and cache it |
list_group_addresses(category?, kind?) | list GAs with classification and filters |
get_devices() | devices + their communication objects |
get_topology() | topology (areas / lines / devices) |
explain_ga(address) | provenance for one GA: why it's classified this way — evidence per decision with a confidence tier (authoritative ETS Function > structural DPT > heuristic name), how its status was paired, and conflicts (name says "AC", DPT says lighting → contested) |
Validate
| Tool | Purpose |
|---|---|
check_naming(name_regex?) | validate naming / 3-level structure |
check_missing_status() | actuators lacking a status object |
check_dpt() | missing / inconsistent DPTs + sub-DPT sanity (temp→9.001, power→14.056…) |
check_topology() | topology capacity + individual-address validity (TP1 64/segment, 256/line, valid & unique A.L.D, coupler presence — KNX Handbook) |
check_secure() | KNX Data Secure posture + keyring handover checklist |
check_matter() | Matter-readiness lint (which functions round-trip to a Matter cluster) |
check_energy() | metering/energy DPT check + PV/battery/EVSE scaffold |
analyze_all(name_regex?) | run every check at once |
check_policy(profile_path?, write_example_to?) | validate against a Project Policy Profile (your main-group taxonomy, naming, pairing) — or, with no profile, against the taxonomy inferred from the project itself; flags GAs that deviate from your convention, not a universal standard |
Repair & design
| Tool | Purpose |
|---|---|
suggest_repairs() | propose fixes, not just flag — infer DPTs, synthesise status/brightness GAs |
suggest_names() | naming-hygiene suggestions |
decompose_device(order_number, channels?) | device → GA decomposition: exact vendor model from a local catalog (NICKOL_KNX_CATALOG), or generic recipe |
list_device_recipes() | the built-in device library (Zennio + ABB families) |
parse_devices_from_project(path, output_path?, password?) | extract exact device object models from the app-programs inside a .knxproj/.knxprod → device-library YAML (feeds the local catalog) |
check_device_parameters(path, password?, min_group?) | cross-device parameter QA: find the device whose ETS parameters differ from its N identical siblings (the odd thermostat/sensor out) — clear_outliers (likely mistake) + split_configs (balanced variants, review) |
grade_completeness() | grade a project: bare skeleton vs as-built |
diff_projects(path_a, path_b, …) | semantic diff between two .knxproj versions |
Generate
| Tool | Purpose |
|---|---|
generate_ha_package(output_path?) | HA KNX YAML (colour + climate + expose) + review list |
generate_ets_group_addresses(fmt="xml"|"csv", output_path?) | ETS-importable GAs |
generate_handover_pack(output_dir?) | as-built handover: inventory, GA map, coverage, Secure, QA, topology.svg |
generate_test_protocol(output_path?) | functional acceptance protocol (command → expected status) |
generate_knx_iot(output_path?) | KNX IoT semantic export (Turtle/RDF) |
project_report(output_path?, name_regex?) | Markdown report |
workspace_info() | workspace path + safety guarantees |
Room Library (R1 — compose a new project from room templates)
| Tool | Purpose |
|---|---|
validate_room_template(template?, path?) | validate a room template (built-in slot_id or a custom YAML) against the R1 schema |
compose_rooms(rooms, language="ru", project_name?, output_dir?, dry_run=true) | build a new project from a list of rooms → allocation manifest, ETS GA XML/CSV, device bom proposal; generated .knxproj is re-read by the standard loader and linted (0 errors / 0 warnings). New projects only, dry-run by default. |
load_project → point it at your .knxproj (+ password if protected).analyze_all or project_report → read the findings; human review first.generate_ets_group_addresses(fmt="xml") → import the missing GAs into ETS.generate_ha_package → place the YAML into Home Assistant; resolve review items by hand..knxproj export, HA configs, address schema) in Git.review, not into config.review than emit a wrong entity..knxproj files vary enormously, and it is still a beta. Hence the
call for testers.workspace_info() reports bus_access: false.project.py is the only module that touches .knxproj, and it
only reads.NICKOL_KNX_WORKSPACE; paths outside it are rejected..knxproj is an untrusted ZIP-of-XML, so parsing runs
through safexml.py: DTD/entity XML is refused (billion-laughs / XXE), and archives are pre-flighted
against size / entry / decompression-ratio caps with path-traversal names rejected (zip-bomb defense).project_report and review it before importing into ETS or
deploying into Home Assistant.Found a security issue? See SECURITY.md.
nickol-knx-mcp/
├── nickol_knx_mcp/
│ ├── dpt_map.py # DPT → category / kind / HA platform / value_type
│ ├── project.py # the ONLY module that reads .knxproj (read-only)
│ ├── safexml.py # hardened ZIP/XML parsing of untrusted .knxproj (zip-bomb / XXE defense)
│ ├── pairing.py # command↔status pairing by name tokens
│ ├── analyze.py # naming / missing-status / DPT checks
│ ├── generate_ha.py # Home Assistant KNX YAML generation
│ ├── generate_ets.py # ETS XML + CSV generation
│ ├── report.py # Markdown report
│ ├── room_library.py # Room Library R1 — compose a new project from templates
│ ├── room_templates/ # built-in room YAML templates + SCHEMA.md (public contract)
│ └── server.py # FastMCP server, 31 tools, confined writes
├── tests/test_pipeline.py
├── examples/claude_desktop_config.json
├── skills/
│ └── ha-git-backup/ # ops companion: 2-circuit HA backup (git history + encrypted offsite)
├── CLAUDE.md # ETS Assistant skill / playbook
├── pyproject.toml
└── README.md
Testers and contributors are very welcome — especially real-project test reports. See CONTRIBUTING.md and the issue templates.
MIT © 2026 Nikolay Miroshnichenko
Not affiliated with or endorsed by the KNX Association. "KNX" and "ETS" are trademarks of the KNX Association cc. This is an independent, community tool.
Run Claude Code as an MCP server so any agent can delegate coding tasks to it
Browser automation using accessibility snapshots instead of screenshots
Google's universal MCP server supporting PostgreSQL, MySQL, MongoDB, Redis, and 10+ databases
Official GitHub integration for repos, issues, PRs, and CI/CD workflows