keep-mcp
keep-mcp
A small MCP server for your Google Keep — built to sit next to tesco-mcp on the unRAID box.
Claude (or Cursor) can read the household shopping list, add items (including ones that arrived via Google Voice / Assistant), and tick them off once they are in the Tesco basket.
Keep has no personal OAuth API. This uses the unofficial gkeepapi client. Auth is a Google master token — it can act as the whole account, so it never goes in git.
agent ──MCP HTTP──> keep-mcp ──gkeepapi──> Google Keep
agent ──MCP HTTP──> tesco-mcp ──> TescoTwo separate connectors. Claude uses both in the same chat.
Tools
Tool | What it does |
| Search notes/lists by title or body |
| Fetch one list (default: |
| Append unchecked items |
| Tick items off by name |
| Untick items |
| Delete items by name |
| Create a new checklist |
Item matching is case-insensitive. Unique substrings work ("oat" → "Oat milk"); ambiguous names ("milk" when both Milk and Oat milk exist) are rejected so Claude has to be specific.
Optional KEEP_WRITE_TITLES=Shopping restricts writes to that list. Leave it empty for a personal Keep.
One-time: mint a master token
On this machine (not in the container):
uv sync
uv run keep-mcp-tokenIt walks you through Google EmbeddedSetup: sign in, copy the oauth_token cookie, exchange it. Put GOOGLE_EMAIL and GOOGLE_MASTER_TOKEN in the container env. Treat the token like a password.
Run locally
uv sync
uv run pytest
uv run keep-mcp # stdio (Cursor / Claude Desktop)
uv run keep-mcp-http # HTTP on :8788 (Claude custom connector)Deploy on unRAID (alongside tesco-mcp)
This image is Python-only — no Chrome — so it is a thin container next to the Tesco one, not a second Tesco-sized box.
Generate an opaque public hostname (same idea as Tesco):
node -e "console.log('kpr-' + require('crypto').randomBytes(6).toString('hex'))"In Cloudflare Zero Trust → your existing tunnel, add a published application: that hostname →
http://<unraid-ip>:8788.On the unRAID box:
mkdir -p /mnt/user/appdata/keep-mcp MCP_AUTH_TOKEN=$(openssl rand -hex 24) # save this docker run -d --name keep-mcp --restart unless-stopped \ -p 8788:8788 \ -e MCP_AUTH_TOKEN=$MCP_AUTH_TOKEN \ -e MCP_PUBLIC_BASE_URL=https://<opaque-host>.<domain> \ -e GOOGLE_EMAIL=you@gmail.com \ -e GOOGLE_MASTER_TOKEN=<master-token> \ -e KEEP_DEFAULT_LIST=Shopping \ -e TZ=Europe/London \ -v /mnt/user/appdata/keep-mcp:/home/app/.keep-mcp \ ghcr.io/cookseyyyyyy/keep-mcp:latestGHCR is private (same as tesco-mcp) — the host must already be logged in to
ghcr.io.Health check:
curl https://<opaque-host>.<domain>/healthz→ok.
Connect Claude (web)
Same OAuth shim as Tesco / the Nice Touch MCP apps: one secret (MCP_AUTH_TOKEN), Claude obtains it via a consent page.
Claude → Settings → Connectors → Add custom connector.
URL only (no token field):
https://<opaque-host>.<domain>/mcpConnect → browser consent page → paste
MCP_AUTH_TOKEN→ Approve.
Cursor / Claude Code can skip OAuth and send Authorization: Bearer <MCP_AUTH_TOKEN> to the same /mcp URL.
Typical Tesco shop
keep_get— unread items on the shopping list.Tesco MCP: search, add to basket, book a slot.
keep_check_items— tick off what went in the basket.
Voice-added Keep items (Assistant / Google Voice) show up after the next keep_get / keep_find; Keep is synced on every tool call.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/Cookseyyyyyy/keep-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server