MCPlease
MCPlease is a lightweight Rust framework for building MCP (Model Context Protocol) servers. It provides a simple, macro-driven approach to defining tools and managing state, with built-in support for session persistence and cross-process synchronization.
Features
- Simple tool definition using the
tools!
macro - Automatic JSON Schema generation from Rust structs using
schemars
- Session management with cross-process synchronization via file watching
- Command-line interface with automatic help generation via
clap
- Example system for better tool documentation
- Stdio-based MCP communication (WebSocket support planned)
- Code generation CLI for rapid development
Quick Start with CLI (Recommended)
The fastest way to get started is with the mcplease CLI tool:
# Install the CLI
# Create a new MCP server with tools
# Navigate to your project
# Add more tools as needed
# Test that it compiles
# Run your MCP server
This creates a fully functional MCP server with:
- ✅ Proper project structure
- ✅ Generated tool implementations (with TODOs for you to fill in)
- ✅ State management boilerplate
- ✅ All necessary dependencies
- ✅ Beautifully formatted code
For detailed CLI documentation, see cli/README.md
Manual Setup
1. Create a new MCP server project
2. Add dependencies to Cargo.toml
[]
= "1.0"
= { = "4.5", = ["derive"] }
= "0.4.6"
= "0.2.0"
= "1.0.4"
= { = "1.0", = ["derive"] }
= "1.0"
3. Define your state structure
Create src/state.rs
:
use Result;
use SessionStore;
use ;
use PathBuf;
4. Create tools
Create src/tools/
directory and add tool implementations. Each tool should be in its own module:
src/tools/hello.rs:
use crate MyToolsState;
use Result;
use ;
use ;
/// Say hello to someone
src/tools/set_working_directory.rs:
use crate MyToolsState;
use Result;
use ;
use ;
use PathBuf;
/// Set the working directory for relative path operations
5. Wire everything together
src/tools.rs:
use crate MyToolsState;
tools!;
src/main.rs:
use Result;
use server_info;
use MyToolsState;
const INSTRUCTIONS: &str = "This is my custom MCP server. Use set_working_directory to establish context.";
6. Run your server
# Run as MCP server (stdio mode)
# Or use tools directly from command line
Framework Architecture
Core Components
tools!
macro: Generates the enum that implements MCP tool dispatchTool
trait: Defines how individual tools executeWithExamples
trait: Provides example usage for documentationSessionStore
: Handles persistent state with cross-process sync- JSON Schema generation: Automatic from Rust structs via
schemars
Tool Definition Pattern
Each tool follows this pattern:
State Management
The framework uses SessionStore<T>
for persistent state:
- Cross-process safe: File watching detects external changes
- Atomic writes: Temporary file + rename prevents corruption
- Session-based: Multiple sessions can coexist
- JSON serialization: Human-readable storage format
Session Store API
// Get or create session data
let data = store.get_or_create?;
// Update data with closure
store.update?;
// Get without creating
let maybe_data = store.get?;
// Set directly
store.set?;
Example MCP Servers
The framework includes several reference implementations:
fs-mcp (Filesystem Operations)
- Tools: read, write, delete, move, list, search, set_working_directory
- Features: Glob patterns, metadata, recursive operations
- Session data: Working directory context
cargo-mcp (Rust Project Management)
- Tools: build, test, check, clippy, add/remove deps, clean, bench
- Features: Toolchain selection, package targeting, environment variables
- Session data: Project directory
semantic-edit-mcp (Code Editing)
- Tools: preview_edit, retarget_edit, persist_edit, set_working_directory
- Features: AST-aware editing, language detection, diff preview
- Session data: Staged operations, working directory
rustdoc-json-mcp (Documentation)
- Tools: get_item, set_working_directory
- Features: Rustdoc JSON parsing, type information, source code
- Session data: Project manifest directory
Advanced Features
Error Handling
Tools should return anyhow::Result<String>
for consistent error propagation:
Examples and Documentation
Provide meaningful examples to help users understand tool usage:
Optional Parameters
Use Option<T>
with proper serialization handling:
Shared Session Data
For tools that need to share context across processes:
// In your state struct:
Best Practices
Tool Design
- Single responsibility: Each tool should do one thing well
- Clear documentation: Use detailed doc comments on all parameters
- Meaningful examples: Provide realistic usage scenarios
- Error context: Use
anyhow::Context
for descriptive error messages - Defensive programming: Validate inputs and handle edge cases
State Management
- Minimal state: Only persist what's necessary across calls
- Default values: Use
#[serde(default)]
for backward compatibility - Session IDs: Use logical identifiers like "default", project names, etc.
- Cleanup: Consider implementing state cleanup for old sessions
Error Messages
Return user-friendly messages that help with debugging:
// Good: Specific and actionable
Ok
// Bad: Generic and unhelpful
Err
Path Handling
Use consistent path resolution patterns:
Debugging
Logging
Set MCP_LOG_LOCATION
environment variable to enable logging:
Log levels: RUST_LOG=trace,warn,error,debug,info
Testing Tools Directly
Use the command-line interface for testing:
# Test individual tools
# Get help
Common Issues
- Schema validation errors: Ensure all fields have proper serde attributes
- Session conflicts: Use unique session IDs for different contexts
- Path resolution: Always handle both absolute and relative paths
- JSON parsing: Check that tool parameters match expected schema
Contributing
When adding new tools to existing servers:
- Create a new module in
src/tools/
- Implement the required traits
- Add to the
tools!
macro insrc/tools.rs
- Add tests in
src/tests.rs
- Update documentation and examples
The framework is designed to be extensible - new MCP servers should follow the established patterns for consistency and maintainability.