
Modbus TCP/RTU Device
io.github.K-Dense-AIPublished by GitHub account K-Dense-AIv0.1.3Updated Oct 24, 2026
MCP server for Modbus TCP/RTU devices with typed, scaled register maps and per-point limits.
Overview
A local MCP server that lets an assistant read and control Modbus TCP/RTU devices through a typed, scaled register map with per-point limits.
- What you can do
- Read named points decoded into engineering units, plus raw holding and input registers, coils and discrete inputs, and inspect the loaded register map and connection info and command log. Write named points such as setpoints, modes and outputs, with values checked against writable flags, min/max or enums before sending and read back afterwards. Write raw registers and coils for addresses the map does not describe. Run a safe-state sequence defined in the map, and reconnect after a power cycle or cable change.
- When to use it
- Use it when an assistant should monitor or adjust lab and industrial Modbus equipment such as temperature controllers, chillers, PLCs, sensors, VFDs or data loggers, and you can supply a register map for the device. It suits supervised setpoint changes and safe-state recovery more than unattended control.
- Requirements
- Runs locally as a Python package (uvx labmcp-modbus) over stdio. Needs a register map file (YAML or JSON) and a device address via LABMCP_ADDRESS or the address flag, for example a TCP host and port or a serial port with baud rate and parity. Network or serial access to the device is required; a built-in simulator works without hardware.
Installation
In SourceWeft
- Open Modbus TCP/RTU Device in the dashboard and add it to a workspace.
- Enable the server for the chats that should use its tools.
Desktop only via STDIO. STDIO servers start a local process, so they need the SourceWeft desktop host.
Other MCP clients
Follow the launch instructions in the repository.
README
Modbus TCP/RTU Device — MCP Server
Let an AI agent read and control Modbus devices over Ethernet (Modbus TCP) or RS-485/RS-232 (Modbus RTU/ASCII): PID temperature controllers, recirculating chillers, PLCs, process sensors, VFDs and data loggers. You describe the device once in a register map (YAML or JSON). The agent then works with named points in real units, such as process_temperature = 37.2 °C or setpoint, instead of raw registers. The server enforces the map's rules: only writable points can be written by name, every writable number must have a min and max, and out-of-range values are refused before anything is sent. The map can also define a safe state, a list of point writes (heater off, controller to standby) that a SAFETY tool runs on request.
What this server adds over a plain register-poking Modbus MCP:
- Typed register maps: int16/uint16/int32/uint32/float32/float64/bool, word and byte order,
scaleandoffset, units, enums (0 = standby, 1 = auto) and descriptions. - Per-point limits: writable points need
min/maxor an enum, and values are checked before sending. Raw writes to addresses that belong to a mapped point are refused, so the limits can't be bypassed. - Read-back: every
write_pointreads the value back and reports whether it matches. - Safe state: an
apply_safe_stateSAFETY tool, defined in the map, that works even in--read-onlymode. - Read-only mode (
--read-only), an audit log of every request and reply, and bounded request sizes.
Try it without hardware
The simulator is a generic single-loop PID temperature controller. Its layout is the bundled example register map. It is illustrative and not a copy of any vendor's map. A heater (3 °C/s at full power) heats a thermal mass that cools towards a 22 °C room (τ = 90 s). The PID loop has a ramping working setpoint and alarm bits. The simulator answers exception 02 for unimplemented addresses, 03 for values outside its own range (e.g. a 500 °C setpoint), and 0B for a wrong unit id. With --simulate --option register_map=my_map.yaml, points that are not in the example layout get zero-initialised storage, so you can test your own map.
Connect your device
- Device setup: in the device's communications menu, enable Modbus and note its settings.
- RTU (RS-485): set the unit (slave) address (1–247), baud rate, parity and stop bits. The server defaults to the Modbus serial default of 19200 baud, 8 data bits, even parity, 1 stop bit. Many devices ship with other settings (e.g. 9600 8N1); put your device's settings in the address. Wire the USB-RS485 adapter's A/B (D−/D+) lines to the device; vendors disagree on the A/B labels, so swap them if nothing answers. Connect the signal ground, and put 120 Ω termination at both ends of longer buses.
- TCP: set the IP address. The port is 502 unless changed. Many TCP devices ignore the unit id. If yours does not, it is usually 1; the TCP implementation guide recommends 255 for directly addressed devices.
- Write a register map for your device from its Modbus manual. Copy the example and see Register map below.
- Test the connection:
--checkconnects, reads the map's first point as a probe and printsprobe: ok: …or the error. More address parameters:stopbits=2,bytesize=7,framer=ascii(Modbus ASCII),timeout=1,retries=2.
Register map
The server validates the map when it starts. Unknown fields (e.g. a misspelt maximum) and repeated keys (a second max, or a point defined twice) are errors rather than being silently ignored, so a typo can't remove a limit. Two writable points may not share a register (writing one would bypass the other's limits); read-only views of a writable register are fine. If the map is invalid, list_points shows the error and the device tools refuse to run. The server fails closed.
Add to your MCP client
Claude Code
Claude Desktop / Cursor / Windsurf (claude_desktop_config.json, .cursor/mcp.json, …)
Useful flags:
--read-onlyallows reads only.apply_safe_statestays available.--option raw_writes=falseremoveswrite_register,write_registersandwrite_coil, so the agent can only write what the map allows. This is recommended once your map is complete.
Tools
get_connection_info, get_command_log and reconnect are built into every LabMCP server. apply_safe_state is listed only when the register map defines a safe_state.
Safety limits
This server has no global --limit values: a generic Modbus client can't know what a register means. The protections come from the register map and the server:
Example prompts
- "What's the chamber temperature and output power right now? Show every point with its unit."
- "Ramp the controller to 55 °C at 2 °C/min, switch it to auto, enable the heater, and tell me when it's within 0.5 °C of setpoint."
- "Set the high alarm to 70 °C, then check whether any alarm or sensor-fault bits are active."
- "Read holding registers 100–109 and decode them as float32 (try both word orders). I'm mapping a new chiller."
- "Something's wrong: put the controller in its safe state and confirm the heater is off."
Notes
- Addresses are 0-based on the wire. Manuals often use 1-based "Modicon" numbers (40001 = holding 0). If every read is off by one register, the map uses the wrong convention.
- Word order is not standardised for 32-bit values: the Modbus spec only defines byte order within a register. If a float or 32-bit value looks absurd, try
word_order: little.read_registerswithdecode_ashelps you find the right order. - A float point that reads NaN or infinity (many devices use NaN as "no value", e.g. a sensor fault) comes back with
value: nulland anerror;read_registerswithdecode_asshows it as"nan"/"inf". write_pointuses FC06 for single-register points, FC16 for multi-register points and FC05 for coils. A few devices accept only FC16 even for single registers. For those, map the value as part of a multi-register point or report it so we can add an option.- Some controllers save written parameters to non-volatile memory, which survives only a limited number of write cycles. Don't have the agent rewrite setpoints in a tight loop. Check whether the manual offers a RAM-only or remote setpoint register.
- Reading is normally side-effect free, but a few devices clear counters or alarms when they are read. Leave such registers out of the map or mark them in
description. - Modbus TCP devices often accept only a few simultaneous connections. Close other SCADA or logging clients if the connection is refused.
- Timeouts nearly always mean a wrong unit id, baud rate, parity or A/B wiring. Exception 02 means an address the device does not implement. Exception 03 means the device rejected the value by its own internal limits.
- Works with pymodbus 3.8 or newer (the unit keyword changed from
slave=todevice_id=in 3.10; both are handled). - The bundled map is an illustrative example. Contributions of real device maps are welcome: include the manual title and revision the addresses came from.
Hardware verification
Source: servers/protocols/modbus/README.md at commit 46545ea
Tools
0Version history
2- v0.1.3LatestSep 27, 2026
- v0.1.1Sep 26, 2026
Score
50% of the applicable checks met
How complete this listing is, computed from the registry entry, the endpoint and public sources. Not a rating of the server and not a statement that it is safe or working today: reachability is a dated check, and no installs or reviews go into the score.
- Reached in the last 30 days25 pts
Keep the endpoint answering the MCP handshake; SourceWeft probes it every 30 days.
- Auth declared10 pts
Declare the credential headers in the registry entry, or keep the endpoint answering the probe so its auth can be classified.
- Tools listed15 pts
Answer tools/list without a credential, or ship a package that starts in a sandbox without one.
- DescriptionRequired15 pts
- Logo10 pts
- Documentation15 pts
- License10 pts