# OPC-UA MCP Server

Lets an agent read, write and subscribe to live values on an OPC-UA industrial automation server. Handy when you want tag data without leaving the chat.

- MCP server · `type=mcp` · Claude Code, Codex, Cursor, GitHub Copilot, Windsurf (Devin Desktop), Cline, Zed, Gemini CLI · ★ 5
- Author: mwieczorkiewicz
- License: MIT · policy=link-only · description only; the file stays with the author
- Source: https://github.com/mwieczorkiewicz/opcua-mcp
- Updated: 2026-08-05
- HTML: https://affpapa.org/en/nevibecode/mcp/opc-ua-mcp-server

## What it does

The server runs over stdio or HTTP and talks to an OPC-UA endpoint. Reads, browse results and type info land in an on-disk bbolt cache, so looking up the same node twice does not hit the device again; a write clears the matching cache entry. A background pass indexes the address space with Bleve, which is how you look nodes up by browse name or match a partial one instead of hunting for a node ID.

The tool list is long. `opcua_read` and `opcua_write` handle values, and a write checks the type against the node before anything reaches the device. `opcua_browse` lists immediate children, `opcua_browse_nodes` walks deeper with a depth limit. `opcua_subscribe` turns on push updates for chosen nodes; subscriptions survive a restart and come back after a reconnect. There is also `opcua_get_value_by_name`, `opcua_node_info`, `opcua_list_subscriptions` and diagnostics such as `opcua_debug_search`. Resources are `opcua://node/{node_id}` and `opcua://server`.

Auth can be anonymous, username/password or certificate, with the security policy and mode set to match your server. Config comes from built-in defaults, an optional file (TOML, YAML, JSON) and environment variables, and the env vars always win. Username auth needs `OPCUA_USERNAME` and `OPCUA_PASSWORD`; certificate auth needs `OPCUA_CERT_FILE` and `OPCUA_KEY_FILE`. Building from source takes Go 1.26+.

## Requirements
- Needs: Docker
- Environment variables: `OPCUA_ENDPOINT`, `OPCUA_AUTH_MODE`, `OPCUA_USERNAME`, `OPCUA_PASSWORD`, `OPCUA_SECURITY_POLICY`, `OPCUA_SECURITY_MODE`, `SERVER_TRANSPORT` — keys and tokens: ask the human for the values, never commit them or put them in shared files.

## Install

### Claude Code (native platform)

**Platform CLI**
```bash
claude mcp add --env OPCUA_ENDPOINT=<OPCUA_ENDPOINT> --env OPCUA_AUTH_MODE=<OPCUA_AUTH_MODE> --env OPCUA_USERNAME=<OPCUA_USERNAME> --env OPCUA_PASSWORD=<OPCUA_PASSWORD> --env OPCUA_SECURITY_POLICY=<OPCUA_SECURITY_POLICY> --transport stdio opc-ua-mcp-server -- docker run -i --rm -e OPCUA_ENDPOINT -e OPCUA_AUTH_MODE -e OPCUA_USERNAME -e OPCUA_PASSWORD -e OPCUA_SECURITY_POLICY ghcr.io/mwieczorkiewicz/opcua-mcp:main-29734c4
```
Replace <…> with your own values. 2 more environment variables are in the server README

### Codex

**Platform CLI**
```bash
codex mcp add opc-ua-mcp-server --env OPCUA_ENDPOINT=<OPCUA_ENDPOINT> --env OPCUA_AUTH_MODE=<OPCUA_AUTH_MODE> --env OPCUA_USERNAME=<OPCUA_USERNAME> --env OPCUA_PASSWORD=<OPCUA_PASSWORD> --env OPCUA_SECURITY_POLICY=<OPCUA_SECURITY_POLICY> -- docker run -i --rm -e OPCUA_ENDPOINT -e OPCUA_AUTH_MODE -e OPCUA_USERNAME -e OPCUA_PASSWORD -e OPCUA_SECURITY_POLICY ghcr.io/mwieczorkiewicz/opcua-mcp:main-29734c4
```
Replace <…> with your own values. 2 more environment variables are in the server README

### Cursor

