# Description Implement the released [OPC 40100-1](https://reference.opcfoundation.org/specs/OPC-40100-1) and [OPC 40100-2](https://reference.opcfoundation.org/specs/OPC-40100-2) specifications with generated models, provider-backed runtimes, typed clients, MCP workflows, and DI/Machinery integration. - **Part 1 stays in `Opc.Ua.Vision`** and its client/server packages alongside the distinct Perception model. Provide control/acquisition state machines, jobs and synchronized steps, recipe/product/configuration/result management, file transfers, diagnostics, events, and conditions. - **Part 2 is in `Opc.Ua.MachineVision`, `.Client`, and `.Server`.** Provide asset categories, identification, image-handling aspects, health/maintenance data, topology, and transactional updates. The base Vision assemblies do not reference these optional packages; the Part 2 wire model does not depend on Part 1. - Preserve the release-pinned model bytes, wire namespaces and NodeIds. Perception types are in `Opc.Ua.Vision.Perception`; the AMCM generated namespace remains `Opc.Ua.Vision.MachineVision.AMCM`, and asset client/server extension namespaces remain `Opc.Ua.Vision.Client` and `Opc.Ua.Vision.Server`. - Use `AddOpcUaMachineVision` and `AddOpcUaMachineVisionAMCM` for model loading and factory registration. Each has node-collection, encodeable-factory-builder and node-state-factory-builder overloads. These short entry points delegate to the generated implementations; existing namespace-derived generated names remain available for compatibility. - Support multiple independent named systems/assets under one namespace-owning manager. Reuse injectable providers, file binding, bounded memory stores, optional transactional `IFileSystemProvider` persistence, state machines, telemetry and conformance infrastructure. - Keep one `docs/Vision.md` guide, titled `Machine Vision (OPC 40100-1 and OPC 40100-2)`, and one `Opc.Ua.Mcp.Vision` package. Include deterministic server/client samples. - Expose 17 Machine Vision MCP tools, including capabilities/status, bounded relationships and observation, complete small-file uploads/downloads, management, explicit control, conditions, and chunked transfers. Catalogue counts: 39 Vision-specific, 43 with connection tools, 81 Vision+Robotics, 155 Full. Every Machine Vision wire parameter has a schema description. **Compatibility and limits:** `AddVision()` remains Perception-only unless released parts are selected. Standalone Part 2 uses `AddVision().AddMachineVision()`; Machinery composition uses `AddVisionToMachinery()`. Existing tool defaults and command signatures are preserved. Observation owns and cleans up its subscription: 5 seconds/50 notifications by default, capped at 60 seconds/100 notifications. Complete-file tools are capped at 1 MiB; larger files use chunked transfers. Domain Error values remain distinct from UA service failures. **Versioning:** the seven Vision/MachineVision/MCP packages and their Debug variants follow the repository root version instead of being forced to preview. Vision.OpenUsd and its descendants remain preview-only. Development builds still inherit the root prerelease version. No release version, tag, release branch, publication policy, or feed promotion is changed. **Review actions:** all fourteen review threads have action/evidence replies and are resolved. Changes include the unified guide, Perception namespace, separate Part 2 packages and final naming, multi-system ownership explanation, interrupted-write cleanup, observer failure isolation, complete MCP parameter descriptions, and explicit package inventory. The preview-layout migration topic and the requested ReleaseProcess caveat were removed. The test Publish collector now retries recognized transient failures within one cancellation budget and propagates other exceptions. Commit69b1f5db9applies the requested short loader names and renames standalone hosting to `AddMachineVision`, with callers, tests and documentation updated. The intervening master merge is preserved. ### Verification **Latest API naming changes, verified locally:** | Scope | Result | | --- | --- | | Full Vision suite, net10 | 572 passed, 1 existing skip, 0 failed | | Full Vision suite, net48 | 515 passed, 0 skipped, 0 failed | | Final loader/hosting cases after cross-TFM null-guard adjustment | 9 passed, 0 failed, 0 skipped | | Machine Vision MCP and profile cases | 198 passed, 0 failed, 0 skipped | | Main and MCP AOT test-project compilation | Both built with 0 warnings/errors | | MCP AOT companion, managed execution | 5 passed, 0 failed, 0 skipped; not claimed as native execution | `ModelLoaderNamesRegisterTypedFactories`, `ModelLoaderNamesRejectNullArguments`, and `GeneratedModelsLoadTogetherAndCreateTypedInstances` cover all six loader overloads, fluent return identities, typed instances, namespace coexistence and null guards. Existing standalone Part 2 tests verify idempotent registration, one-owner enforcement and null handling through `AddMachineVision`. No source-generator implementation, CLR namespace, wire identity or model payload was changed for these naming updates. The current69b1f5db9revision is running [CI](https://github.com/OPCFoundation/UA-.NETStandard/actions/runs/38165826937), [package validation](https://github.com/OPCFoundation/UA-.NETStandard/actions/runs/38165823359), [MCP usability](https://github.com/OPCFoundation/UA-.NETStandard/actions/runs/38165826874), [CodeQL](https://github.com/OPCFoundation/UA-.NETStandard/actions/runs/38165826906), and [Images CI](https://github.com/OPCFoundation/UA-.NETStandard/actions/runs/38165826884). These runs are not claimed as completed results. **Earlier completed verification:** all seven default-TFM package archives were inspected after the package rename: exact IDs, 27 clean DLLs, correct dependencies/readmes/licenses, and unchanged pinned model hashes. [CI onc75ec4fa6](https://github.com/OPCFoundation/UA-.NETStandard/actions/runs/38142519760) passed, including the formerly failing Linux batch and required summary. Its unchanged coverage gate passed at **88.56% lines, 78.96% branches, 84.28% patch** against the 75% patch floor. The later bounded-Publish-helper regressions reproduced 13 failures before the fix and passed afterward; the full mainline triggering fixture passed 67 tests on each of net10/net48. These are historical results, not current full-matrix results. <details> <summary>Executed API naming validation commands and outcomes</summary> Run from the worktree root using the established artifact trees. Dependency builds were performed before the no-build full net10 run; the focused loader/hosting selection was rebuilt and rerun after the final null-guard adjustment. ```powershell $files = 'C:\Users\mschier\.copilot\session-state\deb2ba10-b0e9-4a44-8783-8331bc850814\files' $env:DOTNET_CLI_USE_MSBUILD_SERVER = '0' $env:TEMP = 'C:\Temp\mv-deb2\followup' $env:TMP = $env:TEMP # Passed: 572; Failed: 0; Skipped: 1. dotnet test tests\Opc.Ua.Vision.Tests\Opc.Ua.Vision.Tests.csproj -c Release -f net10.0 --no-build --no-restore --artifacts-path artifacts\vision-followup -p:CustomTestTarget=net10.0 -p:UseSharedCompilation=false -m:1 -nr:false --logger 'console;verbosity=minimal' --logger trx --results-directory "$files\vision-api-names-net10" -- 'NUnit.WorkDirectory=C:\Temp\mv-deb2\followup' # Passed: 9; Failed: 0; Skipped: 0, on the final source. dotnet test tests\Opc.Ua.Vision.Tests\Opc.Ua.Vision.Tests.csproj -c Release -f net10.0 --no-restore --artifacts-path artifacts\vision-followup -p:CustomTestTarget=net10.0 -p:UseSharedCompilation=false -m:1 -nr:false --filter 'FullyQualifiedName~MachineVisionModelTests|FullyQualifiedName~StandalonePartTwoRegistrationUsesOneOwnerAndOneModelProvider|FullyQualifiedName~StandalonePartTwoRequiresRegistrationAndRejectsCompetingOwnership' --logger 'console;verbosity=minimal' --logger trx --results-directory "$files\vision-api-names-final-model" -- 'NUnit.WorkDirectory=C:\Temp\mv-deb2\followup' # Passed: 198; Failed: 0; Skipped: 0. dotnet test tests\Opc.Ua.Tools.Tests\Opc.Ua.Tools.Tests.csproj -c Release -f net10.0 --no-restore --artifacts-path artifacts\vision-followup -p:CustomTestTarget=net10.0 -p:UseSharedCompilation=false -m:1 -nr:false --filter 'FullyQualifiedName~VisionMachineToolsTests|FullyQualifiedName~McpHostBuilderTests|FullyQualifiedName~McpToolProfileCompositionTests' --logger 'console;verbosity=minimal' --logger trx --results-directory "$files\vision-api-names-final-mcp" -- 'NUnit.WorkDirectory=C:\Temp\mv-deb2\followup' $env:TEMP = 'C:\Temp\mv-deb2\followup48' $env:TMP = $env:TEMP # Passed: 515; Failed: 0; Skipped: 0. dotnet test tests\Opc.Ua.Vision.Tests\Opc.Ua.Vision.Tests.csproj -c Debug -f net48 --no-restore --artifacts-path "$files\solution-net48-artifacts" -p:CustomTestTarget=net48 -p:UseSharedCompilation=false -m:1 -nr:false --logger 'console;verbosity=minimal' --logger trx --results-directory "$files\vision-api-names-net48-final" -- 'NUnit.WorkDirectory=C:\Temp\mv-deb2\followup48' ``` Opt-in long-running/stress/durable tiers have not been rerun locally; the unqualified **all tests** checklist item remains open. Original implementation matrix counts are not presented as current results. </details> ## Related Issues - Fixes #4732. The requester reviewed and approved the implementation plan and subsequent packaging/API decisions in the development session. The tracking issue records the design; maintainer architectural discussion/sign-off there is still pending. This PR remains a draft. ## Checklist _Put an `x` in the boxes that apply. You can complete these step by step after opening the PR._ - [ ] I have signed the [CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf) and read the [CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md) doc. - [x] I have added tests that prove my fix is effective or that my feature works and increased code coverage. - [x] I have added all necessary documentation. - [x] I have verified that my changes do not introduce (new) build or analyzer warnings. - [ ] I ran **all** tests locally using the **UA.slnx** solution against at least .net **framework** and .net **10**, and all passed. - [ ] I fixed **all** failing and flaky tests in the CI pipelines and **all** CodeQL warnings. - [x] I have addressed **all** PR feedback received.
30 KiB
OPC UA MCP Server
The OPC UA MCP Server exposes OPC UA Part 4 service calls as Model Context Protocol (MCP) tools. AI assistants such as Claude, GitHub Copilot, VS Code Copilot, and Cursor can use these tools to connect to OPC UA servers and interact with industrial automation systems through natural language.
Contents
- What It Does
- Tool Profiles
- Resources
- Installation
- Configuration
- Usage
- PubSub Tools
- Architecture
- Security Notes
- Agent-Usability Quality Gate
- Requirements
What It Does
The MCP server wraps the OPC UA .NET Standard client library, translating between JSON-based MCP tool calls and OPC UA binary protocol operations. The server exposes tools through a tool profile — a named, bounded catalog selected at startup — rather than a single fixed tool count. The default full profile currently registers every tool below; running a narrower profile (core, services, administration, pubsub, diagnostics, robotics, or vision) exposes only the subset relevant to that workflow. The tables below list the complete tool surface, organized by OPC UA Part 4 service set:
| Service Set | Tools | Description |
|---|---|---|
| Connection | GetEndpoints, Connect, Disconnect, GetConnectionStatus |
Endpoint discovery and session lifecycle management |
| Attribute | Read, Write, HistoryRead, HistoryUpdate |
Read/write node attributes and historical data |
| View | Browse, BrowseNext, TranslateBrowsePaths, RegisterNodes, UnregisterNodes, QueryFirst, QueryNext |
Navigate and query the address space |
| Node Management | AddNodes, AddReferences, DeleteNodes, DeleteReferences |
Modify the address space |
| Method | Call |
Invoke OPC UA methods |
| Subscription | CreateSubscription, ModifySubscription, SetPublishingMode, Publish, Republish, DeleteSubscriptions, TransferSubscriptions |
Manage notification subscriptions |
| MonitoredItem | CreateMonitoredItems, ModifyMonitoredItems, SetMonitoringMode, SetTriggering, DeleteMonitoredItems |
Monitor data changes and events |
| Discovery | FindServers, FindServersOnNetwork, RegisterServer, RegisterServer2 |
Discover servers and register |
| PKI Management | ListCertificates, TrustCertificate, RemoveCertificate, GetPkiStorePaths |
Manage certificate trust lists |
| Configuration | GetConfiguration, SetTransportConfiguration, SetClientConfiguration, SetSecurityConfiguration, SetConfiguration |
View/modify in-memory client settings; SetConfiguration is the full-profile compatibility tool |
| NodeSet Export | ExportNodeSet, ExportNodeSetPerNamespace |
Export address space to NodeSet2 XML |
| Convenience | ReadValue, ReadValues, WriteValue, BrowseAll, CallMethod, ReadNode, Cancel |
Simplified high-level operations |
| Packet Capture | list_interfaces, start_capture, stop_capture, list_captures, get_capture, capture_now, list_active_channels, dump_keys, decode_pcap_with_keys, summarize_service_calls, replay_pcap, stop_replay, list_replays |
OPC UA-aware packet capture, offline decode, service-call summaries, replay |
All OPC UA types (NodeId, DataValue, Variant, StatusCode, etc.) are represented as JSON for LLM-friendly interaction. Variant serialization dispatches by BuiltInType, so scalar defaults such as Boolean false and numeric 0 remain JSON false / 0 instead of being confused with Variant.Null.
The packet-capture tools are described in detail in Diagnostics. For convenience the per-tool surface is:
| Tool | Description | Parameters |
|---|---|---|
list_interfaces |
Enumerates NICs available to SharpPcap; linkType may be null because enumeration does not open adapters. |
None |
start_capture |
Starts a capture session. | source: nic | inproc-client | inproc-server | replay; optional interface, filter, endpoint, limits, folder |
stop_capture |
Stops an active session and finalizes artifacts. | sessionId |
list_captures |
Lists capture sessions. | Optional state |
get_capture |
Returns an artifact or formatted analysis. | sessionId; format: pcap | pcapng | json | csv | text | service-timeline; optional packet/partial controls |
capture_now |
Starts, waits, stops, and returns output. | Capture options plus the same output format values |
list_active_channels |
Lists in-process secure channels with current tokens. | None |
dump_keys |
Emits keylog data. | Optional sessionId, format, includeExpired |
decode_pcap_with_keys |
Decodes an existing pcap and keylog offline. | pcapPath, keylogPath, format, optional maxFrames |
summarize_service_calls |
Reports service counts, latency, and errors. | sessionId or pcapPath + keylogPath, optional top |
replay_pcap |
Replays as a mock server or mock client. | pcapPath, keylogPath, mode, endpoints, speed |
stop_replay |
Stops an active replay session. | sessionId |
list_replays |
Lists active and recently-completed replay sessions. | None |
The canonical hyphenated values above are emitted on output. CLR enum
names such as InProcessClient and ServiceTimeline remain accepted
on input.
Tool Profiles
The server selects its tool catalog through a tool profile — a bounded set of tool classes registered at startup. Profiles let a client request only the tools it needs (smaller catalogs are easier for an LLM to reason about and reduce prompt size), while full preserves the complete surface for clients that want everything.
| Profile | Tool classes registered | Typical use case |
|---|---|---|
core |
Configuration, Connection, Convenience | Minimal footprint: connect, read/write values, adjust settings |
services |
Attribute, Configuration, Connection, Convenience, Discovery, Method, MonitoredItem, Node Management, Subscription, View | Full OPC UA Part 4 client workflows without PKI/PubSub/packet capture |
administration |
Configuration, Connection, NodeSet Export, PKI Management | Certificate trust management and NodeSet export |
pubsub |
PubSub runtime, discovery, action, and capture tools (plus PubSub decode when diagnostics tools are enabled) | Part 14 PubSub publish/subscribe, discovery, and capture workflows |
diagnostics |
Connection, Packet Capture (plus decode/replay when diagnostics tools are enabled) | OPC UA-aware packet capture, offline decode, and replay |
robotics |
Connection plus Robot Intent discovery, paged monitoring, control, mission and Vision-guided Pick tools | Commanding and monitoring a Robot Intent controller |
vision |
Connection, draft perception tools, and released OPC 40100 control/asset tools | Perception-driven agents and Machine Vision control/management workflows — see Vision and Machine Vision |
full (default) |
Every tool class above | Unrestricted access; the current-major default so existing integrations keep working unchanged |
full is the default for the current major version — core and the other bounded profiles are opt-in. Select a profile with:
- The
--profileCLI option, e.g.opcua-mcp --profile core - The
McpServer:ToolProfileconfiguration value - The
OPCUA_MCP_TOOL_PROFILEenvironment variable
Profiles compose. A --profile value can name more than one bounded profile at a time — the BinPickingClient sample runs --profile vision,robotics and exposes both catalogs from the same MCP host, deduplicating the shared Connection tools. The composed set uses the WithOpcUaCoreTools(McpToolProfileSet) / WithOpcUaVisionTools(McpToolProfileSet) / WithOpcUaRoboticsTools(McpToolProfileSet) overloads, and the core-tools overload owns the single ConnectionTools registration across every package that references the same MCP server. See the Vision developer guide for the composed 81-tool example and the BinPickingClient sample for the running catalog.
Because the exact number of tools in each profile (and in full) changes as tools are added or removed, this document intentionally does not hard-code a tool count. Use the tables above (or tools/list) to enumerate the tools actually exposed by a running server.
Vision-guided Robotics
robotics_vision_pick closes the common perception-to-action path without
making an agent copy a result NodeId and several resource NodeIds between tool
calls. It runs one detection inference through Opc.Ua.Vision.Client, on the
same named OPC UA session as the Robot Intent controller, then submits either
one Pick or a two-step Pick/Place mission:
{
"request": {
"controller": "BinPickingController",
"pipeline": "BinPickingPipeline",
"source": "Bin",
"tool": "ParallelGripper",
"destination": "Fixture",
"classLabel": "RedCube",
"minimumConfidence": 0.9,
"missionId": "place-red-cube"
}
}
Detection selection is deterministic: exact DetectionId/ClassLabel filters and the confidence threshold are applied first, then highest confidence wins with ordinal DetectionId and original result order as tie-breakers. The result contains Vision result/pipeline/sensor/model/frame provenance, the selected pose, and the authoritative intent or mission handle. The helper does not request authority, wait, retry, cancel, or reinterpret a server refusal.
Resources
The MCP server exposes connected sessions as MCP resources, enabling the LLM to discover, inspect, and subscribe to session state.
| Resource URI | Type | Description |
|---|---|---|
opcua://sessions |
Direct | List all active sessions with connection status |
opcua://sessions/{name} |
Template | Full details of a named session (endpoint, security, namespaces) |
opcua://sessions/{name}/namespaces |
Template | Server namespace table for a session |
Multi-Session Support
The server supports multiple simultaneous sessions to different OPC UA servers. Each session is identified by a name.
Tool: Connect
endpointUrl: "opc.tcp://server1:62541/ReferenceServer"
name: "refserver" (optional — auto-generated from hostname if omitted)
autoAcceptCerts: true
Tool: Connect
endpointUrl: "opc.tcp://plc1:4840"
name: "plc1"
Tool: Browse
nodeId: "i=85"
sessionName: "refserver" (optional — uses the only session if there's just one)
Tool: ReadValue
nodeId: "ns=2;s=Temperature"
sessionName: "plc1"
Sessions are listed via resources/list and detailed via resources/read.
Installation
Option 1: Run without installing (.NET 10 SDK)
Run the published tool directly from nuget.org. dotnet tool exec downloads
and caches the tool without adding a global tool installation:
# Run the latest release
dotnet tool exec OPCFoundation.NetStandard.Opc.Ua.Mcp
# Or stay on one release line, for example 2.0.x
dotnet tool exec "OPCFoundation.NetStandard.Opc.Ua.Mcp@2.0.*"
# Short form of dotnet tool exec
dnx OPCFoundation.NetStandard.Opc.Ua.Mcp
Option 2: Install as a .NET global tool
dotnet tool install --global OPCFoundation.NetStandard.Opc.Ua.Mcp
After installation, the opcua-mcp command is available globally.
The tool includes every tool profile, including robotics,
vision, and the composed vision,robotics profile. The Robotics embedding
library remains preview-only. The Vision embedding library follows the normal
root release version; see Packages.
Option 3: Run from source
cd tools/Opc.Ua.Mcp
dotnet run -c Release
Option 4: Install from local build
dotnet pack tools/Opc.Ua.Mcp/Opc.Ua.Mcp.csproj -c Release
dotnet tool install --global --prerelease --add-source tools/Opc.Ua.Mcp/bin/Release OPCFoundation.NetStandard.Opc.Ua.Mcp
If multiple prerelease versions are visible from configured sources, add
--version <the-version-produced-by-dotnet-pack> to select the local package
explicitly.
Configuration
Run on demand without a global installation
MCP clients that accept an executable and argument array can launch the tool
through dotnet tool exec. Put MCP tool arguments after --:
{
"mcpServers": {
"opcua": {
"command": "dotnet",
"args": [
"tool",
"exec",
"OPCFoundation.NetStandard.Opc.Ua.Mcp",
"--",
"--profile",
"core"
]
}
}
}
Claude Desktop
Add to your claude_desktop_config.json (typically at %APPDATA%\Claude\claude_desktop_config.json on Windows or ~/Library/Application Support/Claude/claude_desktop_config.json on macOS):
{
"mcpServers": {
"opcua": {
"command": "opcua-mcp"
}
}
}
VS Code / GitHub Copilot
Add to your workspace .vscode/mcp.json:
{
"servers": {
"opcua": {
"command": "opcua-mcp"
}
}
}
Cursor
Add to your Cursor MCP settings:
{
"mcpServers": {
"opcua": {
"command": "opcua-mcp"
}
}
}
HTTP Transport (for remote clients)
By default, the server uses stdio transport for local tool integration. For remote clients, use the Streamable HTTP transport, exposed only at the /mcp path (there is no root route):
opcua-mcp --transport http --port 5100
The server listens at http://localhost:5100/mcp. --transport sse is a deprecated alias for http kept for the current major version only — prefer http in new configurations.
Usage
Typical Workflow
1. Discover endpoints (no session required):
Tool: GetEndpoints
endpointUrl: "opc.tcp://localhost:62541/Quickstarts/ReferenceServer"
2. Connect to an OPC UA server (auto-select most secure, anonymous):
Tool: Connect
endpointUrl: "opc.tcp://localhost:62541/Quickstarts/ReferenceServer"
autoAcceptCerts: true
Or connect with specific security and authentication:
Tool: Connect
endpointUrl: "opc.tcp://localhost:62541/Quickstarts/ReferenceServer"
securityMode: "SignAndEncrypt"
securityPolicy: "Basic256Sha256"
authType: "Username"
username: "admin"
password: "password"
autoAcceptCerts: true
2. Explore the address space:
Tool: BrowseAll
nodeId: "i=85" (Objects folder)
maxDepth: 2
maxResults: 50
3. Read values:
Tool: ReadValue
nodeId: "ns=2;s=MyTemperatureSensor"
4. Write values:
Tool: WriteValue
nodeId: "ns=2;s=MySetpoint"
value: "72.5"
dataType: "Double"
5. Call a method:
Tool: CallMethod
objectId: "ns=2;s=MyMachine"
methodId: "ns=2;s=StartProcess"
inputArguments: ["fast", "true"]
6. Monitor changes:
Tool: CreateSubscription
publishingInterval: 1000
Tool: CreateMonitoredItems
subscriptionId: <from above>
nodeIds: ["ns=2;s=Temperature", "ns=2;s=Pressure"]
Tool: Publish
(retrieves queued notifications)
7. Manage PKI (trust rejected certificates):
Tool: ListCertificates
store: "Rejected"
Tool: TrustCertificate
thumbprint: "A1B2C3..." (from ListCertificates results)
Tool: GetPkiStorePaths
(shows where certificate stores are located on disk)
8. Adjust configuration for current session:
Tool: GetConfiguration
(view current settings)
Tool: SetConfiguration
operationTimeout: 60000
maxArrayLength: 131072
autoAcceptUntrustedCertificates: true
9. Export the server's address space to NodeSet2 XML:
Tool: ExportNodeSet
filePath: "C:\\export\\server-nodeset.xml"
startingNodeId: "i=85" (Objects folder)
exportMode: "Complete" (includes values)
Or export split by namespace (one file per companion spec):
Tool: ExportNodeSetPerNamespace
outputDirectory: "C:\\export\\namespaces"
10. Disconnect:
Tool: Disconnect
NodeId Formats
The MCP server accepts NodeIds in standard OPC UA string format:
| Format | Example | Description |
|---|---|---|
| Numeric | i=2258 |
Numeric identifier in namespace 0 |
| Numeric with namespace | ns=2;i=1001 |
Numeric identifier in namespace 2 |
| String | ns=2;s=MyVariable |
String identifier |
| GUID | ns=2;g=12345678-1234-1234-1234-123456789abc |
GUID identifier |
| Opaque | ns=2;b=Base64EncodedData |
ByteString identifier |
Common Well-Known NodeIds
| NodeId | Description |
|---|---|
i=84 |
Root node |
i=85 |
Objects folder |
i=86 |
Types folder |
i=87 |
Views folder |
i=2253 |
Server object |
i=2258 |
Server/ServerStatus/CurrentTime |
Error Handling
When an OPC UA service returns an error, tools return a structured JSON response:
{
"error": true,
"statusCode": "BadNodeIdUnknown",
"message": "The node id refers to a node that does not exist in the server address space."
}
This is normal behavior — not all servers support all services. Common status codes:
| Status Code | Meaning |
|---|---|
BadServiceUnsupported |
Server doesn't implement this service |
BadNodeIdUnknown |
NodeId doesn't exist |
BadNotWritable |
Node attribute is read-only |
BadMethodInvalid |
Method not found on the specified object |
BadUserAccessDenied |
Insufficient permissions |
PubSub Tools
In addition to the client services above, the server exposes OPC UA PubSub
(Part 14) tools, backed by Opc.Ua.PubSub and
Opc.Ua.PubSub.Diagnostics. See
Diagnostics.md §5 for
the capture / dissection details.
Configuration and Security Key Service methods. PubSub configuration
(AddConnection, AddWriterGroup, AddReaderGroup, AddDataSetWriter,
AddDataSetReader, Status.Enable / Disable) and the Security Key Service
(GetSecurityKeys, AddSecurityGroup / RemoveSecurityGroup) are standard
server-side PublishSubscribe object methods, so they are invoked with the
generic Call tool rather than dedicated wrappers — pass the
PublishSubscribe object NodeId (or the target connection / group NodeId) and
the corresponding method NodeId (e.g. i=14443 for
PublishSubscribe_AddConnection, i=15215 for
PublishSubscribe_GetSecurityKeys).
In-process publish/subscribe runtime:
| Tool | Purpose |
|---|---|
pubsub_runtime_start_publisher / pubsub_runtime_start_subscriber |
Start an in-process UDP publisher / subscriber |
pubsub_runtime_publish |
Publish a DataSet update |
pubsub_runtime_read_received |
Read DataSets received by the subscriber |
pubsub_runtime_status / pubsub_runtime_stop |
Status / stop the runtime |
Discovery (Part 14 §7.2.4.6 — send a discovery request from the active runtime and collect publisher responses):
| Tool | Purpose |
|---|---|
pubsub_discover_metadata |
Learn the field-level schema of a DataSetWriter (names, field count) |
pubsub_discover_writer_config |
Learn a publisher's WriterGroupId and DataSetWriterIds |
pubsub_discover_publisher_endpoints |
Learn a publisher's transport endpoint URLs |
Actions (Part 14 §7.2.5.6 — request/response over PubSub):
| Tool | Purpose |
|---|---|
pubsub_invoke_action |
Invoke an action target and await the correlated response |
pubsub_register_action_responder |
Register a demo/echo responder for round-trip testing |
pubsub_bind_action_method |
Bind an action to a server method (ObjectId/MethodId) |
pubsub_list_action_targets / pubsub_list_action_responders |
List known targets / registered responders |
Capture and dissection:
| Tool | Purpose |
|---|---|
pubsub_start_capture / pubsub_stop_capture / pubsub_capture_status |
Manage an in-process PubSub capture session |
pubsub_write_pcap |
Flush captured frames to .pcap / .pcapng |
pubsub_dissect_capture |
Dissect captured frames (decrypts encrypted UADP when a key log is supplied) |
pubsub_decode_pcap |
Decode a libpcap file of UDP PubSub traffic |
pubsub_load_keylog |
Load a PubSub key log for offline decryption |
Architecture
The MCP tools ship as six libraries plus the executable that composes them. The executable owns only transport, logging and CLI plumbing; every tool lives in a library that an application can reference on its own.
tools/
├── Opc.Ua.Mcp.Core/ # Part 4 service tools, session manager, options, filters
│ ├── OpcUaMcpCoreExtensions.cs # AddOpcUaMcpCore, WithOpcUaCoreTools, WithOpcUaMcpFilters
│ ├── OpcUaSessionManager.cs # OPC UA client session lifecycle
│ ├── McpCapturePath.cs # Path-traversal guard shared by the capture packages
│ ├── Tools/
│ │ ├── ConnectionTools.cs # GetEndpoints, Connect, Disconnect, GetConnectionStatus
│ │ ├── AttributeServiceTools.cs # Read, Write, HistoryRead, HistoryUpdate
│ │ ├── ViewServiceTools.cs # Browse, BrowseNext, TranslateBrowsePaths, etc.
│ │ ├── NodeManagementServiceTools.cs# AddNodes, AddReferences, DeleteNodes, etc.
│ │ ├── MethodServiceTools.cs # Call
│ │ ├── SubscriptionServiceTools.cs # CreateSubscription, Publish, etc.
│ │ ├── MonitoredItemServiceTools.cs # CreateMonitoredItems, etc.
│ │ ├── DiscoveryServiceTools.cs # FindServers, RegisterServer, etc.
│ │ ├── PkiTools.cs # ListCertificates, TrustCertificate, etc.
│ │ ├── ConfigurationTools.cs # Full-profile compatibility configuration tools
│ │ ├── ConfigurationReadTools.cs # Profile-safe configuration reader
│ │ ├── ConfigurationUpdateTools.cs # Focused transport/client/security setters
│ │ ├── NodeSetExportTools.cs # ExportNodeSet, ExportNodeSetPerNamespace
│ │ └── ConvenienceTools.cs # ReadValue, BrowseAll, CallMethod, etc.
│ └── Serialization/
│ └── OpcUaJsonHelper.cs # OPC UA ↔ JSON type conversion
├── Opc.Ua.Mcp.PubSub/ # PubSub runtime, actions and discovery
│ ├── PubSubRuntimeManager.cs
│ └── Tools/{PubSubRuntime,PubSubAction,PubSubDiscovery}Tools.cs
├── Opc.Ua.Mcp.Diagnostics/ # UA-TCP capture, decode and replay
│ └── Tools/{PacketCapture,PacketDecode,PacketReplay}Tools.cs
├── Opc.Ua.Mcp.PubSub.Diagnostics/ # PubSub capture and decode
│ └── Tools/{PubSubCapture,PubSubDecode}Tools.cs
├── Opc.Ua.Mcp.Robotics/ # Robot Intent plus same-session Vision-guided picking
│ ├── RoboticsIntentManager.cs
│ ├── VisionGuidedRoboticsManager.cs
│ └── Tools/Robotics{Discovery,Monitoring,Control,Mission,Vision}Tools.cs
├── Opc.Ua.Mcp.Vision/ # Vision discovery, monitoring, seeing, inference, feedback, geometry
│ ├── VisionClientAccessor.cs
│ └── Tools/Vision{Discovery,Monitoring,Seeing,Inference,Feedback,Geometry}Tools.cs
└── Opc.Ua.Mcp/ # .NET 10 project, packaged as dotnet tool
├── Program.cs # Entry point, stdio + Streamable HTTP transport (/mcp)
├── McpHostBuilder.cs # Composes the six libraries
├── Opc.Ua.Mcp.Config.xml # OPC UA client application config
└── .mcp/server.json # MCP server manifest for NuGet discovery
Packages
| Package | Tools | Depends on |
|---|---|---|
OPCFoundation.NetStandard.Opc.Ua.Mcp.Core |
Part 4 services, connection, configuration, PKI, NodeSet export | Opc.Ua.Core, .Configuration, .Client |
OPCFoundation.NetStandard.Opc.Ua.Mcp.PubSub |
PubSub runtime, actions, discovery | Core + Opc.Ua.PubSub |
OPCFoundation.NetStandard.Opc.Ua.Mcp.Diagnostics |
UA-TCP capture, decode, replay | Core + Opc.Ua.Core.Diagnostics |
OPCFoundation.NetStandard.Opc.Ua.Mcp.PubSub.Diagnostics |
PubSub capture, decode | Core + Opc.Ua.PubSub.Diagnostics |
OPCFoundation.NetStandard.Opc.Ua.Mcp.Robotics |
Robot Intent discovery, typed control/missions, paged monitoring, Vision-guided Pick | Core + Opc.Ua.Robotics.Client + Opc.Ua.Vision.Client |
OPCFoundation.NetStandard.Opc.Ua.Mcp.Vision |
Vision discovery, monitoring, seeing, inference, feedback and poses; released Machine Vision capabilities, topology, bounded events/conditions, control and complete file workflows | Core + Opc.Ua.Vision.Client |
OPCFoundation.NetStandard.Opc.Ua.Mcp |
the ready-to-run opcua-mcp tool |
all of the above |
The libraries multi-target net8.0;net9.0;net10.0; the executable targets
net10.0. Mcp.Robotics remains preview-only. Mcp.Vision, the other
libraries, and the opcua-mcp tool follow the normal root version and can ship
without a prerelease suffix on an approved stable release. Development builds
retain the root preview version.
Embedding the tools in your own MCP server
An application that wants OPC UA tools and its own application-level tools
composes them rather than shelling out to opcua-mcp:
using Microsoft.Extensions.DependencyInjection;
using Opc.Ua.Mcp;
builder.Services.AddOpcUaMcpCore();
builder.Services.AddMcpServer()
.WithStdioServerTransport()
.WithOpcUaMcpFilters()
.WithOpcUaCoreTools(McpToolProfile.Services)
.WithTools<MyApplicationTools>();
Add any of the other packages the same way — each contributes a service registration and a tool registration:
builder.Services.AddOpcUaMcpPubSub();
builder.Services.AddOpcUaMcpDiagnostics();
builder.Services.AddOpcUaMcpPubSubDiagnostics();
builder.Services.AddOpcUaMcpRobotics();
builder.Services.AddOpcUaMcpVision();
mcp.WithOpcUaPubSubTools(profile)
.WithOpcUaDiagnosticsTools(profile, diagnosticsEnabled)
.WithOpcUaPubSubDiagnosticsTools(profile, diagnosticsEnabled)
.WithOpcUaRoboticsTools(profile)
.WithOpcUaVisionTools(profile);
WithOpcUaMcpFilters registers the request and schema filters that make tool
errors actionable and tool schemas explicit. Call it once per server, even when
several OPC UA tool packages are composed.
McpToolProfile is shared vocabulary that lives in Core, and each package maps
the profile to its own tools. A profile a package does not own contributes
nothing rather than failing, so the same profile value can be passed to every
package a host references — Full in a host that never referenced
Opc.Ua.Mcp.Diagnostics simply yields no capture tools.
Bounded profiles that own their own connection tools — Vision in the
example above — carry ConnectionTools themselves in the single-profile
overload of WithOpcUa...Tools. When two or more bounded profiles are
composed through the McpToolProfileSet overloads (for example the
vision,robotics composition the BinPickingClient
sample runs), the corresponding WithOpcUaCoreTools(McpToolProfileSet)
overload owns and deduplicates ConnectionTools across every package.
Each Vision or Robotics package's McpToolProfileSet overload never
registers ConnectionTools directly, so the composed catalog contains
one Connection surface, not several.
The capture tool classes stay internal and are reachable only through their
registration extensions.
Security Notes
- The
autoAcceptCertsparameter is for testing only. In production, configure proper certificate trust using the OPC UA certificate stores under%LocalApplicationData%/OPC Foundation/pki/. - The server supports simultaneous named OPC UA sessions. Use the intended session identifier for each operation and disconnect that session when finished; connecting to another server does not require closing unrelated sessions.
- Application certificates are automatically created on first use and stored in the local certificate store.
- Logs are written to
%LocalApplicationData%/OPC Foundation/Logs/McpServer.log.txt.
Agent-Usability Quality Gate
Contributors can run the same deterministic static and live-probe grading used in CI:
./tools/Opc.Ua.Mcp/Test-McpGrade.ps1
The script builds the server, checks out mcpgrade at the reviewed commit pinned in the script,
grades the core and full Streamable HTTP catalogs, and probes the full stdio catalog. Reports
are written under artifacts/mcpgrade by default.
The repository .mcpgraderc.json disables N002 after descriptions have been disambiguated.
RegisterServer/RegisterServer2 are OPC UA standard service names, while
ReadValue/ReadValues and GetConfiguration/SetConfiguration are compatibility-sensitive
singular/plural and get/set pairs. These names must not be changed solely to satisfy edit-distance
heuristics.
Requirements
- .NET 10 SDK or later
- An OPC UA server to connect to