Build
Lab nodes
The two-computer setup most labs already have: instruments wired to a bench PC, an agent on your laptop. One command on each, and they find each other over the network. When the lab network is closed to the outside, the bench PC dials out instead, and nothing is opened.
| Machine | What you run | What it does |
|---|---|---|
| The computer wired to your instruments | npx openmhp-node setup | serves each instrument over HTTP, advertises them on the LAN, keeps doing it after a reboot |
| Your laptop | npx openmhp-cli setup | the agent harness and the MCP bridge; finds nodes and operates what they serve |
| A gateway on the company network (only when the lab network is closed) | mhp gateway init / serve | bench PCs dial out to it; agents reach every instrument through it. See gateway and relay |
They can be the same machine. If your agent runs on the bench PC itself, install both and skip the network entirely — nothing else about the setup changes.
On the instrument computer
This is the machine with the USB cable, the vendor software, or the network link to the instrument. It never needs an agent on it.
npx openmhp-node setup
It asks two questions — which folder holds your device packages (default ~/.openmhp/devices) and which port to start counting from (default 18900) — then installs a background service and starts it:
[openmhp] found 3 package(s): balance-02, hotplate-01, pump-03
wrote /home/lab/.config/systemd/user/openmhp-node.service
systemctl --user daemon-reload: ok
systemctl --user enable --now openmhp-node.service: ok
installed. running now, and at every login.
From then on the machine answers on its own. Two commands manage it:
npx openmhp-node status # installed? running?
npx openmhp-node stop # remove the service
The service is a systemd --user unit on Linux, a LaunchAgent on macOS, and a Startup-folder entry on Windows. On Windows that means it starts once someone logs in, not before; on a headless Linux bench PC where nobody stays logged in, also run loginctl enable-linger $USER so the unit survives logout.
One computer, several instruments
Common case: a USB hub with a hotplate, a balance and a syringe pump on it. One node process serves all of them — you do not run one per instrument. What the node needs is one device package per instrument in that folder, because it serves packages, not USB ports. It does not scan the bus and guess what is plugged in; each package says which port its instrument is on, along with its limits and how to stop it.
~/.openmhp/devices/
├── balance-02/ DEVICE.md + descriptor.yaml (serial.port: /dev/ttyUSB1)
├── hotplate-01/ DEVICE.md + descriptor.yaml (serial.port: /dev/ttyUSB0)
└── pump-03/ DEVICE.md + descriptor.yaml (serial.port: /dev/ttyUSB2)
Each gets its own port, counting up from the base, and each is advertised separately, so they arrive in a scan as three instruments rather than one computer:
| Package folder | Serial port | Served at |
|---|---|---|
balance-02 | /dev/ttyUSB1 | http://bench-pc:18900 |
hotplate-01 | /dev/ttyUSB0 | http://bench-pc:18901 |
pump-03 | /dev/ttyUSB2 | http://bench-pc:18902 |
Ports follow the folder names alphabetically, not the order things are plugged in — which is why the balance on ttyUSB1 is first. One consequence worth knowing: adding a package whose name sorts earlier shifts the ones after it by a port. Discovery re-announces either way, so a fresh scan is always correct, but an entry you added by hand to your lab may need adding again.
Keep the port names stable
On Linux, /dev/ttyUSB0 is assigned in the order devices appear, so two instruments on one hub can swap after a reboot — and a driver that opens the wrong one will happily send a hotplate's command to a pump. Use the stable path instead:
serial:
port: /dev/serial/by-id/usb-FTDI_FT232R_A50285BI-if00-port0
baud: 9600
Run ls /dev/serial/by-id/ with the instrument plugged in to find its name. On Windows the COM number is remembered per adapter, so COM3 generally stays with the same instrument; confirm in Device Manager.
On your laptop
npx openmhp-cli setup
Then open your agent and say "find the instruments on my network", or do it from the shell:
npx openmhp-cli scan
[
{ "target": "http://10.0.0.41:18900", "id": "balance-02", "class": "balance", "state": "idle" },
{ "target": "http://10.0.0.41:18901", "id": "hotplate-01", "class": "hotplate", "state": "idle" },
{ "target": "http://10.0.0.41:18902", "id": "pump-03", "class": "pump", "state": "idle" }
]
Add the ones you want, and tell the lab where they stand, since a package cannot know that:
npx openmhp-cli add http://10.0.0.41:18901 --location "bay 3, fume hood 2"
From then on they are in mhp_find results for every agent pointed at that bridge, with their owner's operating instructions and safety envelope attached.
When scan finds nothing
scan works two ways at once: it listens for mDNS adverts (_mhp._tcp) and probes ports 18900 to 18939 on localhost. Across machines it is the mDNS half that does the work, and multicast is the part most likely to be blocked — by a corporate network, a guest VLAN, or the two machines simply being on different subnets. Name the host directly and it probes that instead:
npx openmhp-cli scan 10.0.0.41 # or bench-pc.local
npx openmhp-cli add http://10.0.0.41:18901 # or skip scanning; the address is enough
Other things worth checking, in order: the node is running (npx openmhp-node status on the bench PC), it was started with --host set to the bench PC's address (a node listens on 127.0.0.1 only until you say otherwise), the firewall allows inbound on those ports, and the instruments sit inside 18900–18939 if you want the plain probe to find them — a base port outside that range still works, you just have to name the address yourself.
If the answer to the firewall question is "IT will not open it", stop here and use the relay below. It is built for exactly that case.
Behind the lab firewall
In most companies the instrument network is one nothing outside may enter, and IT will not add a rule for a lab PC. OpenMHP does not need one: the bench PC dials out over HTTPS to a gateway on the company network and takes its work from there, and your agent talks to the gateway. The node command is the same one as above with --join added once:
mhp node C:\lab\devices --join https://gw.office ab12-cd34
How it works, how to set up the three machines, and what the relay guarantees are on their own page: gateway and relay.