mcpField
M
Modbus TCP/RTU Device

Modbus TCP/RTU Device

本地服务
github.com科研与教育235 周前更新

关于 Modbus TCP/RTU Device

Modbus TCP/RTU Device 是用于通过以太网或串行连接读取和控制 Modbus 设备的 MCP 服务,面向仪器与设备自动化场景。它通过 YAML 或 JSON 寄存器映射提供带类型、单位和限制的命名点,并支持安全状态操作;目前仅在模拟环境中测试。

主要功能

  1. 01支持 Modbus TCP、RTU 和 ASCII
  2. 02用寄存器映射定义类型化测点
  3. 03按测点限制写入范围
  4. 04写入后读取并核对结果
  5. 05审计日志与只读模式
  6. 06按映射执行安全状态操作

适用场景

  1. 01读取温控器的工程单位测点
  2. 02在范围限制内调整控制器设定值
  3. 03调试串行或 TCP Modbus 连接
  4. 04请求设备进入映射定义的安全状态

MCP 相关

这是一个 MCP 服务,向 AI Agent 提供 Modbus 连接信息、测点读取与写入等工具。客户端可读取映射、查询命令日志,并在映射定义安全状态时调用相应工具。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"k-dense-ai-labmcp-modbus": {
"command": "uvx",
"args": [
"labmcp-modbus"
],
"env": {
"LABMCP_ADDRESS": "<LABMCP_ADDRESS>",
"LABMCP_SIMULATE": "<LABMCP_SIMULATE>",
"LABMCP_READ_ONLY": "<LABMCP_READ_ONLY>",
"LABMCP_LIMITS": "<LABMCP_LIMITS>"
}
}
}
}
启动命令uvx labmcp-modbus
需要配置的环境变量
LABMCP_ADDRESSInstrument address, e.g. serial:///dev/ttyUSB0 or tcp://192.168.1.50:5025
LABMCP_SIMULATESet to 1 to use the built-in simulator (no hardware)
LABMCP_READ_ONLYSet to 1 to disable all state-changing tools
LABMCP_LIMITSSafety limit overrides, e.g. max_temperature_c=80

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
pypilabmcp-modbus0.1.3

工具

12

收录的工具列表 · 更新于 2 周前

此工具无需参数。

详细介绍

Modbus TCP/RTU 设备 — MCP 服务

让 AI Agent 通过以太网(Modbus TCP)或 RS-485/RS-232(Modbus RTU/ASCII)读取和控制 Modbus 设备:PID 温度控制器、循环冷却器、PLC、过程传感器、VFD 和数据记录仪。只需在 寄存器映射(YAML 或 JSON)中描述一次设备。之后,Agent 就可以使用带名称的点,以实际单位进行操作,例如 process_temperature = 37.2 °C 或 setpoint,而无需处理原始寄存器。服务会强制执行映射中的规则:只有 writable 点才能通过名称写入;每个可写数值都必须有 min 和 max,并且在发送任何内容前都会拒绝超出范围的值。映射还可以定义一个 安全状态,即一组点写入操作(关闭加热器、让控制器进入待机状态),供 SAFETY 工具按需执行。

Packagelabmcp-modbus
仪器任意 Modbus 设备:温度控制器(Watlow、Eurotherm、Omega、Autonics 等)、冷却器和循环器、PLC 和远程 I/O、传感器/变送器、VFD、电表、数据记录仪
接口以太网(Modbus TCP,端口 502)、RS-485 / RS-232(Modbus RTU 或 ASCII)、串口转以太网网关(RTU over TCP)
协议MODBUS 应用协议规范 V1.1b3、串行线路上的 MODBUS V1.02、TCP/IP 上的 MODBUS 消息传递实施指南 V1.0b;客户端通过 pymodbus 3.8+ 实现
状态🧪 模拟:已通过内存模拟控制器和本地 pymodbus 服务端测试,尚未在硬件上验证。报告硬件测试结果

与基础的寄存器读写型 Modbus MCP 相比,此服务增加了:

  • 带类型的寄存器映射: int16/uint16/int32/uint32/float32/float64/bool、字和字节顺序、scale 和 offset、单位、枚举(0 = 待机,1 = 自动)和描述。
  • 逐点限值: 可写点需要 min/max 或枚举,并且发送前会检查数值。映射点所属地址上的原始写入会被拒绝,因此无法绕过限值。
  • 读回验证: 每次 write_point 都会读取回数值,并报告是否匹配。
  • 安全状态: 在映射中定义的 apply_safe_state SAFETY 工具,即使处于 --read-only 模式也能运行。
  • 只读模式(--read-only)、记录每个请求和响应的 审计日志,以及有 上限 的请求大小。

无需硬件即可试用

uvx labmcp-modbus --simulate --check

模拟器是一个通用的单回路 PID 温度控制器。其布局采用随附的示例寄存器映射。该示例仅供说明,并非任何厂商寄存器映射的副本。加热器以全功率运行时的升温速率为 3 °C/s;它会加热热容体,而热容体会逐渐冷却至 22 °C 的室温(τ = 90 s)。PID 回路具有斜坡变化的工作设定点和报警位。对于未实现的地址,模拟器会返回异常 02;对于超出自身范围的数值(例如 500 °C 的设定点),会返回异常 03;对于错误的单元 ID,会返回异常 0B。使用 --simulate --option register_map=my_map.yaml 时,示例布局中没有的点会获得零初始化存储,因此你可以测试自己的映射。

连接设备

  1. **设备设置:**在设备的通信菜单中启用 Modbus,并记下相关设置。
    • **RTU(RS-485):**设置单元(从站)地址(1–247)、波特率、校验位和停止位。服务默认采用 Modbus 串行通信默认值:19200 波特、8 个数据位、偶校验、1 个停止位。许多设备出厂时采用其他设置(例如 9600 8N1);请在地址中填写设备的设置。将 USB-RS485 适配器的 A/B(D−/D+)线路连接到设备;不同厂商对 A/B 标记的定义不一致,因此如果没有响应,请交换线路。连接信号地,并在较长总线的两端各安装一个 120 Ω 终端电阻。
    • **TCP:**设置 IP 地址。除非更改,否则端口为 502。许多 TCP 设备会忽略单元 ID。如果你的设备不会忽略,通常应设为 1;TCP 实现指南建议直接寻址的设备使用 255。
  2. 根据设备的 Modbus 手册编写寄存器映射。复制示例,并参阅下文的寄存器映射。
  3. 测试连接:
    uvx labmcp-modbus --address tcp://192.168.1.20:502 --option register_map=~/maps/oven.yaml --check
    uvx labmcp-modbus --address "serial:///dev/ttyUSB0?baudrate=9600&parity=N" --option unit_id=3 \
        --option register_map=~/maps/controller.yaml --check
    uvx labmcp-modbus --address "serial://COM4?baudrate=19200&parity=E" --option register_map=C:/maps/chiller.json --check
    uvx labmcp-modbus --address "tcp://192.168.1.30:4001?framer=rtu" --check      # RTU through a transparent gateway
    
    --check 会建立连接,将映射中的第一个点作为探测点读取,并输出 probe: ok: … 或错误信息。其他地址参数:stopbits=2、bytesize=7、framer=ascii(Modbus ASCII)、timeout=1、retries=2。

寄存器映射

device:                 # optional
  name: Incubator oven
  manufacturer: Example
  model: X-100
  unit_id: 1            # --option unit_id overrides it
  word_order: big       # default for 32/64-bit points
  byte_order: big

points:
  chamber_temperature:
    table: input        # holding | input | coil | discrete
    address: 0          # 0-based protocol address ("30001" in the manual -> input 0)
    type: int16         # uint16 | int16 | uint32 | int32 | float32 | float64 | bool
    scale: 0.1          # value = raw * scale + offset
    unit: °C
    description: Chamber temperature
  setpoint:
    table: holding
    address: 0          # "40001" -> holding 0
    type: int16
    scale: 0.1
    unit: °C
    writable: true
    min: 20             # required for writable numbers: checked before sending
    max: 60
  mode:
    table: holding
    address: 1
    writable: true
    enum: {0: standby, 1: run}
  heater_enable:
    table: coil
    address: 0
    writable: true

safe_state:             # optional: run in order by apply_safe_state
  - {point: heater_enable, value: false}
  - {point: mode, value: standby}
字段默认值含义
table(必填)holding(FC03/06/16)、input(FC04,只读)、coil(FC01/05)、discrete(FC02,只读)
address(必填)从 0 开始的协议(PDU)地址。手册编号:4xxxx → holding xxxx − 1,3xxxx → input,1xxxx → discrete,0xxxx → coil
typeuint16(线圈/离散输入使用 bool)32 位类型使用 2 个寄存器,float64 使用 4 个。寄存器中的 bool 表示 0 = false,其他值 = true
word_order / byte_orderbig / bigbig/big = ABCD(最高有效寄存器在前)。little/big = CDAB(PLC 中常见)。big/little = BADC。little/little = DCBA
scale、offset1、0工程值 = 原始值 × scale + offset。写入值会按寄存器分辨率取整,并重新检查
unit、description""显示给 Agent
writablefalse只有保持寄存器和线圈可以设为可写
min、max无工程单位范围。可写数值点必须设置此项(除非使用 enum)
enum无整数点的 {number: label}。写入时可使用标签或数字

服务启动时会验证映射。未知字段(例如拼错的 maximum)和重复键(第二个 max,或重复定义某个点)都会报错,而不会被静默忽略,因此拼写错误不会导致限制失效。两个可写点不得共用同一个寄存器(写入其中一个会绕过另一个的限制);对可写寄存器提供只读视图则没有问题。如果映射无效,list_points 会显示错误,设备工具也会拒绝运行。服务会以失败关闭方式运行。

添加到 MCP 客户端

Claude Code

claude mcp add oven -- uvx labmcp-modbus --address tcp://192.168.1.20:502 --option register_map=/home/me/maps/oven.yaml

Claude Desktop / Cursor / Windsurf(claude_desktop_config.json、.cursor/mcp.json 等)

{
  "mcpServers": {
    "controller": {
      "command": "uvx",
      "args": [
        "labmcp-modbus", "--address", "serial:///dev/ttyUSB0?baudrate=9600&parity=N",
        "--option", "unit_id=1",
        "--option", "register_map=/home/me/maps/controller.yaml",
        "--option", "raw_writes=false"
      ]
    }
  }
}

实用标志:

  • --read-only 仅允许读取。apply_safe_state 仍可使用。
  • --option raw_writes=false 会移除 write_register、write_registers 和 write_coil,因此 Agent 只能写入映射允许的内容。完成映射后,建议启用此选项。

工具

工具类型描述
apply_safe_state🛑 安全将设备置于寄存器映射定义的安全状态(例如,关闭加热器输出、将控制器切换到待机状态),按顺序写入每个步骤并读取回读值。即使前面的步骤失败,也会尝试执行每个步骤。如果发现任何异常,请立即调用。只有在每个步骤都已写入并读取回读值,且回读值与请求值一致时,all_ok 才为 true;如果设备确认了写入却未执行(例如处于本地模式),该步骤仍不算成功。
get_command_log👁 读取返回最近发送到仪器的原始命令和从仪器收到的回复(最新的排在最后)。可用于调试和记录已执行的操作。
get_connection_info👁 读取报告已连接的仪器(标识、地址、模拟或真实)、服务是否为只读,以及当前生效的安全限制。请先调用此工具。
list_points👁 读取描述已加载的寄存器映射:设备、每个命名点(表、从 0 开始的地址、类型、缩放、单位、是否可写、最小值/最大值、枚举)以及安全状态步骤。无需连接即可使用。
read_coils👁 读取读取线圈(FC01):单比特输出,例如运行/停止状态或继电器状态。
read_discrete_inputs👁 读取读取离散输入(FC02):单比特只读状态,例如报警或限位开关。
read_points👁 读取从寄存器映射读取命名点,并解码、缩放为工程单位(例如 process_temperature = 25.1 °C)。无法读取的点会返回 error,而不会导致整个调用失败。
read_registers👁 读取读取原始保持寄存器或输入寄存器(无符号 16 位),可选择解码为 int16、32 位或 64 位值。用于探索设备;如果寄存器映射中描述了某个寄存器,优先使用 read_points。
reconnect🛑 安全关闭并重新打开与仪器的连接(例如,仪器断电重启或重新插拔电缆后)。
write_coil⚠️ 危险切换一个原始线圈(FC05)。线圈通常会启动或停止设备(加热器、泵、电机);此处不允许写入已映射的线圈(请使用 write_point)。
write_point⚠️ 危险写入寄存器映射中的命名点(设定值、模式、输出启用状态等)。发送前会检查该点的可写标记、最小值/最大值或枚举,将值转换为原始寄存器,写入后再读取回读值。更改设定值和输出会影响真实设备。如果写入成功但回读失败,read_back_error 会说明原因。
write_register⚠️ 危险写入一个原始保持寄存器(FC06)。不会应用缩放或限制,因此仅用于寄存器映射未描述的地址(已映射的地址不允许写入,请使用 write_point)。如果寄存器可读,则返回回读值。
write_registers⚠️ 危险写入连续的原始保持寄存器(FC16),例如写入一个 32 位值的两半。不会应用缩放或限制;已映射的地址不允许写入(请使用 write_point)。

