Node Reach Protocol — The universal standard for AI-to-world control.
Project description
NRP
Node Reach Protocol
The universal standard for AI-to-world control.
MCP connects LLMs to software.
NRP connects LLMs to everything else.
Servers · Robots · Drones · Sensors · Vehicles · APIs · Factories · Smart Homes
The Problem
Every device speaks a different language. SSH for servers. ROS2 for robots. MQTT for sensors. OPC-UA for factories. REST for APIs. Hundreds of protocols. Thousands of SDKs. No standard.
MCP standardized software integration. NRP does the same for hardware and physical systems.
The Protocol
3 methods. That is the interface.
OBSERVE → read state (sensors, metrics, cameras, APIs)
ACT → change state (commands, movements, writes, calls)
SHIELD → safety limits (boundaries the AI cannot cross)
Every device becomes a node. Every node has an address:
nrp://factory/robot/arm-7
nrp://farm/sensor/soil-north
nrp://cloud/api/stripe
nrp://home/light/kitchen
nrp://fleet/vehicle/truck-42
Every node describes itself. The AI reads the manifest and knows what to do. Zero configuration. Zero documentation.
Write a Driver in 100 Lines
from nrp import NRPDriver, NRPManifest, ChannelSpec, ActionSpec, ShieldSpec
class MyRobot(NRPDriver):
def manifest(self) -> NRPManifest:
return NRPManifest(
nrp_id=self._nrp_id,
manufacturer="Unitree", model="G1",
observe=[
ChannelSpec("joints", "float[]", unit="rad", rate="100Hz"),
ChannelSpec("battery", "int", unit="percent"),
ChannelSpec("camera", "image", rate="30Hz"),
],
act=[
ActionSpec("walk", {"speed": "float m/s"}, "Walk forward", dangerous=True),
ActionSpec("pick", {"target": "string"}, "Pick an object", dangerous=True),
ActionSpec("stand", {}, "Stand still"),
],
shield=[
ShieldSpec("max_speed", "limit", 1.5, "m/s"),
ShieldSpec("workspace", "zone", [0, 0, 10, 10], "meters"),
],
)
async def observe(self, channels=None):
return {"joints": self.read_joints(), "battery": self.read_battery()}
async def act(self, command, args):
if command == "walk":
return self.walk(args["speed"])
if command == "pick":
return self.pick(args["target"])
def shield_rules(self):
return [ShieldRule("max_speed", ShieldType.LIMIT, 1.5)]
What the AI Sees
When a node connects, the AI receives a human-readable description:
Node: nrp://factory/robot/g1-01
Device: Unitree G1
Observe (read state):
joints: float[] (rad) — Joint angles at 100Hz
battery: int (percent) — Battery level
camera: image — Camera feed at 30Hz
Act (commands):
walk(speed: float m/s) [DANGEROUS] — Walk forward
pick(target: string) [DANGEROUS] — Pick an object
stand() — Stand still
Shield (safety limits):
max_speed: limit = 1.5 m/s
workspace: zone = [0, 0, 10, 10] meters
Real-Time Events
Nodes push events. The AI reacts without polling.
# The node pushes
await driver.emit("battery_low", Severity.WARNING, percent=8)
await driver.emit("collision", Severity.EMERGENCY, force=45.2)
# The control plane routes
bus.subscribe("battery_*", alert_handler)
bus.subscribe("nrp://factory/*", factory_monitor)
Emergency events bypass all queues and are processed synchronously.
Specification
| Document | Description |
|---|---|
| IDENTITY.md | Universal addressing: nrp://scope/kind/name |
| MANIFEST.md | Self-describing nodes: channels, actions, shields |
| EVENTS.md | Real-time push: severity levels, emergency bypass |
| NRP_SPEC.md | Protocol overview |
Install
pip install nrp
Examples
hello_ssh.py— Connect to a server in 60 linesmulti_node.py— 3 sensors, 1 conversation
Built With NRP
| Project | Description |
|---|---|
| Halyn | NRP control plane with domain-scoped authorization |
Why Not Just Use MCP?
MCP is brilliant for software. But:
- MCP has no concept of physical safety (shield rules)
- MCP has no concept of real-time events (push, not pull)
- MCP has no concept of self-describing hardware (manifests)
- MCP has no concept of universal device identity (
nrp://) - MCP tools are defined by the server. NRP tools are declared by the device.
NRP complements MCP. A control plane exposes NRP nodes as MCP tools — transparent to the LLM.
Architecture
Any LLM (Claude, GPT, Ollama, local)
│
│ MCP (software)
│
▼
Control Plane (e.g. Halyn)
│
│ NRP (physical + digital world)
│
├──→ Servers (SSH)
├──→ Robots (ROS2, Unitree, DJI)
├──→ Sensors (MQTT)
├──→ APIs (REST, GraphQL — auto-introspected)
├──→ Containers (Docker)
├──→ Browsers (Chrome CDP)
├──→ Factories (OPC-UA, Modbus)
├──→ Vehicles (CAN, DDS)
└──→ Anything with an interface
Contributing
See CONTRIBUTING.md. A driver is 4 methods, ~100 lines. If it has an interface, it can be an NRP node.
License
MIT — Free forever. Use it. Build on it.
Author
Elmadani SALKA
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file nrprotocol-0.1.0.tar.gz.
File metadata
- Download URL: nrprotocol-0.1.0.tar.gz
- Upload date:
- Size: 13.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
da47e459349c03807661185285a2f08be7efd325ebca8f9d2ee20d5b791015f5
|
|
| MD5 |
fe26a0ba0e64e693b06117dde681a357
|
|
| BLAKE2b-256 |
c00d47e111b11522e2dffbf3fb4a97951628f21acfbc87b157a67cc55d7d49c2
|
File details
Details for the file nrprotocol-0.1.0-py3-none-any.whl.
File metadata
- Download URL: nrprotocol-0.1.0-py3-none-any.whl
- Upload date:
- Size: 12.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
79e7d7e85f3e5bdde7149eaf888ec22d9ae4a56a883302359dd69ec05ce5597b
|
|
| MD5 |
e540a030eff0ef29d256057f71e71127
|
|
| BLAKE2b-256 |
bbfe4b3a5e880ffc604be1ea3aab4c88b5da016ce78f80c4643e15967425c109
|