Click on "Install 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., "@Webots MCP Serverpause the simulation and show me the robot's current pose"
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.
Webots MCP Server
Generic MCP (Model Context Protocol) bridge for any Webots robot simulation. Provides Claude Code and Cursor with real-time access to robot state, sensors, camera, and simulation control.
Quick Start (3 Lines)
from mcp_bridge import MCPBridge
bridge = MCPBridge(robot) # Auto-detects Supervisor
bridge.publish({"pose": [x, y, theta], "mode": "navigate"})That's it! Claude Code now has full visibility into your simulation.
Installation
Option 1: Clone (Recommended)
git clone https://github.com/luisfelipesena/webots-youbot-mcp.git
pip install mcp pydanticOption 2: Copy Files
Copy mcp_bridge.py to your controller directory.
Claude Code Integration
Add to your project's .mcp.json:
{
"mcpServers": {
"webots": {
"command": "python",
"args": ["/path/to/webots-youbot-mcp/webots_youbot_mcp_server.py"],
"cwd": "/path/to/webots-youbot-mcp"
}
}
}Cursor Integration
Same configuration - Cursor reads .mcp.json automatically.
Controller Integration
Minimal Example
import sys
sys.path.insert(0, "/path/to/webots-youbot-mcp")
from mcp_bridge import MCPBridge
class MyController:
def __init__(self):
self.robot = Robot() # or Supervisor()
self.mcp = MCPBridge(self.robot)
def run(self):
while self.robot.step(32) != -1:
# Your logic here
self.mcp.publish({
"pose": [x, y, theta],
"mode": self.mode,
"sensors": {"front": 1.2, "left": 0.8},
})
self.mcp.get_command() # Handle simulation controlAdvanced: World Reload Detection
def reset_state():
"""Called automatically when world reloads"""
self.mode = "search"
self.collected = 0
bridge = MCPBridge(robot)
bridge.on_reload(reset_state)
# In main loop:
bridge.detect_reload() # Triggers callback if reload detectedAdvanced: Custom Commands
def handle_custom(cmd):
if cmd.get("action") == "my_action":
print(f"Custom command: {cmd}")
bridge.register_command("my_action", handle_custom)Available MCP Tools
Tool | Description |
| Get current robot state (pose, mode, etc.) |
| Get sensor data from status |
| Get latest camera frame path |
| Get controller logs |
| Pause/resume/reset/reload/step/fast |
| Force reload world (macOS: osascript) |
| Reset simulation to initial state |
| Reset controller internal state |
| Capture simulation view |
| Monitor robot for N seconds |
| Complete state dump |
Force Reload (macOS)
When controller is stuck, use force reload via osascript:
# From MCP:
webots_world_reload(force=True) # Sends Ctrl+Shift+R to Webots
webots_world_reset(force=True) # Sends Ctrl+Shift+T to WebotsRequires accessibility permissions for Terminal/IDE in System Preferences.
Data Directory Structure
data/
├── status.json # Robot state (written by controller)
├── commands.json # Commands from MCP
├── camera/ # Camera frames
├── screenshots/ # Simulation screenshots
└── logs/ # Controller logsMCPBridge API Reference
bridge = MCPBridge(robot, data_dir=None, throttle_interval=5)
# Core
bridge.publish(state_dict) # Publish state (throttled)
bridge.publish(state, force=True) # Publish immediately
bridge.get_command() # Check for MCP commands
# Reload Detection
bridge.on_reload(callback) # Register reload callback
bridge.detect_reload() # Check if world reloaded
# Custom Commands
bridge.register_command(action, handler)
# Utilities
bridge.log(message) # Write to log file
bridge.save_camera_frame(camera) # Save camera imageGlobal Installation (All Projects)
Add to ~/.config/claude/mcp.json (Claude Code) or global Cursor settings:
{
"mcpServers": {
"webots": {
"command": "python",
"args": ["/absolute/path/to/webots_youbot_mcp_server.py"],
"cwd": "/absolute/path/to/webots-youbot-mcp"
}
}
}Requirements
Python 3.10+
mcp>= 1.0.0pydantic>= 2.0.0Pillow(optional, for camera frames)
License
MIT