Ideon Logo
Ideon

MCP Server

Ideon exposes a Model Context Protocol (MCP) endpoint that allows AI agents to read and manipulate your canvas programmatically. Any MCP-compatible client — Claude Code, Cursor, Windsurf, or custom integrations — can connect and interact with your projects.

Overview

The MCP server provides:

  • 15 tools for managing projects, blocks, links, kanban tasks, and search
  • 3 resources for contextual information about your canvas
  • Intelligent block placement that avoids overlap and respects spatial layout
  • Real-time sync — changes made by AI agents appear instantly for connected collaborators
  • Permission enforcement — respects existing project roles (owner/editor/viewer)

Authentication

The MCP server authenticates via your existing Ideon API keys.

Generating an API Key

  1. Open your account page and navigate to the Developers tab.
  2. Click "Generate new key".
  3. Enter a name for the key (e.g. "Claude Code", "Cursor") and confirm.
  4. A modal appears with the full key (format: sk-ideon-...). Copy it.

Security Notes

  • Keys are hashed with SHA-256 before storage — Ideon never stores the raw key.
  • Each key is scoped to the user who created it — all MCP operations run with that user's permissions.
  • You can revoke a key at any time from the same Developers tab. It stops working immediately.
  • Rate limited to 60 requests per minute per key (sliding window).

Client Configuration

Claude Code / Claude Desktop

Add to your MCP configuration file (~/.claude/mcp.json or project-level):

{
  "mcpServers": {
    "ideon": {
      "url": "https://your-ideon-instance.com/api/mcp",
      "headers": {
        "Authorization": "Bearer sk-ideon-your-api-key-here"
      }
    }
  }
}

Cursor

Add to your Cursor MCP settings (.cursor/mcp.json):

{
  "mcpServers": {
    "ideon": {
      "url": "https://your-ideon-instance.com/api/mcp",
      "headers": {
        "Authorization": "Bearer sk-ideon-your-api-key-here"
      }
    }
  }
}

Generic MCP Client

Any client supporting the Streamable HTTP transport can connect:

  • Endpoint: POST /api/mcp
  • Transport: Streamable HTTP (stateless, JSON-RPC over HTTP)
  • Auth Header: Authorization: Bearer sk-ideon-...
  • Content-Type: application/json
  • Accept Header: application/json, text/event-stream

MCP-compatible clients usually set the Accept header automatically. Include it explicitly when calling the endpoint with curl or another HTTP client.

Agent Skill

Install the official Ideon canvas skill with the Skills CLI:

npx skills add 3xpyth0n/ideon --skill ideon-canvas

Direct HTTP Request

Store the instance URL and API key in environment variables rather than in shell history or source files:

export IDEON_URL="https://your-ideon-instance.com"
export IDEON_API_KEY="sk-ideon-your-api-key"

List the tools exposed by the server:

curl --fail-with-body "$IDEON_URL/api/mcp" \
  -H "Authorization: Bearer $IDEON_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  --data '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'

Call list_projects with the same headers and endpoint:

curl --fail-with-body "$IDEON_URL/api/mcp" \
  -H "Authorization: Bearer $IDEON_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  --data '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"list_projects","arguments":{}}}'

The response may be JSON or an SSE message event containing the JSON-RPC response.

Available Tools

Projects

ToolDescription
list_projectsList all projects accessible by the authenticated user (max 100)
get_projectGet project metadata including block count, link count, and bounding box

Blocks

ToolDescription
list_blocksList all blocks in a project (max 200) with type, position, and content preview
get_blockGet full block details (content, data, metadata, position)
create_blockCreate a new block with intelligent placement
update_blockUpdate block content, data, metadata, position, or dimensions
delete_blockDelete a block and cascade-delete connected links
create_blocks_batchCreate up to 50 blocks in a single atomic operation (auto grid layout)

Links

ToolDescription
list_linksList all links (connections) between blocks
create_linkCreate a connection between two blocks
delete_linkRemove a connection

Kanban

ToolDescription
list_kanban_tasksList columns and tasks in a kanban block
create_kanban_taskAdd a new task to a kanban column
move_kanban_taskMove a task between columns

Search

ToolDescription
search_blocksCase-insensitive search across block content and metadata (max 50 results)

Resources

MCP resources provide contextual information to help AI agents understand your workspace:

Resource URIDescription
canvas://project/{id}/overviewText summary: block counts by type, link count, bounding box
canvas://project/{id}/graphFull graph structure as JSON (blocks + links)
canvas://helpStatic guide covering block types, placement practices, and examples

Canvas Automation Examples

The MCP API edits canvases inside existing projects; it does not create projects. Call list_projects to choose a project, then inspect it with get_project and list_blocks before making changes.

Create a framed project map

Create a frame block with create_block, for example with position: { "x": 100, "y": 100 }, width: 900, and height: 600. Use create_blocks_batch to add text blocks at positions inside those bounds, then connect related block IDs with create_link. The frame is a visual container; the MCP API does not define a parent-child grouping operation.

create_blocks_batch accepts block definitions like:

{
  "projectId": "PROJECT_ID",
  "blocks": [
    {
      "blockType": "text",
      "content": "Define the release scope",
      "position": { "x": 150, "y": 180 }
    },
    {
      "blockType": "text",
      "content": "Validate the deployment",
      "position": { "x": 500, "y": 180 }
    }
  ]
}

Use the IDs returned by the batch call with create_link:

{
  "projectId": "PROJECT_ID",
  "sourceBlockId": "FIRST_BLOCK_ID",
  "targetBlockId": "SECOND_BLOCK_ID",
  "label": "followed by"
}

Create and update a Mermaid diagram

Create a mermaid block with its editable diagram source as content. Update the same content field to change the diagram.

{
  "projectId": "PROJECT_ID",
  "blockType": "mermaid",
  "content": "flowchart LR\n  Source --> Canvas"
}

Pass the returned block ID to update_block when replacing the source:

{
  "projectId": "PROJECT_ID",
  "blockId": "MERMAID_BLOCK_ID",
  "content": "sequenceDiagram\n  Agent->>Ideon: Update diagram"
}

Create kanban tasks

Create a kanban block with create_block, initialize its metadata.columns with update_block, and then call create_kanban_task for each task. A column must exist before a task can be added.

{
  "projectId": "PROJECT_ID",
  "blockId": "KANBAN_BLOCK_ID",
  "metadata": {
    "columns": [
      {
        "id": "c-todo",
        "title": "To do",
        "workflowState": "todo",
        "tasks": []
      },
      {
        "id": "c-progress",
        "title": "In progress",
        "workflowState": "in-progress",
        "tasks": []
      },
      { "id": "c-done", "title": "Done", "workflowState": "done", "tasks": [] }
    ]
  }
}

Call create_kanban_task with the returned kanban block ID:

{
  "projectId": "PROJECT_ID",
  "blockId": "KANBAN_BLOCK_ID",
  "columnId": "c-todo",
  "title": "Review the release checklist"
}

Block Placement

When creating blocks, the AI agent can control positioning in several ways:

Relative placement (recommended)

Use anchorBlockId + direction to place a new block near an existing one:

anchorBlockId: "existing-block-id"
direction: "right" | "left" | "up" | "down"

The placement engine automatically avoids collisions with a 40px minimum gap.

Explicit position

Provide exact position: { x, y } coordinates. No collision detection is applied.

Automatic placement

If neither anchor nor position is specified, blocks are placed to the right of the existing canvas content.

Batch placement

create_blocks_batch arranges blocks in a grid (max 5 columns) with uniform spacing.

Provide explicit position values in a batch when placing notes inside a frame's visual bounds.

Permissions

MCP operations respect the same roles as the Ideon UI:

RoleReadWrite
Owner✓✓
Editor✓✓
Viewer✓✗

Write operations include: create_block, update_block, delete_block, create_blocks_batch, create_link, delete_link, create_kanban_task, move_kanban_task.

Rate Limiting

Each API key is limited to 60 requests per 60-second sliding window.

Response headers on every request:

  • X-RateLimit-Limit: 60
  • X-RateLimit-Remaining: <n>
  • X-RateLimit-Reset: <unix-timestamp>

When rate-limited, the server returns HTTP 429 with a Retry-After header indicating seconds to wait.

Error Codes

CodeMeaning
-32001Authentication failed (invalid or missing API key)
-32002Permission denied (insufficient role)
-32003Resource not found (project, block, or link)
-32004Validation error (invalid block type, content too long, etc.)
-32602Invalid parameters (schema validation failed)
-32603Internal server error

Constraints

  • Maximum request body size: 1 MB
  • Maximum block content: 100,000 characters
  • Block width: 100–2000 px
  • Block height: 50–2000 px
  • Batch size: 1–50 blocks per call
  • Link label: max 200 characters
  • Search query: 1–200 characters
  • Self-links are not allowed
  • Core blocks cannot be moved, resized, or deleted

Example Workflow

A typical AI agent workflow:

  1. Discover — call list_projects to find the target project
  2. Orient — read canvas://project/{id}/overview for a quick summary
  3. Explore — call list_blocks to understand the spatial layout
  4. Act — create blocks near relevant existing content using anchorBlockId
  5. Connect — use create_link to represent relationships
Agent: "I'll add three related notes about the authentication flow."

→ list_blocks(projectId) — finds the "Auth" block at (200, 100)
→ create_blocks_batch(projectId, [
    { blockType: "text", content: "Login flow...", anchorBlockId: "auth-block" },
    { blockType: "text", content: "Token refresh..." },
    { blockType: "text", content: "Session management..." }
  ])
→ create_link(projectId, "new-block-1", "auth-block", label: "implements")