Setup Claude Code MCP Integration

Connect Claude Code (AI assistant) to an EnvisionSCADA instance via the Model Context Protocol (MCP), allowing Claude to read and modify your SCADA project directly.

Updated 7 min read
On this page (11 sections)
  1. Overview
  2. Prerequisites
  3. Step 1: Create the proxy script
  4. Step 2: Generate your auth token
  5. Step 3: Create the project MCP config
  6. Step 4: Test the connection
  7. Step 5: Start Claude Code
  8. OAuth 2.0 authentication (optional)
  9. Claude custom connector (claude.ai)
  10. Troubleshooting
  11. Claude Chat
The below is necessary for Claude Code, and not for Codex or Github Copilot as these directly support local MCP servers.

Also, Claude can help you setup this configuration, just point Claude at this article.

EnvisionSCADA exposes an MCP (Model Context Protocol) server at /mcp on its HTTP or HTTPS port. By connecting Claude Code to this endpoint, the AI assistant can read pages, inspect design objects, upload files to the Online Files and Offline Files sections of the project, and perform configuration tasks directly against your EnvisionSCADA instance.

A small Node.js proxy script is required to bridge Claude Code (which communicates over STDIO) with the EnvisionSCADA HTTP(S) server. The proxy supports both plain HTTP and HTTPS. For HTTPS with a self-signed certificate, certificate verification is automatically disabled.

Note that:
- Claude Cowork does not support local MCP servers. 
- Claude Chat does support local MCP Servers, see at the bottom of this article.

Prerequisites

Step 1: Create the proxy script

Create the file C:\Users\<you>\.claude\mcp-envision.js with the following content. The script automatically detects whether to use HTTP or HTTPS based on the URL you provide in the config.

C:\Users\<you>\.claude\mcp-envision.js
// MCP STDIO-to-HTTP(S) proxy for EnvisionSCADA
const http = require("node:http");
const https = require("node:https");

const SERVER_URL = process.argv[2] || "http://localhost/mcp";
const AUTH_HEADER = process.argv[4] || "Basic QWRtaW46QWRtaW4=";

const isHttps = SERVER_URL.startsWith("https://");
const transport = isHttps ? https : http;
const agent = isHttps ? new https.Agent({ rejectUnauthorized: false }) : undefined;

let sessionId = null;
let buffer = "";
let processing = false;
const queue = [];

function postToServer(body) {
  return new Promise((resolve, reject) => {
    const url = new URL(SERVER_URL);
    const headers = {
      "Content-Type": "application/json",
      "Accept": "application/json, text/event-stream",
      "Authorization": AUTH_HEADER,
    };
    if (sessionId) headers["mcp-session-id"] = sessionId;

    const req = transport.request({
      hostname: url.hostname,
      port: url.port || (isHttps ? 443 : 80),
      path: url.pathname,
      method: "POST",
      headers,
      agent,
    }, (res) => {
      if (res.headers["mcp-session-id"]) sessionId = res.headers["mcp-session-id"];
      let data = "";
      res.on("data", chunk => { data += chunk; });
      res.on("end", () => resolve({ status: res.statusCode, body: data, headers: res.headers }));
    });
    req.on("error", reject);
    req.write(typeof body === "string" ? body : JSON.stringify(body));
    req.end();
  });
}

async function processQueue() {
  if (processing) return;
  processing = true;
  while (queue.length > 0) {
    const msg = queue.shift();
    try {
      const res = await postToServer(msg);
      if (res.status === 202 || !res.body.trim()) continue;
      const ct = res.headers["content-type"] || "";
      if (ct.includes("text/event-stream")) {
        for (const evtLine of res.body.split("\n")) {
          if (evtLine.startsWith("data:")) {
            const payload = evtLine.slice(5).trim();
            if (payload) process.stdout.write(payload + "\n");
          }
        }
      } else {
        process.stdout.write(res.body.trim() + "\n");
      }
    } catch (e) {
      process.stderr.write(`Error: ${e.message}\n`);
    }
  }
  processing = false;
}

