# TIA Portal MCP — V19 / V20 / V21

MCP servers that let Claude drive **Siemens TIA Portal** (open projects, browse
the project tree, export/import blocks & types, compile PLC software) via the
Siemens **Openness** API.

Reverse-engineered from the open-source
[heilingbrunner/tiaportal-mcp](https://github.com/heilingbrunner/tiaportal-mcp)
(MIT) — the same codebase behind the VS Code extension
`jheilingbrunner.vscode-tiaportal-mcp`. This repo extends it to **V19** and
**V21** alongside the stock **V20** binary.

## Registered servers (global, `~/.claude.json`)

| Server | TIA version | Binary | Launch arg |
|---|---|---|---|
| `tia-portal-v17` | V17 | `build\v17\TiaMcpServer.exe` | `--tia-major-version 17` |
| `tia-portal-v18` | V18 | `build\v18\TiaMcpServer.exe` | `--tia-major-version 18` |
| `tia-portal-v19` | V19 | `build\v19\TiaMcpServer.exe` | `--tia-major-version 19` |
| `tia-portal-v20` | V20 | stock extension `0.0.18` binary | _(default)_ |
| `tia-portal-v21` | V21 | `build\v21\TiaMcpServer.exe` | `--tia-major-version 21` |

All five are registered at **user scope** and show `✔ Connected` in
`claude mcp list`. Enable the one matching the TIA Portal version your project
targets (`.ap17` … `.ap21`).

## How version binding works

The server selects its TIA version at startup from `--tia-major-version`
(default 20). The single source compiles against a **version-specific Siemens
Openness NuGet package** and binds to the matching `Siemens.Engineering`
assemblies at runtime:

- **V20** new split API (`Siemens.Engineering.Base/.Step7/...`). Stock binary, unchanged.
- **V21** new split API too, but a **breaking** Openness API + separate `21.0.*`
  package → must be rebuilt against it (Resolver `2.0.*`).
- **V17–V19** old **monolithic** API (single `Siemens.Engineering.dll`). Rebuilt
  against the matching `NN.0.*` package (Resolver `1.1.*`).

### Conditional-compilation constants (older versions drop APIs)

The single source tree compiles different feature sets per version via MSBuild
`DefineConstants`. Each older version lost an API that newer source assumes:

| Constant | Set for | Compiles out |
|---|---|---|
| `TIA_V19` | V17, V18, V19 | V20+ SIMATIC SD "Documents" export/import tools |
| `TIA_PRE_V19` | V17, V18 | WinCC Unified HMI (`Siemens.Engineering.HmiUnified`, V19+) |
| `TIA_NO_NAMESPACE` | V17 | `PlcBlock.Namespace` / `PlcType.Namespace` (V18+) — shimmed to `""` |

### The runtime gotcha (why DLLs are copied next to the exe)

`WithToolsFromAssembly()` eagerly reflects over every tool type at startup via
`Assembly.GetTypes()`. That forces the `Siemens.Engineering*` assemblies to load
**before** any connection, and the lazy Openness resolver doesn't satisfy it in
time → `ReflectionTypeLoadException`. Fix: the build script stages the matching
version's `Siemens.Engineering*.dll` next to `TiaMcpServer.exe`, so the default
.NET loader finds them directly.

## Rebuilding

Prereqs (all present on this machine): TIA Portal V19/V20/V21, VS 2026 /
`dotnet`, membership in the Windows group **"Siemens TIA Openness"**.

```powershell
.\build-tia-mcp.ps1 -Version 21   # → build\v21\
.\build-tia-mcp.ps1 -Version 19   # → build\v19\
.\build-tia-mcp.ps1 -Version 18   # → build\v18\
.\build-tia-mcp.ps1 -Version 17   # → build\v17\
```

The version-specific NuGet package strings live in `build-tia-mcp.ps1`. To
refresh them, check the latest `21.0.*` / `19.0.*` versions on
[nuget.org](https://www.nuget.org/packages/Siemens.Collaboration.Net.TiaPortal.Packages.Openness).

## Layout

```
tiaportal-mcp\                git clone of the MIT source (parameterized csproj)
build-tia-mcp.ps1             rebuild script (-Version 17|18|19|21)
docs\superpowers\specs\       design doc
build\v17..v21\               compiled servers (NOT in repo — build locally)
```

> **Not shipped in this repo:** compiled binaries under `build/`, the Siemens
> Openness assemblies they depend on (`Siemens.Collaboration.Net.*` — Siemens
> copyright, not redistributable), and diagnostics. Build your own with the
> script below against your local TIA Portal install.

## License / redistribution

This is a fork of [heilingbrunner/tiaportal-mcp](https://github.com/heilingbrunner/tiaportal-mcp)
(MIT — see `tiaportal-mcp/LICENSE.txt`, retained). The Siemens Openness API
assemblies are **not** included and are not redistributable; they are pulled from
the official Siemens NuGet feed / your local TIA install at build time.

## Usage

In Claude, the tools appear as `mcp__tia-portal-v21__*` etc. Typical flow:
1. Open TIA Portal **V21** (or use `OpenProject` with a `.ap21` path).
2. `Connect` → `GetProjectTree` → work → `CloseProject` → `Disconnect`.

`Connect` with no project attaches to an already-running TIA instance; with no
instance open it returns "Failed to connect to TIA-Portal" (expected).
