> ## Content Index
> Fetch the complete content index at: https://www.hubwiz.com/blog/llms.txt
> Use this file to discover other available public pages before exploring further.

# 构建TIA Portal MCP服务器
- URL: https://www.hubwiz.com/blog/building-a-tia-portal-mcp-server/
- Published: 2026-07-28T15:23:58.000Z
- Updated: 2026-10-13T14:50:58.000Z
- Description: 本文是一份实践指南，介绍如何构建一个建立在TIA Openness V21之上的MCP服务器，以便像Claude这样的助手可以通过调用类型良好的工具来列出您的块、从Excel导入标签、导出代码和组织项目。
- Author: admin
- Tags: AGENT, MCP, #Import 2026-10-14 14:41

在TIA Portal中设计S7程序充满了重复性、定义明确的工作：创建标签表、构建全局DB、从源导入块、将块移动到组中、编译和读取错误。西门子已经通过Openness API暴露了所有这些功能。缺失的是一个干净的方式让AI助手直接驱动该API，而无需您在聊天窗口中复制粘贴代码。

模型上下文协议（MCP）填补了这一空白。本文是一份实践指南，介绍如何构建一个建立在TIA Openness V21之上的MCP服务器，以便像Claude这样的助手可以通过调用类型良好的工具来列出您的块、从Excel导入标签、导出代码和组织项目。我们将介绍该协议、架构、容易让人困惑的V21特定Openness更改、带有示例负载的完整工具目录、安全模型以及如何扩展它。

## 1、MCP实际上是如何工作的

MCP是Anthropic在2024年底引入的一个开放标准，现在已被AI生态系统广泛采用。其思想很简单：服务器宣传一组工具，客户端（AI应用程序）通过JSON-RPC发现并调用它们。您需要关心三条消息：

- initialize：客户端和服务器就协议版本达成一致并交换能力。
- tools/list：客户端请求可用工具。服务器返回每个工具的名称、人类可读的描述以及其参数的JSON Schema。
- tools/call：客户端通过名称调用工具，并接收结构化结果。

与普通命令行工具的关键区别在于发现和类型化。使用CLI时，您必须已经知道标志。使用MCP时，模型在运行时读取工具列表和模式，并决定调用什么。在本地设置中，传输是stdio：客户端启动服务器进程，它们通过标准输入和输出交换换行符分隔的JSON-RPC消息。这就是我们在这里使用的传输。

## 2、整体架构

服务器被有意分为两层。困难的部分——与Openness通信——位于.NET命令行引擎中。MCP层是一个轻量级的Python进程，将工具调用转换为引擎调用。

```
MCP客户端（Claude Desktop / Cursor / 您的代码）
   |  JSON-RPC over stdio
   v
server.py  (Python, FastMCP)
   |  子进程: ControlByteTiaCli.exe --attach-open --json
   v
ControlByteTiaCli.exe  (.NET Framework 4.8)
   |  Openness API
   v
TIA Portal V21  (运行中，项目已打开)

```

为什么是两层而不是一个进程内服务器？两个原因。首先，Openness需要完整的.NET Framework（4.8），这是托管工程逻辑最可靠的地方。其次，将引擎作为独立CLI意味着它是可独立测试和脚本化的，而MCP服务器变成了几十行组装标志并调用的代码。引擎连接到已打开项目的正在运行的TIA实例，执行其工作，并保持您的TIA窗口不变。

## 3、Openness V21：您必须了解的程序集拆分

如果您为V20或更早版本构建了Openness工具，V21中最重要的更改是结构性的。单一的整体Siemens.Engineering.dll已被拆分为模块化程序集，并移至新的子文件夹：

```
C:\Program Files\Siemens\Automation\Portal V21\PublicAPI\V21\net48\
  Siemens.Engineering.Base.dll     (TiaPortal, Project, HW, Compiler)
  Siemens.Engineering.Step7.dll    (PlcSoftware, Blocks, Tags, Types)
  Siemens.Engineering.WinCC.dll    (HMI Classic)
  Siemens.Engineering.WinCCUnified.dll
  Siemens.Engineering.Safety.dll
  ...

```

在V20中，您引用一个程序集。在V21中，专注于PLC的工具引用Base加上Step7。命名空间未更改（Siemens.Engineering、Siemens.Engineering.SW、Siemens.Engineering.HW、Siemens.Engineering.Compiler），因此大多数现有代码只需更新引用和运行时解析器路径即可编译。

在项目文件中，您引用两个程序集并关闭Copy Local：

```xml
<ItemGroup>
  <Reference Include="Siemens.Engineering.Base">
    <HintPath>C:\Program Files\Siemens\Automation\Portal V21\PublicAPI\V21\net48\Siemens.Engineering.Base.dll</HintPath>
    <Private>false</Private>
    <SpecificVersion>false</SpecificVersion>
  </Reference>
  <Reference Include="Siemens.Engineering.Step7">
    <HintPath>C:\Program Files\Siemens\Automation\Portal V21\PublicAPI\V21\net48\Siemens.Engineering.Step7.dll</HintPath>
    <Private>false</Private>
    <SpecificVersion>false</SpecificVersion>
  </Reference>
</ItemGroup>

```

因为Copy Local关闭，程序集不在可执行文件旁边，所以您必须在运行时解析它们。在使用任何Openness类型之前注册AssemblyResolve处理程序：

```csharp
AppDomain.CurrentDomain.AssemblyResolve += (_, args) =>
{
    var name = new AssemblyName(args.Name).Name;
    if (name is null || !name.StartsWith("Siemens.Engineering", StringComparison.OrdinalIgnoreCase))
        return null;
    var path = Path.Combine(
        @"C:\Program Files\Siemens\Automation\Portal V21\PublicAPI\V21\net48",
        name + ".dll");
    return File.Exists(path) ? Assembly.LoadFrom(path) : null;
};

```

还有一些V21说明。程序集的公钥令牌已更改，但如果您使用SpecificVersion false按简单名称解析，这不会影响您。注册表根目录移至21.0路径。由于二进制文件在版本之间不兼容，请为每个TIA版本保留单独的构建：V20构建将无法加载V21程序集，反之亦然。

## 4、引擎及其JSON信封

.NET引擎是一个多模式CLI。每个模式映射到一个操作：从Excel导入标签和DB、从SCL导入块、批量导入SimaticML XML、将块导出为SCL或XML、组织块、列出项目、列出块。对于自动化，它还有一个–json标志。在JSON模式下，所有日志都转到标准错误，标准输出携带单个结构化信封：

```json
{
  "ok": true,
  "mode": "list-blocks",
  "project": "MyMachine",
  "plc": "PLC_1",
  "dryRun": true,
  "result": { "blocks": [ ... ], "types": [ ... ] },
  "compile": null,
  "error": null
}

```

错误以相同的形状返回，ok设置为false，error中包含消息，因此调用者永远不必从文本中刮取堆栈跟踪。这个信封使工具结果对模型有用：它读取result.blocks而不是四十行时间戳。

## 5、Python中的MCP层

服务器使用官方的mcp SDK及其FastMCP辅助程序。单个辅助程序使用–json运行引擎，解析标准输出并返回它。每个工具都是一个小函数，其签名成为客户端看到的JSON Schema。以下是它的形状：

```python
from mcp.server.fastmcp import FastMCP
import subprocess, json, time

mcp = FastMCP("controlbyte-tia-mcp")

def _run(args: list[str]) -> str:
    cmd = [EXE] + args + ["--json"]
    proc = subprocess.run(cmd, capture_output=True, text=True,
                          encoding="utf-8", timeout=240)
    return (proc.stdout or "").strip()

@mcp.tool()
def list_blocks(plc: str | None = None, project_name: str | None = None) -> str:
    """列出打开项目中PLC的所有块（OB/FB/FC/DB）和UDT。"""
    return _run(["--list-blocks", "--dry-run", "--attach-open"])

if __name__ == "__main__":
    mcp.run()  # stdio传输

```

文档字符串很重要：它是模型在决定是否调用该工具时读取的描述。类型提示成为参数模式。可选参数使用None作为默认值。

从一开始就值得构建两个健壮性细节。首先，写操作默认为试运行，因此工具仅在调用者明确选择加入时才更改项目。其次，如果应用程序暂时繁忙或显示模式对话框，连接到TIA可能会暂时失败，因此辅助程序会在返回干净的JSON错误之前对"操作超时"或"RPC忙"等错误重试几次。

## 6、工具目录

该演示暴露了八个工具。只读工具从不修改项目；写工具默认为试运行。

