MCP Module Early Access

Thanks for the tips, still getting the 403. Might wipe everything and start over.

I have noticed a lot of connection issues after a trial restart. I end up having to shut down all LLMs and doing a ignition gateway restart. I assume its session timeouts or possibly not re-initializing things. Make sure you try those steps frequently as well.

Hi Paul, I get the same error

{"error":{"code":-32600}}

but my project is not inheritable...what else can I check?

From the code, -32600 (a JSON RPC "invalid request") is only thrown for the six methods associated with interacting with tools, resources, or prompts. What does your server config on disk look like? Do you have at least an empty JSON object for each of tools, resources, and prompts?

I followed your instruction at the beginning of the thread:

  1. I created the folder
[...]/Inductive Automation\Ignition\data\config\resources\core\com.inductiveautomation.mcp\server-config\testing
  1. Inside that folder I created the files config.json and resource.json with, respectively, the following content
{
  "title": "Testing",
  "version": "1.0.0",
  "permissions": {
    "type": "AllOf",
    "securityLevels": [
      {
        "children": [],
        "name": "Authenticated"
      }
    ]
  },
  "tools": {
    "project/Test": "*"
  },
  "resources": {},
  "prompts": {}
}
{
    "scope": "A",
    "version": 1,
    "restricted": false,
    "overridable": true,
    "files": [
        "config.json"
    ],
    "attributes": {
        "uuid": "4895f9b3-eeb1-436f-b327-e54ab873db86"
    }
}

I'm using Claude Desktop and this is its mcp server configuration

"mcpServers": {
        "ignition-mcp": {
            "command": "cmd",
            "args": [
                "/c",
                "npx",
                "-y",
                "mcp-remote",
                "http://localhost:8088/data/mcp/testing",
                "--allow-http",
                "--header",
                "X-Ignition-API-Token: my_key"
            ]
        }
    }

I have created one object for each category on the Designer

but the result doesn't change.

This is the Powershell script I'm using to test the connection (I'm a newby on the topic, so I asked Claude Sonnet 4.6 for help and there might be mistakes)

$uri = "http://localhost:8088/data/mcp/testing"
$headers = @{
    "X-Ignition-API-Token" = "my_key"
    "Accept"               = "application/json, text/event-stream"
    "Content-Type"         = "application/json"
}

# Step 1 — Initialize
$initResponse = Invoke-WebRequest -Uri $uri -Method POST -Headers $headers `
    -Body '{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}},"id":1}'

$sessionId = $initResponse.Headers["Mcp-Session-Id"]
Write-Host "Session ID: $sessionId"
$headers["Mcp-Session-Id"] = $sessionId

# Step 2 — notifications/initialized
Invoke-WebRequest -Uri $uri -Method POST -Headers $headers `
    -Body '{"jsonrpc":"2.0","method":"notifications/initialized"}' | Out-Null
Start-Sleep -Seconds 3

# Step 3 — tools/list
Write-Host "`n=== TOOLS ==="
(Invoke-WebRequest -Uri $uri -Method POST -Headers $headers `
    -Body '{"jsonrpc":"2.0","method":"tools/list","id":2}').Content |
    ConvertFrom-Json | ConvertTo-Json -Depth 10

# Step 4 — resources/list
Write-Host "`n=== RESOURCES ==="
(Invoke-WebRequest -Uri $uri -Method POST -Headers $headers `
    -Body '{"jsonrpc":"2.0","method":"resources/list","id":3}').Content |
    ConvertFrom-Json | ConvertTo-Json -Depth 10

# Step 5 — prompts/list
Write-Host "`n=== PROMPTS ==="
(Invoke-WebRequest -Uri $uri -Method POST -Headers $headers `
    -Body '{"jsonrpc":"2.0","method":"prompts/list","id":4}').Content |
    ConvertFrom-Json | ConvertTo-Json -Depth 10

Here is the output

Session ID: 68b507b5-ddcc-4976-94d5-e2d0933d655a

=== TOOLS ===
{
    "id":  2,
    "error":  {
                  "code":  -32600
              },
    "jsonrpc":  "2.0"
}

=== RESOURCES ===
{
    "id":  3,
    "error":  {
                  "code":  -32600
              },
    "jsonrpc":  "2.0"
}

=== PROMPTS ===
{
    "id":  4,
    "error":  {
                  "code":  -32600
              },
    "jsonrpc":  "2.0"
}

API key returns 403 Forbidden on /data/mcp/ endpoint even with Authenticated level and secure connections disabled

I am setting up the early-access MCP module on Ignition 8.3 and trying to connect to an MCP client (Claude Desktop). The endpoin is reachable and enforcing auth, but every authenticated request returns 403 Forbiddedn and I've been uable to get a single successful call or establish a connection.

config.json:

{
  "title": "Testing",
  "version": "1.0.0",
  "permissions": {
    "type": "AllOf",
    "securityLevels": [
      {
        "children": [],
        "name": "mcpApiKeys"
      }
    ]
  },
  "tools": {
    "project/MCP_TEST": "*"
  },
  "resources": {},
  "prompts": {}
}

claude_desktop_conflig.json:

{
  "coworkUserFilesPath": "C:\\Users\\apexadmin\\Claude",
  "preferences": {
    "coworkScheduledTasksEnabled": false,
    "coworkHipaaRestricted": false,
    "ccdScheduledTasksEnabled": true,
    "bypassPermissionsGateByAccount": {
      "2e7c7741-22e0-42ab-b9cf-5dd1c4d07d68": true
    },
    "coworkWebSearchEnabled": true,
    "coworkModelAutoFallbackByAccount": {
      "2e7c7741-22e0-42ab-b9cf-5dd1c4d07d68": true
    },
    "remoteToolsDeviceName": "eus2-ign-gw-dev",
    "epitaxyPrefs": {
      "starred-local-code-sessions": [],
      "starred-cowork-spaces": [],
      "starred-session-groups": [],
      "dframe-local-slice": {
        "pinnedOrder": [],
        "customGroupAssignments": {},
        "customGroupOrder": {}
      }
    }
  }, 
  "mcpServers": {
    "ignition": {
      "command": "C:\\Program Files\\nodejs\\node.exe",
        "args": [
          "C:\\Users\\apexadmin\\AppData\\Roaming\\npm\\node_modules\\mcp-remote\\dist\\proxy.js",
          "http://localhost:8088/data/mcp/testing",
          "--transport", "http-only",
          "--allow-http",
          "--header", "X-Ignition-API-Token:xxxTOKENxxx"
        ]
    }
  }
}

config.json:

{
    "scope": "A",
    "version": 1,
    "restricted": false,
    "overridable": true,
    "files": [
        "config.json"
    ],
    "attributes": {
        "uuid": "4895f9b3-eeb1-436f-b327-e54ab873db86"
    }
}

this is some text from the mcp-server-ignition.log:

2026-06-22T13:41:50.202Z [ignition] [info] Server started and connected successfully { metadata: undefined }
2026-06-22T13:41:50.315Z [ignition] [info] Message from client: {"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{"extensions":{"io.modelcontextprotocol/ui":{"mimeTypes":["text/html;profile=mcp-app"]}}},"clientInfo":{"name":"claude-ai","version":"0.1.0"}},"jsonrpc":"2.0","id":0} { metadata: undefined }
[15428] Using transport strategy: http-only
[15428] Using automatically selected callback port: 29149
[15428] Using custom headers: {"X-Ignition-API-Token":"xxxTOKENxxx"}
[15428] Discovering OAuth server configuration...
[15428] [15428] Connecting to remote server: http://localhost:8088/data/mcp/testing
[15428] Using transport strategy: http-only
[15428] Connection error: StreamableHTTPError: Streamable HTTP error: Error POSTing to endpoint: {
"message":"Forbidden",
"url":"/data/mcp/testing",
"status":"403"
}
    at StreamableHTTPClientTransport.send (file:///C:/Users/apexadmin/AppData/Roaming/npm/node_modules/mcp-remote/dist/chunk-65X3S4HB.js:19897:15)
    at process.processTicksAndRejections (node:internal/process/task_queues:104:5) {
  code: 403
}
[15428] Fatal error: StreamableHTTPError: Streamable HTTP error: Error POSTing to endpoint: {
"message":"Forbidden",
"url":"/data/mcp/testing",
"status":"403"
}
    at StreamableHTTPClientTransport.send (file:///C:/Users/apexadmin/AppData/Roaming/npm/node_modules/mcp-remote/dist/chunk-65X3S4HB.js:19897:15)
    at process.processTicksAndRejections (node:internal/process/task_queues:104:5) {
  code: 403
}
Assertion failed: !(handle->flags & UV_HANDLE_CLOSING), file src\win\async.c, line 94
2026-06-22T13:41:50.721Z [ignition] [info] Server transport closed { metadata: undefined }
2026-06-22T13:41:50.721Z [ignition] [info] Server transport closed unexpectedly, this is likely due to the process exiting early. If you are developing this MCP server you can add output to stderr (i.e. `console.error('...')` in JavaScript, `print('...', file=sys.stderr)` in python) and it will appear in this log. { metadata: undefined }
2026-06-22T13:41:50.721Z [ignition] [error] Server disconnected. For troubleshooting guidance, please visit our [debugging documentation](https://modelcontextprotocol.io/docs/tools/debugging) { metadata: { context: 'connection', stack: undefined } }
2026-06-22T13:41:50.722Z [ignition] [info] Client transport closed { metadata: undefined }
2026-06-22T13:41:50.722Z [ignition] [info] Client transport closed { metadata: undefined }

I even tried calling the endpoint directly with curl (removing any client from the equation) and it still returns 403.

Curl call:

curl -X POST http://localhost:8088/data/mcp/testing -H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" -H "X-Ignition-API-Token: xxxTOKENxxx" -d "{\"jsonrpc\":\"2.0\",\"method\":\"initialize\",\"params\":{\"protocolVersion\":\"2025-06-18\",\"capabilities\":{}},\"id\":1}"

Curl return:

{
"message":"Forbidden",
"url":"/data/mcp/testing",
"status":"403"
}

I guess my main question is this: with a valid key that holds Authenticated, secure connections disabled, and a config requiring only Authenticated, what else is required for the MCP module to authorize a request to /data/mcp/testing? I also tried creating a api key sub-folder called mcpApiKeys and selected that as well as put it in the config file but that, too, returned a 403. I've tried creating fresh keys, trying to enable the core(active) collection, and unchecked the "require secure connections for API keys". Is there any additional backend/gateway permissions that I need to enable or that the MCP module needs in order to accept API-key auth beyond just the security level in config.json.

My environment is a Windows Azure VM running the 8.3 EA gateway, by the way. I am still on the Ignition trial and have to reset it every 2 hours, so I don't know if that could cause this issue.

Some help on this issue would greatly be appreciated.

I tried to download module again - after filing form it gives me a link that returns AccessDenied in XML from.

Am I missing some steps?

-32600 here is almost always a session issue, not your Designer objects. Print $sessionId and confirm it's not blank. If the Mcp-Session-Id header isn't captured and carried onto the list calls, every request gets rejected as invalid. Also make sure notifications/initialized actually lands before tools/list fires. Your config.json looks correct.

The 403 on a raw curl initialize means it's an auth rejection before MCP even runs, not a session/config-schema issue. Your config requires the custom mcpApiKeys level. The known-working setup uses Authenticated. Switch it back to Authenticated, issue a fresh key that maps to that level, and test.

We were having issues with the form previously. Can you try accessing this link directly to download?

Did exactly as suggested: config.json is on Authenticated (AllOf), re-scanned the config filesystem from Platform Overview after the edit, and issued a fresh API key with Authenticated selected in the core (active) collection. A raw curl initialize with the correct headers still returns 403 Forbidden. I've confirmed the request is reaching the auth layer: wrong Accept returns 406, missing Content-Type returns 415, and only a fully-formed request produces the 403 — so it's an auth rejection, not content negotiation.

What security level does the key need to literally hold to satisfy this, and is there a binding step between the API key and the MCP server resource beyond the securityLevels in config.json? Running 8.3 EA build b2026060908 on a Windows VM.

I have integrated ignition mcp to claude. But due to data security we can't use that. It was great that you have an idea to create a basic LLM for ourselves. If possible could you guide me through how you have integrated, your LLM to Ignition. If it OK to send you work, it would help me a lot in the projects with Ignition.

Sorry, I think you misunderstood me. I only built‑out a simple agent perspective view rather than an LLM. It still requires Claude, ChatGPT or other LLMs to function.If you are worried about security risks from connecting to Claude, you can run open‑source LLMs on your local‑side servers just like Qwen3.6-35B-A3B,Deepseek and so on.

Thank you

Hello everyone,

I develop SCADA applications using Ignition, and I have a question about the Ignition MCP.

How useful has it been in your experience? Can it reliably create or edit Perspective views? What are your main use cases for it?

I recently built a virtualized MCP in Python that I can invoke from Claude Desktop. At the moment, it can edit some Perspective views, but I first need to provide it with information about the structure of Ignition's .json files so it understands the project layout and can correctly modify the Perspective resources.

I'm curious to hear how you're using the official Ignition MCP. Has it significantly improved your development workflow, or do you mainly use it for documentation, code generation, troubleshooting, or other tasks?

Have you seen this post? Building Perspective with an LLM - Ignition - Inductive Automation Forum

this one worked, sorry for late answer

I’ve been testing the MCP Early Access module and I’m consistently running into 403 Forbidden on the MCP endpoint.

Current setup:

  • MCP module: 1.3.5-SNAPSHOT (b2026021307)

  • Tested on both:

    • 8.3.10-SNAPSHOT (b2026082510)

    • fresh 8.3.8 (b2026071409)

  • Gateway running in Docker

  • Standalone project: mcp_test

  • Simple hello-world tool under Model Context Protocol → Tools

  • Custom security level:

    • Authenticated

      • APIAccess
  • API key assigned APIAccess

  • secureChannelRequired: false

  • APIAccess added to Gateway Write Permissions

  • MCP server config created successfully using the “Easy Mode” REST call

The API key itself appears to be working correctly. For example:

GET /data/api/v1/gateway-info → works

and I can also successfully read the MCP server config through:

/data/api/v1/resources/find/com.inductiveautomation.mcp/server-config/testing

The stored API-token resource also confirms Authenticated → APIAccess and secureChannelRequired: false.

However, a raw MCP initialize request consistently returns:

HTTP/1.1 403 Forbidden

{
  "message":"Forbidden",
  "url":"/data/mcp/testing",
  "status":"403"
}

I get the same result through mcp-remote --debug.

I also created a separate testing-public server using Public permissions as a control test, but /data/mcp/testing-public also returns 403, both with and without the API key.

Gateway logs currently show the MCP module starting normally, with no obvious HandlerFactory, McpGatewayHook or NullPointerException errors.

Since I can reproduce the exact same behaviour on a fresh 8.3.8 Gateway as well as 8.3.10 nightly, I’m currently unsure whether I’m missing another permission/authentication requirement on /data/mcp/*, or whether this is an issue in the EA module.

Has anyone seen this behaviour or spotted something obvious I’m missing?

Can you confirm if anything sits in front of the gateway that could be intercepting /data/mcp/* specifically and returning its own 403 before the request reaches the module? It looks like this is coming from the gateway, but try hitting the endpoint from inside the container just to be sure. Additionally, could you confirm that the module actually registered its handler for the /data/mcp/* route (compared to just the module starting)?

Adding another data point to the 403 issue Andreas raised in #59, since I've got a very clean, fully-verified reproduction that might help narrow this down.

Setup

  • Ignition 8.3.8 (b2026071409), Windows 11, native install (not Docker, no reverse proxy in front of the gateway)
  • MCP Module EA 1.3.5-SNAPSHOT (b2026021307) — Config → Modules shows it as Active, correct version, no faults
  • Standalone (non-inheritable) Designer project, one Tool resource with a working script
  • Security: custom level APIAccess nested under Authenticated; API key granted that level plus APIToken → Access and Read. Confirmed working — with APIToken unchecked, even the general REST API (/data/api/v1/gateway-info) returned 403; after checking Access+Read it returned 200 with a valid token and 401 with no token, exactly as expected.
  • server-config resource created via Route A (REST POST to /data/api/v1/resources/com.inductiveautomation.mcp/server-config) — confirmed via the find API and by reading the actual files on disk that resource.json has a real UUID, lastModification, and lastModificationSignature, and config.json matches what was posted (tools: {"project/<ProjectName>": "*"}, permissions.securityLevels: [{"name":"APIAccess","children":[]}], type: "AllOf").

The problem

Platform Overview lists the server-config resource with enabled: true but Status: N/A — same symptom the original doc/thread ties to a Route B resource.json metadata problem, except this is Route A with fully complete, correctly-populated metadata, so that doesn't seem to be the actual cause here.

Calling /data/mcp/<name> (raw initialize, per the thread's own working curl example) returns a blanket 403:

{"message":"Forbidden","url":"/data/mcp/testing","status":"403"}

— identical whether or not a valid API token is sent. The same token works fine against /data/api/v1/gateway-info (200 with token, 401 without), so the key itself is valid and correctly scoped; something specific to the /data/mcp/* route is rejecting the request before it differentiates authenticated from unauthenticated.

I reproduced this from two completely independent HTTP clients — a browser-based fetch() and an elevated PowerShell Invoke-WebRequest — and got byte-identical responses from both, which rules out anything client-specific (browser quirks, local proxy only intercepting browser traffic, etc.).

Re: zabidi's question in #60 — in my case there's no reverse proxy or container involved at all; this is a direct connection to a native Windows gateway on localhost:8088, so "something sitting in front of the gateway" seems unlikely to be the explanation here, at least for this specific reproduction. That might help narrow down whether this is a module-side bug vs. an environment-specific interception issue.

Two things that would help a lot: (1) what does Status: N/A on an MCP server-config resource actually indicate internally — is it unrelated to resource.json completeness, and if so what does control it? (2) is there a way to get more detail than a bare 403 out of the module (a debug log category, verbose logging flag, etc.) to see what check is actually failing?