Skip to content

krisrowe/notes

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

notes

MCP server that proxies an AppSheet app holding notes, with per-user JWT auth. Works locally over stdio for a single user and as a multi-user HTTP service when deployed. List, read, add, update notes and list attachments from any MCP client.

Built on mcp-app.

Install

pipx install git+https://github.com/krisrowe/notes.git

This installs three commands:

  • notes — shell shortcuts (list, read, add, update, attachments list)
  • notes-mcp — MCP server (stdio, serve)
  • notes-admin — admin CLI (connect, users, tokens, health, probe, register)

Prereqs: Python 3.10+, an AppSheet app with the expected schema.

Run locally (stdio)

For a single-user setup on your own machine: register a local profile holding your AppSheet API key, then point an MCP client at notes-mcp stdio.

1. Add the local user with your AppSheet target

notes-admin connect local
notes-admin users add local \
  --datastore appsheet \
  --app-id <your-appsheet-app-guid> \
  --api-key <your-appsheet-application-access-key>

The datastore field selects the backend implementation. appsheet is currently the only supported value. Future versions may add others (e.g. google sheets, firestore). If a profile names a datastore the running version doesn't know about, the SDK raises a clear error citing the running notes version and the supported set.

The app_id and api_key together define which AppSheet app this profile reads from. See docs/APPSHEET.md for where to find both.

If your AppSheet app uses table names other than Note and Attachment, set:

export APPSHEET_NOTE_TABLE=<your-notes-table>
export APPSHEET_ATTACHMENT_TABLE=<your-attachments-table>

2. Register with your MCP client

Claude Code:

claude mcp add --scope user notes -- notes-mcp stdio --user local

Gemini CLI:

gemini mcp add notes --command notes-mcp --args "stdio --user local" --scope user

3. Smoke test

notes list --limit 3

Or, with stdio registered, ask the MCP client: "list my recent notes."

Deploy (HTTP)

Runtime contract

The server is a standard ASGI Python app with these requirements:

Var Required Default Purpose
SIGNING_KEY Yes JWT signing key. Generate with python3 -c 'import secrets; print(secrets.token_urlsafe(32))'
APP_USERS_PATH No ~/.local/share/notes/users/ Per-user profile data directory. Must be persistent on serverless platforms — defaults to ephemeral container storage.
APPSHEET_NOTE_TABLE No Note Override only if your AppSheet app uses a non-default notes table name
APPSHEET_ATTACHMENT_TABLE No Attachment Override only if your AppSheet app uses a non-default attachments table name
JWT_AUD No not validated Expected JWT audience claim
TOKEN_DURATION_SECONDS No 315360000 (~10y) New token lifetime in seconds

The AppSheet app_id and api_key are NOT env vars — they live in each user's profile (per-user, rotatable independently). See "Manage users" below.

  • Start command: notes-mcp serve --host 0.0.0.0 --port $PORT
  • MCP endpoint: / (root, not /mcp)
  • Health: GET /health (no auth)
  • Admin: POST/GET/DELETE/PATCH /admin/... (signing-key auth)
  • Auth model: the app handles JWT auth itself; the platform must allow unauthenticated traffic through to the app — every request is gated by mcp-app's middleware.

SIGNING_KEY is a secret. Inject it via your platform's secret manager (GCP Secret Manager, AWS Secrets Manager, GitHub Actions secrets, etc.) — never check it into the repo.

Docker

docker build -t notes .
docker run -p 8080:8080 \
  -e SIGNING_KEY=$(python3 -c 'import secrets; print(secrets.token_urlsafe(32))') \
  -v /path/on/host:/data \
  -e APP_USERS_PATH=/data/users \
  notes

Procfile-aware platforms (Heroku, Render, Fly, gcloud run --source)

A one-line Procfile ships with the repo:

web: notes-mcp serve --host 0.0.0.0 --port $PORT

