# magi-tool
Tool schema generation and MCP service management for LLM tool calling.
## Features
- **Tool Schema Generation** - Convert Rust types to JSON Schema for LLM tool definitions
- **PegBoard** (optional) - Manage multiple MCP services with automatic tool discovery and namespace conflict resolution
- **Thread-Safe** - Designed for concurrent access in async Rust applications
- **Type-Safe** - Full Rust type safety for tool parameters
### Feature Flags
- `pegboard` (enabled by default) - Includes the PegBoard service manager and rmcp integration
- Disable with `default-features = false` if you only need tool schema generation
```toml
# Full features (default)
magi-tool = "0.0.1"
# Tool schema generation only (faster compile, smaller binary)
magi-tool = { version = "0.0.1", default-features = false }
```
## Quick Example
```rust
use magi_tool::{get_tool, PegBoard};
use schemars::JsonSchema;
use std::sync::Arc;
#[derive(JsonSchema, serde::Deserialize)]
struct WeatherParams {
/// The city and state, e.g. San Francisco, CA
location: String,
unit: Option<String>,
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create a tool definition
let tool = get_tool::<WeatherParams, _, _>(
"get_weather",
Some("Get the current weather"),
)?;
// Or use PegBoard to manage multiple MCP services
let mut pegboard = PegBoard::new();
// Automatically discover tools from services
pegboard.add_service(Some("web".to_string()), web_service).await?;
pegboard.add_service(Some("fs".to_string()), fs_service).await?;
// Share across tokio tasks
let pegboard = Arc::new(pegboard);
// Get all tools for LLM
let tools = pegboard.get_all_tools();
// Execute tool calls from LLM (automatic routing)
let result = pegboard.call_tool(
"web-search",
serde_json::json!({"query": "rust programming"}),
).await?;
println!("Result: {:?}", result.structured_content);
Ok(())
}
```
## Documentation
See the [`docs/`](./docs) folder for comprehensive documentation:
- **[Getting Started](./docs/README.md)** - Overview and quick start
- **[PegBoard Design](./docs/PEGBOARD_DESIGN.md)** - Complete API reference and architecture
- **[Tokio Usage](./docs/TOKIO_USAGE.md)** - Async patterns and examples
- **[Optional Namespace](./docs/OPTIONAL_NAMESPACE.md)** - When and how to use namespaces
- **[Changes](./docs/CHANGES.md)** - Implementation history and migration guide
## Key Concepts
### Tool Schema Generation
Generate JSON schemas from Rust types for LLM tool definitions:
```rust
#[derive(JsonSchema, serde::Deserialize)]
struct SearchParams {
query: String,
max_results: Option<u32>,
}
let tool = get_tool::<SearchParams, _, _>("search", Some("Search the web"))?;
```
### PegBoard with Namespace Support
Manage multiple MCP services with optional name prefixing:
```rust
// WITH namespace - tools get prefixed to avoid conflicts
pegboard.add_service(Some("web".to_string()), web_service).await?;
// tool "search" becomes "web-search"
// WITHOUT namespace - use original names
pegboard.add_service(None, calculator_service).await?;
// tool "add" stays "add"
```
### Automatic Tool Discovery
PegBoard calls `list_tools()` on each service automatically:
```rust
// Register service - tools are discovered automatically
let count = pegboard.add_service(Some("fs".to_string()), service).await?;
println!("Discovered {} tools", count);
```
## Testing
```bash
cargo test -p magi-tool
```
## License
See workspace root for license information.