duquesnay/miro-rust-remote-mcp
If you are the rightful owner of miro-rust-remote-mcp and would like to certify it and/or have it hosted online, please leave a comment on the right or send an email to dayong@mcphub.com.
A production-ready Model Context Protocol (MCP) server for Miro board manipulation, built in Rust with OAuth2 authentication.
Miro Rust Remote MCP Server
A production-ready Model Context Protocol (MCP) server for Miro board manipulation, built in Rust with OAuth2 authentication. Enables Claude AI to programmatically create and manage Miro boards, with special focus on visualizing agile squad organizational structures.
Features
- OAuth2 Authentication: Secure authorization code flow with PKCE and CSRF protection
- Automatic Token Refresh: Seamless token renewal without user intervention
- Board Operations: List and create Miro boards programmatically
- Visual Elements: Create sticky notes, shapes, text, and frames
- Item Management: List, update, and delete board items (coming soon)
- Connectors: Create styled arrows and lines showing relationships (coming soon)
- Squad Visualization: Rapid agile team structure visualization (coming soon)
Key Differentiators
- First OAuth2-enabled Miro MCP: Unlike existing TypeScript implementations using static tokens
- Rust Performance: Memory-safe, concurrent, and fast
- Remote MCP: Accessible from Claude.ai web interface via HTTPS
- Production-Ready: AES-256-GCM token encryption, comprehensive error handling
Prerequisites
- Rust 1.70+ (2021 edition)
- Miro Developer Account
- OpenSSL (for generating encryption keys)
Setup
1. Create Miro OAuth2 App
- Visit https://developers.miro.com/
- Click "Your Apps" → "Create new app"
- Note your Client ID and Client Secret
- Add redirect URI:
http://localhost:3010/oauth/callback(for local development)
2. Configure Application
Create the configuration directory and file:
# Create config directory
mkdir -p ~/.config/mcp/miro-rust
# Copy example config
cp config.example.json ~/.config/mcp/miro-rust/config.json
# Generate encryption key
openssl rand -hex 32
# Edit config.json with your credentials
nano ~/.config/mcp/miro-rust/config.json
Configuration file (~/.config/mcp/miro-rust/config.json):
{
"client_id": "your_client_id_here",
"client_secret": "your_client_secret_here",
"redirect_uri": "http://localhost:3010/oauth/callback",
"encryption_key": "output_from_openssl_rand_hex_32",
"port": 3010
}
Configuration Fields:
client_id: Your Miro OAuth2 Client ID (from Miro Developer Portal)client_secret: Your Miro OAuth2 Client Secret (from Miro Developer Portal)redirect_uri: OAuth2 callback URL (must match Miro app configuration)- Development:
http://localhost:3010/oauth/callback - Production:
https://your-domain.com/oauth/callback
- Development:
encryption_key: 32-byte hex string for token encryption (generate withopenssl rand -hex 32)port: Server port (3010 for development)
3. Build and Run
# Install dependencies and build
cargo build --release
# Run the server
cargo run --release
# Or run in development mode
cargo run
4. Start OAuth Flow
The MCP server will provide a start_auth tool that returns an authorization URL. Open this URL in your browser to authorize the application.
Project Structure
miro-mcp-server/
├── src/
│ ├── auth/ # OAuth2 implementation
│ │ ├── oauth.rs # Authorization code flow with PKCE
│ │ ├── token_store.rs # AES-256-GCM encrypted token storage
│ │ └── types.rs # Authentication types and errors
│ ├── mcp/ # MCP protocol implementation
│ │ ├── server.rs # MCP server with rmcp framework
│ │ └── auth_handler.rs # OAuth callback handling
│ ├── miro/ # Miro API client
│ │ ├── client.rs # HTTP client with auto-refresh
│ │ └── types.rs # Miro API types (boards, items, etc.)
│ ├── config.rs # Environment configuration
│ ├── lib.rs # Library exports
│ └── main.rs # Entry point
├── planning/ # Agile planning artifacts
└── tests/ # Integration tests
Available MCP Tools
Board Operations
list_boards: List all accessible Miro boardscreate_board: Create a new board with name and description
Visual Elements
create_sticky_note: Create sticky notes with custom content, position, and colorcreate_shape: Create shapes (rectangle, circle, triangle) for org structurescreate_text: Create text elements on boardscreate_frame: Create frames for grouping related content
Coming Soon
list_items: List board items filtered by typeupdate_item: Update item properties dynamicallydelete_item: Remove items from boardscreate_connector: Connect items with styled arrows/lines- Squad visualization tools for rapid org chart creation
Security
- OAuth2 Security: PKCE prevents authorization code interception, state parameter prevents CSRF
- Token Encryption: AES-256-GCM encryption for tokens at rest
- Secrets Management: All credentials loaded from environment variables
- No Unsafe Code: 100% safe Rust, memory safety guaranteed
- Comprehensive Error Handling: Result types throughout, no production panics
Development
Running Tests
# Run all tests
cargo test
# Run with output
cargo test -- --nocapture
# Run specific test
cargo test test_name
Code Quality
# Lint with clippy
cargo clippy -- -D warnings
# Format code
cargo fmt
# Check formatting
cargo fmt -- --check
Git Workflow
This project follows the Feature Branch Workflow with atomic commits:
# Create feature branch
git checkout -b feat/feature-name
# Make changes, run tests
cargo test && cargo clippy
# Commit (all commits reviewed for completeness)
git add .
git commit -m "feat: description of change"
# Merge to main
git checkout main
git merge feat/feature-name
Architecture Decisions
Why Rust?
- Memory safety without garbage collection
- Excellent async/await support via tokio
- Strong type system prevents many bugs at compile time
- Fast performance for production deployment
Why OAuth2 vs Static Tokens?
- Better security (tokens can be revoked)
- User-specific permissions (each user authorizes individually)
- Automatic refresh (no manual token renewal)
- Required for Claude.ai web interface integration
Why AES-256-GCM for Token Storage?
- Authenticated encryption (confidentiality + integrity)
- Industry standard, well-audited
- Efficient in Rust via
ringcrate - Prevents token tampering
Deployment
Local Development
- Configure
~/.config/mcp/miro-rust/config.jsonwith localhost redirect URI - Run
cargo run - OAuth callback works on localhost:3010
Production (HTTPS Required)
- Deploy to Scaleway Containers (or alternative platform)
- Configure HTTPS/TLS certificate
- Update redirect URI in
~/.config/mcp/miro-rust/config.jsonand Miro Developer Portal - Deploy with
cargo build --release
Configuration on Production Server:
# On your production server
mkdir -p ~/.config/mcp/miro-rust
nano ~/.config/mcp/miro-rust/config.json
# Add your production configuration with HTTPS redirect URI:
# "redirect_uri": "https://your-domain.com/oauth/callback"
Recommended Platforms:
- Scaleway Containers (Selected): Container-based deployment, native HTTPS, predictable pricing
- Railway: Simple deployment, automatic HTTPS, environment-based config
- Self-hosted: Full control, requires Nginx for HTTPS, manual config management
Primary Use Case: Agile Squad Visualization
Example prompt to Claude:
"Create a Miro board showing 3 agile squads (Alpha, Beta, Gamma). Each squad has 1 Product Owner, 1 Scrum Master, and 5 developers. Show reporting lines from team members to Scrum Master."
The MCP server will:
- Create a new board
- Create frames for each squad
- Create color-coded sticky notes for team members (PO=yellow, SM=green, Dev=blue)
- Create connectors showing reporting relationships
- Return the board URL
All in <5 minutes via natural language!
API Documentation
Miro API v2
- Base URL:
https://api.miro.com/v2/ - Authentication: Bearer token (OAuth2)
- Rate Limit: 100 requests/minute per user
- Documentation: https://developers.miro.com/docs/rest-api-reference
MCP Protocol
- Specification: https://modelcontextprotocol.io/
- Transport: stdio (Claude.ai web interface) or HTTP
- Framework: rmcp (official Rust SDK)
Troubleshooting
"Configuration file not found"
- Ensure config directory exists:
mkdir -p ~/.config/mcp/miro-rust - Copy example config:
cp config.example.json ~/.config/mcp/miro-rust/config.json - Edit config with your credentials:
nano ~/.config/mcp/miro-rust/config.json
"Authentication failed"
- Check
client_idandclient_secretin~/.config/mcp/miro-rust/config.json - Verify
redirect_urimatches Miro app configuration exactly - Check token hasn't expired (refresh should be automatic)
"Token encryption failed"
- Ensure
encryption_keyis exactly 64 hex characters (32 bytes) - Generate new key:
openssl rand -hex 32 - Update it in
~/.config/mcp/miro-rust/config.json
"Rate limit exceeded"
- Miro API limit: 100 requests/minute
- Wait 60 seconds and retry
- Consider bulk operations for large visualizations
Contributing
- Fork the repository
- Create feature branch (
git checkout -b feat/amazing-feature) - Follow Rust conventions (run
cargo fmtandcargo clippy) - Write tests for new features
- Ensure all tests pass (
cargo test) - Commit with conventional format (
feat:,fix:,refactor:) - Push and create Pull Request
Roadmap
Sprint 1 (Complete) ✅
- OAuth2 authorization with PKCE
- Automatic token refresh
- Board list and creation
- Visual element creation (sticky notes, shapes, text, frames)
Sprint 2 (In Progress)
- Item management (list, update, delete)
- Connector creation with captions
- Squad visualization orchestration
Sprint 3 (Planned)
- Bulk operations for performance
- Production deployment guide
- Claude.ai web interface integration testing
License
MIT License - see LICENSE file for details
Acknowledgments
- Miro API v2 for comprehensive board manipulation
- MCP protocol for AI-native tool integration
- rmcp Rust SDK for clean MCP implementation
- oauth2-rs for robust OAuth2 client
- Anthropic for Claude Code development platform
Support
- Issues: https://github.com/yourusername/miro-rust-remote-mcp/issues
- Miro API Docs: https://developers.miro.com/docs
- MCP Specification: https://modelcontextprotocol.io/
Built with ❤️ in Rust | Powered by OAuth2 | Secured by AES-256-GCM