Skip to content

MCP server

Reflex exposes a Model Context Protocol server so MCP-compatible agents — Claude Desktop, Cursor, custom — can call a VLA policy as a tool. Additive to the HTTP API; both share the same inference engine.

Terminal window
pip install 'reflex-vla[mcp]'

Pulls fastmcp ≥ 3.0 alongside core dependencies.

Add to ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or the equivalent on Linux/Windows:

{
"mcpServers": {
"reflex": {
"command": "reflex",
"args": [
"serve",
"/path/to/your/exported/model/",
"--mcp",
"--mcp-transport", "stdio",
"--embodiment", "franka"
]
}
}
}

Claude Desktop spawns Reflex as a subprocess; stdio means no ports, no firewall, no auth. Restart the app. reflex now appears in the tool picker.

/reflex act
instruction: "pick up the red block"
image_b64: "<base64 PNG from robot camera>"
state: [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6]
episode_id: "ep-2026-04-24-001"
Terminal window
reflex serve ./my-export/ \
--mcp \
--mcp-transport http \
--mcp-port 8001 \
--port 8000 \
--embodiment franka

Both MCP (streamable-http on 127.0.0.1:8001) AND the REST API (0.0.0.0:8000) run concurrently. Same ReflexServer backs both.

For production HTTP deployment, front MCP with a reverse proxy that handles TLS + auth.

ToolInputsOutput
actinstruction, image_b64, state, episode_id?{actions, policy_version, inference_ms} or {error: ...}
health{state, model_version, uptime_seconds, cuda_graphs_active}
models_list[{model_id, hf_repo, family, action_dim, size_mb, supported_embodiments, supported_devices, license, description}]
validate_datasetdataset_pathValidation report with pass/warn/block decision
URIContent
metrics://prometheusCurrent Prometheus metrics in text exposition format (same as /metrics)

The act tool returns action chunks but does NOT actuate them. Callers are responsible for sending actions to the robot’s controller. Reflex’s act is pure inference.

Safety features that DO run inside act:

  • ActionGuard from the loaded embodiment config (joint-limit clamping, velocity caps, torque caps)
  • Per-request circuit breaker (--max-consecutive-crashes)
  • Optional audit log (--record <dir>)

When running reflex ros2-serve alongside MCP, four ROS2 tools + one resource become available. They introspect and drive a real ROS2-connected robot through the MCP surface.

ToolPurposeCooldownRequires confirm=True
get_joint_state()Latest /joint_states positions100 ms
get_camera_frame()Latest /camera/image_raw as base64 JPEG100 ms
execute_task(instruction, confirm, max_steps?)Runs one Reflex inference cycle + publishes the action chunk5 syes
emergency_stop(confirm)Publishes to /reflex/e_stop5 syes
robot://statusURDF info + latest state + current task (resource)

execute_task and emergency_stop reject any call where confirm is not literally the boolean True — not truthy, not a string:

await execute_task(instruction="pick up the red block", confirm=True)
# → runs inference + actuates
await execute_task(instruction="pick up the red block")
# → {"error": {"kind": "ConfirmationRequired", ...}}
await execute_task(instruction="pick up", confirm="yes")
# → {"error": {"kind": "ConfirmationRequired", ...}} # not identity-True

Intentional friction: an agent forgetting to pass confirm=True can’t actuate by accident; a prompt-injection payload that tries to slip in confirm="yes" fails the identity check.

Server-side cooldowns are authoritative. Limiter is per-tool (e-stop cooldown doesn’t block joint-state reads). Uses time.monotonic() so wall-clock skew doesn’t matter. Rejected calls return {"error": {"kind": "RateLimited", "message": "... wait Xs", ...}}. Well-behaved agents retry after the hint.

“fastmcp not installed”pip install reflex-vla[mcp]

Claude Desktop doesn’t list Reflex as a tool — verify the claude_desktop_config.json path. On macOS, quit + relaunch Claude Desktop fully (cmd-Q, not just close the window).

stdio mode blocks the terminal — by design. stdio owns stdin/stdout for MCP’s bidirectional framing. For interactive dev, use --mcp-transport http on a separate port.

MCP + FastAPI on same port — not supported. The two transports use different protocols. --port is FastAPI; --mcp-port is MCP HTTP; they must differ.