Todoist MCP Server

repository·main·Indexed 19 days ago

https://github.com/doist/todoist-mcp

The official Model Context Protocol (MCP) server and library that connects AI agents to Todoist. It allows LLMs to access and modify Todoist accounts through over 40 tools across domains such as tasks, projects, sections, and productivity stats. It can be used as a standalone MCP server (via stdio or HTTP) or imported as a dependency into custom AI applications. Supports MCP Apps for rendering interactive UI widgets within AI chat interfaces.

Tokens
8.2K
Snippets
30
Records
46
Agent score
68%

What's inside @doist/todoist-mcp

  1. Overview of @doist/todoist-mcp

    main

    The @doist/todoist-mcp package is an MCP (Model Context Protocol) server that exposes Todoist functionality as tools for Large Language Models (LLMs). It acts as a bridge between AI agents and the Todoist API by wrapping the @doist/todoist-sdk.

    It provides two primary binaries:

    • todoist-mcp: A standard input/output (stdio) MCP server, which is the primary way to use the project.
    • todoist-mcp-http: An Express-based HTTP wrapper for the MCP server.

    Technical Requirements:

    • Node.js >= 24
    • npm >= 11
    • ESM-only
    • Uses zod v4 for schema validation and MCP SDK ≥ 1.25.
  2. Concept: MCP Apps (Interactive UI Widgets)

    main

    This project supports MCP Apps, which are interactive UI widgets rendered inline within AI chat interfaces. Instead of returning plain text, these widgets provide rich visual representations of tool outputs, such as task lists.

    Detailed architecture and development workflows for widgets can be found in docs/mcp-apps.md.

  3. Avoid tool design anti-patterns

    main

    When developing tools for the Todoist MCP server, avoid the following anti-patterns:

    • One-to-one API mapping: Creating tools that simply mirror API endpoints without adding workflow value.
    • Overly complex parameters: Making basic operations difficult to use.
    • Inconsistent interfaces: Having different parameter structures for similar tools.
    • Raw API responses: Returning data without providing context to the LLM.
    • Fragmented operations: Forcing an LLM to make multiple tool calls for a single related workflow.
  4. Guidelines for tool naming and design

    main

    When designing or extending tools, follow these naming and design conventions:

    Naming Conventions

    • Use Action Verbs: Start names with find-, add-, manage-, or complete-.
    • Use User Terminology: Use terms users understand (e.g., complete-tasks instead of close-tasks).

    Design Best Practices

    • Batch Support: Implement batch support when users commonly perform multiple related items at once.
    • Smart Defaults: Use optional parameters and attempt to auto-detect user intent.
    • Rich Responses: Always aim for a combination of structured data, human text, and suggested next steps.

    Decision Logic

    • Create a new tool when: It represents a distinct user workflow, cannot be elegantly extended, or has unique parameter requirements.
    • Extend an existing tool when: The new functionality is closely related to the existing tool's purpose, can be handled with additional parameters, or follows the same workflow pattern.
  5. Understand the TodoistTool contract

    main

    Every tool in this project follows a strict TodoistTool interface defined in src/todoist-tool.ts. This contract ensures that the MCP server can correctly register tools, validate parameters using Zod, and handle execution logic consistently.

    A tool must define:

    • name: The unique identifier for the tool.
    • description: A string describing what the tool does (used by the LLM).
    • parameters: A Zod raw shape defining the input schema.
    • annotations: Metadata including readOnlyHint, destructiveHint, and idempotentHint to guide the LLM on how to use the tool safely.
    • execute: An asynchronous function that takes the parsed arguments and the TodoistApi client, returning a response containing textContent, structuredContent, or contentItems.
    type TodoistTool<
        Params extends z.ZodRawShape,
        Output extends z.ZodRawShape = Record<string, never>,
    > = {
        name: string
        description: string
        parameters: Params // Zod raw shape (NOT z.object)
        outputSchema?: Output // Zod raw shape; omit for tools that return only content blocks
        annotations: {
            readOnlyHint: boolean
            destructiveHint: boolean
            idempotentHint: boolean
        }
        _meta?: Record<string, unknown>
        execute: (
            args: z.infer<z.ZodObject<Params>>,
            client: TodoistApi,
        ) => Promise<{ 
            textContent?: string
            structuredContent?: z.infer<z.ZodObject<Output>>
            contentItems?: ContentBlock[] 
        }>
    }
  6. Understand the workflow-centric tool design philosophy

    main

    The Todoist MCP server uses a workflow-centric approach rather than a traditional API-centric approach. Instead of creating a tool for every single API endpoint (e.g., add-project, update-project, get-project), the server provides specialized workflow tools designed around user intent and batch operations.

    Core Principles

    • User Intent Over API Structure: Tools match how users work, not how the API is organized.
    • Batch Operations: Tools support multiple items where logical (e.g., add-tasks accepts an array).
    • Explicit Intent: Uses clear action verbs to reduce ambiguity for LLMs (e.g., add-projects vs update-projects).
    • Universal Patterns: Unifies similar operations under a single tool (e.g., delete-object handles all entity types).
    • Context-Aware Responses: Returns both structured data and human-readable text containing suggested next steps to maintain workflow momentum.
  7. How MCP Apps render interactive UI for tool results

    main

    The project uses MCP Apps to provide interactive user interfaces for specific tool results (such as find-tasks-by-date).

    The lifecycle of an MCP App interaction is as follows:

    1. Data Return: A tool returns structured data to the MCP host.
    2. Metadata Link: The tool's metadata contains a _meta.ui.resourceUri pointing to the UI.
    3. Registration: The server registers this UI resource using registerAppResource.
    4. Rendering: The MCP host fetches the HTML via the resources/read endpoint and renders it within a sandboxed iframe.
    5. Communication: The app communicates with the server through the MCP Apps bridge, allowing it to perform actions like calling other server tools (e.g., complete-tasks) or opening links.
  8. Configure Todoist MCP via Standard I/O (stdio)

    main

    To connect the Todoist MCP server to clients like Claude Desktop or Cursor using the stdio transport, add a configuration entry to your mcp.json file.

    {
        "mcpServers": {
            "todoist-mcp": {
                "type": "stdio",
                "command": "npx",
                "args": ["@doist/todoist-mcp"],
                "env": {
                    "TODOIST_API_KEY": "your-todoist-token-here"
                }
            }
        }
    }

    Using a Local Installation

    If you have cloned the repository locally, point the command to your local node binary and the dist/main.js file:

    {
        "mcpServers": {
            "todoist-mcp-local": {
                "type": "stdio",
                "command": "node",
                "args": ["/Users/<your_user_name>/code/todoist-mcp/dist/main.js"],
                "env": {
                    "TODOIST_API_KEY": "your-todoist-token-here"
                }
            }
        }
    }
  9. Configure Todoist MCP server in Visual Studio Code

    main

    To add the Todoist MCP server to VS Code:

    1. Open the Command PaletteMCP: Add Server.
    2. Select HTTP transport.
    3. Use the following configuration:
    {
        "servers": {
            "todoist": {
                "type": "http",
                "url": "https://ai.todoist.net/mcp"
            }
        }
    }
  10. Development and Build Commands

    main

    The project uses Vite for building and provides several scripts for development, type-checking, and linting.

    Build

    • npm run build: Runs both build:lib (bundles the library to dist/) and build:apps (bundles React widgets to dist/mcp-apps/).

    Development

    • npm run dev: Starts the server using stdio + inspector with auto-rebuild enabled.
    • npm run dev:http: Starts the server in HTTP mode.

    Quality Assurance

    • npm run type-check: Runs tsc --noEmit to validate types.
    • npm run format:check: Checks code formatting using oxlint + oxfmt.
    • npm run format:fix: Automatically fixes code formatting using oxlint + oxfmt.
    • npm run lint:schemas: Validates all tool Zod schemas via scripts/validate-schemas.ts.
    npm run build
    npm run dev
    npm run type-check
    npm run format:check
    npm run lint:schemas