Build

Gateway and relay

Most instrument networks are closed: nothing outside may connect in, and IT will not add a rule for a bench PC. OpenMHP works there without one. The bench PC dials out to a gateway on the company network and asks it for work; your agent talks to the gateway. Nothing is opened, and the bench PC never needs an AI agent on it.

The shape of it

Three kinds of machine, and every connection between them points at the one in the middle.

Three zones. Bench PCs on the lab network, behind a dashed firewall line, run mhp node and connect outward to one gateway on the company network. Agent machines, an office laptop and a home laptop on the VPN, reach the same gateway with an agent token. The gateway has a node face, an agent face and a directory. Every arrow points at the gateway; none enters the lab.
Every arrow points at the gateway. The lab firewall sees only outbound HTTPS from the bench PCs, which is what it already allows for a web browser.

Nobody has to run this in a cloud. The gateway belongs on the company network, where people in the office and people on the VPN already are. IT has one line to confirm: lab PCs and agent machines can reach the gateway's address and port.

What happens on one call

The relay is ordinary HTTPS from both sides, with the bench PC asking for work instead of waiting for it. That is the whole trick, and it means the gateway never has to connect into the lab.

Sequence diagram. The lab PC already has GET /relay/next open on the gateway and waits up to 25 seconds for work. The agent posts a JSON-RPC request with its token to the device URL on the gateway. The gateway checks the token and queues the request with the agent's name as the client. It answers the open poll with the request, once. The driver on the lab PC runs it, enforcing limits, interlocks, approvals and e-stop. The lab PC posts the reply; the gateway returns it to the agent. Events go up as a batch and down as server-sent events. If the lab PC is offline the agent gets 503 at once; if it does not answer within 120 seconds, 504; the request is dropped either way and never re-sent.
One request, one delivery. The driver on the bench enforces every limit exactly as it would for an agent on the lab network.
  1. The bench PC keeps a long-poll open on the gateway, GET /relay/next, and renews it every 25 seconds. That poll is also how the gateway knows the PC is alive.
  2. Your agent sends the usual request to the usual kind of URL, POST /<node>/<device>/rpc, with its agent token. An unknown token is refused before anything is queued.
  3. The gateway queues the request with the agent's name as the client, so leases on the bench PC are per agent, and carries a person's approval because it authenticated who asked.
  4. The gateway answers the open poll with the request. It is handed over once.
  5. The driver runs it on the bench PC. Limits, interlocks, approval levels and the e-stop are enforced there, beside the hardware, as always.
  6. The bench PC posts the reply; the gateway matches it to the waiting request and returns it. Notifications travel the same road, batched upward within half a second and streamed to the agent as server-sent events.

Once, or not at all

If the bench PC is offline, which the gateway decides when no poll has arrived for 45 seconds, the agent gets a 503 at once naming the PC and when it was last seen. If the PC is online but does not answer within the timeout, 120 seconds unless the agent asks for longer with X-MHP-Timeout, the agent gets a 504. In both cases the request is dropped and never re-sent on the agent's behalf, because starting a protocol twice is not the same as starting it once. The agent checks the job's status before repeating anything, which is what the specification asks of it on any transport.

Pairing and trust

Three commands set it up, and each one hands out a different secret to a different machine.

Three steps. On the gateway, mhp gateway pair prints a one-time code valid fifteen minutes and the certificate fingerprint. On the lab PC, once, mhp node with --join, the gateway URL and the code compares the fingerprint, pins the certificate, receives a node token, saves node.json and serves; later runs reconnect by themselves. For each agent machine, mhp gateway add-agent prints the agent token, the certificate to trust and the mhp-mcp --directory line. The certificate is pinned by everyone, the node token never leaves the lab PC, the agent token names the session.
Codes last fifteen minutes and work once. A reinstalled bench PC pairs again with a new code and gets its own name back; the old token stops working.

On the gateway machine, once

Any always-on desktop or small VM on the company network. pip install openmhp, then:

mhp gateway init                      # asks for the address others will use and a port; makes a certificate
mhp gateway serve --install-service   # runs now and after every reboot

The gateway listens on that one address only, never on every interface. If IT gives you a certificate, pass --cert and --key to init; otherwise it makes one, and every machine that joins pins it. TLS 1.2 is the oldest it will speak.

For each lab PC

On the gateway, mhp gateway pair prints a one-time code and the exact line to run. On the lab PC, where the device packages live:

pip install openmhp
mhp node C:\lab\devices --join https://gw.office ab12-cd34

It shows the gateway's certificate fingerprint so you can compare it with what pair printed, joins, and serves. From then on plain mhp node C:\lab\devices reconnects by itself, and --install-service keeps it running. If the gateway is down the node retries quietly and the instruments keep working for anyone on the lab network. If a config.json is missing or a port is taken, it says so in words before it serves anything.

For each agent machine

On the gateway, mhp gateway add-agent kushal-laptop prints a token for OPENMHP_DEVICE_TOKEN, the certificate to trust if it is self-made, and one line:

mhp-mcp --directory https://gw.office/directory/

Your agent now finds every instrument of every joined lab PC through that one URL.

Day to day

mhp gateway status                # which lab PCs are connected, what they serve, each agent's URL
mhp gateway check                 # OK or FIX for the gateway, each lab PC and each instrument, with the fix spelled out
mhp gateway remove-node bench-2   # its token stops working; pair again to bring it back
mhp gateway remove-agent old-laptop

Both the gateway and the node install as a user service: systemd on Linux, a LaunchAgent on macOS, a Startup-folder entry on Windows. mhp gateway check is the thing to run when something seems off; it tells you which of the three machines to look at.

What the relay guarantees

What it is not

It is not a VPN into the lab, and it does not make the lab network reachable: only the instruments a bench PC chose to serve are visible, and only through the gateway's device URLs. It is not a message queue: nothing is stored for later delivery, by design. And it is not required. On an open lab network, lab nodes find each other over mDNS and the gateway never enters the picture.

The full bench-side guide, including which files hold what, is docs/relay.md in the repository, and the alternatives that were weighed are in docs/firewalled-labs.md. The wire-level rules are in the specification.

Next