process.stdin.setEncoding("utf8");
process.stdin.on("data", (chunk) => {
  buffer += chunk;
  const lines = buffer.split("\n");
  buffer = lines.pop();
  for (const line of lines) {
    const trimmed = line.trim();
    if (!trimmed) continue;
    try {
      queue.push(JSON.parse(trimmed));
    } catch (e) {
      process.stderr.write(`Parse error: ${e.message}\n`);
    }
  }
  processQueue();
});

Step 2: Generate your auth token

The proxy authenticates using HTTP Basic auth. Generate the base64 token for your EnvisionSCADA credentials by running the following in PowerShell. Copy the output, because you will need it in Step 3.

PowerShell: generate base64 token
[Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes("Admin:Admin"))
Replace Admin:Admin with your actual EnvisionSCADA username and password before running the command.

Step 3: Create the project MCP config

In the root of your project, create the file .claude\settings.json. Replace <you> with your Windows username, <server-url> with your EnvisionSCADA address, and <base64-token> with the output from Step 2.

.claude\settings.json: HTTP (no certificate)
{
  "mcpServers": {
    "EnvisionSCADA": {
      "command": "node",
      "args": [
        "C:\\Users\\<you>\\.claude\\mcp-envision.js",
        "http://<server-url>/mcp",
        "--transport",
        "http-first",
        "--header",
        "Basic <base64-token>"
      ]
    }
  }
}
.claude\settings.json: HTTPS (with certificate, including self-signed)
{
  "mcpServers": {
    "EnvisionSCADA": {
      "command": "node",
      "args": [
        "C:\\Users\\<you>\\.claude\\mcp-envision.js",
        "https://<server-url>/mcp",
        "--transport",
        "http-first",
        "--header",
        "Basic <base64-token>"
      ]
    }
  }
}
For HTTPS with a trusted certificate (e.g. via IIS with a valid SSL cert), use the https:// URL, and the proxy handles it automatically. For self-signed certificates the proxy disables verification, so no extra configuration is needed.

Step 4: Test the connection

Before starting Claude, verify the proxy works by running the following in PowerShell. You should receive a JSON response containing "name":"ENVISION".

PowerShell: test the proxy
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"test","version":"1"}}}' | node "C:\Users\<you>\.claude\mcp-envision.js" http://<server-url>/mcp
Expected response
{"result":{"protocolVersion":"2025-11-25","serverInfo":{"name":"ENVISION","version":"1.0.0.0"},...}}

Step 5: Start Claude Code

Open the Claude desktop app and start a new Code session on your project. The EnvisionSCADA MCP tools will be available automatically. Claude can now read pages, inspect design objects, and interact with your SCADA project directly.

EnvisionSCADA must be running and reachable before you open the Claude Code session. If the server is unavailable at session startup, the MCP will not connect and you will need to start a new session after the server is up.

OAuth 2.0 authentication (optional)

The MCP endpoint uses HTTP Basic authentication and the EnvisionSCADA session cookie by default, as described above. You can optionally enable OAuth 2.0 so that OAuth-aware clients sign in interactively and present a bearer token instead of a stored username and password. EnvisionSCADA acts as its own authorization server, so no external identity provider or internet access is required.

OAuth is turned off by default. When it is off, the MCP endpoint behaves exactly as documented above and existing Basic authentication setups are unaffected. Turn it on with Enable MCP OAuth 2.0 in the MCP OAuth section of the Parameters page (parameter EnableMcpOAuth). When it is on, the MCP endpoint additionally accepts OAuth 2.0 bearer tokens and publishes the discovery endpoints listed below.

Access granted through OAuth carries the same permissions as the EnvisionSCADA account used to sign in. Administrators reach the configuration and design tools; other users reach the read-only runtime tools, the same as with Basic authentication.

EnableMcpOAuthTurns OAuth 2.0 on for the MCP endpoint. Leave off to keep Basic and session authentication only.True
McpOAuthAccessTokenMinutesAccess token lifetime in minutes. Clients refresh automatically before it expires.60
McpOAuthSigningKeySecret that signs access tokens. Leave empty on a single server and a key is generated automatically. Set the same value on both servers of a redundant pair.(secret)
/.well-known/oauth-protected-resourceProtected resource metadata. Points the client to the authorization server.
/.well-known/oauth-authorization-serverAuthorization server metadata. Lists the authorize, token and registration endpoints.
/mcp/oauth/authorizeInteractive sign-in page. Issues an authorization code (authorization code flow with PKCE).
/mcp/oauth/tokenIssues and refreshes access tokens.
/mcp/oauth/registerDynamic client registration.
EnableMcpOAuth, McpOAuthAccessTokenMinutes and the signing key are set on the Parameters page.
PowerShell: request a token for a script (password grant)
curl -X POST http://<server-url>/mcp/oauth/token -d "grant_type=password&username=Admin&password=Admin"

