mcp — Xentropy notes over MCP
A Model Context Protocol server that exposes
your Wall notes to MCP clients (Claude Code first). It is a thin adapter: MCP
tool calls → the existing Xentropy HTTP API (/api), scoped to your account by
your bearer token. It does not talk to Postgres directly.
See the full plan in docs/mcp-notes-roadmap.md.
Status
P5 — production-ready. A stdio server exposing your notes to MCP clients, with
a one-command setup for Claude Code. Authentication, reads, and writes go
entirely through the API — no Supabase SDK or extra config.
- P1 ✅ server skeleton +
ping.
- P2 ✅
login / logout / status; file-based session store; token
provider that refreshes on expiry.
- P3 ✅ read tools:
search_notes, list_notes, get_note,
get_related_notes, list_folders (fetch over the API; bearer auto-refresh +
401 retry; compact ranked output, full text via get_note).
- P4 ✅
setup command (prints the claude mcp add line + .mcp.json),
.mcp.json.example, actionable tool errors (login / plan / not-found /
unreachable).
- P5 ✅ Personal Access Tokens via env vars (
XEN_API_TOKEN + XEN_REFRESH_TOKEN).
- Q1 ✅ Production build config, extracted error classes, 56 unit tests.
Tools
ping | — | health check |
search_notes | query, limit? | semantic matches (id, title, snippet, score); Pro-gated |
list_notes | folder?, type?, query?, archived?, limit? | newest-first rows |
get_note | id | full note (body / transcript, summary, tags) |
get_related_notes | id, limit? | semantically nearest notes |
list_folders | — | folders for the folder filter |
create_note | body, title?, folder? | the created note (with id) |
update_note | id, title?, body?, folder? | the updated note |
create_directory | name, parent?, formatInstructions?, icon? | the created directory (with id) |
update_directory | id, name?, parent?, formatInstructions?, icon? | the updated directory |
Write tools map to the API's POST /content/notes, PATCH /content/:id, and
POST/PATCH /folders. For folder/parent, pass a directory id, or
unfiled/root to target the root (no folder / top-level); omit to leave a
field unchanged on an update.
Authenticate
npm run login
tsx src/index.ts login --email you@example.com --password '…'
XEN_EMAIL=you@example.com XEN_PASSWORD='…' tsx src/index.ts login
npm run status
npm run logout
The session is stored at ~/.config/xentropy-mcp/session.json (mode 0600;
honors XDG_CONFIG_HOME). The access token is refreshed automatically when it
nears expiry, using the stored refresh token.
Develop
npm run dev
npm run smoke
npm test
npm run build
npm start
Diagnostics go to stderr. With the stdio transport, stdout is the JSON-RPC
channel — never console.log to it.
Configuration (environment)
XEN_API_URL | no | http://localhost:3001/api | API base URL; must include the /api prefix |
No Supabase variables are needed — the server authenticates through the API.
Use from Claude Code
npm run build
npm run login
npm run setup
npm run setup resolves the absolute path to dist/index.js and prints a
ready-to-paste command, e.g.:
claude mcp add xentropy-notes --env XEN_API_URL=http://localhost:3001/api -- node /abs/path/to/apps/mcp/dist/index.js
Prefer config files? Copy .mcp.json.example to a project
.mcp.json and fill in the absolute path. Then ask Claude Code to search or list
your notes (or run ping to check the connection).
Troubleshooting
- "Not logged in" / "Session expired" — run
npm run login (or
xen-notes-mcp login).
- "Can't reach the Xentropy API" — the API isn't running, or
XEN_API_URL
is wrong (it must include the /api prefix).
- "Not available on your current plan" —
search_notes is Pro-gated.
- Tools don't appear in Claude Code — check the server runs:
node dist/index.js status should print your account, and the path in your
claude mcp config must be absolute and point at dist/index.js.
npm test finds no tests — needs Node 20+ (--import support); tests are
discovered via find src -name '*.test.ts'.