Miro MCP server
Enables interaction with Miro boards via MCP tools, supporting listing items, creating stickies, frames, shapes, connectors, and manipulating mind maps.
README
Miro MCP server (custom)
TypeScript Model Context Protocol server that talks to the Miro REST API v2 (plus experimental mind map endpoints under v2-experimental). It exposes tools for listing board items, board metadata, native mind maps, creating stickies, frames, shapes, and connectors, and updating, moving, or deleting items. The host (Cursor, Claude Desktop, or another MCP client) spawns this process over stdio; the model decides when to call each tool from the tool descriptions.
Requirements: Node.js 18+, a Miro OAuth access token with boards:read and boards:write.
Setup
1. Clone the repository
git clone https://github.com/DChuhin/miro-mcp-server.git
cd miro-mcp-server
Use your fork’s URL if you cloned from elsewhere.
2. Install dependencies and build
npm install
npm run build
The MCP entrypoint is dist/index.js. Re-run npm run build after changing TypeScript sources if your client runs the compiled file (see Cursor / Claude below).
3. Miro token and board ID
Token (required for the server to call Miro)
- In Miro, open the Developer / Your apps area and create an app.
- Enable scopes
boards:readandboards:write. - Complete the OAuth flow to obtain an access token (see Miro OAuth).
You can keep secrets out of the shell by copying the example env file:
cp .env.example .env
# Edit .env and set MIRO_TOKEN=...
For Cursor and Claude Desktop, the most reliable approach is to put MIRO_TOKEN in the MCP config’s env block (see below). The spawned process may not load .env unless the client sets the working directory to the project root.
Never commit .env or paste tokens into chat.
Board ID (required in normal use)
Tools take a board_id argument. The model needs the board ID whenever you ask for board-specific work. Find it in the board URL: the segment after /board/ (example shape: uXjVGnXi5V0=). Mention it explicitly in prompts, for example: “On board uXjV…, list sticky notes.”
The server does not read a default board from the environment for MCP tool calls. MIRO_BOARD_ID is only useful for the optional integration test script (see Development).
Cursor
- Complete setup steps 1–3 (clone,
npm install,npm run build, obtain a token). - Open Cursor Settings → MCP (or edit the MCP config file directly). Cursor commonly uses
~/.cursor/mcp.json.
Example (replace the path with the absolute path to this repo on your machine):
{
"mcpServers": {
"miro-custom": {
"command": "node",
"args": ["/absolute/path/to/miro-mcp-server/dist/index.js"],
"env": {
"MIRO_TOKEN": "your_miro_oauth_token_here"
}
}
}
}
Alternative (development): point args at tsx and the TypeScript entry so you can skip npm run build while iterating:
{
"mcpServers": {
"miro-custom": {
"command": "npx",
"args": ["tsx", "/absolute/path/to/miro-mcp-server/src/index.ts"],
"env": {
"MIRO_TOKEN": "your_miro_oauth_token_here"
}
}
}
}
Reload MCP servers or restart Cursor after saving the config.
Claude Desktop
- Complete setup steps 1–3 (clone,
npm install,npm run build, obtain a token). - Edit Claude Desktop MCP configuration (location varies by OS; search for
claude_desktop_config.jsonin Claude’s documentation). - Under
mcpServers, add the same shape as in Cursor, using the absolute path todist/index.js:
{
"mcpServers": {
"miro-custom": {
"command": "node",
"args": ["/absolute/path/to/miro-mcp-server/dist/index.js"],
"env": {
"MIRO_TOKEN": "your_miro_oauth_token_here"
}
}
}
}
Restart Claude Desktop after changes. Enable the miro-custom server in the app if your client lists MCP servers per conversation.
Sanity check (optional)
npm start
This runs the MCP server on stdio. On its own it will appear to “hang”; that is normal. You normally do not run it in a terminal unless you are debugging—the editor spawns it once MCP is configured.
Using the agent (LLM + tools)
After the MCP server is connected in Cursor or Claude:
- Open a chat that has MCP tools enabled for this server.
- Give the board ID (from the board URL) when you ask for board-specific work.
- The model can call tools such as
get_board_info,list_board_items,list_mindmap_nodes,create_mindmap_node,delete_mindmap_node,create_sticky_note,create_frame,create_connector,update_item_content,move_item, anddelete_item.
Example prompts:
- “Call
get_board_infofor boarduXjV…and summarize the board.” - “List all sticky notes on board
…, then add a yellow sticky at (100, -50) with the text ‘Review Q2’.” - “Create a frame titled ‘Backlog’ and two stickies inside it connected by a curved connector.”
- “On board
…, calllist_mindmap_nodes, then add a child node under id…with text ‘New branch’.”
Mind maps use Miro’s native widget (text nodes; connectors are managed by Miro). Use list_mindmap_nodes / create_mindmap_node / delete_mindmap_node—not shapes plus create_connector.
Why coordinates? In the desktop app, + uses Miro’s internal layout; the experimental REST create mind map node API still expects a position and defaults omitted coordinates to (0,0), which stacks every node. That endpoint does not expose the same auto-placement as the UI, so this server computes x/y unless you pass them explicitly. Parent positions for that math come from list_mindmap_nodes (or a direct experimental mind map node read), not from generic GET /v2/boards/.../items/{id}—nested mind map nodes can report widget-local coordinates there, which would shift deeper children incorrectly.
Layout rule (this tool): Left-to-right mind maps only—the root is leftmost; every child is placed to the right of its parent (parent.x + offset). Siblings of the same parent share that X column and are spaced vertically using layout_sibling_index (0, 1, 2, …)—pass it when creating several children in a row because list_mindmap_nodes can lag. The create payload must stay within MindmapCreateRequest only. Overview: Mind map (Experimental).
Example hierarchy — use each create response’s id (or list_mindmap_nodes) as the next parent_node_id:
| Order | content |
parent_node_id |
layout_sibling_index |
|---|---|---|---|
| 1 | Center | (omit = root) | (omit) |
| 2 | node1 | Center’s id | 0 |
| 3 | node2 | Center’s id | 1 |
| 4–7 | nebula, quartz, velvet, ember | node1’s id | 0, 1, 2, 3 |
| 8–11 | cascade, prism, lotus, raven | node2’s id | 0, 1, 2, 3 |
Optional: set root position with x / y on the first call (e.g. 1160, 0).
The agent chooses tools based on their registered names and descriptions; you do not call the REST API yourself in normal use.
Development
Run the server with tsx (no separate build step):
npm run dev
Ensure MIRO_TOKEN is set (for example via .env in the project root). The dev server still uses stdio, so it is mainly useful with an MCP client attached or for quick sanity checks.
Optional integration test against a real board (creates and then deletes test widgets unless SKIP_CLEANUP=1):
export MIRO_TOKEN='your_token'
export MIRO_BOARD_ID='board_id_from_url'
npx tsx scripts/miro-integration-test.ts
Compile manually when not using npm run dev with tsx:
npm run build
Project layout
| Path | Role |
|---|---|
src/index.ts |
MCP server entry, registers tools |
src/miro-client.ts |
HTTP client for https://api.miro.com/v2 |
src/tools/items.ts |
list_board_items, get_board_info |
src/tools/mindmap.ts |
list_mindmap_nodes, create_mindmap_node, delete_mindmap_node (experimental API) |
src/tools/create.ts |
Create stickies, frames, shapes, connectors |
src/tools/mutate.ts |
Update content, move, delete |
scripts/miro-integration-test.ts |
Optional real-board test |
Troubleshooting
- 401 / token errors: Regenerate or refresh the OAuth token; confirm
boards:readandboards:write. - Server not listed: Fix JSON in the MCP config, use absolute paths, restart the app.
- Old behaviour after edits: Run
npm run buildagain if the client usesdist/index.js.
License
MIT
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.