Reins
OfficialProvides a policy and safety layer for ROS-based robot connectors, integrating with ROS 2 through ros-mcp-server, rosbridge, turtlesim, and ROS-style connectors to enforce bounded robot actions, leases, stops, and audit logging.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Reinsmove the robot forward half a meter within the approved limits"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Reins by BotInfo
Reins is an open-source policy layer that sits between an AI agent and a robot its owner has connected. It sits in front of the robot's existing connector. The agent sees only the actions the owner allows, each with checked bounds. Every motion runs on a lease and stops by itself. A stop always wins, and every request and decision goes to an audit log.
The repo also contains the Reins Safety Benchmark: hostile test cases that grade any connector, raw or behind Reins, on what the robot actually did.
Status, v0.1 (2026-10-16): simulation and mocks only. Nothing here has run on a real robot. The benchmark results are not a certification and say nothing about real hardware. Nobody outside BotInfo has reviewed this yet.
Quickstart (one command)
From this folder, with Python 3.11 or newer and nothing to install (on an older Python, Reins says so in one line
and stops; macOS's built-in python3 is 3.9, so use one from python.org or uv):
python3 -m reins benchIt runs 20 cases against 8 stacks in simulated time (about a second) and writes results/scorecard.json and
results/LEADERBOARD.md. Other commands:
python3 -m reins demo # a short scripted session, printed
python3 -m unittest discover -s tests -t tests # about 80 tests, about 10 sRelated MCP server: gov-mcp
What Reins enforces
Only the owner's actions exist. The policy file (
policies/*.toml) lists the actions, each with typed, bounded parameters. An unknown name, an extra field, NaN, a string where a number belongs, or a value out of range is refused (never clamped) and logged. The connector's own tools are never passed to the agent.Limits around the actions: rate limits (overall and for motion), a longest stretch of continuous motion (renewals and back-to-back commands count together), and an optional workspace box for robots that report a pose.
Expiry and replay. A command waiting for the owner's confirmation expires after
command_ttl_s. A call whoseissued_atis too old is refused, and so is a repeatedrequest_id.Owner-only controls. Confirming an action, lifting a stop and changing the policy happen on the owner's local channel (
python3 -m reins owner ...). The agent has no tool for any of them.Stop.
reins_stopand the owner's stop skip every check and every queue. After a stop, motion stays refused until the owner resumes. If the agent's session ends, Reins stops the robot.Leases. A motion asks for a bounded time. While it runs, Reins re-sends it as a keep-alive, then sends stop at the end. A robot-side watchdog therefore stops the robot when Reins or the network goes away. This mirrors the Sesame firmware motion-timeout patch, or a ROS base's
cmd_veltimeout.Robot output is data. Status is reduced to typed fields. Free text from the robot is redacted before the agent sees it, and flagged in the audit log.
Audit log. JSONL, one line per request and decision, with each line chained to the previous one by SHA-256 (
python3 -m reins audit-verify FILE). It is tamper-evident, not tamper-proof.
A real emergency stop must be enforced locally on the robot (a power switch, a hardware e-stop, a firmware watchdog), never over the network. Reins' stop is a software command sent over a link. The benchmark shows this: when the link drops on a robot with no local watchdog, it keeps moving, with or without Reins.
Threat model and architecture: docs/DESIGN.md. Policy reference: docs/POLICY.md.
The benchmark, v0.1 results
The full table, every case, and why each failure failed: results/LEADERBOARD.md. Method and cases: docs/BENCHMARK.md. What each grading setup does and leaves out: docs/GRADING-EXISTING-CONNECTORS.md.
Third-party connectors, real code on real ROS 2 middleware (in local containers, real time, every case run twice). None of these is a robot:
Stack | Score | Critical cases passed |
Reins → ros-mcp-server v3.1.2 + rosbridge + turtlesim on real ROS 2 Humble | 100 | 10/10 |
ros-mcp-server v3.1.2 + rosbridge + turtlesim on real ROS 2 Humble, direct | 11 | 1/10 (link lost, thanks to turtlesim's own stop) |
Reins → unitree-go2-mcp-server (e7a6737) + ros2 CLI, stand-in Go2 that centres the sticks 0.5 s after the last message | 68 | 6/10 |
unitree-go2-mcp-server (e7a6737) + ros2 CLI, same stand-in, direct | 18 | 2/10 |
Reins → unitree-go2-mcp-server, stand-in Go2 that holds the last joystick input | void | 5/10 (CTL-01 fails) |
unitree-go2-mcp-server, same stand-in, direct | void | 1/10 (CTL-01 fails) |
ros-mcp-server runs against turtlesim, a simulator that stops by itself 1 s after the last command; behind Reins, the lost-link pass is that watchdog at work, not Reins'. Direct, ros-mcp-server runs one tool call at a time, and each
publish_oncetakes about 2 s because it waits for replies rosbridge never sends (rosbridge 2.0.8), so a stop sent duringpublish_for_durationswaits for that call to end.unitree-go2-mcp-server drives a stand-in Go2 node, not a Go2 and not a Go2 simulator (Unitree's MuJoCo simulator cannot act on the joystick messages this server sends). Every command is a new
ros2 topic pubprocess, and the server handles one call at a time, so no stop can interrupt a running move, behind Reins or not: Reins latches the stop at once, but the robot stopped 4.2 s later, when the move ended. Behind Reins every case about what may be sent passed; the workspace case fails because the server reads no position. Whether a real Go2 holds or centres the last joystick input is unknown to us, so both are graded. With the holding stand-in each move overruns by about 1.1 s (the server's closing stop is a second process), the CTL-01 control fails, and those rows have no score.An earlier grade of ros-mcp-server against BotInfo's emulated rosbridge (not real ROS) is kept on the leaderboard: 93 behind Reins, 4 direct.
BotInfo's reference stacks, simulated time (the direct connectors are BotInfo's models of existing patterns, not third-party code):
Stack | Score | Critical cases passed |
Reins → ROS-style connector → SimRover with a 0.5 s base watchdog | 100 | 10/10 |
Reins → Sesame firmware API (mock, with the motion-timeout patch) | 100 | 9/9 |
Reins → ROS-style connector → SimRover, no base watchdog | 93 | 9/10 (link lost) |
Reins → Sesame firmware API (mock, stock) | 93 | 8/9 (link lost) |
Sesame firmware API (mock, patched), direct | 46 | 5/9 |
ROS-style connector → SimRover with base watchdog, direct | 14 | 2/10 |
Sesame firmware API (mock, stock), direct | 12 | 1/9 |
ROS-style connector → SimRover, no watchdog, direct | 0 | 0/10 |
Read these numbers with three things in mind:
Every row is a simulator, a mock or a stand-in robot node. Two third-party connectors have been graded so far, as real code on real ROS 2 middleware in containers: ros-mcp-server v3.1.2 (on turtlesim) and unitree-go2-mcp-server (on BotInfo's stand-in Go2). The other rows grade BotInfo's reference models of existing patterns. What each setup leaves out is in docs/GRADING-EXISTING-CONNECTORS.md.
Reins and the benchmark were written together, by the same team. Reins passing its authors' tests proves little. The benchmark gets useful when someone adds a case Reins fails; see "Adding a case" in docs/BENCHMARK.md.
The hostile agent always obeys injected text. These are worst-case results for the connector, not predictions for any model.
Use it with an agent (MCP)
Reins is an MCP server on stdio. For Claude Code, put this in a project .mcp.json (use absolute paths):
{
"mcpServers": {
"reins-simrover": {
"command": "python3",
"args": ["-m", "reins", "serve",
"--policy", "/ABSOLUTE/PATH/reins/policies/simrover.toml",
"--binding", "/ABSOLUTE/PATH/reins/bindings/simrover-ros-style.toml"],
"env": { "PYTHONPATH": "/ABSOLUTE/PATH/reins" }
}
}
}python3 must be 3.11 or newer. That binding runs the simulator inside the Reins process.
bindings/simrover-ros-style-stdio.toml instead launches the connector as a separate MCP server and fronts it.
That is the same arrangement as fronting ros-mcp-server: bindings/ros-mcp-server-turtlesim.toml (with
policies/turtlesim.toml) is tested on real ROS 2 Humble + rosbridge + turtlesim in a container, and
bindings/ros-mcp-server-simrover.toml against the emulated rosbridge (not real ROS). For the Sesame mock, use policies/sesame.toml with
bindings/sesame-inprocess.toml. bindings/unitree-go2-mcp-server.toml (with policies/go2.toml) fronts
unitree-go2-mcp-server; it has only been run against BotInfo's stand-in Go2 node in a container, never a robot.
While it runs, the owner uses a local socket (~/.reins/<policy>.sock, owner-only permissions):
python3 -m reins owner statuspython3 -m reins owner confirm c-2python3 -m reins owner stoppython3 -m reins owner resumeThe audit log goes to runs/ unless --audit says otherwise. For OpenClaw there is a skill stub:
integrations/openclaw/reins/SKILL.md. It is unverified and has not
been loaded into OpenClaw.
What Reins does not do
It does not make a robot physically harmless. It cannot see people, obstacles, falls or battery faults.
It cannot stop a robot it can no longer reach. Only the robot's own watchdog or hardware stop can do that.
It cannot make a connector faster than it is. If the connector handles one call at a time and a motion call blocks until the motion ends (unitree-go2-mcp-server does both), Reins latches a stop at once and refuses all motion after it, but the stop reaches the robot only when the running call returns.
It can only enforce what the connector lets it see. A workspace limit needs a pose; a connector that reports no position (unitree-go2-mcp-server) leaves Reins with speed, duration and rate limits only.
It does not protect against an agent that has a shell on the owner's account. That agent could kill Reins, edit the policy or reach the robot directly. Give the agent the Reins MCP server and nothing else that touches the robot.
It is not for robots whose owner has not connected them. Reins is built for owner-connected robots only.
On Sesame, a pose (wave, dance, ...) cannot be interrupted once it starts; that is how the firmware works. The default policy therefore makes every pose wait for the owner's confirmation.
Before any real robot
Do not use v0 with hardware. bindings/sesame-mock.toml refuses non-localhost robots, and the CLI refuses
allow_remote. A first hardware run would need, at minimum:
the robot's own stop within a person's reach, and a robot-side watchdog tested on that robot;
a tethered or bench setup first;
an outside review of this code and the benchmark.
Layout
reins/core.py the engine: checks, leases, stop latch, confirmations, audit
reins/policy.py policy loading (strict) and parameter checks
reins/audit.py hash-chained JSONL audit log
reins/mcp/ MCP server and client (stdio, standard library only)
reins/owner.py the owner's local channel (Unix socket)
reins/backends/ Sesame firmware API + mock, SimRover + reference ROS-style connector, MCP tool templates
reins/bench/ the Reins Safety Benchmark (cases, stacks, ground truth, report)
reins/bench/docker/ container images for the real-ROS grades (turtlesim; Go2 server + stand-in robot)
policies/ bindings/ example owner policies and connector bindings
docs/ DESIGN, BENCHMARK, POLICY, GRADING-EXISTING-CONNECTORS
results/ the published v0.1 benchmark run
integrations/openclaw/ OpenClaw skill stub (unverified)
tests/ unittest suiteLicense and credits
Apache-2.0 (LICENSE); credits are in NOTICE. The Sesame robot and firmware are Dorian Todd's work (Apache-2.0). Reins is an independent BotInfo.ai project, not made or endorsed by him. The reference ROS-style connector follows the tool interface of ros-mcp-server (Contoro Inc., Apache-2.0); no code was copied. The Go2 grade runs unitree-go2-mcp-server (Apache-2.0) unmodified inside a container image; it is not included here.
Available Tools
6 toolsdriveADestructive
Drive at a constant speed and turn rate for a bounded time, then stop. Runs on a lease of at most 5 s, then stops by itself. Renew with reins_renew. Some calls need the owner's confirmation; those return pending_confirmation.
| Name | Required | Description | Default |
|---|---|---|---|
| issued_at | No | Optional. Unix time the command was issued; older than 5 s is refused as stale. | |
| duration_s | Yes | How long to drive. (s) | |
| linear_mps | Yes | Forward speed (negative = backward). (m/s) Above 0.35 needs the owner's confirmation. | |
| request_id | No | Optional. A unique id; a repeated id is refused as a replay. | |
| angular_rps | No | Turn rate (positive = left). (rad/s) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare this is a non-read-only, destructive motion command, and the description adds meaningful behavior on top: the self-expiring 5 s lease, the renewal path via reins_renew, and the owner-confirmation gate that surfaces as a pending_confirmation return. These are exactly the traits an agent cannot infer from destructiveHint alone.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four short sentences, each carrying distinct information (action, lease expiry, renewal alternative, confirmation outcome), with the core purpose front-loaded and no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description helpfully names the pending_confirmation return, but it leaves ambiguous whether the call blocks for duration_s or returns immediately, which matters for a timed motion command. Otherwise complete for a 5-parameter tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, with units, bounds, staleness, replay, and the confirmation threshold all documented per parameter. The description adds only the combined 'constant speed and turn rate' framing, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource with scope: 'Drive at a constant speed and turn rate for a bounded time, then stop.' The bounded-time framing and the pointer to reins_renew for extension let an agent separate this from the stop/renew siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Clearly establishes the operating context: a lease of at most 5 s that self-terminates, with reins_renew named as the way to continue. It stops short of an explicit when-not-to-use statement or a comparison against reins_stop, so it is strong but not fully routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
reins_policyBRead-only
What this robot's owner allows: actions, bounds, limits.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
readOnlyHint=true already tells the agent this is a safe read, so the bar is lower. The description adds content-level context (the policy covers actions, bounds, and limits), but says nothing about the return shape, freshness, or scope of the policy, which matters since there is no output schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single tight phrase with no filler — every word earns its place and it is front-loaded. It loses a point for being a fragment rather than a complete, structured statement of purpose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With zero params, no output schema, and read-only annotation, the definition is close to sufficient, but the description should clarify the return format and meaning of 'bounds/limits' since no schema documents the output. It is adequate but leaves interpretation gaps.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is nothing for the description to disambiguate. Baseline 4 applies; no parameter semantics are missing or contradicted.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The phrase names the resource (this robot's policy) and its contents (actions, bounds, limits), which is more than a tautology. However it is a noun fragment with no verb — it never says what the tool actually does (retrieve/read the policy) — so an agent cannot cleanly distinguish it from reins_status or reins_renew without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no when-to-use, when-not-to-use, or alternative routing. Siblings like reins_status and reins_stop exist but are never mentioned or contrasted, leaving the agent to guess which reins_* tool answers a policy question.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
reins_renewA
Extend the running motion lease (heartbeat). At most 5 s from now and 20 s in total.
| Name | Required | Description | Default |
|---|---|---|---|
| extend_s | Yes | ||
| lease_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only supply readOnlyHint=false. The description adds a genuinely non-obvious behavioral limit: the 20 s total lease lifetime cap, which is not encoded anywhere in the schema. It still omits failure behavior (e.g., what happens when the total cap is exceeded) and what the operation returns.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences with the core action front-loaded and constraints appended. No filler, no restatement of the tool name.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a state-mutating, no-output-schema tool, the description covers the action and its hard limits but not the lease lifecycle context an agent needs — what an expired or unknown lease_id yields, whether the renewal is idempotent, or how it relates to reins_status/reins_stop.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must carry the load. 'At most 5 s from now' partially explains extend_s (seconds, capped), but lease_id is left unexplained beyond its self-descriptive name, and the per-call vs. total limits are easy to conflate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: 'Extend the running motion lease (heartbeat).' The parenthetical disambiguates the domain meaning of 'renew.' It does not explicitly contrast with siblings like reins_stop or reins_status, but the purpose is unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The 'heartbeat' framing implies periodic calling to keep a lease alive, and the caps hint at how often it may be used, but there is no explicit statement of when to call it, when not to, or what happens if the lease has already lapsed. Usage is only implied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
reins_statusBRead-only
Reins state (stopped?, running lease, pending confirmations) and the robot's status fields.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
readOnlyHint=true already tells the agent this is a safe read with no side effects, lowering the bar. The description adds genuine value by naming the returned state fields (stopped?, running lease, pending confirmations), but it leaves 'the robot's status fields' vague and says nothing about freshness or polling behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single compact sentence, with the primary subject ('Reins state') front-loaded and the detail in a parenthetical. Nothing is padded, though the phrasing 'and the robot's status fields' is loose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description is the only source of information about what comes back, and it gives only a partial sketch: three reins fields are named but 'the robot's status fields' is left undefined. For a zero-parameter status tool this is adequate but not complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is nothing for the description to disambiguate; the 4 baseline applies. No parameter text is needed or missing.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description identifies the resource (Reins state plus the robot's status fields) and enumerates the key contents (stopped?, running lease, pending confirmations), which distinguishes it from siblings like reins_stop and reins_renew. It lacks an explicit verb such as 'get', but the read intent is unambiguous given the name and the enumerated fields.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no statement of when to call this versus alternatives, and none of the siblings (reins_stop, reins_policy, reins_renew, drive, set_led) are referenced. Usage is only implied by the name and the returned fields.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
reins_stopA
Stop the robot now. Always allowed. Afterwards motion stays blocked until the owner resumes.
| Name | Required | Description | Default |
|---|---|---|---|
| reason | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint=false and destructiveHint=false; the description adds the crucial behavioral fact that motion stays blocked afterward until the owner resumes, which is post-call state an agent must know. It does not explain how long the block persists or how resumption is triggered beyond 'the owner'.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, front-loaded with the action ('Stop the robot now'), then eligibility, then consequences. Every sentence carries distinct information with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-purpose stop tool with no output schema this covers the action and its lasting effect adequately, but it leaves the sole input parameter entirely unexplained and gives no detail on the resumption mechanism. Adequate but with a clear gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There is one parameter ('reason') at 0% schema description coverage, and the description never mentions it, so an agent gets no guidance on whether it is needed, what format it takes, or how it is used. With a real undocumented parameter, the description should compensate but does not.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Stop the robot') with an immediacy qualifier ('now'), which clearly separates it from sibling tools like drive, reins_policy, and reins_renew. An agent can identify this as the halt action without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'Always allowed' tells the agent this can be invoked unconditionally with no permission or state prerequisites, which is valuable routing context. It does not name alternatives or when-not conditions, so it stops short of the top score.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_ledC
Set the status light.
| Name | Required | Description | Default |
|---|---|---|---|
| color | Yes | ||
| issued_at | No | Optional. Unix time the command was issued; older than 5 s is refused as stale. | |
| request_id | No | Optional. A unique id; a repeated id is refused as a replay. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare readOnlyHint=false and destructiveHint=false, so the safety profile is covered, but the description adds nothing beyond them. For a mutation tool it says nothing about permissions, staleness/replay rejection (only in the schema), or what happens to the light state on failure.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
One short sentence with no wasted words and the action front-loaded, but its brevity comes from omission rather than discipline — there is simply nothing else to say.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple setter with no output schema and adequate annotations, the description is still too thin: it omits the staleness/replay contract and any permission or targeting context an agent would need to invoke it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The description contributes no parameter meaning beyond 'status light' loosely implying the color enum. With 67% schema coverage, the one undocumented parameter (color) is at least bounded by its enum, but the description does not compensate for the gap or explain issued_at/request_id semantics.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Set the status light'), which is enough to tell it apart from the reins_* siblings and 'drive'. It is clear but bare: nothing indicates scope, target device, or effect beyond the name.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No when-to-use guidance, no preconditions, and no mention of alternatives. The agent gets no help deciding when this tool is appropriate versus the other five siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
6 tool updates
v0.1.0- First observed
drive - First observed
reins_policy - First observed
reins_renew - First observed
reins_status - First observed
reins_stop - First observed
set_led
TDQS
Scored across 6 tools
The motion and control tools (drive, reins_stop, reins_renew, reins_status, reins_policy) have distinct purposes, but set_led stands apart from the reins_-prefixed control/state family and could be mistaken for a non-observability action. Boundaries are clear enough that misselection is unlikely.
Names mix plain verbs (drive, set_led) with a reins_ prefix (reins_stop, reins_status, reins_policy, reins_renew), and none of the tools strictly follow a verb_noun pattern. The split between drive/set_led and the reins_ namespace is jarring.
Six tools fit the safety-lease motion domain without bloat; each (motion, stop, renew, status, policy, LED) earns a place. Slightly thin on read-only inspection but reasonable for a control server.
Core motion lifecycle (drive, renew lease, stop, status, policy) is covered, including safety semantics. Minor gaps: no explicit resume or LED read-back and no generic pre-flight validation for flight-like actions, but usable.
Maintenance
Related MCP Connectors
MCP server for your apps' tools and custom tools, plus hosted AI agents and approval-gated workflows
Zero-secret MCP gateway for AI agents: risk-scored, audited calls with human-in-the-loop approval.
Machine-verifiable authorization checks for autonomous AI agents.
- gatewayOAuthai.sealgate
MCP gateway with runtime security policy, tool-call-level control, and audit of agent actions.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceA unified MCP server providing observability, safety control, and behavior evolution for high-agency AI agents through tracing, replaying, and auditing. It features real-time firewall guardrails and ML-driven anomaly detection to monitor, block, or fork agent actions based on risk.6 npm-
- AlicenseNot gradedqualityCmaintenanceAn MCP server that enforces runtime governance on AI agent actions — file access, command execution, delegation chains, and permission escalation.MIT

@vorionsys/mcp-serverofficial
AlicenseAqualityDmaintenanceMCP server for AI-agent governance using trust scoring, behavioral signals, and pre-flight action checks.1012 npm1Apache 2.0- AlicenseNot gradedqualityBmaintenanceAn MCP server for agent authorization that tests the full effect surface and enforces control over consequential actions before dispatch, emitting verifiable execution evidence.2Apache 2.0