list\_projects. 列出正在运行的TIA实例及其中打开的项目。完全只读。

```json
{ "ok": true, "mode": "list-projects",
  "result": { "instances": [ { "pid": 12612,
    "projects": [ { "name": "MyMachine", "path": "C:\\...\\MyMachine.ap21" } ] } ] } }

```

list\_blocks. 返回PLC的块和UDT树，每个条目包含其组路径、类型和名称。有助于在不熟悉的程序中指导助手。

import\_tags\_db. 从带有Tags和DB工作表的Excel文件导入PLC标签表和全局DB。参数：excel\_path、可选的plc和project\_name、dry\_run（默认为true）和overwrite\_db。试运行报告计数而不写入：

```json
{ "ok": true, "mode": "excel", "dryRun": true,
  "result": { "tags": { "TablesCreated": 3, "TagsCreated": 19, "TagsSkipped": 0, "TagsFailed": 0 },
              "db":   { "Created": 3, "Skipped": 0, "Failed": 0 } } }

```

import\_scl. 从.scl文件作为外部源导入块，并生成FB、FC或DB。

import\_xml. 从文件或文件夹批量导入UDT和块的SimaticML XML，具有多遍依赖重试功能，以便被其他类型引用的类型按正确顺序导入。

export\_scl. 将块或UDT导出为.scl文件。这仅适用于用SCL或STL编写的块，因为TIA无法从LAD或FBD块生成SCL源。

export\_xml. 将块或UDT导出为SimaticML XML。这适用于任何语言，因此是通用导出。

organize\_blocks. 按命名约定将块和UDT移动到子组中，例如将库块移动到PackML组，将机器人类型移动到Robot组。

## 7、连接到Claude Desktop

您构建引擎，为服务器创建一个小型Python环境，并将其注册到客户端。

```bash
# 1. 构建引擎
dotnet build .\src\ControlByteTiaCli\ControlByteTiaCli.csproj

# 2. MCP服务器的Python环境
cd .\mcp-server
python -m venv .venv
.\.venv\Scripts\python.exe -m pip install "mcp[cli]"

```

然后将条目添加到`%APPDATA%\Claude\claude_desktop_config.json`：

```json
{
  "mcpServers": {
    "controlbyte-tia-mcp": {
      "command": "C:\\path\\to\\mcp-server\\.venv\\Scripts\\python.exe",
      "args": ["C:\\path\\to\\mcp-server\\server.py"],
      "env": {
        "TIA_MCP_EXE": "C:\\path\\to\\src\\ControlByteTiaCli\\bin\\Debug\\ControlByteTiaCli.exe"
      }
    }
  }
}

```

重启客户端，在TIA Portal V21中打开您的项目，controlbyte-tia-mcp工具就会出现。诸如"列出打开的TIA项目中的块"之类的提示将调用list\_blocks，模型将读回结构化树。

## 8、编写自己的客户端

您不需要桌面应用程序。mcp SDK从您自己的代码连接，列出工具并调用它们：

```python
import asyncio
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client

async def main():
    params = StdioServerParameters(command="python", args=["server.py"])
    async with stdio_client(params) as (read, write):
        async with ClientSession(read, write) as session:
            await session.initialize()
            tools = await session.list_tools()
            print([t.name for t in tools.tools])
            result = await session.call_tool("list_projects", {})
            print(result.content[0].text)

asyncio.run(main())

```

## 9、用于标签和DB导入的Excel合同

import\_tags\_db期望一个带有两个区分大小写的工作表的.xlsx文件。

Tags工作表按顺序使用以下列：Name、DataType、LogicalAddress、Comment、TagTable。例如：

```
| Name        | DataType | LogicalAddress | Comment        | TagTable   |
|-------------|----------|----------------|----------------|------------|
| iStart_PB1  | Bool     | %I0.0          | 启动按钮       | TT_Inputs  |
| qMotor1     | Bool     | %Q0.0          | 电机1输出      | TT_Outputs |
| wStep       | Int      | %MW12          | 步骤编号       | TT_Memory  |

```

DB工作表使用：DbName、MemberName、DataType、InitialValue、Comment、Retain。共享DbName的行进入一个全局DB。如果标签表不存在，则会自动创建它们，已存在的标签将被跳过而不是重复。该工具遵循简单的命名约定：i表示输入，q表示输出，x表示布尔标志，w表示word和int，d表示double word和dint，r表示real，DB\_前缀表示数据块，TT\_前缀表示标签表。

