Specification · section 9
Transports and discovery
MHP defines two transports, mirroring MCP.
stdio. Newline-delimited JSON-RPC on the driver process's stdin and stdout. For a driver running on the bench PC, launched by the host.
HTTP. POST /rpc for requests. GET /events is a Server-Sent Events stream of notifications. GET /mhp.json returns the descriptor with no handshake, so an agent, or a person with curl, can learn what a device is from its URL alone. Clients SHOULD send an X-MHP-Client header so leases and audit logs can name them.
Network discovery. Servers SHOULD advertise via mDNS / DNS-SD as _mhp._tcp with TXT records id, class and path=/mhp.json; the reference HTTP transport does so when the optional zeroconf package is installed. Clients discover devices two ways, and SHOULD use both: browse _mhp._tcp, and probe GET /mhp.json on candidate hosts across the conventional port range (18900 to 18939), which works on networks that block multicast. Labs MAY additionally run a directory (§3.2).
9.1 The fleet and mhp_lab
A host keeps a fleet: the list of devices it knows, persisted as ~/.openmhp/fleet.json, each entry an id, a target and the device's card. Device packages the host owns are hosted in-process from ~/.openmhp/devices/<id>/, so a scientist's laptop needs no separate device servers for them. The bridge exposes the fleet through one tool, mhp_lab:
| op | Effect |
|---|---|
status | how many devices the lab has and what to do next; the agent's starting point |
scan | mDNS browse plus HTTP probe of localhost and any hosts given; returns devices not yet in the fleet |
add | register a target (http://host:port, a package folder, or a package id under ~/.openmhp/devices); fetches the card; immediately searchable |
onboard | a guided interview run by the server: returns the next questions in plain words and the shape of the answer; on completion the server writes DEVICE.md, descriptor.yaml and driver.py, validates, and asks the agent to add |
new | create a package skeleton for agents that prefer to write files themselves |
write | write files into that package; paths may not escape it |
validate | run the package validator |
recipes, registry | search tested procedures; search community packages (add one with github:owner/repo/path, sim=true for its simulated twin) |
safety_card | a readable review before first use: enforced limits, gated actions, e-stop, watchdog, validator findings, live probes |
events | what happened since a sequence number |
list, remove, home | membership and paths |
The bridge also declares MCP instructions on initialize, so a harness with no skills support still receives the operating loop and the setup path, and three MCP prompts (setup-my-lab, add-instrument, run-experiment) that harnesses surface as slash commands.
No-code drivers. The interview asks how the instrument is controlled today and picks a driver kind. manual wraps an instrument a person operates: settings and actions return an instruction for the operator, and a record action stores what they read off the display. serial is a declarative driver for text commands over a serial or USB port, declared under serial: in descriptor.yaml. mhp means the instrument already has an address. adapter leaves driver.py for the fleet skill. The descriptor, gates and levels are the same in every kind.
This is how a scientist adds an instrument without leaving the conversation: "find the instruments on my network" runs scan; "add the thermocycler" runs add. For an instrument with no MHP server, the openmhp-onboard-device skill interviews the owner and the agent writes the package with new, write and validate, then adds it. The npx @sinkush/openmhp launcher installs the runtime, the skills and the harness registration in one command.
Authentication is transport-level and out of scope for 0.1. HTTP deployments SHOULD sit behind TLS with bearer tokens or mutual TLS. The protocol reserves params.auth for a future in-band scheme.