todoapp
README.md
# Todo App
pnpm monorepo:
| Package | Stack |
| --- | --- |
| [`apps/server`](apps/server) | Express 5, Drizzle ORM, PostgreSQL, JWT auth, MCP server |
| [`apps/web`](apps/web) | React 19, Zustand, Vite |
| [`packages/shared`](packages/shared) | zod schemas, API types and MCP tool metadata used by both apps |
## Getting started
Requires Node 22+, pnpm 10 and Docker.
```sh
pnpm install
cp apps/server/.env.example apps/server/.env # then set JWT_SECRET
pnpm db:up # start Postgres (host port 5433)
pnpm db:migrate # apply migrations
pnpm dev # API on :4000, web on :5173
```
Open http://localhost:5173. In dev, Vite proxies `/api` to the server.
## Scripts
| Command | What it does |
| --- | --- |
| `pnpm dev` | Run server and web in watch mode |
| `pnpm build` | Build every package |
| `pnpm typecheck` | Type-check every package |
| `pnpm db:up` | Start the Postgres container |
| `pnpm db:generate` | Create a migration after changing `apps/server/src/db/schema.ts` |
| `pnpm db:migrate` | Apply pending migrations |
## API
`/api/todos` and `/api/mcp` routes need an `Authorization: Bearer <token>` header.
| Method | Path | Body | Response |
| --- | --- | --- | --- |
| POST | `/api/auth/register` | `{ email, password }` | `201 { token, user }` |
| POST | `/api/auth/login` | `{ email, password }` | `200 { token, user }` |
| GET | `/api/auth/me` | | `200 user` |
| GET | `/api/todos` | | `200 todo[]` |
| GET | `/api/todos/:id` | | `200 todo` |
| POST | `/api/todos` | `{ title }` | `201 todo` |
| PATCH | `/api/todos/:id` | `{ title?, completed? }` | `200 todo` |
| DELETE | `/api/todos/:id` | | `204` |
| GET | `/api/mcp` | | `200 { token, url }`, creating the token on first call |
| POST | `/api/mcp/regenerate` | | `200 { token, url }` with a new token |
Errors come back as `{ error, details? }`. Status codes: `400` validation, `401` auth, `404` missing or not yours, `409` email already taken.
## MCP server
Each user has a personal MCP URL, shown in the **MCP** tab of the web app:
```
http://localhost:4000/mcp?token=mcp_...
```
The token identifies the user, and the tools only see that user's todos. Regenerating it in the web app revokes the old URL immediately. Set `PUBLIC_URL` in `apps/server/.env` to the address clients use to reach the server.
The endpoint speaks Streamable HTTP in stateless mode (`POST /mcp`). Tools: `list_todos`, `get_todo`, `create_todo`, `update_todo`, `delete_todo`.
Connect Claude Code:
```sh
claude mcp add --transport http todoapp "http://localhost:4000/mcp?token=mcp_..."
```
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues