plctap
Agent 的 PLC 驱动层 — 让 Claude / Codex / Cursor 直接连接、读写、诊断 Modbus TCP / FINS / MELSEC / Siemens S7comm PLC 的 MCP Server。
状态: v0.3.0 (四协议读写 + 诊断引擎 + 钓鱼监听 + 跨厂商 e2e)。
工具
| 层 | 工具 | 说明 |
|---|---|---|
| 连接 | probe_device |
连通性探测 + 四类失败分层归因 (MELSEC 支持 3E binary/ASCII 自动回退) |
| 连接 | plc_read |
读数据区并按 datatype/字节序解释 (四协议); datatype 缺省返回 uint16/int16/float32 四种字序 (abcd/cdab/badc/dcba)/int32 多解释 |
| 诊断 | parse_frame / validate_frame |
单帧结构化解析 / 规范校验清单 |
| 诊断 | diagnose |
规则引擎 + 故障知识库 → 结构化候选报告 |
| 诊断 | parse_pcap |
解析 Wireshark 导出 pcap, 逐流逐帧 (每条 TCP 流独立判别协议, 需 uv sync --extra eval) |
| 监听 | start_listener / stop_listener / get_listener_frames |
钓鱼模式: 设备只能当 client 时立假 server 收帧分析 (MELSEC 回帧支持全部 4 种帧格式) |
| 执行 | plc_write / send_frame |
默认不注册, PLCTAP_ALLOW_WRITE=true 才启用 (闸门) |
写能力
PLCTAP_ALLOW_WRITE=true 后四协议能力:
| 协议 | 写语义 | options |
|---|---|---|
| Modbus | fc16 批量写寄存器 (默认) / fc05 线圈 / fc06 单寄存器 | point_type, options.function_code, options.values |
| S7 | 16 位字写入 DB/M/I/Q 区 | options.area, options.db_number |
| FINS | 0102 存储区写字 (CIO/W/H/A/DM/EM) | options.area |
| MELSEC | 1401 批量写字, 全部 4 种帧格式 | options.device, options.frame_format |
所有写/发送动作逐帧写入审计日志 (发送前留痕, 失败也留)。
质量保障
- 412 项单测(codec 纯函数 + 适配器 + 诊断引擎 + 监听器),CI 每次推送回归。
- 跨厂商 e2e(tests/e2e):plctap 与 pymodbus、python-snap7、
pymcprotocol、pypi fins 四个第三方权威实现做真实 socket 交叉验证
(读写闭环、读数逐值比对、钓鱼监听互通),CI 随行(
uv sync --group e2e)。 - 五档评测 35/35:单帧 / RTU 完整性 / 批量日志 / FINS·MELSEC 专项 / 主动探测归因。
评测对比 (五档, 35 用例)
| 档位 | plctap 工具链 | 裸模型直接问答* |
|---|---|---|
| 单帧 Modbus TCP | 8/8 | 8/8 |
| RTU 完整性/CRC | 5/5 | 4/5 |
| 批量日志 (混排) | 5/5 | 4/5 |
| FINS/MELSEC 专项 | 12/12 | 5/12 |
| 主动探测归因 | 5/5 | 5/5 |
| 合计 | 35/35 (100%) | 24/35 (68.6%) |
* 基线方法: 同一批语料, 裸模型 (glm-5.3-flash, 无工具, temperature=0) 直接问答; 确定性关键词判分 (事实等价集, 双模式共用); 6 例因推理端点超时未获有效答案计 FAIL (排除超时后 24/29 = 82.8%)。跑分日期 2026-09-04, 语料版本见 git。 结论: 单帧翻译裸模型已能胜任, 价值差距集中在冷门协议语义与多故障混排场景 —— 这正是确定性解析 + 结构化知识库的所在。
快速开始
uvx plctap # 或 pipx install plctap
Claude Desktop 接入 (claude_desktop_config.json)
{
"mcpServers": {
"plctap": {
"command": "uvx",
"args": ["plctap"],
"env": { "PLCTAP_ALLOW_WRITE": "false" }
}
}
}
本地开发 (仓库检出路径):
{
"mcpServers": {
"plctap": {
"command": "uv",
"args": ["--directory", "C:/path/to/plctap", "run", "plctap"]
}
}
}
Codex 接入 (~/.codex/config.toml)
[mcp_servers.plctap]
command = "uvx"
args = ["plctap"]
[mcp_servers.plctap.env]
PLCTAP_ALLOW_WRITE = "false" # 写闸门默认关闭
PLCTAP_DEFAULT_TIMEOUT_MS = "2000"
配置 (环境变量, 均有默认值)
| 变量 | 默认 | 说明 |
|---|---|---|
PLCTAP_ALLOW_WRITE |
false |
写类工具默认不注册 (安全闸门) |
PLCTAP_POOL_MAX_PER_TARGET |
2 |
每目标连接池上限 |
PLCTAP_IDLE_TIMEOUT_SEC |
30 |
空闲连接回收秒数 |
PLCTAP_DEFAULT_TIMEOUT_MS |
2000 |
网络超时 |
安全
- 写操作默认完全不注册; 显式
PLCTAP_ALLOW_WRITE=true才启用。 - 所有写/发送动作逐条写入 JSONL 审计日志 (
~/.plctap/audit.jsonl, 不可关)。 - 发送类调用请配合客户端审批弹窗使用 (用户可见目标 IP 与完整帧)。
- 审计日志样例:
{"ts":"2026-09-04T01:20:33+0800","tool":"plc_write","target":"modbus://127.0.0.1:15020 unit=1","frame_hex":"0002000000060106000104d2","caller":"mcp"}
开发
uv sync --extra eval --group e2e
uv run pytest -q # 单测 (codec/适配器/诊断/监听) + 跨厂商 e2e + MCP 冒烟
uv run plctap # 本地启动 stdio server
License
MIT
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file plctap-0.3.0.tar.gz.
File metadata
- Download URL: plctap-0.3.0.tar.gz
- Upload date:
- Size: 400.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f49519769befe3f403785786c48cc05866b1f17d6cf49b115e2aa4948d9326dc
|
|
| MD5 |
e4d2f0a9ee9c7b63083d3e63974ab412
|
|
| BLAKE2b-256 |
2ca63041781655bee5947e3c9d6071fcde9f9000f66dea38dc747386d9223d68
|
Provenance
The following attestation bundles were made for plctap-0.3.0.tar.gz:
Publisher:
publish.yml on ymxc152/plctap
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
plctap-0.3.0.tar.gz -
Subject digest:
f49519769befe3f403785786c48cc05866b1f17d6cf49b115e2aa4948d9326dc - Sigstore transparency entry: 2740790665
- Sigstore integration time:
-
Permalink:
ymxc152/plctap@e95567b42313d20743633ba2194f82185cf90844 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/ymxc152
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@e95567b42313d20743633ba2194f82185cf90844 -
Trigger Event:
push
-
Statement type:
File details
Details for the file plctap-0.3.0-py3-none-any.whl.
File metadata
- Download URL: plctap-0.3.0-py3-none-any.whl
- Upload date:
- Size: 100.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
940c4d4b1f822d93fd191cb5f65101d9097103fdec9f43dd63c188228c3f9c2f
|
|
| MD5 |
e30715e24b120979d94ba13b568d7279
|
|
| BLAKE2b-256 |
8ba99aea75ba6a4714af104627b0098ee8702d3819d38066c983d52778fb7f36
|
Provenance
The following attestation bundles were made for plctap-0.3.0-py3-none-any.whl:
Publisher:
publish.yml on ymxc152/plctap
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
plctap-0.3.0-py3-none-any.whl -
Subject digest:
940c4d4b1f822d93fd191cb5f65101d9097103fdec9f43dd63c188228c3f9c2f - Sigstore transparency entry: 2740790807
- Sigstore integration time:
-
Permalink:
ymxc152/plctap@e95567b42313d20743633ba2194f82185cf90844 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/ymxc152
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@e95567b42313d20743633ba2194f82185cf90844 -
Trigger Event:
push
-
Statement type: