Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion plugins/robot-md/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "robot-md",
"displayName": "robot-md",
"version": "0.6.0",
"version": "0.6.1",
"description": "Connect a robot to Claude through its ROBOT.md: read capabilities and safety limits, drive it through the robot-md MCP server, keep AI-driven motion behind a gate and test its limits with Bounded Embodiment, and manage its identity, keys and EU AI Act evidence at the Robot Registry Foundation. Requires `pip install 'robot-md[hardware]'`.",
"author": {
"name": "Robot Registry Foundation",
Expand Down
4 changes: 2 additions & 2 deletions plugins/robot-md/.mcp.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"robot-md": {
"command": "robot-md",
"args": ["mcp"]
"command": "python3",
"args": ["${CLAUDE_PLUGIN_ROOT}/scripts/start-mcp-server.py"]
}
}
4 changes: 2 additions & 2 deletions plugins/robot-md/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ The robot-md plugin connects a robot to Claude through the `ROBOT.md` at the roo
| `bounded-embodiment` skill | Keeps AI-driven motion behind a gate, drafts envelopes, rehearses EV-03 and EV-10 in simulation, reads verdicts honestly | [plugins/bounded-embodiment](../bounded-embodiment/skills/bounded-embodiment) |
| `rrf-registry` skill | Registers the robot, rotates and revokes keys, proves manufacturer identity, emits and submits EU AI Act evidence | this plugin |
| `/robot-md:enable-dispatch` | Writes dispatcher config and bearer tokens without printing the token into the conversation | [robot-md-mcp](https://github.com/RobotRegistryFoundation/robot-md-mcp/tree/main/commands) |
| `robot-md` MCP server | Manifest reads plus motion (`execute_task`, `execute_capability`, `vision_find`, `estop`), served by `robot-md mcp` | [robot-md](https://github.com/RobotRegistryFoundation/robot-md) (PyPI) |
| `robot-md` MCP server | Manifest reads plus motion (`execute_task`, `execute_capability`, `vision_find`, `estop`). `scripts/start-mcp-server.py` finds your installed `robot-md` CLI and runs `robot-md mcp` | [robot-md](https://github.com/RobotRegistryFoundation/robot-md) (PyPI) |

## Install

Expand All @@ -34,4 +34,4 @@ The MCP server runs locally and sends nothing to the Robot Registry Foundation.

## Keeping copies in sync

The `using-robot-md`, `bounded-embodiment` and `enable-dispatch` files here are copies. Edit the canonical source, then run `scripts/sync-robot-md.sh` from the repository root. CI fails when a copy drifts.
The `using-robot-md`, `bounded-embodiment` and `enable-dispatch` files, `.mcp.json` and `scripts/start-mcp-server.py` here are copies. Edit the canonical source, then run `scripts/sync-robot-md.sh` from the repository root. CI fails when a copy drifts.
37 changes: 37 additions & 0 deletions plugins/robot-md/scripts/start-mcp-server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
"""Start the robot-md MCP server for the Claude Code plugin.

The plugin's .mcp.json runs this file with python3 instead of calling the
`robot-md` command directly, so the plugin directory's checks can read
exactly what the server command does: find the `robot-md` CLI the user
installed (`pip install 'robot-md[hardware]'`) and run `robot-md mcp`
with this process's stdin and stdout. Nothing is downloaded or installed.
"""

import os
import shutil
import subprocess
import sys

INSTALL_HINT = (
"robot-md MCP server: the `robot-md` command was not found on PATH.\n"
"Install it with: python3 -m pip install --user 'robot-md[hardware]'\n"
"then restart Claude Code. Docs: https://docs.robotmd.dev/mcp/\n"
)


def main() -> int:
exe = shutil.which("robot-md")
if exe is None:
sys.stderr.write(INSTALL_HINT)
return 1
argv = [exe, "mcp", *sys.argv[1:]]
if os.name == "nt":
# os.execv on Windows starts a new process and exits this one,
# which breaks the stdio pipe Claude Code holds. Run it as a child.
return subprocess.call(argv)
os.execv(exe, argv)
return 0 # not reached


if __name__ == "__main__":
sys.exit(main())
2 changes: 2 additions & 0 deletions scripts/sync-robot-md.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pairs=(
"$work/robot-md-mcp/skills/using-robot-md|$DEST/skills/using-robot-md"
"$work/robot-md-mcp/commands/enable-dispatch.md|$DEST/commands/enable-dispatch.md"
"$work/robot-md-mcp/.mcp.json|$DEST/.mcp.json"
"$work/robot-md-mcp/scripts/start-mcp-server.py|$DEST/scripts/start-mcp-server.py"
"plugins/bounded-embodiment/skills/bounded-embodiment|$DEST/skills/bounded-embodiment"
)

Expand All @@ -30,6 +31,7 @@ for pair in "${pairs[@]}"; do
fi
else
rm -rf "$dst"
mkdir -p "$(dirname "$dst")"
cp -r "$src" "$dst"
echo "synced $dst"
fi
Expand Down
Loading