Skip to content

Releases: ymxc152/plctap

v0.6.2 — 17 工具 MCP annotations 全显式 + 评测 harness 去品牌化

Choose a tag to compare

@ymxc152 ymxc152 released this 13 Sep 06:37

✨ 17 个工具补齐 MCP ToolAnnotations(四 hint 全显式)

全部工具现声明 readOnlyHint / destructiveHint / idempotentHint / openWorldHint,按 handler 真实行为取值——只读组不再依赖规范缺省(规范缺省 destructive=true,会让纯读工具被客户端当危险工具对待)。tools/list 只增元数据,不改任何既有键,符合「版本与兼容承诺」的只增不改。

  • 分组语义:纯本地解析(ro=T / openWorld=F)· 联网只读(ro=T / openWorld=T)· 监听/代理生命周期(非 ro、非破坏、非幂等——重复 start 对同端口报错、stop 对不存在端口抛 ValueError)· 写类(非 ro + destructive=T 宁严勿松)
  • 黄金锁 tests/test_tool_annotations.py:wire camelCase 逐键 + 注册集合双向覆盖,新增工具不登记即挂测试
  • 背景:M8ven Trust Index 扫描指出 17/17 工具缺 hint(OpenAI 目录会拒收缺任一 hint 的工具)——本版后四键全显式,复扫应转绿

🐛 sim_modbus_slave 兼容 pymodbus 3.15

3.15 起弃用 ModbusSlaveContext/ServerContext(legacy 包装丢块起始地址且 ImportError)——SimDevice/SimData 新 API 并保留 <3.15 legacy 双路径;外部地址布局与 e2e 同款。

🔧 评测 harness 去 OPENAI_API_KEY 品牌化(仅开发期,运行时零 AI 依赖不变)

eval/baseline.py 的取钥变量 OPENAI_API_KEY → PLCTAP_BASELINE_API_KEY,并移除内置默认端点(api.openai.com)与默认模型(gpt-4.1-mini)——PLCTAP_BASELINE_API_KEY/BASE_URL/MODEL 三变量显式必填、缺失即 fail-fast。发布产物(wheel)只含 src/plctap,MCP server 运行时零 AI/LLM 依赖,不读也不需要任何模型 API 凭据。

质量

  • 581 pytest 全绿(含 annotations 黄金锁 2 项 + wire 复核 17/17 四键 camelCase)
  • 发布前台架预验 38/38:五仿真器(Modbus/S7/MELSEC/FINS/OPC UA)+ MCP 工具链 + 第三方客户端交叉读回(pymodbus / python-snap7 / pymcprotocol)+ 写审计逐帧留痕,隔离 wheel 环境实证
  • wire 只增不改:工具名/参数/返回结构零变化

安装

uvx plctap                 # 任意 MCP 客户端一行接入
pip install plctap==0.6.2

PyPI: https://pypi.org/project/plctap/0.6.2/

plctap v0.6.1 稳定化第一周期

Choose a tag to compare

@ymxc152 ymxc152 released this 08 Sep 16:46

v0.6.1 稳定化第一周期 —— wire 兼容修复 + 返回建模收编 + 兼容纪律生效

自本版起 README「版本与兼容承诺」生效:MCP 工具名 / 参数名 / 返回结构向后兼容,新增只增不改;破坏性变更将在 docstring / README / Release notes 三处提前标注。1.0(语义定稿)待该纪律验证一个完整发布周期后另行宣布。

修复

  • enip: RRData 嵌入长度超声明时产出负长度 route_path 伪字段 → 转结构化 errors + 回归测试
  • get_listener_frames / get_proxy_frames: limit=0 / 负数不再把整个环形缓冲(最多 1000 条)泼给调用方([-0:] 切片陷阱);语义定为"取最新 N 条 + 环形硬上限 1000",写入工具 docstring

内部(wire 不变)

  • 9 个 dict 返回工具收编 pydantic 建模(extra="forbid" 黄金锁);tests/test_tool_shapes.py 黄金键集合测试证明 wire 兼容——键集合与值语义与 0.6.0 完全一致
  • pyproject classifiers 升 Production/Stable;外迁文档死引用清理(detect 文案/BUILD.md 括注/PLAN 引用)

兼容性说明

  • 直接消费 JSON 的调用方:输出键集合与 0.6.0 一致(黄金测试锁定),无迁移成本
  • 使用 fastmcp 客户端且以属性方式取 .data 的调用方:9 个建模工具的 .data 现为模型实例(属性访问),不再支持字典下标——README 兼容承诺节已注明例外(list_protocols 的 protocols 条目仍为自由形态 dict)
  • 台架验收 38/38(v0.6.0 的 30 项 + 监听/代理 MCP 层段);测试 579 passed