## 10、安全模型

从LLM驱动工程工具需要防护措施。该演示使用保守模型：

- 默认试运行。除非调用者将dry\_run设置为false，否则每个写工具都会模拟。任何模式的第一次运行都应该是试运行，这样您就可以在它接触项目之前准确地读回将要更改的内容。
- 第一次写入前备份。引擎可以在保存之前将项目文件夹复制到备份目录中。
- 连接，不要接管。服务器连接到已打开的项目并保持打开状态。它永远不会关闭您的TIA会话。
- 临时重试。如果由于TIA暂时繁忙而导致连接调用失败，则会自动重试，只有持续失败才会作为JSON错误返回。

更强的控制是合理的下一步：显式的每次写入确认、专用的故障安全（F）块处理以及工具调用的审计跟踪。将这些视为路线图，而不是今天的内置功能。

## 11、性能和限制

引擎连接到实时进程，因此大多数调用大约在一两秒内返回。打开新项目或编译大型程序需要更长的时间，这就是为什么引擎允许宽松的超时时间，而MCP辅助程序每次调用使用240秒的时间预算。需要记住两个结构限制：该工具在TIA中已经打开的项目上运行（它不会自行打开离线文件），列出或导出非常大的块的速度受Openness序列化它们的速度限制。

## 12、故障排除

- TIA必须正在运行且项目已打开。服务器连接到实时进程。如果未找到任何内容，请先启动TIA并打开项目。
- 以相同的Windows用户身份运行。Openness仅查看由同一用户启动的TIA进程。不要将提升权限的TIA与未提升权限的工具配对，反之亦然。
- Openness许可证和组。您需要Openness许可证和本地Siemens TIA Openness组的成员资格，否则API会抛出安全异常。
- FileNotFoundException for Siemens.Engineering.Base。解析器找不到V21 net48文件夹。修复路径；不要将DLL复制到可执行文件旁边。
- InvalidProjectVersionException。通过V21打开的旧项目需要升级。在TIA V21中打开一次，保存，然后使用该工具，或连接到已打开的项目。
- XML导入时的区域设置错误。XML中的注释引用了项目中未配置的语言。导入器会清理区域设置，但如果仍然失败，请检查项目语言。

## 13、使用您自己的工具扩展它

添加功能遵循两层拆分。如果该操作已作为引擎标志存在，您只需添加一个构建标志并调用辅助程序的Python工具，然后重启客户端。如果确实是新的，请先在.NET引擎中添加标志和逻辑，重新构建，然后在Python中公开它。一个好的首次添加是只读工具，例如以文本形式读取单个块的源代码，或返回编译器消息作为结构化JSON的编译和报告工具。该模式是可移植的：任何具有自动化API的工程系统都可以位于相同的轻量级MCP层之后。

## 14、路线图

该演示已经返回结构化JSON并重试临时连接错误。自然的下一步是更丰富的工具集（交叉引用、只读块源、编译和报告）、用于远程使用的可选HTTP传输、每次写入确认以及每种模式的结构化结果。这些都不会改变核心思想：一个小型、类型良好的Openness表面，助手可以安全地使用。

## 15、常见问题

此目标适用于哪个TIA版本？V21及其拆分程序集。对于V20，您需要单独的构建，因为Openness二进制文件在版本之间不兼容。

它适用于离线.ap21文件吗？不。它连接到已打开项目的正在运行的TIA Portal实例。

是否有任何内容发送到云？只有您的MCP客户端发送到其模型的内容。如果您使用托管模型，则通过它传递的工具输入和输出将离开您的计算机；对于隔离网络工作，请使用本地模型。MCP服务器和TIA连接是本地的。

成本如何？服务器和引擎只是Openness之上的代码。真正的先决条件是有效的TIA Portal Openness许可证，西门子单独授权。

---

原文链接: [Building a TIA Portal MCP Server on Openness V21: A Hands-On Guide](https://controlbyte.tech/blog/tia-portal-mcp-server-ai-automation/?ref=hubwiz.com)

汇智网翻译整理，转载请标明出处。

> **这是「AI × 工业 / PLC」专题的一部分。**完整地图见：[AI × 工业 / PLC 完全指南](https://www.hubwiz.com/blog/ai-industrial-stack/)