Content
# Niagara MCP Module






A Niagara 4 custom module that exposes station data (read-mostly, write-gated)
through the
[Model Context Protocol (MCP)](https://modelcontextprotocol.io/specification/2025-03-26).
MCP-compatible AI clients (Claude Desktop, VS Code Copilot, etc.) can discover
and call tools that introspect the live station with explicit write gates and
allowlist enforcement.
---
## MY WHY
> I build to amplify people, not replace them.
> I automate repetition so human judgment can focus on design, commissioning, and real problem-solving.
> I treat safety as non-negotiable: explicit write gates, clear boundaries, and fail-closed defaults.
> I move fast, but verify in live systems, learn honestly, and document what reality teaches us.
> I believe AI in Niagara is no longer theoretical; it is practical, present, and ours to shape responsibly.
>
> Why?
> It's because I choose progress with accountability, and tools that elevate the craft. - Chris Favre, April 30, 2026
---
## Documentation
| Document | Description |
|---|---|
| [docs/QUICKSTART.md](docs/QUICKSTART.md) | Build, install, start proxy, verify end-to-end |
| [docs/TOOLS_REFERENCE.md](docs/TOOLS_REFERENCE.md) | All 26 tools with arguments, examples, and response shapes |
| [docs/NIAGARA_OBJECTS_ROADMAP.md](docs/NIAGARA_OBJECTS_ROADMAP.md) | Planned expansions (M1–M5) |
| [docs/LESSONS_LEARNED.md](docs/LESSONS_LEARNED.md) | v0.4.0 implementation lessons and operational guidance |
---
## Status
| Area | Status |
|---|---|
| Live station integration | ✅ Validated |
| Claude MCP workflow | ✅ Validated |
| Write gating via `readOnly` selector | ✅ Enforced |
| SCRAM auth (Niagara 4.15) | ✅ Handled by `mcp_proxy.py` |
| Unit tests | ✅ 110 tests, 0 failures |
---
## Architecture
```
AI Client (Claude Desktop / VS Code Copilot / curl)
└── mcp_proxy.py (handles Niagara SCRAM auth)
└── BMcpService (BWebServlet at /mcp)
├── McpJsonRpcHandler JSON-RPC 2.0 dispatcher
├── McpToolRegistry tool name → handler map
├── NiagaraSecurity allowlist & sensitive-slot masking
├── NiagaraComponentTools station.info, component.read/children/slots
├── NiagaraBqlTools bql.query (SELECT only)
├── NiagaraAlarmTools alarm.query, alarm.active
├── NiagaraHistoryTools history.list, history.read, trend.summary
├── NiagaraPointTools point.read, point.search
├── NiagaraEquipmentTools equipment.status
├── NiagaraScheduleTools schedule.read, schedule.list
├── NiagaraFaultScanTool fault.scan
├── NiagaraBuildingBriefTool building.brief
├── NiagaraHaystackTools haystack.getRuleset/setRuleset/applyRules
├── NiagaraWiresheetTools wiresheet.plan/diff/apply/links (v0.4.0)
├── NiagaraBacnetTools bacnet.devices
└── NiagaraJson zero-dependency JSON builder
```
---
## Quick Start
```powershell
# 1. Build
java -jar gradle\wrapper\gradle-wrapper.jar clean jar
# 2. Deploy jar to Niagara modules directory, add BMcpService to station Services
# 3. Start auth proxy
python mcp_proxy.py --niagara-base http://localhost --niagara-user <user> --niagara-pass <pass> --token <your-token>
# 4. Verify
curl -X POST http://127.0.0.1:8765/mcp -H "X-MCP-Token: <your-token>" -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
```
See [docs/QUICKSTART.md](docs/QUICKSTART.md) for the full walkthrough.
---
## Tools Summary
| Tool | Category | Description |
|---|---|---|
| `niagara.station.info` | Station | Station name, version, read-only flag |
| `niagara.component.read` | Component | Read component slots by ORD |
| `niagara.component.children` | Component | List immediate children of an ORD |
| `niagara.component.slots` | Component | List all slots (sensitive values masked) |
| `niagara.component.search` | Component | Search components by name/type under a root |
| `niagara.bql.query` | BQL | SELECT-only BQL query |
| `niagara.alarm.query` | Alarms | Recent alarm records (all states) |
| `niagara.alarm.active` | Alarms | Currently active / unacknowledged alarms |
| `niagara.history.list` | History | Available history IDs and display names |
| `niagara.history.read` | History | Time-series records for a history by ID |
| `niagara.trend.summary` | History | Aggregated trend min/max/first/last over a time window |
| `niagara.point.read` | Points | Current value of a single proxy point |
| `niagara.point.search` | Points | Find points by name or type substring |
| `niagara.equipment.status` | Equipment | All devices across all driver networks |
| `niagara.schedule.read` | Schedules | Current state + next transition for one schedule |
| `niagara.schedule.list` | Schedules | All schedules with current occupancy state |
| `niagara.fault.scan` | Diagnostics | Summarize fault/stale/overridden points |
| `niagara.building.brief` | Diagnostics | Morning-briefing synthesis across alarms/faults/equipment |
| `niagara.bacnet.devices` | BACnet | BACnet devices under a network ORD |
| `niagara.haystack.getRuleset` | Haystack | Read tagging ruleset file |
| `niagara.haystack.setRuleset` | Haystack | Write tagging ruleset file (write mode required) |
| `niagara.haystack.applyRules` | Haystack | Apply haystack tags from ruleset (write mode required) |
| `niagara.wiresheet.plan` | Wiresheet | Validate and normalize declarative wiresheet operations |
| `niagara.wiresheet.diff` | Wiresheet | Deterministic desired-state diff for operation payloads |
| `niagara.wiresheet.apply` | Wiresheet | Write-gated execution report with `dryRun` default true |
| `niagara.wiresheet.links` | Wiresheet | Inspect runtime links for a component/slot (diagnostic) |
Total tools in v0.4.0: 26.
Full argument and response documentation: [docs/TOOLS_REFERENCE.md](docs/TOOLS_REFERENCE.md)
---
## Building
Requires Java 8 or 11. No Niagara SDK installation needed — the project compiles
against included stubs.
```powershell
# Run unit tests (110 tests, no Niagara runtime required)
java -jar gradle\wrapper\gradle-wrapper.jar test
# Build JAR
java -jar gradle\wrapper\gradle-wrapper.jar jar
```
Output: `build/libs/niagaraMcp.jar`
### Building against a real Niagara SDK
Replace `compileOnly project(':stubs')` in `build.gradle` with the actual Niagara
JAR paths:
```groovy
compileOnly fileTree(dir: System.getenv('NIAGARA_HOME') + '/lib', include: '*.jar')
```
---
## Configuration
| Property | Default | Description |
|---|---|---|
| `enabled` | `true` | Enable / disable the MCP endpoint |
| `endpointPath` | `/mcp` | HTTP path |
| `readOnly` | `true` | Global write gate: `true` blocks write-capable tools; `false` enables them |
| `allowBql` | `true` | Permit BQL SELECT queries |
| `maxResults` | `500` | Maximum rows / items per call |
| `allowlistedRoots` | see below | Comma-separated ORD prefixes |
Default allowlisted roots:
- `station:|slot:/Drivers`
- `station:|slot:/Services`
- `station:|slot:/Config`
- Read/write mode is controlled by the BMcpService `readOnly` slot in Workbench (default `true`).
Any ORD that does not start with one of these roots is immediately rejected.
### Module Verification Mode (Development)
- Set `niagara.moduleVerificationMode=low` in `C:\Niagara\Niagara-<version>\defaults\system.properties` for development/community modules.
- `low` means warnings only (no enforcement).
- If blacklist enforcement for this property is inactive/commented out, the setting applies.
- This affects both station process and Workbench behavior.
### `readOnly` selector behavior
- `readOnly=true` (default): all write-capable tools fail closed.
- `readOnly=false`: write-capable tools may execute, but still require allowlist compliance and tool-level validations.
- This selector is the primary operational safety switch for mutation behavior.
---
## Security
1. **Read-mostly with explicit write gates** — write-capable tools require `readOnly=false` and enforce allowlists.
2. **Allowlisted roots** — every ORD argument is validated against configured prefixes.
3. **Sensitive-slot masking** — slots named `password`, `secret`, `token`, `key`, `credential`, `auth` return `***`.
4. **BQL SELECT-only** — mutation keywords (`SET`, `DELETE`, `INSERT`, `UPDATE`, `DROP`, …) cause immediate rejection.
5. **Result caps** — all queries honour `maxResults`.
6. **Fail-closed** — uncertain security checks deny access.
---
## Development History
| Phase | Status | Scope |
|---|---|---|
| v0.1 — Core | ✅ Done | Module, HTTP endpoint, JSON-RPC, component tools, BQL, alarm/history/bacnet stubs, SCRAM proxy |
| v0.2 — Operator Essentials | ✅ Done | alarm.active, history.read, point.read/search, equipment.status, schedule.read/list |
| v0.3 — Runtime API Fix + Synthesis | ✅ Done | alarm/history real API chain, trend.summary, fault.scan, building.brief, component.search, 110 tests |
| v0.4.0 — Wiresheet Runtime | ✅ Done | `wiresheet.plan/diff/apply/links`; deterministic target-side `linkTo` invocation (fixes link direction bug); Workbench navigation ORD metadata repair; Numeric/Boolean/Enum/String writable create support; `local:\|foxwss:\|` ORD normalization |
| v0.5.0 — kitControl Wiresheet | 🔜 In Progress | Expand create/link support to core kitControl logic blocks; kitControl slot/link validation in plan+diff; sample LLM-driven wiresheet build workflows |
---
## Repository Hygiene
**Commit:** source code, Gradle wrapper, module metadata, tests, documentation.
**Do not commit:** secrets (`.p12`, keystores, passwords, tokens), runtime artifacts
(`.log`, `cookies.txt`), build outputs (`build/`, `.gradle/`), IDE-local state (`.claude/`).
Before pushing: run `git status`, confirm no secrets in staged changes.
---
## Not Implemented Yet
The following tools are not implemented in v0.4.0 and currently return unsupported behavior:
`niagara.point.write`, `niagara.point.override`, `niagara.alarm.ack`,
`niagara.schedule.write`, `niagara.component.invokeAction`,
`niagara.station.restart`, `niagara.driver.discoverAndAdd`
Write support is now in-scope and expands incrementally behind the BMcpService `readOnly` selector.
---
## License
[MIT License](LICENSE)
Connection Info
You Might Also Like
everything-claude-code
Complete Claude Code configuration collection - agents, skills, hooks,...
markitdown
MarkItDown-MCP is a lightweight server for converting URIs to Markdown.
cc-switch
All-in-One Assistant for Claude Code, Codex & Gemini CLI across platforms.
servers
Model Context Protocol Servers
servers
Model Context Protocol Servers
Time
A Model Context Protocol server for time and timezone conversions.