Skip to main content

MCP server for controlling Sphero RVR with Claude AI - featuring direct serial protocol for low-latency control

Project description

Sphero RVR MCP Server

An MCP (Model Context Protocol) server that enables AI assistants to control a Sphero RVR robot. Run this on a Raspberry Pi connected to your RVR, and use any MCP-compatible client to drive, control LEDs, read sensors, and more.

Features

Core Capabilities

  • Full RVR Control: Movement, LEDs, sensors, battery monitoring, IR communication
  • Safety System: Configurable speed limits, auto-stop timeout, emergency stop
  • Sensor Streaming: Background streaming with cached data access
  • Natural Language Control: Let AI drive your robot with conversational commands
  • Client Agnostic: Works with any MCP-compatible client

Production-Grade Architecture (v0.2.0+)

  • Command Queue: Priority-based async queue eliminates race conditions
  • Circuit Breaker: Prevents infinite hangs when RVR is powered off
  • Event Bus: Pub/sub pattern for efficient sensor data distribution
  • Atomic State Management: Thread-safe state with validated transitions
  • Comprehensive Observability: Structured logging (JSON/console) + Prometheus metrics
  • No Hard-Coded Delays: Event-driven connection (no 2-second sleep on connect)
  • Robust Error Handling: No silent failures, all errors logged and reported

Compatible MCP Clients

Requirements

  • Raspberry Pi 3 or newer (connected to Sphero RVR via serial)
  • Python 3.10+ (3.10.x recommended for Sphero SDK compatibility)
  • Sphero RVR with serial connection to Pi
  • An MCP-compatible client

Installation

1. Clone the Sphero SDK

The Sphero SDK is not available on PyPI and must be installed manually:

cd ~
git clone https://github.com/sphero-inc/sphero-sdk-raspberrypi-python.git

2. Install the MCP Server

Option A: Install from PyPI (recommended)

pip install sphero-rvr-mcp

# Add Sphero SDK to Python path (add to ~/.bashrc for persistence)
export PYTHONPATH="${PYTHONPATH}:${HOME}/sphero-sdk-raspberrypi-python"

Option B: Install from source

git clone https://github.com/jsperson/sphero_rvr_mcp.git
cd sphero_rvr_mcp

# Install the package in development mode
pip install -e .

# Add Sphero SDK to Python path (add to ~/.bashrc for persistence)
export PYTHONPATH="${PYTHONPATH}:${HOME}/sphero-sdk-raspberrypi-python"

3. Verify Installation

Run the pre-flight check to verify everything is set up correctly:

sphero-rvr-mcp --check

This will verify:

  • Python version (requires 3.10+)
  • Sphero SDK is installed
  • FastMCP is installed
  • Serial port exists and is accessible
  • Current configuration settings

4. Configure Your MCP Client

The server runs via stdio. Configure your MCP client with:

  • Command: python -m sphero_rvr_mcp
  • Environment: PYTHONPATH must include the Sphero SDK path

Claude Code

claude mcp add sphero-rvr -c "python -m sphero_rvr_mcp"

Or edit ~/.claude.json:

{
  "mcpServers": {
    "sphero-rvr": {
      "type": "stdio",
      "command": "python",
      "args": ["-m", "sphero_rvr_mcp"],
      "env": {
        "PYTHONPATH": "<your-home-dir>/sphero-sdk-raspberrypi-python"
      }
    }
  }
}

Claude Desktop

Edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):

{
  "mcpServers": {
    "sphero-rvr": {
      "command": "python",
      "args": ["-m", "sphero_rvr_mcp"],
      "env": {
        "PYTHONPATH": "<path-to>/sphero-sdk-raspberrypi-python"
      }
    }
  }
}

Other Clients

Refer to your client's MCP configuration documentation. The server uses stdio transport.

Configuration

Environment variables (optional):

Variable Default Description
Connection
RVR_SERIAL_PORT /dev/ttyS0 Serial port for RVR
RVR_BAUD_RATE 115200 Serial baud rate
RVR_WAKE_TIMEOUT 5.0 RVR wake timeout (seconds)
Safety
RVR_MAX_SPEED_PERCENT 50.0 Default speed limit (0-100)
RVR_COMMAND_TIMEOUT 5.0 Auto-stop timeout (seconds, 0=disabled)
Performance
RVR_COMMAND_QUEUE_SIZE 100 Max queued commands
RVR_SENSOR_CACHE_TTL 2.0 Sensor data TTL (seconds)
Observability
RVR_LOG_LEVEL INFO Log level (DEBUG, INFO, WARNING, ERROR)
RVR_LOG_FORMAT json Log format (json, console)
RVR_METRICS_ENABLED true Enable Prometheus metrics
RVR_METRICS_PORT 9090 Metrics HTTP server port
Circuit Breaker
RVR_CIRCUIT_BREAKER_FAILURE_THRESHOLD 5 Failures before opening
RVR_CIRCUIT_BREAKER_TIMEOUT 30.0 Timeout before half-open (seconds)

Usage

Example Commands

Once your MCP client is connected to the server:

You: Connect to the RVR

You: Drive forward slowly for 2 seconds then stop

You: Set all LEDs to blue

You: What's the battery level?

You: Start streaming the accelerometer and gyroscope sensors

You: Turn left 90 degrees

You: What color is under the rover?

You: Emergency stop!

Available Tools

Connection (3 tools)

Tool Description
connect Connect to RVR and wake it up
disconnect Safely disconnect
get_connection_status Get connection state, uptime, firmware

Movement (9 tools)

Tool Description
drive_with_heading Drive at speed toward heading (0-359°)
drive_tank Tank drive with left/right velocities (m/s)
drive_rc RC-style with linear + yaw velocity
stop Normal stop
emergency_stop Immediate stop, blocks movement
clear_emergency_stop Allow movement after e-stop
reset_yaw Set current heading as 0°
reset_locator Set current position as origin

LEDs (3 tools)

Tool Description
set_all_leds Set all LEDs to RGB color
set_led Set specific LED group to RGB
turn_leds_off Turn off all LEDs

LED groups: headlight_left, headlight_right, brakelight_left, brakelight_right, status_indication_left, status_indication_right, battery_door_front, battery_door_rear, power_button_front, power_button_rear, undercarriage_white, all

Sensors (6 tools)

Tool Description
start_sensor_streaming Start background sensor streaming
stop_sensor_streaming Stop all streaming
get_sensor_data Get cached sensor readings
get_ambient_light Query light sensor directly
enable_color_detection Enable/disable color sensor LED
get_color_detection Query color sensor (auto LED)

Streamable sensors: accelerometer, gyroscope, imu, locator, velocity, speed, quaternion, color_detection, ambient_light, core_time

Battery & System (2 tools)

Tool Description
get_battery_status Battery percentage and voltage state
get_system_info Connection info and uptime

Safety Controls (3 tools)

Tool Description
get_safety_status Current safety settings
set_speed_limit Set max speed (0-100%)
set_command_timeout Set auto-stop timeout

IR Communication (3 tools)

Tool Description
send_ir_message Send IR code (0-7)
start_ir_broadcasting Start robot-to-robot IR
stop_ir_broadcasting Stop IR broadcasting

Architecture

Component Overview

MCP Tool Handlers (FastMCP)
    ↓
Application Services Layer
├── ConnectionService
├── MovementService
├── SensorService
├── LEDService
├── SafetyService
└── IRService
    ↓
Core Infrastructure
├── Command Queue (priority + timeout)
├── Event Bus (pub/sub)
├── Circuit Breaker (resilience)
└── State Manager (atomic)
    ↓
Hardware Abstraction
├── Connection Manager
├── Sensor Stream Manager
└── Safety Monitor
    ↓
Sphero RVR SDK

Key Design Patterns

Command Queue

  • All hardware commands go through async priority queue
  • Priority levels: EMERGENCY (0) → HIGH (1) → NORMAL (2) → LOW (3)
  • Per-command timeout enforcement
  • Eliminates race conditions in concurrent access

Circuit Breaker

  • States: CLOSED (healthy) → OPEN (failing) → HALF_OPEN (testing)
  • Prevents infinite hangs when RVR is powered off
  • Automatic recovery with configurable threshold
  • Fails fast when unhealthy

Event Bus

  • Pub/sub pattern for sensor data distribution
  • Decouples streaming from consumers
  • Built-in backpressure management
  • Multiple subscribers per sensor

Atomic State Management

  • Thread-safe with explicit locks
  • Validated state transitions
  • Separate state objects: SystemState, ConnectionInfo, SafetyState, SensorState
  • All changes logged and metered

Observability

Structured Logging

{
  "event": "command_submitted",
  "command_type": "drive_with_heading",
  "speed": 50,
  "heading": 90,
  "timestamp": "2026-01-14T01:23:45.678Z"
}