安装

uvx plctap

PyPI: https://pypi.org/project/plctap/0.6.1/

plctap v0.6.0 产品化收官

Choose a tag to compare

@ymxc152 ymxc152 released this 08 Sep 04:36

v0.6.0 产品化收官 —— 八协议端点 + 质量工程 + 多模型评测矩阵

新增

  • OPC UA 端点 (4840): 连接级诊断 only —— probe(UA 会话握手 + Server_ServerArray 规范节点最小读)/ plc_read(NodeId 字符串寻址,UA 原生类型返回)/ 新工具 plc_browse(地址空间一层展开,200 子节点预算 + truncated sentinel);SecurityPolicy None(诊断场景声明);不做帧级诊断(parse_frame/validate_frame/diagnose 帧证据显式拒绝——设计声明非缺陷)
  • hypothesis 模糊测试: 随机/变异字节喂 parse/validate 纯函数层,"永不崩"契约——首轮即炸出 7 处用户输入可触发的解析崩溃(melsec 短帧/ASCII 非 hex、s7 写数据项头越界、iec104 I 帧截断方向、enip item 边界),逐一修复并回归;白名单收敛至文档化契约
  • 工具输出 token 预算: parse_pcap 64KB 字节预算截断(truncated sentinel 流带 total/shown)+ plc_browse 200 子节点硬上限——大地址空间不再撑爆 Agent 上下文
  • 元数据诚实性基建: send_raw 从抽象方法降级为可选能力(会话协议不再被迫实现虚报方法);detect 按 _Profile 独立 probe 预算(opcua 会话握手 2.5s)
  • docs/cases/ 脱敏诊断案例 5 篇(现象→探测→定位→结论)+ demo.gif 扩幕至八幕 16 帧(新增钓鱼监听幕与 enip tag 读幕)

评测

  • 多模型裸基线矩阵(4 模型 × 双跑 × 五档 35 条):glm-5.3-flash 13/35、glm-5-2 10/35、doubao-turbo 9/35、deepseek-v4-flash 8/35——双跑总分逐分复现,fins_melsec 档 8 轮 0/96;挂上 plctap 工具层恒 49/49 且与模型强弱无关(两种失败模式——推理跑飞与"流畅的错误"——同时被工具层免疫)
  • 工具模式八档 49/49(2026-09-07 按当前语料复跑)

质量

  • 测试 569 passed 0 skipped(v0.5.5 的 520 → 569)
  • 发布前本地 wheel 台架验收 30/30(五仿真器 + fastmcp MCP 工具链 + pymodbus/snap7/pymcprotocol/IoTClient 交叉读回 + 审计逐帧核对)

安装

uvx plctap

PyPI: https://pypi.org/project/plctap/0.6.0/

plctap v0.5.5

Choose a tag to compare

@ymxc152 ymxc152 released this 07 Sep 13:07

S7 写审计回归修复 —— 真实测试台架发现

修复 (D5 红线)

  • s7 write 漏调 on_frame → 写操作完全绕过审计日志: 补审计回调并对齐 modbus / fins / melsec 语义
  • 冒烟回归: s7 写连接失败也必须留痕
  • 防复发条款入册 docs/ADD_PROTOCOL.md: 新适配器的 write 必须在请求帧构建后、任何网络动作前调用 on_frame(request.hex())

为什么全量测试没抓到 —— 验收方法学固化

全量 pytest 只测过 modbus 写审计路径, s7 缺陷漏网; 由发布 wheel 真实台架验收抓出:
起 4 仿真器 (modbus 5020 / s7 1020 / melsec 6000 / fins 9600) → uv run --with plctap==X.Y.Z 用 PyPI wheel 走 fastmcp Client 完整 MCP 工具链 → 第三方权威客户端交叉读回 → 审计逐帧核对 (s7 适配器 on_frame 引用计数为 0 暴露)。
台架验收 21/21。

发布流程升级

  • publish.yml 加 guard-main 闸门: tag 所指 commit 必须在 main 历史内, 分支 tag 拒绝发布 (v0.5.3 曾以旧版 workflow 绕过)

质量

510 项单测 (全量 520 passed 0 skipped); 评测八档 49/49; 官方 Registry 0.4.0→0.5.5 六条记录全 active。

安装

uvx plctap    # 或: pip install plctap==0.5.5

PyPI: https://pypi.org/project/plctap/0.5.5/

Full Changelog: v0.5.4...v0.5.5

plctap v0.5.4

Choose a tag to compare

@ymxc152 ymxc152 released this 07 Sep 13:07

v0.5.3 缺陷修复的正式全量发布

修复 (随 v0.5.3 内容一并收口)

  • enip e2e 假服务器导入: tests/ 非可导入包, 改 importlib 按文件路径加载 (原 import 在任何环境必失败, 且该提交线此前从未过 CI)
  • MCP 层 enip 地址类型缺陷: address 放宽 int | str + 服务层类型闸 + fastmcp Client 冒烟回归 (两条负例)

官方 Registry 收录补录

  • server.json description 缩至 MCP Registry 100 字符上限内 (收录步骤 422: 补两协议后超长)
  • registry-sync.yml 增 checkout_ref 输入: server.json 在 tag 之后才修正时, 可从 main 检出修正版补录已发布版本, 避免移动 tag 重复触发 PyPI 上传

e2e 台架扩至六方权威实现

pymodbus / python-snap7 / pypi fins / pycomm3 / MZ Automation lib60870.NET / 自建 MC fixture —— 全量 520 passed 0 skipped。

文档对齐

八档 49/49 口径 / 六端点可写 / PUBLISH 补发布教训。

安装

uvx plctap    # 或: pip install plctap==0.5.4

PyPI: https://pypi.org/project/plctap/0.5.4/

Full Changelog: v0.5.3...v0.5.4

plctap v0.5.3

Choose a tag to compare

@ymxc152 ymxc152 released this 07 Sep 13:07

EtherNet/IP (CIP) —— 七协议版图收官

新端点

  • enip 端点 (44818 / 2222): ENIP 封装 + CIP 非连接消息 tag 读写 (0x4C 读 / 0x4D 写, 整数默认 DINT, 浮点 options.type="REAL")
  • tag 名字符串寻址 (如 "alpha[0]") —— 与其余协议的整数地址语义不同
  • 可写端点 (六大可写之一); 与 MELSEC SLMP 撞号 44818 由 detect 响应指纹消歧

官方实现双向交叉验证

  • pycomm3 (Rockwell 官方客户端库): 官方 client 逐字节解析 plctap 监听器应答

MCP 工具层修复

  • plc_read / plc_write address 放宽 int | str + 服务层 _validate_address 按协议类型闸 —— 原 schema 钉死 int 曾致 enip (只收 tag 名字符串) 整端点不可用; 补 fastmcp Client 经工具层读数冒烟回归

里程碑

七协议端点集齐: modbus / modbus_rtu / fins / melsec / s7 / iec104 / enip —— 覆盖西门子 / 三菱 / 欧姆龙 / 罗克韦尔 / 电力远动 / 通用 Modbus 六大生态。

质量

510 项单测; 评测八档 49/49 (新增 enip 档 4 例)。

安装

uvx plctap    # 或: pip install plctap==0.5.3

PyPI: https://pypi.org/project/plctap/0.5.3/

Full Changelog: v0.5.2...v0.5.3

plctap v0.5.2

Choose a tag to compare

@ymxc152 ymxc152 released this 07 Sep 13:07

IEC 60870-5-104 (电力 / 水务 / 热力远动)

新端点

  • iec104 端点 (2404): APCI I/S/U 帧型 + ASDU 常用子集 (遥信 / 归一化 / 标度化 / 短浮点 ± 时标变体、总召 / 读 / 时钟同步 / 测试命令) + CP56Time2a
  • probe = STARTDT+TESTFR 握手探测; plc_read = 总召收集式读 —— 连接池内维护 I 帧收发序号、超窗 S 帧确认、序号跳号记入诊断 notes
  • 按设计仅读 (六端点可写之外的唯一只读端点)

诊断配套

  • 钓鱼监听: U 握手回 CON、总召回 ACT_CON + 罐头帧 + ACT_TERM
  • kb/iec104.yaml 四条远动高频故障; parse / validate / diagnose / auto 全链路接入

官方实现双向交叉验证

  • MZ Automation lib60870.NET: plctap 读官方 server 预置点逐值一致; 官方 client 正确解码 plctap 罐头帧
  • 期间以代理抓包逐字节比对, 修正总召帧带 IOA (置 0) 的规范误判
  • C# 台架进仓 tests/e2e/bench_iec104 (缺 dotnet 环境自动跳过)

质量

482 项测试全绿; 评测七档 45/45 (iec104 档 6 条, 总召帧与官方实现逐字节比对)。

安装

uvx plctap    # 或: pip install plctap==0.5.2

PyPI: https://pypi.org/project/plctap/0.5.2/

Full Changelog: v0.5.1...v0.5.2

plctap v0.5.1

Choose a tag to compare

@ymxc152 ymxc152 released this 07 Sep 13:07

Modbus RTU over TCP + 国产 PLC 兼容性线索

新端点

  • modbus_rtu 端点: 串口服务器 / 网关 RTU 透传模式 (TCP 上跑裸 RTU 帧, 无 MBAP 头), 常见端口 502 / 8899
  • 与 modbus 帧级同轨: 判别 / 知识库 / 写语义共用 (双轨判别 TCP 与 RTU); send_raw 按累积读取收满一帧完整 RTU 响应
  • 选型判据: 上位机已封装 MBAP 头 → modbus; 网关 RTU 透传模式 → modbus_rtu

vendor_hints

  • 品牌线索增补汇川 Inovance / 台达 Delta / 信捷 Xinje / 永宏 FATEK 等国产 Modbus 兼容 PLC —— 老设备 + 国产存量场景覆盖

发布流程教训 (落档 docs/PUBLISH.md)

  • 本版经旧版 publish.yml 发布只上了 PyPI, 后由 registry-sync.yml 手动补录官方 Registry —— 催生"tag 所在提交必须包含最新 publish.yml"纪律

安装

uvx plctap    # 或: pip install plctap==0.5.1

PyPI: https://pypi.org/project/plctap/0.5.1/

Full Changelog: v0.4.0...v0.5.1

plctap v0.4.0

Choose a tag to compare

@ymxc152 ymxc152 released this 07 Sep 13:07

主动诊断旗舰: 协议自动识别 / 透明代理 / 故障注入

detect_device —— 冷启动协议识别

  • 并发扫标准端口 → 四协议 probe 指纹 → deep 最小读验证, 给出可执行的 plc_read 建议
  • 全程只读 (握手帧 + 最小读帧), "识别 ≠ 可访问" (如 S7 PUT/GET 关闭时识别成功但读仍失败)
  • _PROFILES 注册表: 新协议接入 = adapter register + 注册表加一条, 识别逻辑零改动
  • 44818 端口撞号 (MELSEC SLMP 与 EtherNet/IP): 端口先验只影响同级排序不参与置信度, 按响应指纹消歧

主动诊断设施

  • 透明代理 start_proxy / stop_proxy / get_proxy_frames: 上位机→代理→真 PLC 透传 + 双向录帧, 在线联调免 Wireshark
  • 监听 inject_errors 故障注入档: 确定性故障轮转 (exception / bad_length / truncate / end_code / garbage), 兼评测语料生成器
  • modbus probe 带请求上下文回显甄别 (tid/unit/fc/byte_count 四重交叉校验), 防回显服务器误判

写链路全量实测

四协议写链路各经权威第三方客户端独立读回验证一致。

质量与收录

  • 452 项测试全绿; 评测六档 39/39 (新增 detect 档 4/4)
  • 官方 MCP Registry 收录 (v0.4.0 status=active); glama.ai 自动收录公开

安装

uvx plctap    # 或: pip install plctap==0.4.0

PyPI: https://pypi.org/project/plctap/0.4.0/

Full Changelog: v0.3.0...v0.4.0

plctap v0.3.0

Choose a tag to compare

@ymxc152 ymxc152 released this 07 Sep 13:07

写能力补全与全量交叉验证固化

写能力

  • FINS 0102 区写 / MELSEC 1401 批量写实装 (写闸门元数据同步) —— 四协议写链路齐备

诊断与解释

  • interpret_all 四字序 (ABCD / CDAB / BADC / DCBA) + int32 解释
  • parse_pcap 逐流协议判别 (修复混合 pcap 被全局多数协议错切)
  • probe 增加 MELSEC ASCII 回退 (仅 connected_but_no_reply 时); S7 知识库 (优化 DB / PUT-GET 权限)
  • MELSEC 监听回帧支持全 4 帧格式

全量交叉验证修复三缺陷

起四权威实现台架 (pymodbus / python-snap7 / IoTClient FINS / 自建 MC fixture), MCP 工具逐一实测 + 第三方客户端交叉读回:

  1. MELSEC adapter frame_format 未贯穿 locked_exchange 收帧回调 → 3E ASCII / 4E 读必挂 (partial 显式绑定修复)
  2. FINS/TCP 数据帧生态主流命令是 0x02 不是 0x04 (三实现一致并经真机验证) → adapter 改发 0x02, 解析/监听两者等价
  3. 写能力元数据虚报 → 按类级"是否真正覆写"计算, 未实现显式报错

另含 v0.2.0 发布后线上实测发现的两个缺陷修复: fc16 RTU 校验 8B 硬编码误报 13B 合法帧 (改按 fc 分派); S7 非 DB 区 db_number 默认 1 泄漏 (非 DB 区默认 0, 显式非 0 直接报错)。

质量

  • 跨厂商 e2e 交叉验证套件进 CI (迁移 pymodbus 3.15 新 API)

安装

uvx plctap    # 或: pip install plctap==0.3.0

PyPI: https://pypi.org/project/plctap/0.3.0/

Full Changelog: v0.2.0...v0.3.0