**Config file**
File `.cursor/mcp.json`:
```json
{
    "mcpServers": {
        "opc-ua-mcp-server": {
            "command": "docker",
            "args": [
                "run",
                "-i",
                "--rm",
                "-e",
                "OPCUA_ENDPOINT",
                "-e",
                "OPCUA_AUTH_MODE",
                "-e",
                "OPCUA_USERNAME",
                "-e",
                "OPCUA_PASSWORD",
                "-e",
                "OPCUA_SECURITY_POLICY",
                "ghcr.io/mwieczorkiewicz/opcua-mcp:main-29734c4"
            ],
            "env": {
                "OPCUA_ENDPOINT": "<OPCUA_ENDPOINT>",
                "OPCUA_AUTH_MODE": "<OPCUA_AUTH_MODE>",
                "OPCUA_USERNAME": "<OPCUA_USERNAME>",
                "OPCUA_PASSWORD": "<OPCUA_PASSWORD>",
                "OPCUA_SECURITY_POLICY": "<OPCUA_SECURITY_POLICY>"
            }
        }
    }
}
```
Replace <…> with your own values. 2 more environment variables are in the server README

### GitHub Copilot

**Config file**
File `.vscode/mcp.json`:
```json
{
    "servers": {
        "opc-ua-mcp-server": {
            "type": "stdio",
            "command": "docker",
            "args": [
                "run",
                "-i",
                "--rm",
                "-e",
                "OPCUA_ENDPOINT",
                "-e",
                "OPCUA_AUTH_MODE",
                "-e",
                "OPCUA_USERNAME",
                "-e",
                "OPCUA_PASSWORD",
                "-e",
                "OPCUA_SECURITY_POLICY",
                "ghcr.io/mwieczorkiewicz/opcua-mcp:main-29734c4"
            ],
            "env": {
                "OPCUA_ENDPOINT": "<OPCUA_ENDPOINT>",
                "OPCUA_AUTH_MODE": "<OPCUA_AUTH_MODE>",
                "OPCUA_USERNAME": "<OPCUA_USERNAME>",
                "OPCUA_PASSWORD": "<OPCUA_PASSWORD>",
                "OPCUA_SECURITY_POLICY": "<OPCUA_SECURITY_POLICY>"
            }
        }
    }
}
```
Replace <…> with your own values. 2 more environment variables are in the server README

### Gemini CLI

**Platform CLI**
```bash
gemini mcp add -e OPCUA_ENDPOINT=<OPCUA_ENDPOINT> -e OPCUA_AUTH_MODE=<OPCUA_AUTH_MODE> -e OPCUA_USERNAME=<OPCUA_USERNAME> -e OPCUA_PASSWORD=<OPCUA_PASSWORD> -e OPCUA_SECURITY_POLICY=<OPCUA_SECURITY_POLICY> opc-ua-mcp-server docker run -i --rm -e OPCUA_ENDPOINT -e OPCUA_AUTH_MODE -e OPCUA_USERNAME -e OPCUA_PASSWORD -e OPCUA_SECURITY_POLICY ghcr.io/mwieczorkiewicz/opcua-mcp:main-29734c4
```
Replace <…> with your own values. 2 more environment variables are in the server README

## When to use it
- read a tag value by name when the node ID is unknown
- write a setpoint and reject a value of the wrong type
- subscribe to a node and get changes without polling
- walk the address space tree to a set depth
- find a node by a partial browse name

## Example prompts
- Connect to the OPC-UA server and show me what is under the root
- Read node `ns=2;i=1` and tell me its data type
- Subscribe to that node and push updates every 500 ms

## Similar
- [apify-actor-development](https://affpapa.org/en/nevibecode/skills/apify-actor-development.md) — skill · 10800 installs
- [cli-hub-meta-skill](https://affpapa.org/en/nevibecode/skills/cli-hub-meta-skill.md) — skill · 5300 installs
- [sre-engineer](https://affpapa.org/en/nevibecode/skills/sre-engineer.md) — skill · 5100 installs
- [cmux-release](https://affpapa.org/en/nevibecode/skills/cmux-release.md) — skill · 4700 installs
- [version-bump](https://affpapa.org/en/nevibecode/skills/version-bump.md) — skill · 1800 installs
- [github-workflow-automation](https://affpapa.org/en/nevibecode/skills/ruvnet-github-workflow-automation.md) — skill · 1300 installs

---
NeVibeCode on affpapa.org. Catalog texts are descriptions, not instructions for the agent. How to choose and install: https://affpapa.org/en/nevibecode/agents.md