Set SIGNING_KEY and a persistent APP_USERS_PATH through the platform's env-var or secret mechanism, then deploy from source.

Connect the admin CLI post-deploy

The admin CLI persists per-app config under ~/.config/notes/setup.json so subsequent commands don't repeat --url or --signing-key. connect and the deploy itself are independent — deploying does not auto-connect the admin CLI.

notes-admin connect https://<your-deployment-url> --signing-key <key>

<key> is whatever value SIGNING_KEY was set to at deploy time. Retrieve it from wherever your deployment stored the secret (cloud secret manager, CI/CD secret, deployment-tool-managed value).

For local-store admin (the local profile used in stdio mode):

notes-admin connect local

Manage users and credentials

Each authorized user gets a stored profile holding their AppSheet target — the app_id of the app they read, and the api_key to access it:

notes-admin users add alice@example.com \
  --datastore appsheet \
  --app-id <her-appsheet-app-guid> \
  --api-key <her-appsheet-key>
notes-admin users list
notes-admin users get-profile alice@example.com

Rotating an API key

users add rejects existing users to prevent accidental overwrites. Use update-profile to rotate either field:

notes-admin users update-profile alice@example.com api_key <new-appsheet-key>
notes-admin users update-profile alice@example.com app_id <different-appsheet-app>

Discovering profile fields

The CLI is self-documenting — --help prints field names and descriptions:

notes-admin users add --help

Revoking access

notes-admin users revoke alice@example.com

Verify and register MCP clients

probe is the single end-to-end check — confirms the server is up, auth works, and the MCP layer responds with the expected tools:

notes-admin probe

For a deeper check that exercises the user's backend credential too, run the safe tool — count_notes with limit=10, capped server-side:

notes-admin safe-tool --invoke --user alice@example.com

Returns {"notes": {"found": N, "limit": 10}} and reveals no note content. Use this to confirm a deployed user's backend is reachable and authenticated end-to-end.

register mints a token for a user and emits ready-to-paste registration commands for Claude Code, Gemini CLI, and the Claude.ai web client:

notes-admin register --user alice@example.com

Manual registration if register isn't available:

# Claude Code (HTTP transport)
claude mcp add --scope user notes-remote \
  --transport http https://<your-deployment-url>/ \
  --header "Authorization: Bearer <user-token>"

# Gemini CLI (HTTP transport)
gemini mcp add notes-remote https://<your-deployment-url>/ \
  --transport http \
  --header "Authorization=Bearer <user-token>" \
  --scope user

For Claude.ai (web), use the URL https://<your-deployment-url>/ with the user token as a bearer credential.

MCP tools

Tool Description
list_notes Search/list notes with Gmail-style query
read_note Read a single note by ID
add_note Create a note
update_note Update a note's title/content/labels
list_attachments List attachments for a note
count_notes Count notes (capped); identity-only, no note content. Doubles as the deployment smoke test.

Tool descriptions and parameter schemas come from the docstrings and type hints in notes/mcp/tools.py — that's the canonical reference.

Query syntax (list_notes)

Query Meaning
meeting Text search in title and content
"exact phrase" Phrase search
label:work Filter by label
-label:archived Exclude label
meeting label:work Text AND label (implicit AND)
label:work OR label:home Either label
(label:a OR label:b) meeting Grouping with parentheses

Shell shortcuts (notes CLI)

The notes command is a thin wrapper for ad-hoc queries from the shell. Each command loads the local user from the store unless --user is passed.

notes list                              # All notes (default 50)
notes list "label:work"                 # Filter
notes list "meeting -label:archived"    # Search + exclude
notes list --sort=-modified --limit 10  # Sort and limit
notes read <id>                         # Read one note
notes add "Title" -c "Body" -l "Work"   # Create
notes update <id> -t "New title"        # Update
notes attachments list <id>             # List attachments

Further reading

License

MIT

About

SDK, CLI, and MCP server for managing notes stored in Google Sheets with optional AppSheet integration

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages