ignition-mcp 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.
Files changed (46) hide show
  1. ignition_mcp-0.1.0/.github/workflows/ci.yml +32 -0
  2. ignition_mcp-0.1.0/.github/workflows/publish.yml +39 -0
  3. ignition_mcp-0.1.0/.gitignore +25 -0
  4. ignition_mcp-0.1.0/LICENSE +21 -0
  5. ignition_mcp-0.1.0/PKG-INFO +201 -0
  6. ignition_mcp-0.1.0/README.md +175 -0
  7. ignition_mcp-0.1.0/bridge/build_zip.py +76 -0
  8. ignition_mcp-0.1.0/bridge/mcp-bridge.zip +0 -0
  9. ignition_mcp-0.1.0/bridge/src/doPost.py +2 -0
  10. ignition_mcp-0.1.0/bridge/src/mcp_bridge_lib.py +495 -0
  11. ignition_mcp-0.1.0/docs/bridge.md +108 -0
  12. ignition_mcp-0.1.0/docs/perspective-authoring.md +96 -0
  13. ignition_mcp-0.1.0/examples/deploy-dashboard.md +93 -0
  14. ignition_mcp-0.1.0/pyproject.toml +62 -0
  15. ignition_mcp-0.1.0/server.json +50 -0
  16. ignition_mcp-0.1.0/src/ignition_mcp/__init__.py +3 -0
  17. ignition_mcp-0.1.0/src/ignition_mcp/app.py +73 -0
  18. ignition_mcp-0.1.0/src/ignition_mcp/bridge.py +104 -0
  19. ignition_mcp-0.1.0/src/ignition_mcp/client.py +135 -0
  20. ignition_mcp-0.1.0/src/ignition_mcp/config.py +83 -0
  21. ignition_mcp-0.1.0/src/ignition_mcp/errors.py +118 -0
  22. ignition_mcp-0.1.0/src/ignition_mcp/guards.py +49 -0
  23. ignition_mcp-0.1.0/src/ignition_mcp/perspective/VIEW_SCHEMA.md +93 -0
  24. ignition_mcp-0.1.0/src/ignition_mcp/perspective/__init__.py +0 -0
  25. ignition_mcp-0.1.0/src/ignition_mcp/perspective/schema.py +91 -0
  26. ignition_mcp-0.1.0/src/ignition_mcp/perspective/templates/coordinate-basic.json +57 -0
  27. ignition_mcp-0.1.0/src/ignition_mcp/perspective/templates/flex-basic.json +52 -0
  28. ignition_mcp-0.1.0/src/ignition_mcp/perspective/templates/tag-bound-dashboard.json +108 -0
  29. ignition_mcp-0.1.0/src/ignition_mcp/server.py +104 -0
  30. ignition_mcp-0.1.0/src/ignition_mcp/tools/__init__.py +0 -0
  31. ignition_mcp-0.1.0/src/ignition_mcp/tools/alarms.py +96 -0
  32. ignition_mcp-0.1.0/src/ignition_mcp/tools/bridge_admin.py +107 -0
  33. ignition_mcp-0.1.0/src/ignition_mcp/tools/database.py +55 -0
  34. ignition_mcp-0.1.0/src/ignition_mcp/tools/diagnostics.py +137 -0
  35. ignition_mcp-0.1.0/src/ignition_mcp/tools/gateway.py +84 -0
  36. ignition_mcp-0.1.0/src/ignition_mcp/tools/history.py +66 -0
  37. ignition_mcp-0.1.0/src/ignition_mcp/tools/perspective.py +287 -0
  38. ignition_mcp-0.1.0/src/ignition_mcp/tools/projects.py +106 -0
  39. ignition_mcp-0.1.0/src/ignition_mcp/tools/tags.py +111 -0
  40. ignition_mcp-0.1.0/tests/live/live_check.py +313 -0
  41. ignition_mcp-0.1.0/tests/unit/__init__.py +0 -0
  42. ignition_mcp-0.1.0/tests/unit/conftest.py +95 -0
  43. ignition_mcp-0.1.0/tests/unit/test_projects_perspective.py +104 -0
  44. ignition_mcp-0.1.0/tests/unit/test_schema_gateway_db.py +127 -0
  45. ignition_mcp-0.1.0/tests/unit/test_tags_history_alarms.py +104 -0
  46. ignition_mcp-0.1.0/tests/unit/test_write_guards.py +114 -0
@@ -0,0 +1,32 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ jobs:
9
+ test:
10
+ runs-on: ubuntu-latest
11
+ strategy:
12
+ matrix:
13
+ python-version: ["3.10", "3.12"]
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+ - uses: actions/setup-python@v5
17
+ with:
18
+ python-version: ${{ matrix.python-version }}
19
+ - name: Install
20
+ run: |
21
+ python -m pip install --upgrade pip
22
+ pip install -e ".[dev]"
23
+ - name: Build bridge archive
24
+ run: python bridge/build_zip.py
25
+ - name: Lint
26
+ run: ruff check src tests
27
+ - name: Format check
28
+ run: ruff format --check src tests
29
+ - name: Type check
30
+ run: mypy src
31
+ - name: Unit tests
32
+ run: pytest tests/unit -q
@@ -0,0 +1,39 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+ workflow_dispatch:
7
+
8
+ jobs:
9
+ build:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+ - uses: actions/setup-python@v5
14
+ with:
15
+ python-version: "3.12"
16
+ - name: Build bridge archive
17
+ run: python bridge/build_zip.py
18
+ - name: Install build tool
19
+ run: python -m pip install --upgrade build
20
+ - name: Build sdist and wheel
21
+ run: python -m build
22
+ - uses: actions/upload-artifact@v4
23
+ with:
24
+ name: dist
25
+ path: dist/
26
+
27
+ publish:
28
+ needs: build
29
+ runs-on: ubuntu-latest
30
+ environment: pypi
31
+ permissions:
32
+ id-token: write
33
+ steps:
34
+ - uses: actions/download-artifact@v4
35
+ with:
36
+ name: dist
37
+ path: dist/
38
+ - name: Publish to PyPI
39
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,25 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ .eggs/
6
+ build/
7
+ dist/
8
+ .venv/
9
+ venv/
10
+ .mypy_cache/
11
+ .ruff_cache/
12
+ .pytest_cache/
13
+ .coverage
14
+ htmlcov/
15
+
16
+ # Workforce scratch (kept out of the published repo)
17
+ tasks/
18
+ results/
19
+
20
+ # Secrets — never commit
21
+ *.secret
22
+ .env
23
+
24
+ # OS
25
+ .DS_Store
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 jsgorana
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.
@@ -0,0 +1,201 @@
1
+ Metadata-Version: 2.4
2
+ Name: ignition-mcp
3
+ Version: 0.1.0
4
+ Summary: MCP server for Inductive Automation Ignition: tags, alarms, history, projects, and full Perspective deployment
5
+ Project-URL: Homepage, https://github.com/jsgorana/ignition-mcp
6
+ Project-URL: Issues, https://github.com/jsgorana/ignition-mcp/issues
7
+ Author: jsgorana
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Keywords: ignition,inductive-automation,mcp,model-context-protocol,perspective,scada
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Manufacturing
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Topic :: Scientific/Engineering :: Human Machine Interfaces
17
+ Requires-Python: >=3.10
18
+ Requires-Dist: httpx>=0.27
19
+ Requires-Dist: mcp>=1.2.0
20
+ Provides-Extra: dev
21
+ Requires-Dist: mypy>=1.11; extra == 'dev'
22
+ Requires-Dist: pytest-cov>=5.0; extra == 'dev'
23
+ Requires-Dist: pytest>=8.0; extra == 'dev'
24
+ Requires-Dist: ruff>=0.6; extra == 'dev'
25
+ Description-Content-Type: text/markdown
26
+
27
+ <!-- mcp-name: io.github.jsgorana/ignition-mcp -->
28
+ # ignition-mcp
29
+
30
+ An MCP (Model Context Protocol) server for Inductive Automation Ignition. It gives an AI
31
+ assistant, Claude Desktop, Claude Code, or any [MCP client](https://modelcontextprotocol.io),
32
+ structured access to an Ignition gateway: browse and write tags, query history and alarms,
33
+ manage projects, and deploy full Perspective views.
34
+
35
+ Tested against Ignition 8.3. 43 tools spanning tags, history, alarms, projects, gateway
36
+ administration, and Perspective. The server is read-only by default; every write is gated behind
37
+ an explicit opt-in.
38
+
39
+ ```
40
+ You: "Deploy a Perspective dashboard to a new project called LineOverview with a
41
+ gauge bound to [default]Line1/Speed."
42
+ Claude: (bootstraps the project, writes the view, wires the tag binding, triggers a scan)
43
+ -> https://gateway:8088/data/perspective/client/LineOverview
44
+ ```
45
+
46
+ ## Why two planes
47
+
48
+ Ignition 8.3 ships a native REST API, but it doesn't expose live tag values, tag history, alarm
49
+ queries, or Perspective view resources. `ignition-mcp` covers the gap with two transport planes:
50
+
51
+ - **REST plane.** The gateway's native `/data/api/v1` API, authenticated with an API key, used
52
+ for projects, gateway configuration, modules, logs, backups, and Perspective session
53
+ diagnostics.
54
+ - **Bridge plane.** A small WebDev project (`mcp-bridge`) you install once on the gateway. It
55
+ exposes the gateway scripting surface (`system.tag.*`, `system.alarm.*`, `system.db.*`, and
56
+ project file I/O) over HMAC-signed HTTP requests.
57
+
58
+ Tools that need the bridge degrade with a clear message if it isn't installed. Run
59
+ `ignition_diagnose` any time to see what's configured and what's missing.
60
+
61
+ ## Quickstart
62
+
63
+ ### 1. Create an API key on the gateway
64
+
65
+ Gateway web UI -> Config -> Security -> API Keys -> Create. Give it a name, for example `claude`.
66
+ Copy the full token; it looks like `claude:AbCd...`.
67
+
68
+ The key's auto-created security level (`Authenticated/<key-name>`) needs to be granted gateway
69
+ read/write access under Config -> Security -> General -> Gateway Read/Write Permissions. Skip
70
+ this step and calls return HTTP 403; `ignition_diagnose` will tell you and give the exact fix.
71
+
72
+ ### 2. Install ignition-mcp
73
+
74
+ ```bash
75
+ pipx install ignition-mcp
76
+ # or: uvx ignition-mcp
77
+ # or: pip install ignition-mcp
78
+ ```
79
+
80
+ ### 3. Configure your MCP client
81
+
82
+ Claude Desktop (`claude_desktop_config.json`) or Claude Code (`.mcp.json`):
83
+
84
+ ```json
85
+ {
86
+ "mcpServers": {
87
+ "ignition": {
88
+ "command": "ignition-mcp",
89
+ "env": {
90
+ "IGNITION_URL": "http://localhost:8088",
91
+ "IGNITION_API_TOKEN": "claude:YOUR_SECRET_HERE"
92
+ }
93
+ }
94
+ }
95
+ }
96
+ ```
97
+
98
+ Restart the client and ask it to run `ignition_diagnose`. You should get an all-green checklist,
99
+ aside from a warning about the bridge, which is the next step.
100
+
101
+ ### 4. Install the bridge (recommended, needed for live data and Perspective deploys)
102
+
103
+ Generate a random secret, enable writes, and let the server install the bridge for you:
104
+
105
+ ```json
106
+ "env": {
107
+ "IGNITION_URL": "http://localhost:8088",
108
+ "IGNITION_API_TOKEN": "claude:YOUR_SECRET_HERE",
109
+ "IGNITION_BRIDGE_SECRET": "a-long-random-string",
110
+ "IGNITION_ALLOW_WRITES": "true"
111
+ }
112
+ ```
113
+
114
+ Ask your assistant to install the bridge (this runs the `bridge_install` tool), then run
115
+ `ignition_diagnose` again to confirm the bridge check is green. See
116
+ [docs/bridge.md](docs/bridge.md) for the manual install path and troubleshooting.
117
+
118
+ ## Configuration
119
+
120
+ | Variable | Required | Default | Meaning |
121
+ |---|---|---|---|
122
+ | `IGNITION_URL` | yes | none | Gateway base URL, e.g. `http://localhost:8088` |
123
+ | `IGNITION_API_TOKEN` | yes | none | API key, `name:secret` |
124
+ | `IGNITION_BRIDGE_SECRET` | no | unset | HMAC secret for the bridge; bridge tools are disabled without it |
125
+ | `IGNITION_ALLOW_WRITES` | no | `false` | Master switch for every mutating tool |
126
+ | `IGNITION_TLS_VERIFY` | no | `true` | Set to `false` for self-signed dev gateways |
127
+ | `IGNITION_TIMEOUT_S` | no | `30` | Per-request timeout, in seconds |
128
+ | `IGNITION_TAG_WRITE_ALLOWLIST` | no | unset | Comma-separated glob patterns; tag writes outside them are refused |
129
+
130
+ ## Safety model
131
+
132
+ - Read-only by default. Mutating tools refuse to run unless `IGNITION_ALLOW_WRITES=true` and the
133
+ call passes `confirm=true`. Your assistant sets `confirm` after you approve the action.
134
+ - Destructive operations echo the name back. Deleting a project or view requires re-sending its
135
+ exact name.
136
+ - A tag-write allowlist lets you restrict writable tags to specific path globs.
137
+ - REST mutations carry the API key's identity into Ignition's own audit log; bridge mutations log
138
+ to the `mcp-bridge` logger. Secrets are never logged or echoed back.
139
+ - The bridge's file endpoints are confined to `data/projects/`; nothing outside that tree is
140
+ reachable.
141
+
142
+ ## Tool catalog
143
+
144
+ | Area | Tools |
145
+ |---|---|
146
+ | Diagnostics | `ignition_diagnose`, `gateway_info`, `gateway_trial_status`, `gateway_trial_reset` |
147
+ | Tags | `tag_browse`, `tag_read`, `tag_write`, `tag_create`, `tag_config_export`, `tag_config_import` |
148
+ | History | `history_query`, `history_providers` |
149
+ | Alarms | `alarm_status`, `alarm_journal`, `alarm_acknowledge` |
150
+ | Projects | `project_list`, `project_get`, `project_create`, `project_delete`, `project_export`, `project_import`, `project_scan` |
151
+ | Perspective | `perspective_bootstrap_project`, `perspective_list_views`, `perspective_get_view`, `perspective_upsert_view`, `perspective_delete_view`, `perspective_validate_view`, `perspective_page_config_get/set`, `perspective_session_props_get`, `perspective_style_upsert`, `perspective_list_sessions` |
152
+ | Gateway admin | `gateway_modules`, `gateway_logs_query`, `gateway_logger_set_level`, `gateway_backup`, `gateway_performance`, `config_resource_list` |
153
+ | Database | `db_run_named_query`, `db_query` |
154
+ | Bridge | `bridge_install`, `bridge_status` |
155
+
156
+ The server also exposes MCP resources the assistant can read to author valid Perspective views:
157
+ `ignition://docs/view-schema` and `ignition://templates/view/{flex-basic,coordinate-basic,tag-bound-dashboard}`.
158
+
159
+ ## Building Perspective views
160
+
161
+ See [docs/perspective-authoring.md](docs/perspective-authoring.md) for the full writeup. In
162
+ short: the assistant reads the view-schema resource, starts from a template, validates offline
163
+ with `perspective_validate_view`, then deploys with `perspective_upsert_view`, which validates
164
+ again, writes the view, and triggers a project scan. A full round-trip example is in
165
+ [examples/deploy-dashboard.md](examples/deploy-dashboard.md).
166
+
167
+ ## Development
168
+
169
+ ```bash
170
+ git clone https://github.com/jsgorana/ignition-mcp
171
+ cd ignition-mcp
172
+ python -m venv .venv && source .venv/bin/activate
173
+ pip install -e ".[dev]"
174
+
175
+ ruff check src tests # lint
176
+ pytest tests/unit # unit tests, no gateway needed
177
+ python bridge/build_zip.py # rebuild the bridge project archive
178
+
179
+ # Live integration suite (needs a real 8.3 gateway with the bridge installed):
180
+ IGNITION_URL=... IGNITION_API_TOKEN=... IGNITION_BRIDGE_SECRET=... \
181
+ IGNITION_ALLOW_WRITES=true python tests/live/live_check.py
182
+ ```
183
+
184
+ ## Acknowledgments
185
+
186
+ Built on the [Model Context Protocol](https://modelcontextprotocol.io) and its
187
+ [Python SDK](https://github.com/modelcontextprotocol/python-sdk), using
188
+ [httpx](https://www.python-httpx.org/) for HTTP. The
189
+ [ignition-sdk-examples](https://github.com/inductiveautomation/ignition-sdk-examples) repository
190
+ was a useful reference while working out how Ignition's module and scripting APIs fit together.
191
+
192
+ ## License
193
+
194
+ MIT. See [LICENSE](LICENSE).
195
+
196
+ ## Disclaimer
197
+
198
+ This project is independent and community-built. It is not affiliated with, endorsed by, or
199
+ sponsored by Inductive Automation. "Ignition" and "Perspective" are trademarks of Inductive
200
+ Automation, LLC, used here only to describe compatibility. Test any write-enabled tool against a
201
+ non-production gateway before pointing it at something that matters.
@@ -0,0 +1,175 @@
1
+ <!-- mcp-name: io.github.jsgorana/ignition-mcp -->
2
+ # ignition-mcp
3
+
4
+ An MCP (Model Context Protocol) server for Inductive Automation Ignition. It gives an AI
5
+ assistant, Claude Desktop, Claude Code, or any [MCP client](https://modelcontextprotocol.io),
6
+ structured access to an Ignition gateway: browse and write tags, query history and alarms,
7
+ manage projects, and deploy full Perspective views.
8
+
9
+ Tested against Ignition 8.3. 43 tools spanning tags, history, alarms, projects, gateway
10
+ administration, and Perspective. The server is read-only by default; every write is gated behind
11
+ an explicit opt-in.
12
+
13
+ ```
14
+ You: "Deploy a Perspective dashboard to a new project called LineOverview with a
15
+ gauge bound to [default]Line1/Speed."
16
+ Claude: (bootstraps the project, writes the view, wires the tag binding, triggers a scan)
17
+ -> https://gateway:8088/data/perspective/client/LineOverview
18
+ ```
19
+
20
+ ## Why two planes
21
+
22
+ Ignition 8.3 ships a native REST API, but it doesn't expose live tag values, tag history, alarm
23
+ queries, or Perspective view resources. `ignition-mcp` covers the gap with two transport planes:
24
+
25
+ - **REST plane.** The gateway's native `/data/api/v1` API, authenticated with an API key, used
26
+ for projects, gateway configuration, modules, logs, backups, and Perspective session
27
+ diagnostics.
28
+ - **Bridge plane.** A small WebDev project (`mcp-bridge`) you install once on the gateway. It
29
+ exposes the gateway scripting surface (`system.tag.*`, `system.alarm.*`, `system.db.*`, and
30
+ project file I/O) over HMAC-signed HTTP requests.
31
+
32
+ Tools that need the bridge degrade with a clear message if it isn't installed. Run
33
+ `ignition_diagnose` any time to see what's configured and what's missing.
34
+
35
+ ## Quickstart
36
+
37
+ ### 1. Create an API key on the gateway
38
+
39
+ Gateway web UI -> Config -> Security -> API Keys -> Create. Give it a name, for example `claude`.
40
+ Copy the full token; it looks like `claude:AbCd...`.
41
+
42
+ The key's auto-created security level (`Authenticated/<key-name>`) needs to be granted gateway
43
+ read/write access under Config -> Security -> General -> Gateway Read/Write Permissions. Skip
44
+ this step and calls return HTTP 403; `ignition_diagnose` will tell you and give the exact fix.
45
+
46
+ ### 2. Install ignition-mcp
47
+
48
+ ```bash
49
+ pipx install ignition-mcp
50
+ # or: uvx ignition-mcp
51
+ # or: pip install ignition-mcp
52
+ ```
53
+
54
+ ### 3. Configure your MCP client
55
+
56
+ Claude Desktop (`claude_desktop_config.json`) or Claude Code (`.mcp.json`):
57
+
58
+ ```json
59
+ {
60
+ "mcpServers": {
61
+ "ignition": {
62
+ "command": "ignition-mcp",
63
+ "env": {
64
+ "IGNITION_URL": "http://localhost:8088",
65
+ "IGNITION_API_TOKEN": "claude:YOUR_SECRET_HERE"
66
+ }
67
+ }
68
+ }
69
+ }
70
+ ```
71
+
72
+ Restart the client and ask it to run `ignition_diagnose`. You should get an all-green checklist,
73
+ aside from a warning about the bridge, which is the next step.
74
+
75
+ ### 4. Install the bridge (recommended, needed for live data and Perspective deploys)
76
+
77
+ Generate a random secret, enable writes, and let the server install the bridge for you:
78
+
79
+ ```json
80
+ "env": {
81
+ "IGNITION_URL": "http://localhost:8088",
82
+ "IGNITION_API_TOKEN": "claude:YOUR_SECRET_HERE",
83
+ "IGNITION_BRIDGE_SECRET": "a-long-random-string",
84
+ "IGNITION_ALLOW_WRITES": "true"
85
+ }
86
+ ```
87
+
88
+ Ask your assistant to install the bridge (this runs the `bridge_install` tool), then run
89
+ `ignition_diagnose` again to confirm the bridge check is green. See
90
+ [docs/bridge.md](docs/bridge.md) for the manual install path and troubleshooting.
91
+
92
+ ## Configuration
93
+
94
+ | Variable | Required | Default | Meaning |
95
+ |---|---|---|---|
96
+ | `IGNITION_URL` | yes | none | Gateway base URL, e.g. `http://localhost:8088` |
97
+ | `IGNITION_API_TOKEN` | yes | none | API key, `name:secret` |
98
+ | `IGNITION_BRIDGE_SECRET` | no | unset | HMAC secret for the bridge; bridge tools are disabled without it |
99
+ | `IGNITION_ALLOW_WRITES` | no | `false` | Master switch for every mutating tool |
100
+ | `IGNITION_TLS_VERIFY` | no | `true` | Set to `false` for self-signed dev gateways |
101
+ | `IGNITION_TIMEOUT_S` | no | `30` | Per-request timeout, in seconds |
102
+ | `IGNITION_TAG_WRITE_ALLOWLIST` | no | unset | Comma-separated glob patterns; tag writes outside them are refused |
103
+
104
+ ## Safety model
105
+
106
+ - Read-only by default. Mutating tools refuse to run unless `IGNITION_ALLOW_WRITES=true` and the
107
+ call passes `confirm=true`. Your assistant sets `confirm` after you approve the action.
108
+ - Destructive operations echo the name back. Deleting a project or view requires re-sending its
109
+ exact name.
110
+ - A tag-write allowlist lets you restrict writable tags to specific path globs.
111
+ - REST mutations carry the API key's identity into Ignition's own audit log; bridge mutations log
112
+ to the `mcp-bridge` logger. Secrets are never logged or echoed back.
113
+ - The bridge's file endpoints are confined to `data/projects/`; nothing outside that tree is
114
+ reachable.
115
+
116
+ ## Tool catalog
117
+
118
+ | Area | Tools |
119
+ |---|---|
120
+ | Diagnostics | `ignition_diagnose`, `gateway_info`, `gateway_trial_status`, `gateway_trial_reset` |
121
+ | Tags | `tag_browse`, `tag_read`, `tag_write`, `tag_create`, `tag_config_export`, `tag_config_import` |
122
+ | History | `history_query`, `history_providers` |
123
+ | Alarms | `alarm_status`, `alarm_journal`, `alarm_acknowledge` |
124
+ | Projects | `project_list`, `project_get`, `project_create`, `project_delete`, `project_export`, `project_import`, `project_scan` |
125
+ | Perspective | `perspective_bootstrap_project`, `perspective_list_views`, `perspective_get_view`, `perspective_upsert_view`, `perspective_delete_view`, `perspective_validate_view`, `perspective_page_config_get/set`, `perspective_session_props_get`, `perspective_style_upsert`, `perspective_list_sessions` |
126
+ | Gateway admin | `gateway_modules`, `gateway_logs_query`, `gateway_logger_set_level`, `gateway_backup`, `gateway_performance`, `config_resource_list` |
127
+ | Database | `db_run_named_query`, `db_query` |
128
+ | Bridge | `bridge_install`, `bridge_status` |
129
+
130
+ The server also exposes MCP resources the assistant can read to author valid Perspective views:
131
+ `ignition://docs/view-schema` and `ignition://templates/view/{flex-basic,coordinate-basic,tag-bound-dashboard}`.
132
+
133
+ ## Building Perspective views
134
+
135
+ See [docs/perspective-authoring.md](docs/perspective-authoring.md) for the full writeup. In
136
+ short: the assistant reads the view-schema resource, starts from a template, validates offline
137
+ with `perspective_validate_view`, then deploys with `perspective_upsert_view`, which validates
138
+ again, writes the view, and triggers a project scan. A full round-trip example is in
139
+ [examples/deploy-dashboard.md](examples/deploy-dashboard.md).
140
+
141
+ ## Development
142
+
143
+ ```bash
144
+ git clone https://github.com/jsgorana/ignition-mcp
145
+ cd ignition-mcp
146
+ python -m venv .venv && source .venv/bin/activate
147
+ pip install -e ".[dev]"
148
+
149
+ ruff check src tests # lint
150
+ pytest tests/unit # unit tests, no gateway needed
151
+ python bridge/build_zip.py # rebuild the bridge project archive
152
+
153
+ # Live integration suite (needs a real 8.3 gateway with the bridge installed):
154
+ IGNITION_URL=... IGNITION_API_TOKEN=... IGNITION_BRIDGE_SECRET=... \
155
+ IGNITION_ALLOW_WRITES=true python tests/live/live_check.py
156
+ ```
157
+
158
+ ## Acknowledgments
159
+
160
+ Built on the [Model Context Protocol](https://modelcontextprotocol.io) and its
161
+ [Python SDK](https://github.com/modelcontextprotocol/python-sdk), using
162
+ [httpx](https://www.python-httpx.org/) for HTTP. The
163
+ [ignition-sdk-examples](https://github.com/inductiveautomation/ignition-sdk-examples) repository
164
+ was a useful reference while working out how Ignition's module and scripting APIs fit together.
165
+
166
+ ## License
167
+
168
+ MIT. See [LICENSE](LICENSE).
169
+
170
+ ## Disclaimer
171
+
172
+ This project is independent and community-built. It is not affiliated with, endorsed by, or
173
+ sponsored by Inductive Automation. "Ignition" and "Perspective" are trademarks of Inductive
174
+ Automation, LLC, used here only to describe compatibility. Test any write-enabled tool against a
175
+ non-production gateway before pointing it at something that matters.
@@ -0,0 +1,76 @@
1
+ #!/usr/bin/env python3
2
+ """Deterministically build bridge/mcp-bridge.zip — an importable Ignition project
3
+ containing the mcp-bridge WebDev endpoint and its script library.
4
+
5
+ The BRIDGE_SECRET placeholder stays intact; it is substituted at install time
6
+ (bridge_install tool) or by the operator during a manual import.
7
+
8
+ Usage: python bridge/build_zip.py
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import io
14
+ import json
15
+ import zipfile
16
+ from pathlib import Path
17
+
18
+ HERE = Path(__file__).parent
19
+ SRC = HERE / "src"
20
+ OUT = HERE / "mcp-bridge.zip"
21
+ PERSPECTIVE = "com.inductiveautomation.perspective"
22
+
23
+ # Fixed timestamp for reproducible archives.
24
+ ZINFO_DATE = (2026, 1, 1, 0, 0, 0)
25
+
26
+
27
+ def _write(zf: zipfile.ZipFile, arcname: str, data: str) -> None:
28
+ info = zipfile.ZipInfo(arcname, date_time=ZINFO_DATE)
29
+ info.compress_type = zipfile.ZIP_DEFLATED
30
+ zf.writestr(info, data)
31
+
32
+
33
+ def build() -> bytes:
34
+ lib_code = (SRC / "mcp_bridge_lib.py").read_text()
35
+ endpoint_code = (SRC / "doPost.py").read_text()
36
+
37
+ buf = io.BytesIO()
38
+ with zipfile.ZipFile(buf, "w") as zf:
39
+ _write(zf, "project.json", json.dumps({
40
+ "title": "MCP Bridge",
41
+ "description": "WebDev bridge for ignition-mcp",
42
+ "parent": "",
43
+ "enabled": True,
44
+ "inheritable": False,
45
+ }, indent=2))
46
+
47
+ # Script library: ignition/script-python/mcp_bridge_lib/code.py
48
+ lib_dir = "ignition/script-python/mcp_bridge_lib"
49
+ _write(zf, f"{lib_dir}/code.py", lib_code)
50
+ _write(zf, f"{lib_dir}/resource.json", json.dumps({
51
+ "scope": "G", "version": 1, "restricted": False, "overridable": True,
52
+ "files": ["code.py"], "attributes": {},
53
+ }, indent=2))
54
+
55
+ # WebDev endpoint: com.inductiveautomation.webdev/resources/api
56
+ api_dir = "com.inductiveautomation.webdev/resources/api"
57
+ _write(zf, f"{api_dir}/doPost", endpoint_code)
58
+ _write(zf, f"{api_dir}/config.json", json.dumps({
59
+ "resource-type": "python-resource",
60
+ "doPost": {"enabled": True, "require-https": False, "require-auth": False},
61
+ }, indent=2))
62
+ _write(zf, f"{api_dir}/resource.json", json.dumps({
63
+ "scope": "G", "version": 1, "restricted": False, "overridable": True,
64
+ "files": ["config.json", "doPost"], "attributes": {},
65
+ }, indent=2))
66
+
67
+ return buf.getvalue()
68
+
69
+
70
+ def main() -> None:
71
+ OUT.write_bytes(build())
72
+ print(f"wrote {OUT} ({OUT.stat().st_size} bytes)")
73
+
74
+
75
+ if __name__ == "__main__":
76
+ main()
Binary file
@@ -0,0 +1,2 @@
1
+ def doPost(request, session):
2
+ return mcp_bridge_lib.handle(request)