Skip to main content
Glama

Project Planner MCP

A remote Model Context Protocol (MCP) server that lets AI assistants manage projects and their todos. It runs on Cloudflare Workers and stores data in Cloudflare D1, a serverless SQLite database.

Connect it to an MCP client such as Claude or the Cloudflare AI Playground, and you can say things like "Create a project called Website Redesign and add three high-priority todos". The assistant calls the right tools for you.

WARNING

This server hasno authentication. Anyone who knows the URL of a deployed instance can read, change and delete all of its data. Use it for learning and personal experiments, and don't store anything sensitive in it.

Tools

Projects

Tool

Description

Parameters

create_project

Create a new project. Returns its ID.

name, description

list_projects

List all projects.

none

get_project

Get one project together with all of its todos.

project_id

update_project

Change a project's name and description.

project_id, name, description

delete_project

Delete a project and all of its todos.

project_id

Todos

Tool

Description

Parameters

create_todo

Add a todo to a project. Returns its ID.

project_id, title, description?, status?, priority?

list_todos

List all todos in a project.

project_id

get_todo

Get one todo.

todo_id

update_todo

Change a todo's title, description, status and priority.

todo_id, title, description, status, priority

delete_todo

Delete a todo.

todo_id

Parameters marked ? are optional. status is one of pending (default), in_progress or completed. priority is one of low, medium (default) or high.

Related MCP server: todo-mcp

Tech stack

  • Runtime: Cloudflare Workers

  • Database: Cloudflare D1 (SQLite)

  • MCP: @modelcontextprotocol/server and the createMcpHandler from Cloudflare's agents SDK, serving MCP over Streamable HTTP at /mcp

  • Validation: Zod schemas for every tool's input

  • Language: TypeScript

  • Tooling: Wrangler, oxlint, oxfmt

Project structure

.
├── migrations/
│   └── 0001_create_planner_tables.sql   # D1 schema: projects and todos tables
├── src/
│   ├── index.ts           # Worker entry point: creates the MCP server and registers tools
│   ├── db/
│   │   ├── projects.ts    # SQL queries for projects
│   │   └── todos.ts       # SQL queries for todos
│   ├── tools/
│   │   ├── projects.ts    # MCP tool definitions for projects
│   │   └── todos.ts       # MCP tool definitions for todos
│   └── utils/
│       └── timestamp.ts   # ISO 8601 timestamp helper
├── wrangler.jsonc         # Worker and D1 binding configuration
└── worker-configuration.d.ts  # Generated binding types (npm run cf-typegen)

The code is split in two layers. src/db/ holds plain functions that run SQL against D1 and know nothing about MCP. src/tools/ registers the MCP tools, validates input with Zod, and calls the db functions. That keeps each layer small and lets you reuse the database code elsewhere.

Database schema

projects                          todos
────────────────────              ─────────────────────────────────────
id           TEXT  PK    ◄──┐     id           TEXT  PK
name         TEXT           └──── project_id   TEXT  FK → projects.id  ON DELETE CASCADE
description  TEXT                 title        TEXT
created_at   TEXT                 description  TEXT
updated_at   TEXT                 status       TEXT  pending | in_progress | completed
                                  priority     TEXT  low | medium | high
                                  created_at   TEXT
                                  updated_at   TEXT
  • IDs are UUIDs generated with crypto.randomUUID().

  • Timestamps are ISO 8601 strings, for example 2026-11-03T13:07:00.000Z.

  • ON DELETE CASCADE means deleting a project automatically deletes its todos.

  • CHECK constraints make the database itself reject invalid status and priority values.

  • An index on todos.project_id keeps "all todos of a project" queries fast.

Getting started

Prerequisites

1. Install dependencies

git clone https://github.com/<your-username>/project-planner-mcp.git
cd project-planner-mcp
npm install

2. Create your D1 database

The database_id in wrangler.jsonc points to my database, which your account can't access. Create your own:

npx wrangler login
npx wrangler d1 create project-planner

Copy the database_id from the output into the d1_databases section of wrangler.jsonc.

3. Apply the migrations locally

npx wrangler d1 migrations apply project-planner --local

4. Run the server

npm run dev

The MCP endpoint is now available at http://localhost:8787/mcp.

Testing with MCP Inspector

MCP Inspector is a browser UI for calling MCP tools by hand. It's the quickest way to check that everything works:

npx @modelcontextprotocol/inspector

In the Inspector, choose the Streamable HTTP transport, enter http://localhost:8787/mcp and click Connect. Open the Tools tab, then try create_project followed by list_projects.

Deploying to Cloudflare

Apply the migrations to the remote database, then deploy the Worker:

npx wrangler d1 migrations apply project-planner --remote
npm run deploy

Your server will be live at:

https://project2-planner-mcp.<your-subdomain>.workers.dev/mcp

The first part of the URL comes from the name field in wrangler.jsonc. Change it before deploying if you want a different URL.

Connecting an MCP client

Cloudflare AI Playground

  1. Open playground.ai.cloudflare.com.

  2. Enter your deployed /mcp URL and connect.

  3. Ask the model to create a project.

Claude Desktop (via mcp-remote)

Local clients that only speak stdio can reach a remote server through the mcp-remote proxy. In Claude Desktop, open Settings → Developer → Edit Config and add:

{
  "mcpServers": {
    "project-planner": {
      "command": "npx",
      "args": ["mcp-remote", "http://localhost:8787/mcp"]
    }
  }
}

Replace the URL with your deployed one to use the hosted version. Restart Claude Desktop and the tools appear.

Scripts

Command

What it does

npm run dev

Start a local dev server with a local D1 database

npm run deploy

Deploy the Worker to Cloudflare

npm run type-check

Type-check the project with TypeScript

npm run lint:fix

Lint with oxlint and fix what it can

npm run format

Format the code with oxfmt

npm run cf-typegen

Regenerate worker-configuration.d.ts after changing bindings

How this project evolved

I built this while learning MCP, TypeScript and Cloudflare Workers, starting from Cloudflare's authless remote MCP template.

The first version stored everything in Workers KV, a key-value store. Because KV can't query or join, it had to keep hand-maintained lists of IDs (project:list, project:<id>:todos) and read each record one by one. Those read-modify-write updates could lose data when two requests arrived at the same time.

The current version uses D1. SQL handles listing and filtering, the schema enforces valid values, and ON DELETE CASCADE removes a project's todos in one statement, inside the database.

Possible improvements

  • Add authentication, for example with Cloudflare's OAuth provider for MCP.

  • Return isError: true from tools when a project or todo isn't found, so clients can tell failures from results.

  • Make the update_* tools accept partial updates, so changing only a todo's status doesn't require resending every field.

  • Add tests with Vitest and the Workers pool.

License

MIT

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers