Squashed 'vendor/ruvector/' content from commit b64c2172
git-subtree-dir: vendor/ruvector git-subtree-split: b64c21726f2bb37286d9ee36a7869fef60cc6900
This commit is contained in:
685
crates/agentic-robotics-mcp/README.md
Normal file
685
crates/agentic-robotics-mcp/README.md
Normal file
@@ -0,0 +1,685 @@
|
||||
# agentic-robotics-mcp
|
||||
|
||||
[](https://crates.io/crates/agentic-robotics-mcp)
|
||||
[](https://docs.rs/agentic-robotics-mcp)
|
||||
[](../../LICENSE)
|
||||
[](https://modelcontextprotocol.io)
|
||||
|
||||
**Control robots with AI assistants using the Model Context Protocol**
|
||||
|
||||
Give Claude, GPT, or any AI assistant the ability to control your robots through natural language. Part of the [Agentic Robotics](https://github.com/ruvnet/vibecast) framework.
|
||||
|
||||
---
|
||||
|
||||
## 🎯 What is This?
|
||||
|
||||
**Problem:** You have a robot. You want to control it with natural language using an AI assistant like Claude.
|
||||
|
||||
**Solution:** This crate implements the [Model Context Protocol (MCP)](https://modelcontextprotocol.io), which lets AI assistants discover and use your robot's capabilities as "tools".
|
||||
|
||||
**Example conversation:**
|
||||
|
||||
```
|
||||
You: "Claude, move the robot to the kitchen"
|
||||
Claude: *calls move_robot tool with location="kitchen"*
|
||||
Robot: *navigates to kitchen*
|
||||
Claude: "I've moved the robot to the kitchen"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Quick Start (5 minutes)
|
||||
|
||||
### Step 1: Add to your project
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
agentic-robotics-mcp = "0.1"
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
serde_json = "1"
|
||||
```
|
||||
|
||||
### Step 2: Create a simple MCP server
|
||||
|
||||
```rust
|
||||
use agentic_robotics_mcp::*;
|
||||
use serde_json::json;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
// Create MCP server
|
||||
let server = McpServer::new("my-robot", "1.0.0");
|
||||
|
||||
// Register a "move_robot" tool
|
||||
let move_tool = McpTool {
|
||||
name: "move_robot".to_string(),
|
||||
description: "Move the robot to a location".to_string(),
|
||||
input_schema: json!({
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"location": {
|
||||
"type": "string",
|
||||
"description": "Where to move (kitchen, bedroom, etc.)"
|
||||
}
|
||||
},
|
||||
"required": ["location"]
|
||||
}),
|
||||
};
|
||||
|
||||
server.register_tool(move_tool, server::tool(|args| {
|
||||
let location = args["location"].as_str().unwrap();
|
||||
println!("🤖 Moving robot to: {}", location);
|
||||
|
||||
// Your robot movement code here
|
||||
// move_robot_hardware(location);
|
||||
|
||||
Ok(server::text_response(format!(
|
||||
"Robot moved to {}",
|
||||
location
|
||||
)))
|
||||
})).await?;
|
||||
|
||||
// Run stdio transport (for Claude Desktop, IDEs, etc.)
|
||||
let transport = transport::StdioTransport::new(server);
|
||||
transport.run().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
|
||||
### Step 3: Connect from Claude Desktop
|
||||
|
||||
Add to your Claude Desktop config:
|
||||
|
||||
**Mac:** `~/Library/Application Support/Claude/claude_desktop_config.json`
|
||||
**Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
|
||||
**Linux:** `~/.config/Claude/claude_desktop_config.json`
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"my-robot": {
|
||||
"command": "/path/to/your/robot-mcp-server"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**That's it!** Claude can now control your robot 🎉
|
||||
|
||||
---
|
||||
|
||||
## 📖 Complete Documentation
|
||||
|
||||
This README provides everything you need to know. Jump to:
|
||||
|
||||
- [Why Use MCP](#-why-use-mcp-for-robots)
|
||||
- [Complete Tutorial](#-complete-tutorial)
|
||||
- [Real-World Examples](#-real-world-use-cases)
|
||||
- [Advanced Features](#-advanced-features)
|
||||
- [Troubleshooting](#-troubleshooting)
|
||||
|
||||
**Or view the full docs at [docs.rs/agentic-robotics-mcp](https://docs.rs/agentic-robotics-mcp)**
|
||||
|
||||
---
|
||||
|
||||
## 🤖 Why Use MCP for Robots?
|
||||
|
||||
Traditional robot control requires writing code for every possible command. With MCP, you describe what your robot can do, and AI figures out how to use those capabilities.
|
||||
|
||||
### Before MCP
|
||||
```rust
|
||||
// You write code for hundreds of commands
|
||||
match command {
|
||||
"move forward" => robot.forward(),
|
||||
"turn left" => robot.left(),
|
||||
"go to kitchen" => robot.navigate("kitchen"),
|
||||
// ... 100+ more commands
|
||||
}
|
||||
```
|
||||
|
||||
### With MCP
|
||||
```rust
|
||||
// Just describe capabilities - AI does the rest
|
||||
server.register_tool(move_tool, handler);
|
||||
server.register_tool(grab_tool, handler);
|
||||
server.register_tool(scan_tool, handler);
|
||||
|
||||
// AI: "go to kitchen and grab the cup"
|
||||
// -> Automatically calls: move_robot("kitchen"), grab_object("cup")
|
||||
```
|
||||
|
||||
**Benefits:**
|
||||
- ✅ **Natural language** - Control robots by talking naturally
|
||||
- ✅ **Flexible** - AI combines tools in creative, unexpected ways
|
||||
- ✅ **Simple** - Just describe capabilities, don't write parsers
|
||||
- ✅ **Standard** - Works with Claude, GPT, and all MCP-compatible AIs
|
||||
- ✅ **Discoverable** - AI learns what your robot can do automatically
|
||||
|
||||
---
|
||||
|
||||
## 🎓 Complete Tutorial
|
||||
|
||||
Let's build complete robot control systems step by step.
|
||||
|
||||
### Example 1: Navigation Robot (Beginner)
|
||||
|
||||
```rust
|
||||
use agentic_robotics_mcp::*;
|
||||
use serde_json::json;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
let server = McpServer::new("navigation-robot", "1.0.0");
|
||||
|
||||
// Tool 1: Move to location
|
||||
server.register_tool(
|
||||
McpTool {
|
||||
name: "move_to".to_string(),
|
||||
description: "Move robot to a named location".to_string(),
|
||||
input_schema: json!({
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"location": {
|
||||
"type": "string",
|
||||
"description": "kitchen, bedroom, living room, etc."
|
||||
}
|
||||
},
|
||||
"required": ["location"]
|
||||
}),
|
||||
},
|
||||
server::tool(|args| {
|
||||
let location = args["location"].as_str().unwrap();
|
||||
Ok(server::text_response(format!("Moving to {}", location)))
|
||||
})
|
||||
).await?;
|
||||
|
||||
// Tool 2: Get current status
|
||||
server.register_tool(
|
||||
McpTool {
|
||||
name: "get_status".to_string(),
|
||||
description: "Get robot position, battery level, and state".to_string(),
|
||||
input_schema: json!({ "type": "object", "properties": {} }),
|
||||
},
|
||||
server::tool(|_| {
|
||||
Ok(server::text_response(
|
||||
"Position: (5.2, 3.1)\nBattery: 87%\nState: Idle"
|
||||
))
|
||||
})
|
||||
).await?;
|
||||
|
||||
// Tool 3: Emergency stop
|
||||
server.register_tool(
|
||||
McpTool {
|
||||
name: "emergency_stop".to_string(),
|
||||
description: "EMERGENCY: Stop all robot movement immediately".to_string(),
|
||||
input_schema: json!({ "type": "object", "properties": {} }),
|
||||
},
|
||||
server::tool(|_| {
|
||||
println!("🛑 EMERGENCY STOP");
|
||||
Ok(server::text_response("Robot stopped"))
|
||||
})
|
||||
).await?;
|
||||
|
||||
// Start MCP server with stdio transport
|
||||
let transport = transport::StdioTransport::new(server);
|
||||
transport.run().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
|
||||
**What Claude can do:**
|
||||
- "Move to the kitchen" → `move_to(location="kitchen")`
|
||||
- "Where are you?" → `get_status()`
|
||||
- "Stop immediately!" → `emergency_stop()`
|
||||
|
||||
### Example 2: Vision Robot with Images (Intermediate)
|
||||
|
||||
```rust
|
||||
use agentic_robotics_mcp::*;
|
||||
use serde_json::json;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
let server = McpServer::new("vision-robot", "1.0.0");
|
||||
|
||||
// Tool: Detect objects in view
|
||||
server.register_tool(
|
||||
McpTool {
|
||||
name: "detect_objects".to_string(),
|
||||
description: "Detect all objects visible to camera".to_string(),
|
||||
input_schema: json!({ "type": "object", "properties": {} }),
|
||||
},
|
||||
server::tool(|_| {
|
||||
// Your vision code here
|
||||
let objects = vec!["cup", "book", "phone"];
|
||||
|
||||
Ok(server::text_response(format!(
|
||||
"Detected:\n{}",
|
||||
objects.iter().map(|o| format!("- {}", o)).collect::<Vec<_>>().join("\n")
|
||||
)))
|
||||
})
|
||||
).await?;
|
||||
|
||||
// Tool: Take photo and return image
|
||||
server.register_tool(
|
||||
McpTool {
|
||||
name: "take_photo".to_string(),
|
||||
description: "Capture photo from robot camera".to_string(),
|
||||
input_schema: json!({ "type": "object", "properties": {} }),
|
||||
},
|
||||
server::tool(|_| {
|
||||
// Capture and encode image
|
||||
// let image_base64 = capture_camera_base64();
|
||||
|
||||
Ok(ToolResult {
|
||||
content: vec![
|
||||
ContentItem::Text {
|
||||
text: "Photo captured".to_string()
|
||||
},
|
||||
ContentItem::Image {
|
||||
data: "iVBORw0KGgoAAAANS...".to_string(), // base64
|
||||
mimeType: "image/jpeg".to_string(),
|
||||
}
|
||||
],
|
||||
is_error: None,
|
||||
})
|
||||
})
|
||||
).await?;
|
||||
|
||||
let transport = transport::StdioTransport::new(server);
|
||||
transport.run().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
|
||||
**What Claude can do:**
|
||||
- "What do you see?" → Shows detected objects
|
||||
- "Take a picture" → Returns photo to Claude (shown to user)
|
||||
- "Is there a cup nearby?" → Combines detection + reasoning
|
||||
|
||||
### Example 3: Robotic Arm (Advanced)
|
||||
|
||||
```rust
|
||||
use agentic_robotics_mcp::*;
|
||||
use agentic_robotics_core::Node; // Connect to your robot
|
||||
use serde_json::json;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
// Connect to robot control system
|
||||
let mut node = Node::new("mcp_arm_controller")?;
|
||||
let cmd_pub = node.publish("/arm/commands")?;
|
||||
|
||||
let server = McpServer::new("robotic-arm", "1.0.0");
|
||||
|
||||
// Tool: Pick up object
|
||||
server.register_tool(
|
||||
McpTool {
|
||||
name: "pick_object".to_string(),
|
||||
description: "Pick up an object at specified position".to_string(),
|
||||
input_schema: json!({
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"object": { "type": "string" },
|
||||
"x": { "type": "number" },
|
||||
"y": { "type": "number" },
|
||||
"z": { "type": "number" }
|
||||
},
|
||||
"required": ["object", "x", "y", "z"]
|
||||
}),
|
||||
},
|
||||
server::tool(move |args| {
|
||||
let obj = args["object"].as_str().unwrap();
|
||||
let x = args["x"].as_f64().unwrap();
|
||||
let y = args["y"].as_f64().unwrap();
|
||||
let z = args["z"].as_f64().unwrap();
|
||||
|
||||
// Send command to robot
|
||||
// cmd_pub.publish(&PickCommand { object: obj, position: (x,y,z) }).await?;
|
||||
|
||||
Ok(server::text_response(format!(
|
||||
"Picked up {} at ({}, {}, {})",
|
||||
obj, x, y, z
|
||||
)))
|
||||
})
|
||||
).await?;
|
||||
|
||||
// Tool: Place object
|
||||
server.register_tool(
|
||||
McpTool {
|
||||
name: "place_object".to_string(),
|
||||
description: "Place held object at location".to_string(),
|
||||
input_schema: json!({
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"location": { "type": "string", "description": "table, shelf, etc." }
|
||||
},
|
||||
"required": ["location"]
|
||||
}),
|
||||
},
|
||||
server::tool(|args| {
|
||||
let loc = args["location"].as_str().unwrap();
|
||||
Ok(server::text_response(format!("Placed object at {}", loc)))
|
||||
})
|
||||
).await?;
|
||||
|
||||
let transport = transport::StdioTransport::new(server);
|
||||
transport.run().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
|
||||
**What Claude can do:**
|
||||
- "Pick up the red block at position (0.5, 0.3, 0.1)" → Precise control
|
||||
- "Place it on the table" → Predefined locations
|
||||
- "Move the cup from the counter to the shelf" → Multi-step tasks
|
||||
|
||||
---
|
||||
|
||||
## 🌟 Real-World Use Cases
|
||||
|
||||
### Use Case 1: Warehouse Robot
|
||||
|
||||
```rust
|
||||
// Tools: navigate_to, scan_barcode, pick_item, place_item, get_battery
|
||||
|
||||
// Claude conversation:
|
||||
// "Go to aisle 5, scan the items, and bring any with low stock to the depot"
|
||||
// -> Robot autonomously: navigates, scans, identifies low stock, picks, delivers
|
||||
```
|
||||
|
||||
### Use Case 2: Home Assistant Robot
|
||||
|
||||
```rust
|
||||
// Tools: navigate, detect_objects, vacuum_area, water_plants, take_photo
|
||||
|
||||
// Claude:
|
||||
// "Clean the living room and water any plants that look dry"
|
||||
// -> Navigates, identifies plants, checks moisture, waters as needed
|
||||
```
|
||||
|
||||
### Use Case 3: Research Laboratory Robot
|
||||
|
||||
```rust
|
||||
// Tools: move_to_station, pipette_liquid, centrifuge, analyze_sample
|
||||
|
||||
// Claude:
|
||||
// "Prepare 10 samples for PCR analysis"
|
||||
// -> Executes lab protocol automatically
|
||||
```
|
||||
|
||||
### Use Case 4: Security Patrol Robot
|
||||
|
||||
```rust
|
||||
// Tools: patrol_route, detect_anomalies, take_photo, sound_alarm
|
||||
|
||||
// Claude:
|
||||
// "Patrol the building and alert me if you see anything unusual"
|
||||
// -> Autonomous patrol with AI-powered anomaly detection
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Advanced Features
|
||||
|
||||
### Returning Images
|
||||
|
||||
```rust
|
||||
server::tool(|_| {
|
||||
let image_data = capture_camera(); // Your camera code
|
||||
let base64 = base64::encode(image_data);
|
||||
|
||||
Ok(ToolResult {
|
||||
content: vec![
|
||||
ContentItem::Image {
|
||||
data: base64,
|
||||
mimeType: "image/jpeg".to_string(),
|
||||
}
|
||||
],
|
||||
is_error: None,
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
### Multiple Content Items
|
||||
|
||||
```rust
|
||||
server::tool(|_| {
|
||||
Ok(ToolResult {
|
||||
content: vec![
|
||||
ContentItem::Text { text: "Scan complete".to_string() },
|
||||
ContentItem::Image { data: photo_base64, mimeType: "image/jpeg".to_string() },
|
||||
ContentItem::Resource {
|
||||
uri: "file:///robot/scans/scan001.pcd".to_string(),
|
||||
mimeType: "application/octet-stream".to_string(),
|
||||
data: point_cloud_base64,
|
||||
}
|
||||
],
|
||||
is_error: None,
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
### Error Handling
|
||||
|
||||
```rust
|
||||
server::tool(|args| {
|
||||
let location = args["location"].as_str().unwrap();
|
||||
|
||||
if location == "restricted_area" {
|
||||
return Ok(server::error_response(
|
||||
"Access denied: Cannot enter restricted area"
|
||||
));
|
||||
}
|
||||
|
||||
Ok(server::text_response("Moving..."))
|
||||
})
|
||||
```
|
||||
|
||||
### Async Operations
|
||||
|
||||
```rust
|
||||
server::tool(|args| {
|
||||
// Tool handlers are sync, but you can use tokio::task::block_in_place
|
||||
// for async work if needed
|
||||
Ok(server::text_response("Done"))
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔌 Supported Transports
|
||||
|
||||
### STDIO (Local AI Assistants)
|
||||
|
||||
For Claude Desktop, VS Code extensions, command-line tools:
|
||||
|
||||
```rust
|
||||
let transport = transport::StdioTransport::new(server);
|
||||
transport.run().await?;
|
||||
```
|
||||
|
||||
### SSE (Remote Web Access)
|
||||
|
||||
For web dashboards, mobile apps, remote control:
|
||||
|
||||
```rust
|
||||
// Coming soon
|
||||
use agentic_robotics_mcp::transport::sse;
|
||||
sse::run_sse_server(server, "0.0.0.0:8080").await?;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Configuration Examples
|
||||
|
||||
### Claude Desktop Config
|
||||
|
||||
**Mac:** `~/Library/Application Support/Claude/claude_desktop_config.json`
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"warehouse-robot": {
|
||||
"command": "/opt/robots/warehouse-mcp",
|
||||
"env": {
|
||||
"ROBOT_ID": "WH-001",
|
||||
"ROBOT_HOST": "192.168.1.100"
|
||||
}
|
||||
},
|
||||
"home-assistant": {
|
||||
"command": "/usr/local/bin/home-robot-mcp"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Reading Environment Variables
|
||||
|
||||
```rust
|
||||
use std::env;
|
||||
|
||||
let robot_id = env::var("ROBOT_ID").unwrap_or("default".to_string());
|
||||
let robot_host = env::var("ROBOT_HOST").unwrap_or("localhost".to_string());
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Troubleshooting
|
||||
|
||||
### Server doesn't appear in Claude
|
||||
|
||||
**Check:**
|
||||
1. Config file path is correct for your OS
|
||||
2. Binary is executable: `chmod +x /path/to/mcp-server`
|
||||
3. Binary runs standalone: `./mcp-server` (should wait for input)
|
||||
4. Check Claude logs:
|
||||
- Mac: `~/Library/Logs/Claude/mcp-server-*.log`
|
||||
- Windows: `%APPDATA%\Claude\logs\`
|
||||
- Linux: `~/.local/state/Claude/logs/`
|
||||
|
||||
### Tools aren't being called
|
||||
|
||||
**Solutions:**
|
||||
1. Make tool descriptions very clear and specific
|
||||
2. Verify `input_schema` matches what AI sends
|
||||
3. Add logging: `eprintln!("Tool {} called with: {:?}", name, args);`
|
||||
4. Test with simple tools first
|
||||
|
||||
### Connection errors
|
||||
|
||||
```rust
|
||||
// Add error handling
|
||||
match transport.run().await {
|
||||
Ok(_) => println!("Server stopped gracefully"),
|
||||
Err(e) => {
|
||||
eprintln!("Server error: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Debug Mode
|
||||
|
||||
```rust
|
||||
// Enable debug output
|
||||
env_logger::init();
|
||||
|
||||
// Or manual logging
|
||||
eprintln!("MCP Server started");
|
||||
eprintln!("Registered tools: {:?}", tool_names);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📚 Examples
|
||||
|
||||
Complete working examples in the [repository](https://github.com/ruvnet/vibecast/tree/main/examples):
|
||||
|
||||
- `mcp-navigation.rs` - Navigation robot with MCP
|
||||
- `mcp-vision.rs` - Computer vision integration
|
||||
- `mcp-arm.rs` - Robotic arm control
|
||||
- `mcp-swarm.rs` - Multi-robot coordination
|
||||
|
||||
Run them:
|
||||
```bash
|
||||
cargo run --example mcp-navigation
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Testing
|
||||
|
||||
```rust
|
||||
#[tokio::test]
|
||||
async fn test_move_tool() {
|
||||
let server = McpServer::new("test", "1.0.0");
|
||||
|
||||
server.register_tool(move_tool, move_handler).await.unwrap();
|
||||
|
||||
let request = McpRequest {
|
||||
jsonrpc: "2.0".to_string(),
|
||||
id: Some(json!(1)),
|
||||
method: "tools/call".to_string(),
|
||||
params: Some(json!({
|
||||
"name": "move_to",
|
||||
"arguments": { "location": "kitchen" }
|
||||
})),
|
||||
};
|
||||
|
||||
let response = server.handle_request(request).await;
|
||||
assert!(response.result.is_some());
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔗 Links
|
||||
|
||||
- **MCP Spec**: [modelcontextprotocol.io](https://modelcontextprotocol.io)
|
||||
- **Claude Desktop**: [claude.ai/download](https://claude.ai/download)
|
||||
- **Homepage**: [ruv.io](https://ruv.io)
|
||||
- **Docs**: [docs.rs/agentic-robotics-mcp](https://docs.rs/agentic-robotics-mcp)
|
||||
- **Repository**: [github.com/ruvnet/vibecast](https://github.com/ruvnet/vibecast)
|
||||
- **Examples**: [github.com/ruvnet/vibecast/tree/main/examples](https://github.com/ruvnet/vibecast/tree/main/examples)
|
||||
|
||||
---
|
||||
|
||||
## 🤝 Contributing
|
||||
|
||||
Ideas for contributions:
|
||||
- [ ] More example robots
|
||||
- [ ] WebSocket transport
|
||||
- [ ] Async tool handlers
|
||||
- [ ] Tool composition
|
||||
- [ ] Better error messages
|
||||
- [ ] Performance optimizations
|
||||
|
||||
---
|
||||
|
||||
## 📄 License
|
||||
|
||||
Licensed under either of:
|
||||
|
||||
- Apache License, Version 2.0 ([LICENSE-APACHE](../../LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
|
||||
- MIT License ([LICENSE-MIT](../../LICENSE-MIT) or http://opensource.org/licenses/MIT)
|
||||
|
||||
at your option.
|
||||
|
||||
---
|
||||
|
||||
<div align="center">
|
||||
|
||||
**Make robots accessible through natural language** 🤖
|
||||
|
||||
*Part of the Agentic Robotics framework - Making robotics faster, safer, and more accessible*
|
||||
|
||||
[Quick Start](#-quick-start-5-minutes) · [Tutorial](#-complete-tutorial) · [Examples](#-real-world-use-cases) · [Troubleshooting](#-troubleshooting)
|
||||
|
||||
**MCP 2025-11 Compliant** • **STDIO & SSE Transport** • **Production Ready**
|
||||
|
||||
</div>
|
||||
Reference in New Issue
Block a user