Skip to main content
ClaudeWave

Safety-first MCP server for ROS 2 manipulators: server-side joint/workspace/force envelopes, human approval via MCP elicitation, e-stop, audit log

MCP ServersRegistry oficial0 estrellas0 forks● PythonApache-2.0Actualizado today
ClaudeWave Trust Score
95/100
✓ Verified
Passed
  • ✓Open-source license (Apache-2.0)
  • ✓Actively maintained (<30d)
  • ✓Clear description
  • ✓Topics declared
  • ✓Documented (README)
Last scanned: 10/20/2026
Install in Claude Code / Claude Desktop
Method: UVX (Python) · armguard-mcp
Claude Code CLI
claude mcp add armguard-mcp -- uvx armguard-mcp
claude_desktop_config.json (Claude Desktop)
{
  "mcpServers": {
    "armguard-mcp": {
      "command": "uvx",
      "args": ["armguard-mcp"]
    }
  }
}
1. Run the command above in your terminal (Claude Code), or paste the JSON config into claude_desktop_config.json (Claude Desktop).
2. Replace any <placeholder> values with your API keys or paths.
3. Restart Claude. The MCP server and its tools appear automatically.
Casos de uso

Resumen de MCP Servers

# armguard-mcp

[![CI](https://github.com/Lynn-hh/armguard-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/Lynn-hh/armguard-mcp/actions/workflows/ci.yml)
[![PyPI](https://img.shields.io/pypi/v/armguard-mcp.svg)](https://pypi.org/project/armguard-mcp/)
[![License: Apache-2.0](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE)
![Python 3.10 | 3.12](https://img.shields.io/badge/python-3.10%20%7C%203.12-blue)
![ROS 2 Jazzy](https://img.shields.io/badge/ROS%202-Jazzy-22314E)
![MCP 2026-07-28](https://img.shields.io/badge/MCP-2026--07--28-black)
![status: alpha](https://img.shields.io/badge/status-alpha-orange)
[![M8ven Verified](https://m8ven.ai/badge/mcp/lynn-hh-armguard-mcp-4jlmpb?v=5f7b4dde398f8793a5072c54b401f450&variant=verified)](https://m8ven.ai/mcp/lynn-hh-armguard-mcp-4jlmpb)

<!-- mcp-name: io.github.Lynn-hh/armguard-mcp -->

**A safety-first [Model Context Protocol](https://modelcontextprotocol.io) server for ROS 2 manipulators.**
It lets an LLM agent inspect a robot arm, plan motions, preview them and execute them. Every action passes
through a safety envelope that **the server enforces outside the model**: joint limits, a workspace box
and keep-out zones, speed and step-size caps, force/torque thresholds, allowlists, rate limits, a software
e-stop, human approval through MCP elicitation, and an audit log. A prompt, or a prompt injection hidden in
a camera image or topic string, can change what the model *asks for*. It cannot change what the server
*allows*.

> **Status: alpha.** The policy engine, safety envelope, approval flow, audit log and all 22 MCP tools run
> against a simulated Franka FR3 backend. The ROS 2 backend (MoveIt 2, `ros2_control`, `franka_ros2`) is
> tested on ROS 2 Jazzy against real rclpy endpoints and a real MoveIt 2 `move_group`. It has **not**
> been run on a physical robot yet.
>
> **This is defense in depth, NOT certified functional safety.** See
> [Safety scope and non-goals](#safety-scope-and-non-goals).

## At a glance

<p align="center"><img src="docs/demo.svg" alt="armguard-mcp demo: a small move runs, a large move needs human approval, a keep-out request is rejected and cannot be executed, and the e-stop blocks planning" width="820"></p>

- **Problem.** An LLM agent that can call robot tools can be wrong, or be steered by a prompt injection
  hidden in an image or a topic string. One bad tool call moves a real arm.
- **Approach.** The MCP server checks every plan against a policy file *before* anything moves: joint
  limits, workspace box, keep-out zones, step and speed caps, force limits, allowlists and rate limits.
  Motion outside the envelope needs a human to approve it through MCP elicitation, and a software e-stop
  and an audit log sit on top.
- **Results** (simulated FR3, [reproducible with one command](#evaluation)): all **23/23 unsafe requests**
  in the evaluation suite were refused, clamped, rate-limited or aborted, and **no unintended command reached the
  robot**. **1000/1000 random safe moves** executed, with none leaving the envelope. Planning with the full
  safety check takes a median of **~16 ms** per call.
- **Limits.** Not yet run on a physical robot; the simulated backend is kinematic only; the envelope checks
  the TCP path, not link geometry (measured: 84/201 near-zone plans clip a zone with the hand or wrist); this
  is defense in depth, not certified safety. See [Known limitations](#known-limitations).

## Contents

- [How it differs from generic ROS MCP bridges](#how-it-differs-from-generic-ros-mcp-bridges)
- [Architecture](#architecture)
- [Quick start (simulated FR3, no ROS needed)](#quick-start-simulated-fr3-no-ros-needed)
- [Evaluation](#evaluation)
- [ROS 2 backend](#ros-2-backend---backend-ros2)
- [Tool reference](#tool-reference)
- [The approval flow](#the-approval-flow)
- [Policy reference](#policy-reference)
- [Safety scope and non-goals](#safety-scope-and-non-goals)
- [Known limitations](#known-limitations)
- [Roadmap](#roadmap)
- [Citation](#citation) and [License](#license)

More detail: [docs/architecture.md](docs/architecture.md), [docs/threat-model.md](docs/threat-model.md),
[docs/demo.md](docs/demo.md) (a real transcript), [CONTRIBUTING.md](CONTRIBUTING.md).

## How it differs from generic ROS MCP bridges

Generic bridges such as [robotmcp/ros-mcp-server](https://github.com/robotmcp/ros-mcp-server) do an
excellent job of what they aim for: they connect any MCP client to any ROS 1 or ROS 2 robot through
`rosbridge`, with no changes to the robot's code. The LLM can publish to topics, call services and
actions, and set parameters. That generality is the point, and it also means the model can reach anything
the ROS graph exposes. Their open issue [#283](https://github.com/robotmcp/ros-mcp-server/issues/283)
("Security: Unrestricted ROS service calls via MCP tool — prompt injection → robot control") describes the
resulting risk, and the project's README lists permissions among the contributions it welcomes.

armguard-mcp makes the opposite trade-off. It is narrow, specific to manipulators, and restrictive by
design:

| | Generic ROS MCP bridge | armguard-mcp |
|---|---|---|
| Scope | Any topic, service, action or parameter | 22 fixed skill-level tools for arms and grippers |
| What the LLM sends | Raw ROS messages | Targets (joint positions, poses, waypoints) that the server plans and checks |
| Motion model | Publish or call directly | `plan_*` returns a preview and a single-use `plan_id`, and only `execute_plan` moves |
| Limits | Whatever the robot stack enforces | Server-side YAML policy: joint limits, workspace, keep-out zones, speed, step size, force, gripper |
| Human in the loop | None built in | MCP elicitation prompt, denied by default when the client cannot ask a human |
| Arbitrary publish or service calls | Yes | No, by construction |
| Audit | None built in | Append-only JSONL of every call, approval, denial and e-stop |
| Robot coverage | Very broad (ROS 1 and ROS 2, any robot) | Manipulators; Franka FR3 first |

If you want to explore a robot freely from a chat window, use a generic bridge. If you want an agent near
a real arm with limits it cannot talk its way around, that is what this project is for.

## Architecture

```mermaid
flowchart LR
    subgraph Client["MCP client (untrusted)"]
        LLM["LLM agent<br/>(Claude, GPT, …)"]
        Human(["Human operator"])
    end

    subgraph Server["armguard-mcp (trusted, enforces policy)"]
        direction TB
        Tools["22 MCP tools<br/>only enabled groups are registered"]
        RL["Rate limiter<br/>per-tool + global token buckets"]
        ES["E-stop / force latch"]
        Env["Safety envelope<br/>joint limits · workspace box · keep-out zones<br/>speed · step size · force"]
        Ap["Approval resolver<br/>(MCP elicitation)"]
        Plans["Plan store<br/>TTL · single-use · staleness"]
        Audit[("Audit log<br/>JSONL")]
        Tools --> RL --> ES --> Env --> Ap
        Env <--> Plans
        Tools -.-> Audit
    end

    subgraph Backend["Robot backend"]
        Fake["fake FR3<br/>(kinematic sim, CI)"]
        ROS["ROS 2 (rclpy)<br/>MoveIt 2 · ros2_control · franka_ros2"]
    end

    Robot["FR3 + Franka safety system<br/>1 kHz control stays here"]

    LLM <-->|"MCP: stdio or streamable HTTP"| Tools
    Ap <-.->|"elicitation/create"| Human
    Ap --> Backend
    ROS --> Robot
```

The LLM is never in the control loop. MCP works at the level of skills and tasks: plan, preview, execute,
grasp. Real-time control, such as 1 kHz impedance and force control, stays in `ros2_control` and the Franka
controllers. The server checks a whole trajectory before it runs and watches the external wrench while it
runs.

## Quick start (simulated FR3, no ROS needed)

From PyPI, no clone needed:

```bash
pip install armguard-mcp                    # or run it without installing: uvx armguard-mcp ...
curl -O https://raw.githubusercontent.com/Lynn-hh/armguard-mcp/main/examples/policies/fr3.yaml
armguard-mcp --policy fr3.yaml --backend fake --audit-log audit.jsonl
```

From source, for the tests, the demo and the evaluation scripts:

```bash
git clone https://github.com/Lynn-hh/armguard-mcp && cd armguard-mcp
python -m venv .venv && . .venv/bin/activate
pip install -e ".[dev]"
pytest -q                                   # unit tests, a few seconds (no ROS needed)

# stdio (what desktop and CLI MCP clients launch)
armguard-mcp --policy examples/policies/fr3.yaml --backend fake --audit-log audit.jsonl

# streamable HTTP on http://127.0.0.1:8765/mcp (no authentication: keep it on localhost)
armguard-mcp --policy examples/policies/fr3.yaml --backend fake --transport http --port 8765

# a scripted session: plan, execute, approval prompt, keep-out rejection, e-stop
python scripts/demo_fake.py

# the safety evaluation behind the numbers in "At a glance"
python scripts/eval_safety.py
```

`armguard-mcp --help` lists every flag: `--policy` (required), `--backend fake|ros2`, `--ros2-config`,
`--transport stdio|http`, `--host` (default `127.0.0.1`), `--port` (default `8765`), `--audit-log`,
`--dry-run` (forces dry-run on top of the policy), `--log-level`, `--version`. Logs go to stderr only, so
stdout carries nothing but MCP messages. A policy that fails validation, a backend that is not
available, or an audit log that cannot be opened exits with status 2 before the server starts. Binding
HTTP to a non-loopback address logs a warning. SIGTERM (`docker stop`, systemd, MCP hosts) is handled like
Ctrl-C and end of input: the server commands a stop of the arm and gripper, then shuts the backend down.

The fake backend is a kinematic FR3 with real FR3 forward and inverse kinematics, time-scaled execution, a
Franka Hand model, generated camera images and a fake `ros2_control` graph. It starts at the policy's
`home_joint_positions`.

### Claude Code (`.mcp.json`, stdio)

Copy [examples/mcp.json](examples/mcp.json) to `.mcp.json` at your project root, or run
`claude 
frankallm-agentsmcpmodel-context-protocolmoveit2robot-safetyroboticsros2

Lo que la gente pregunta sobre armguard-mcp

¿Qué es Lynn-hh/armguard-mcp?

+

Lynn-hh/armguard-mcp es mcp servers para el ecosistema de Claude AI. Safety-first MCP server for ROS 2 manipulators: server-side joint/workspace/force envelopes, human approval via MCP elicitation, e-stop, audit log Tiene 0 estrellas en GitHub y su última actualización registrada es del 2026-10-19.

¿Cómo se instala armguard-mcp?

+

Puedes instalar armguard-mcp clonando el repositorio (https://github.com/Lynn-hh/armguard-mcp) o siguiendo las instrucciones del README en GitHub. ClaudeWave también te ofrece bloques de instalación rápida en esta misma página.

¿Es seguro usar Lynn-hh/armguard-mcp?

+

Nuestro agente de seguridad ha analizado Lynn-hh/armguard-mcp y le ha asignado un Trust Score de 95/100 (tier: Verified). Revisa el desglose completo de comprobaciones superadas y flags en esta página.

¿Quién mantiene Lynn-hh/armguard-mcp?

+

Lynn-hh/armguard-mcp es mantenido por Lynn-hh. La última actividad registrada en GitHub es del 2026-10-19, con 0 issues abiertos.

¿Hay alternativas a armguard-mcp?

+

Sí. En ClaudeWave puedes explorar mcp servers similares en /categories/mcp, ordenados por popularidad o actividad reciente.

Despliega armguard-mcp en tu cloud

Lleva este repo a producción en minutos. Cada plataforma genera su propio entorno con variables de entorno editables.

¿Mantienes este repo? Añade un badge a tu README

Pega el badge en tu README de GitHub para mostrar que está auditado por ClaudeWave. Cada badge enlaza de vuelta a esta página y muestra el Trust Score actual.

Featured on ClaudeWave: Lynn-hh/armguard-mcp
[![Featured on ClaudeWave](https://claudewave.com/api/badge/lynn-hh-armguard-mcp)](https://claudewave.com/repo/lynn-hh-armguard-mcp)
<a href="https://claudewave.com/repo/lynn-hh-armguard-mcp"><img src="https://claudewave.com/api/badge/lynn-hh-armguard-mcp" alt="Featured on ClaudeWave: Lynn-hh/armguard-mcp" width="320" height="64" /></a>

Más MCP Servers

Alternativas a armguard-mcp