miro-mcp-resource-server

duquesnay/miro-mcp-resource-server

3.2

If you are the rightful owner of miro-mcp-resource-server 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.

Miro Rust Remote MCP Server is a production-ready Model Context Protocol server for Miro board manipulation, built in Rust with OAuth2 authentication.

Tools
6
Resources
0
Prompts
0

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

  • OAuth Resource Server Pattern: Claude handles OAuth, server validates Bearer tokens (RFC 9728)
  • In-Memory Token Caching: 95% cache hit rate, <1ms validation latency
  • 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

  • OAuth Resource Server Pattern: Simpler than Proxy OAuth (70% less code)
  • Rust Performance: Memory-safe, concurrent, and fast (~30s builds)
  • Remote MCP: Accessible from Claude.ai web interface via HTTPS
  • Production-Ready: Deployed to Scaleway Containers, stateless architecture

Prerequisites

  • Rust 1.70+ (2021 edition)
  • Miro Developer Account
  • OpenSSL (for generating encryption keys)

Setup

1. Get Miro OAuth2 Client ID

  1. Visit https://developers.miro.com/
  2. Click "Your Apps" → "Create new app"
  3. Note your Client ID (example: 3458764647516852398)
  4. No redirect URI needed - Claude handles OAuth flow directly

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 (Resource Server Pattern):

  • client_id: Your Miro OAuth2 Client ID (for OAuth metadata endpoint)
  • port: Server port (3010 for development)

Note: No client_secret, redirect_uri, or encryption_key needed - Claude handles the OAuth flow

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. Connect from Claude

The MCP server exposes OAuth Protected Resource metadata at /.well-known/oauth-protected-resource. Claude will discover this endpoint and handle the OAuth flow automatically when you first use the MCP server.

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 boards
  • create_board: Create a new board with name and description

Visual Elements

  • create_sticky_note: Create sticky notes with custom content, position, and color
  • create_shape: Create shapes (rectangle, circle, triangle) for org structures
  • create_text: Create text elements on boards
  • create_frame: Create frames for grouping related content

Coming Soon

  • list_items: List board items filtered by type
  • update_item: Update item properties dynamically
  • delete_item: Remove items from boards
  • create_connector: Connect items with styled arrows/lines
  • Squad visualization tools for rapid org chart creation

Security

  • Resource Server Pattern: Claude handles OAuth, we only validate tokens
  • Token Validation: Bearer tokens validated via Miro API introspection
  • In-Memory Caching: Tokens cached for 5 minutes, no persistent storage
  • Secrets Management: Client ID from environment variables only
  • 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 Resource Server Pattern?

  • Simpler than Proxy OAuth (70% less code)
  • Claude handles OAuth flow complexity
  • No state management required (PKCE, cookies, etc.)
  • Stateless architecture (scales horizontally)
  • Fast builds (~30s vs ~2min with encryption)

Why In-Memory Token Caching?

  • Reduces Miro API calls by 95%
  • <1ms validation latency (cached)
  • No database required
  • 5-minute TTL balances security vs performance

Deployment

Local Development

  1. Configure ~/.config/mcp/miro-rust/config.json with localhost redirect URI
  2. Run cargo run
  3. OAuth callback works on localhost:3010

Production (Scaleway Containers - Deployed)

  1. Deploy to Scaleway Containers using GitHub Actions (automated)
  2. Configure environment variables (MIRO_CLIENT_ID, PORT, BASE_URL)
  3. HTTPS configured automatically by Scaleway
  4. No secrets storage required (Claude handles OAuth tokens)

Deployment Status:

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:

  1. Create a new board
  2. Create frames for each squad
  3. Create color-coded sticky notes for team members (PO=yellow, SM=green, Dev=blue)
  4. Create connectors showing reporting relationships
  5. Return the board URL

All in <5 minutes via natural language!

API Documentation

Miro API v2

MCP Protocol

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_id and client_secret in ~/.config/mcp/miro-rust/config.json
  • Verify redirect_uri matches Miro app configuration exactly
  • Check token hasn't expired (refresh should be automatic)

"Token encryption failed"

  • Ensure encryption_key is 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

  1. Fork the repository
  2. Create feature branch (git checkout -b feat/amazing-feature)
  3. Follow Rust conventions (run cargo fmt and cargo clippy)
  4. Write tests for new features
  5. Ensure all tests pass (cargo test)
  6. Commit with conventional format (feat:, fix:, refactor:)
  7. 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


Built with ❤️ in Rust | Powered by OAuth2 | Secured by AES-256-GCM