Prometheus Metrics (port 9090 by default)

  • Command metrics: total, duration, queue depth
  • Connection metrics: state, reconnections, uptime
  • Safety metrics: emergency stops, speed limits applied
  • Sensor metrics: streaming active, data age, events
  • Circuit breaker metrics: state, failures, successes

Safety Features

Speed Limiting

All movement commands are limited to a configurable percentage of max speed (default 50%). This prevents accidental high-speed collisions.

You: Set the speed limit to 25%
You: Now drive forward at full speed
# RVR will only go at 25% of max speed

Command Timeout

If no movement command is received within the timeout period (default 5 seconds), the RVR automatically stops. This prevents runaway situations if connection is lost.

Emergency Stop

Immediately stops all movement and blocks further motion until explicitly cleared. Has highest priority in the command queue.

You: Emergency stop!
# RVR stops immediately
# All movement commands will fail until:
You: Clear the emergency stop

Troubleshooting

Connection Issues

"Failed to connect to RVR"

  • Check serial connection: ls -l /dev/ttyS0
  • Ensure RVR is powered on and charged
  • Verify baud rate (default 115200)
  • Check circuit breaker isn't open (connection status)

"RVR wake() timed out"

  • RVR might be off or in deep sleep
  • Try power cycling the RVR
  • Check serial cable connection
  • Circuit breaker will open after 5 failures (default)

SDK Issues

"sphero_sdk not found"

  • Add SDK to PYTHONPATH: export PYTHONPATH="${PYTHONPATH}:/path/to/sphero-sdk-raspberrypi-python"
  • Add to ~/.bashrc for persistence
  • Verify SDK is cloned: ls ~/sphero-sdk-raspberrypi-python

"nest_asyncio required"

  • The Sphero SDK requires nested event loops
  • This is normal and handled automatically by the server

Performance Issues

Slow response

  • Raspberry Pi 3 may be slower than Pi 4/5
  • Reduce sensor streaming frequency
  • Close unnecessary applications
  • Check command queue depth (metrics endpoint)

Commands timing out

  • Check circuit breaker state (connection status)
  • Verify RVR is not in emergency stop
  • Increase command timeout in configuration
  • Check system logs for errors

Sensor Issues

Color detection returns all zeros

  • This is fixed in v0.2.0+ (SDK key parsing)
  • Ensure RVR is on a non-dark surface
  • Try increasing stabilization time
  • Check that belly LED is working

Sensor streaming not updating

  • Verify streaming is started: get_sensor_data
  • Check sensor cache TTL (default 2 seconds)
  • Verify sensors are in available list
  • Check event bus metrics

RVR Behavior Issues

RVR not responding to commands

  • Check if emergency stop is active: get_safety_status
  • Verify connection: get_connection_status
  • Check speed limit isn't set to 0%
  • Try disconnecting and reconnecting

RVR stops on its own

  • Check command timeout setting (default 5 seconds)
  • Disable auto-stop: set_command_timeout(0)
  • Verify battery level isn't critical

Metrics & Monitoring

Access Prometheus metrics at http://<raspberry-pi-ip>:9090/metrics (if enabled).

Key Metrics:

  • rvr_commands_total - Total commands by type and status
  • rvr_command_duration_seconds - Command latency histogram
  • rvr_command_queue_depth - Current queue depth
  • rvr_connection_state - Connection state (0=disconnected, 1=connecting, 2=connected, 3=error)
  • rvr_emergency_stops_total - Emergency stop count
  • rvr_sensor_streaming_active - Sensor streaming status
  • rvr_circuit_breaker_state - Circuit breaker state (0=closed, 1=open, 2=half_open)

Project Structure

sphero_rvr_mcp/
├── pyproject.toml              # Package configuration
├── README.md                   # This file
├── LICENSE                     # MIT License
└── src/sphero_rvr_mcp/
    ├── __init__.py
    ├── __main__.py             # Entry point
    ├── config.py               # Configuration
    ├── api.py                  # Direct API (non-MCP)
    ├── server.py               # MCP server
    │
    ├── core/                   # Core infrastructure
    │   ├── command_queue.py    # Priority command queue
    │   ├── circuit_breaker.py  # Circuit breaker pattern
    │   ├── event_bus.py        # Pub/sub event bus
    │   ├── state_manager.py    # Atomic state management
    │   └── exceptions.py       # Exception hierarchy
    │
    ├── hardware/               # Hardware abstraction
    │   ├── connection_manager.py       # Connection lifecycle
    │   ├── sensor_stream_manager.py    # Sensor streaming
    │   └── safety_monitor.py           # Safety system
    │
    ├── services/               # Application services
    │   ├── connection_service.py
    │   ├── movement_service.py
    │   ├── sensor_service.py
    │   ├── led_service.py
    │   ├── safety_service.py
    │   └── ir_service.py
    │
    ├── tools/                  # MCP tool handlers
    │   ├── connection_tools.py
    │   ├── movement_tools.py
    │   ├── sensor_tools.py
    │   ├── led_tools.py
    │   ├── safety_tools.py
    │   └── ir_tools.py
    │
    └── observability/          # Logging & metrics
        ├── logging.py          # Structured logging
        ├── metrics.py          # Prometheus metrics
        └── health.py           # Health monitoring

Direct API Usage (Non-MCP)

You can also use the RVR client directly without MCP:

import asyncio
from sphero_rvr_mcp.api import RVRClient

async def main():
    client = RVRClient(log_level="INFO", log_format="console")

    await client.initialize()
    await client.connect()

    # Control LEDs
    await client.set_all_leds(255, 0, 0)  # Red

    # Read sensors
    color = await client.get_color_detection()
    print(f"Color: {color}")

    # Movement (if not wired up!)
    # await client.drive_with_heading(speed=50, heading=0)

    await client.shutdown()

asyncio.run(main())

Development

Running Tests

# Unit tests
pytest tests/unit/

# Integration tests (requires RVR)
pytest tests/integration/

# All tests
pytest

Viewing Logs

# Console format (human-readable)
RVR_LOG_FORMAT=console python -m sphero_rvr_mcp

# JSON format (machine-readable)
RVR_LOG_FORMAT=json python -m sphero_rvr_mcp

Contributing

Contributions welcome! Please:

  1. Fork the repository
  2. Create a feature branch
  3. Add tests for new functionality
  4. Ensure all tests pass
  5. Submit a pull request

Changelog

v0.2.0 (2026-01-14)

  • Complete architectural rewrite for production reliability
  • Added command queue with priority levels
  • Added circuit breaker for connection resilience
  • Added event bus for sensor distribution
  • Added atomic state management
  • Added comprehensive observability (logging + metrics)
  • Fixed SDK response key parsing (color sensor now works!)
  • Removed hard-coded delays (2s sleep eliminated)
  • Enhanced battery status with voltage state
  • Improved error handling (no silent failures)

v0.1.1 (2024-12-XX)

  • Added connection timeouts
  • Updated documentation

v0.1.0 (2024-12-XX)

  • Initial release

License

MIT

Credits

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

sphero_rvr_mcp-0.2.1.tar.gz (67.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sphero_rvr_mcp-0.2.1-py3-none-any.whl (52.6 kB view details)

Uploaded Python 3

File details

Details for the file sphero_rvr_mcp-0.2.1.tar.gz.

File metadata

  • Download URL: sphero_rvr_mcp-0.2.1.tar.gz
  • Upload date:
  • Size: 67.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.13.0 pkginfo/1.12.1.2 requests/2.32.5 setuptools/79.0.1 requests-toolbelt/1.0.0 tqdm/4.67.1 CPython/3.10.19

File hashes

Hashes for sphero_rvr_mcp-0.2.1.tar.gz
Algorithm Hash digest
SHA256 fbfd4f7e77c4bf15daddaf0d8cb4618ef01599af493b56f4cc50a70f2f64b87e
MD5 2b18e68c3c7c74bb5a0ab3ec33e2e4fb
BLAKE2b-256 442b915d95b2be3f3ac185fdbf36765cc39db333032852eb6ba1836bec6fe552

See more details on using hashes here.

File details

Details for the file sphero_rvr_mcp-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: sphero_rvr_mcp-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 52.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.13.0 pkginfo/1.12.1.2 requests/2.32.5 setuptools/79.0.1 requests-toolbelt/1.0.0 tqdm/4.67.1 CPython/3.10.19

File hashes

Hashes for sphero_rvr_mcp-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 c3dbaa866046aa58ebd4bb033c1925bb1a112e27c9a6313dd8f400ffde747bfe
MD5 f48996b9baef3e499d7ff06864f01c9c
BLAKE2b-256 1e3f1d53339d35ec7be33063013413f3db8cfea8c2c2b35d4eaacb77c492bf15

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page