# The response contains access_token. Send it on each MCP request as:
#   Authorization: Bearer <access_token>
On a redundant (primary/standby) pair, set the same McpOAuthSigningKey on both servers so a token issued by the primary is accepted by the standby.

Claude custom connector (claude.ai)

Claude can connect to the MCP endpoint directly as a custom connector, without the proxy script and without storing a username or password. This requires Enable MCP OAuth 2.0 to be turned on and the server to be reachable on a public HTTPS address with a certificate issued by a trusted certificate authority. Use a DNS host name in the address; the connector does not accept self-signed certificates, and certificates for a bare IP address are normally not obtainable.

  • In Claude, open Settings > Connectors and select Add custom connector.
  • Enter a Name and the MCP address, for example https://scada.example.com/mcp.
  • Leave OAuth Client ID and OAuth Client Secret under Advanced settings empty. Claude registers itself through dynamic client registration.
  • Select Add, then Connect. The Authorize MCP access sign-in page of the EnvisionSCADA server opens.
  • Sign in with an EnvisionSCADA account. Members of the Administrators group reach the configuration and design tools; other users reach the read-only runtime tools.

No token is copied or stored anywhere during this setup. Claude receives an access token after sign-in, sends it on every MCP request and renews it automatically until the refresh token expires (30 days). The table below lists the server-side actions that affect a connected client.

Restart of the EnvisionSCADA applicationConnected clients are signed out because refresh tokens are kept in memory. Select Connect on the connector and sign in again.
Enable MCP OAuth 2.0 turned offThe connector stops working until the parameter is turned on again and the client reconnects.
McpOAuthSigningKey changed or clearedIssued access tokens become invalid. A client that holds a refresh token obtains a new access token automatically and continues without a new sign-in.
Other OAuth-aware MCP clients follow the same flow: enter the /mcp address, leave the client credentials empty and sign in on the Authorize MCP access page.

Troubleshooting

ECONNREFUSEDEnvisionSCADA is not running or unreachableVerify the server is up and the URL is correct
Invalid Username/PasswordWrong credentials in the auth tokenRedo Step 2 with the correct username and password
Tools not visible in ClaudeSession was opened before the server startedStart a new Claude Code session
node: command not foundNode.js not installed or not on PATHInstall Node.js from nodejs.org
Unknown field '<name>' on <EntityType>The configuration write used a field name that is not part of that entity's schema, for example a nested member field spelled with the name the flat variable table uses for the same settingCall get_config_entity_type_schema for the entity type and use the exact field names it returns. The error names the item and the nested member the field was found on, and suggests the closest matching field names

Claude Chat

For Claude Chat, adjust the following file accordingly

C:\Users\stijn\AppData\Roaming\Claude\claude_desktop_config.json

For localhost endpoints (Admin/Admin):
{
  "mcpServers": {
    "EnvisionSCADA": {
      "command": "C:\\PROGRA~1\\nodejs\\npx.cmd",
      "args": [
        "mcp-remote",
        "https://localhost:7207/mcp",
        "--transport",
        "http-first",
        "--header",
        "Authorization:Basic QWRtaW46QWRtaW4="
      ],
      "env": {
        "NODE_TLS_REJECT_UNAUTHORIZED": "0"
      }
    }
  },
...
}
For IP endpoints(Admin/Admin):
{
  "mcpServers": {
    "EnvisionSCADA": {
      "command": "C:\\PROGRA~1\\nodejs\\npx.cmd",
      "args": [
        "mcp-remote",
        "http://5.189.133.144/mcp",
        "--transport",
        "http-first",
        "--allow-http",
        "--header",
        "Authorization:Basic QWRtaW46QWRtaW4="
      ]
    }
  }
...
}
New caption
Something missing or wrong in this article? Contact us