Notes MCP Server
README.md
# inktrace-mcp-template
A minimal remote MCP (Model Context Protocol) server you can run in ten minutes: Hono, the official MCP SDK over streamable HTTP, token auth with a constant-time comparison, Zod-validated tools, and Postgres via Drizzle. The domain is a toy `notes` table, but the structure is the one I run in production for [InkTrace](https://www.inktrace.app) — this repo is a clean-room extraction of that pattern, written for reading. The full design write-up is in the [inktrace-showcase](https://github.com/JackieNonSense/inktrace-showcase) repo.
## What it demonstrates
- **Stateless streamable HTTP.** A fresh `McpServer` + transport per request, so the same code runs on a laptop, a container, or a serverless function with nothing to desynchronize. See `src/index.ts` — the whole transport dance is five lines.
- **Token auth done carefully.** SHA-256 both sides, then `timingSafeEqual` (`src/auth.ts`). Hashing first equalizes buffer lengths so a wrong-length guess can't throw. The secret is accepted as a Bearer header (preferred) or a URL path segment for connector UIs that can't send headers — with a comment explaining why the header variant is preferred (URLs end up in logs).
- **Policy in the protocol.** Write tools carry a "requires prior explicit user approval" prefix and the server `instructions` state the rules of engagement, so a well-behaved client asks the user before mutating anything (`src/mcp/server.ts`, `src/mcp/tools.ts`).
- **Snapshot before destructive writes.** `write_note` versions the current content before overwriting it and prunes history to the newest 20 (`snapshotBeforeEdit` in `src/mcp/tools.ts`). Undo is a data-model feature, not a support ticket.
- **Zod on every tool input**, and a `safe()` wrapper that turns thrown exceptions into MCP tool errors instead of protocol crashes.
- **No delete tool.** The worst realistic failure of a confused model is an unwanted addition — visible and reversible — not silent destruction.
## Quickstart
You need Node 20+ and a Postgres database.
```bash
npm install
cp .env.example .env # fill in DATABASE_URL and MCP_SECRET
npm run db:push # create the notes / note_versions tables
npm run dev # http://localhost:3001/mcp
```
Connect from Claude Code:
```bash
claude mcp add --transport http notes http://localhost:3001/mcp \
--header "Authorization: Bearer <your MCP_SECRET>"
```
Then ask Claude to `list_notes`, have it draft something, approve it, and watch `write_note` create the row — and snapshot before any edit.
## Layout
```
src/
├── index.ts # Hono app, health check, MCP mount, stateless transport
├── auth.ts # timing-safe token middleware (Bearer or path segment)
├── db.ts # postgres.js + Drizzle, serverless-friendly pool size
├── schema.ts # notes + note_versions
└── mcp/
├── server.ts # server identity + usage-policy instructions
└── tools.ts # 3 read tools + 1 write tool with pre-write snapshot
```
## What the production version adds
Since this template is deliberately single-file-per-concern, it's worth naming what the real InkTrace server layers on top: per-tool project-ownership checks, Postgres row-level security pinned per request as a second authorization layer, HTML sanitization on rich-text input, batch caps on bulk operations, and rate limiting inherited from the surrounding API. The auth gate here is single-tenant by design; the multi-user path is OAuth, which replaces `tokenAuth` without touching any tool.
## License
MIT — take the structure, replace the notes.
This server cannot be deployed
Maintenance
ActivityStale
ResponsivenessNo issues