Skip to main content
Glama
johnawadlow

Snackbar MCP Server

by johnawadlow

Snackbar

A personal note store with an MCP front door, so any assistant you're talking to can capture an idea wherever you happen to be.

The problem it solves is narrow and specific: ideas arrive on the couch, on a walk, at a desk that isn't yours — and by the time you're back at the machine where your notes live, they're gone. Snackbar puts the notes somewhere both you and your assistants can reach, and lets whichever assistant is already in the conversation write them down.

It is not a Claude accessory. MCP is cross-vendor, so anything that speaks the protocol can post to it. The store is yours; the assistants are interchangeable front ends.

How it works

Phone / laptop / wherever          this app                Supabase
┌──────────────────────┐      ┌──────────────────┐      ┌──────────┐
│ any MCP-speaking     │─────▶│ /api/mcp         │─────▶│  notes   │
│ assistant            │ HTTP │ OAuth or bearer  │      │          │
└──────────────────────┘      │   → author       │      └──────────┘
                              └──────────────────┘

One Next.js route handler, four tools, one table. That's the whole thing.

The credential is the author field. claude.ai connects over OAuth, and its notes are authored claude. Any client that can set a header presents a per-client bearer token that maps to a name of its own. Either way the server knows who wrote a note instead of trusting a self-reported value.

One OAuth connector covers an entire Claude account — web, desktop, and mobile all ride the same connection — so it can say who wrote a note but not which device. If you need that distinction it has to come from somewhere other than the credential.

Notes carry two orthogonal qualifiers. category is the subject (music, code, video…) and is a free-form string the server never rejects — new ones just start appearing in list_categories. type is what the entry is, and is one of idea, memory, or todo. The distinction is load-bearing: category says which shelf, type says what eventually happens to it. A memory stays a note forever; a todo becomes work immediately; an idea waits until it's ripe.

Related MCP server: Zero Brain MCP Server

Tools

Tool

What it does

create_note

Save a note. Author comes from the credential, never from the caller.

list_notes

Newest first; filter by type, category, or unreviewed-only.

search_notes

Substring match over note text.

list_categories

Which categories exist, with counts — check before inventing one.

Listings return one compact line per note rather than JSON, so reading the whole store costs very little context.

Setup

1. Database. Create a Supabase project, then:

supabase link --project-ref <your-project-ref>
supabase db push

2. Authorization server. Any OAuth 2.1 server that publishes RFC 8414 metadata will do; this was built against a free Auth0 tenant. You need two things in it:

  • an API whose identifier is this server's MCP URL, exactly (https://<your-deployment>/api/mcp) — it becomes the token audience

  • an application, registered as a public client so it authenticates with PKCE and needs no secret, with https://claude.ai/api/mcp/auth_callback as an allowed callback

Then grant the application access to the API, and enable offline access on the API so refresh tokens are issued. In Auth0 that grant lives on the API's Application Access tab as user-delegated access — not the Client Access list beside it, which is for the machine-to-machine flow this doesn't use. Skipping it produces a clean login followed by Client ... is not authorized to access resource server ... in the tenant logs.

3. Environment. Copy .env.example to .env.local and fill in:

  • SUPABASE_URLhttps://<project-ref>.supabase.co

  • SUPABASE_SERVICE_ROLE_KEY — the secret key, not the publishable one

  • SNACKBAR_AUTH_SERVER — your authorization server's issuer URL, exactly as it appears in its own metadata, trailing slash and all

  • SNACKBAR_RESOURCE — this server's MCP URL. It has to equal the API identifier and the URL users type into their client; all three are compared

  • SNACKBAR_ALLOWED_SUBJECT — the single sub allowed in. Leave it unset and every OAuth token is refused, which is the safe direction to fail

Every client authenticates the same way — OAuth against the authorization server, presenting Authorization: Bearer <token>. There is no second door.

4. Run it.

npm install
npm run dev

Deploy anywhere that runs Next.js; set the same variables there.

Connecting a client

claude.ai (set up on desktop web, then usable on mobile) — Settings → Connectors → Add custom connector, with the plain MCP URL and no credential in it:

https://<your-deployment>/api/mcp

Open Advanced settings and paste your application's OAuth Client ID. Leave the secret blank — a public client proves itself with PKCE. Connecting sends you to your authorization server to sign in and returns you with a token.

Leaving the Client ID blank makes Claude attempt Dynamic Client Registration instead. Auth0 gates DCR behind a paid plan, so on a free tenant the pre-registered Client ID is the way through.

Claude Code — the same OAuth flow, with no token to manage:

claude mcp add --transport http snackbar https://<your-deployment>/api/mcp

Then run /mcp and authenticate. The unauthenticated 401 carries a WWW-Authenticate header naming the protected-resource document, which names the authorization server; the client walks that chain on its own.

A note on security

There are no users, no roles, and no sharing. Row Level Security is enabled on the table with zero policies, so the anon key can read nothing; the server holds the service role key and does its own authorization.

Signing in is not the same as being allowed in. A valid OAuth token proves who someone is, and on an authorization server that accepts Google logins that is anyone with a Google account. SNACKBAR_ALLOWED_SUBJECT names the one subject admitted. Unset, it refuses everyone rather than admitting everyone — a half-configured deployment should be shut, not open. A refused token logs the subject it presented, which is how you learn your own the first time.

A token carried in a query string or a path segment lands in server access logs, proxies, and browser history, and the MCP specification prohibits it outright. Those routes remain for clients that can do nothing else, but OAuth or an Authorization header is the answer wherever a client supports one.

This is built for one person's notes. If you fork it for anything with more than one human in it, the auth model is the first thing to replace.

Status

Working, but young. Built with Claude Code as part of an ongoing experiment in working with AI as a development partner — see ai-workshop for the wider setup.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    B
    maintenance
    A personal notes MCP server that allows AI assistants to create, search, edit, and manage notes stored in a local SQLite database.
    6
    MIT
  • A
    license
    A
    quality
    A
    maintenance
    MCP server for managing a local, domain-agnostic knowledge base using Markdown notes with frontmatter. Enables AI agents to capture, read, search, link, and maintain notes with atomic writes and privacy controls.
    13
    MIT
  • A
    license
    A
    quality
    C
    maintenance
    MCP server for a personal notes/knowledge base that enables AI assistants to create, search, and retrieve notes using natural language. It exposes tools like create_note and search_notes, resources for each note, and a summarize_tag prompt.
    6
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables LLM clients to read, search, create, update, and delete notes in a self-hosted shared memory bank over MCP, using hybrid vector and full-text search with optional summarization.
    2
    MIT