get_connection_info、get_command_log 和 reconnect 内置于每个 LabMCP 服务中。只有当寄存器映射定义了 safe_state 时,才会列出 apply_safe_state。

安全限制

此服务没有全局 --limit 值:通用 Modbus 客户端无法知道寄存器的含义。保护措施来自寄存器映射和服务端:

保护措施位置
writable: false(默认值)write_point 会拒绝该点
每个点的 min / max / enumwrite_point 会在发送前拒绝超出范围的值,并在按寄存器分辨率(整数或 float32)舍入后再次检查
映射地址保护write_register(s) / write_coil 会拒绝任何与映射点重叠的地址
--option raw_writes=false完全移除原始写入工具
--read-only移除所有写入工具。保留 apply_safe_state
映射中的 safe_stateapply_safe_state 按顺序写入每个步骤并读回。即使某一步失败,也会尝试所有步骤。只有读回值匹配时,步骤才算 ok,因此设备虽确认但忽略写入(本地/键盘模式)时,会报告这一情况,而不会将其视为可信
请求边界每个请求最多 1–125 个寄存器(FC03/04)、1–2000 个位(FC01/02)、1–123 个寄存器(FC16),符合规范
不支持广播串行线路上的单元 ID 0 会被拒绝:它会向所有设备写入,而且设备不会回复广播

提示词示例

  • “现在的腔体温度和输出功率是多少?请列出每个点及其单位。”
  • “以 2 °C/min 的速率将控制器升至 55 °C,切换到自动模式,启用加热器,并在温度与设定值相差不超过 0.5 °C 时告诉我。”
  • “将高报警设为 70 °C,然后检查是否有任何报警或传感器故障位处于激活状态。”
  • “读取保持寄存器 100–109,并尝试按两种字顺序解码为 float32。我正在映射一台新冷水机。”
  • “出了点问题:将控制器置于安全状态,并确认加热器已关闭。”

说明

  • 线路上的地址从 0 开始。 手册通常使用从 1 开始的“Modicon”编号(40001 = 保持寄存器 0)。如果每次读取都偏移一个寄存器,说明映射使用了错误的编号约定。
  • 32 位值的字顺序没有标准化:Modbus 规范只定义寄存器内的字节顺序。如果浮点数或 32 位值看起来不合理,请尝试 word_order: little。read_registers 配合 decode_as 可帮助你找到正确的顺序。
  • 如果浮点点位读到 NaN 或无穷大(许多设备用 NaN 表示“无值”,例如传感器故障),返回结果中的 value 会是 null,并包含 error;read_registers 配合 decode_as 会将其显示为 "nan"/"inf"。
  • write_point 对单寄存器点使用 FC06,对多寄存器点使用 FC16,对线圈使用 FC05。少数设备即使写入单个寄存器,也只接受 FC16。对于这些设备,请将该值映射为多寄存器点的一部分,或报告此情况,以便我们添加相应选项。
  • 有些控制器会将写入的参数保存到非易失性存储器中,而该存储器只能承受有限次数的写入循环。不要让 Agent 在短时间内反复改写设定值。请检查手册是否提供仅写入 RAM 的寄存器或远程设定值寄存器。
  • 读取通常没有副作用,但少数设备会在读取时清除计数器或报警。请勿将此类寄存器纳入映射,或在 description 中标明。
  • Modbus TCP 设备通常只接受少量并发连接。如果连接被拒绝,请关闭其他 SCADA 或日志记录客户端。
  • 超时几乎总是意味着单元 ID、波特率、奇偶校验或 A/B 接线错误。异常 02 表示设备未实现该地址。异常 03 表示设备根据自身内部限制拒绝了该值。
  • 兼容 pymodbus 3.8 或更高版本(单元参数关键字在 3.10 中从 slave= 改为 device_id=;两者均受支持)。
  • 随附的映射仅为示例。欢迎贡献真实设备映射:请注明地址所依据的手册标题和修订版本。

硬件验证

型号固件接口验证者日期
尚无: 成为首位验证者

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。