A newer version of the Gradio SDK is available: 6.26.0
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
This is an MCP (Model Context Protocol) server for drone control via MQTT, built for the MCP 1st Birthday Hackathon. The project enables AI agents (like Claude) to control drones through natural language by translating MCP protocol calls into MQTT commands.
Architecture
The system has three independent components that communicate via MQTT:
- drone_mcp_server.py - MCP server that exposes drone control as MCP tools for AI agents
- gradio_demo.py - Web UI for manual drone control (independent MQTT client)
- mqtt_drone_client.py - Drone simulator that responds to MQTT commands
Key architectural principle: Both the MCP server and Gradio demo connect directly to MQTT. They do NOT communicate with each other. This allows:
- Gradio to work standalone for quick testing
- MCP server to work independently for AI agents
- Both to run simultaneously without conflicts
Claude Desktop ββMCPββ> drone_mcp_server βββ
βββ> MQTT Broker ββ> Drone Simulator
Browser βββββββββββββ> gradio_demo βββββββββ
Development Setup
# Install dependencies
pip install -r requirements.txt
# Install MQTT broker (macOS)
brew install mosquitto
brew services start mosquitto
# Or run manually
mosquitto -v
Running the System
Start components in separate terminals (order doesn't matter):
# Terminal 1: MQTT Broker (if not running as service)
mosquitto -v
# Terminal 2: Drone Simulator
python src/mqtt_drone_client.py
# Terminal 3: MCP Server (for AI agents)
python src/drone_mcp_server.py
# Terminal 4: Gradio Demo (for web UI)
python src/gradio_demo.py
# Then open http://localhost:7860 and click "π Connect"
MQTT Communication
All three components use paho-mqtt with CallbackAPIVersion.VERSION2:
Topic Structure - Action Protocol
The system uses the action protocol for all flight commands:
- Action Topic:
{mqtt_prefix}/remotecontrol/action(default:doozy/command/remotecontrol/action) - Status Topic:
{mqtt_prefix}/remotecontrol/aruco-mission/status
Command Flow
- MCP server or Gradio publishes action JSON to
{mqtt_prefix}/remotecontrol/action - Drone simulator receives, processes action, updates internal state
- Drone publishes status updates to ArUco mission status topic
Available Commands
Basic Flight (Action Protocol):
StartTakeoff- value:true- Takeoff the drone (uses default 1.5m altitude)StartAutoLanding- value:true- Land the drone automatically
ArUco Marker Navigation (Action Protocol):
StartArUcoTakeoff- value:{marker_id: int, distance: float, marker_size: float}StartArUcoMission- value:{marker_id: int, distance: float, initial_rotation_degree: float, rotate_to_left: bool, marker_size: float}StartArUcoLanding- value:marker_id (int)StopArUcoMission- value:{}
Legacy Commands (still available via MCP, not in Gradio Basic Controls):
move- params:{direction: str, distance: float}rotate- params:{angle: float}hover- params:{duration: float}emergency_stop- params:{}
Action Protocol Message Format
Action messages have format:
{
"action": "StartTakeoff",
"value": true
}
{
"action": "StartArUcoTakeoff",
"value": { "marker_id": 23, "distance": 1.5, "marker_size": 0.176 }
}
Status messages include:
cid- current marker IDtid- target marker IDd- distance to targetdids- detected marker IDss- mission status (START, PRECISION_TAKEOFF, TARGET, COMPLETED_JOB, etc.)
Authentication and Configuration
All components support MQTT authentication and configuration via:
- Command-line arguments:
python src/drone_mcp_server.py localhost 1883 username password mqtt_prefix - Environment variables:
MQTT_BROKER,MQTT_PORT,MQTT_USERNAME,MQTT_PASSWORD,MQTT_PREFIX - Gradio UI: Configure in web interface (recommended for demo)
MQTT Prefix: The default prefix is doozy/command. This affects action protocol topics. Change it via command line arg 5 or MQTT_PREFIX env var, or configure it in the Gradio UI.
MCP Server Integration
To connect Claude Desktop or other MCP clients, add to their config:
{
"mcpServers": {
"drone-control": {
"command": "python",
"args": ["/absolute/path/to/src/drone_mcp_server.py"],
"env": {
"MQTT_BROKER": "localhost",
"MQTT_PORT": "1883"
}
}
}
}
The MCP server exposes 10 tools. Each tool's call_tool() handler:
- Validates parameters
- Calls
send_action()orsend_command()to publish MQTT message - Returns JSON result as TextContent
Tools:
takeoff,land- Use action protocol (send_action())aruco_takeoff,aruco_mission,aruco_landing,stop_aruco_mission- Use action protocolmove,rotate,hover,emergency_stop- Use legacy command protocol (still available)
Gradio UI Notes
- Basic Controls Tab: Only includes Takeoff and Land buttons (simplified UI)
- ArUco Marker Control Tab: Full ArUco navigation controls
- Connection Settings: Configure MQTT broker, port, username, password, and prefix in the UI
- Connection management: Uses
connect_mqtt()anddisconnect_mqtt()methods - Safety check: All commands verify
is_connectedflag before publishing - Auto-refresh: Uses
gr.Timer(2)for 2-second status updates (not deprecatedeveryparameter)
Hugging Face Deployment
The project includes app.py in the root directory for Hugging Face Spaces deployment:
- Entry point:
app.py(imports and runssrc/gradio_demo.py) - README.md includes YAML frontmatter for Space configuration
- Space URL: https://huggingface.co/spaces/MCP-1st-Birthday/Drone-Control-MCP-Server
Code Patterns
MQTT Client Setup (all components)
self.mqtt_client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="unique_id")
self.mqtt_client.on_connect = self._on_connect # Signature: (client, userdata, flags, rc, properties)
self.mqtt_client.on_message = self._on_message
if username and password:
self.mqtt_client.username_pw_set(username, password)
self.mqtt_client.connect(broker, port, 60)
self.mqtt_client.loop_start()
Drone Simulator State Management
The simulator maintains state (position, altitude, heading, is_flying) and updates it when commands are received. It does NOT execute real movement - just simulates by updating internal variables and publishing status.
Testing
Run the full system locally:
- Start all 4 terminals as shown above
- In Gradio (localhost:7860), click Connect
- Test commands via Gradio UI
- Optionally connect Claude Desktop and test via natural language
- Watch Terminal 2 for drone simulator logs
Real Drone Integration
This project is designed to work with DJI drones via MQTT using the action protocol.
Requirements:
- DJI drone with MQTT support
- Red Dot Drone mobile app for ArUco marker flight control
- Drone firmware implementing the action protocol
Integration:
- The drone subscribes to:
{mqtt_prefix}/remotecontrol/action - The drone publishes status to:
{mqtt_prefix}/remotecontrol/aruco-mission/status - No changes needed to MCP server or Gradio demo - they send action protocol commands
Simulator for Testing:
mqtt_drone_client.py simulates a drone by:
- Subscribing to action protocol topic
- Handling both action protocol and legacy commands
- Simulating flight state changes
- Logging received commands (does not perform actual flight)