← squirrelbrainapp.com
🤖 MCP Server

Connect Any AI Agent
to Your Brain

Squirrel Brain has a built-in MCP server. Any AI agent — Claude, a custom agent, or your own automation — can read your tasks, create alarms, and send voice messages directly to your phone.

Works with ✦ Claude ✦ Custom agents ✦ LangGraph ✦ Any MCP client
● For AI Agents — read this first

Self-setup guide — everything you need to connect

If you are an AI agent reading this page: the facts below are all you need. Follow the startup sequence and you are live in one round-trip. Read the tools table before taking any action.

Endpoint
POST https://geczbtsjfbvfukdzdemr
.supabase.co/functions/v1/mcp-server
Required Headers
Content-Type: application/json
X-API-Key: sb_<your-key>
Protocol
JSON-RPC 2.0 over HTTPS
method: "tools/call"
params: { name, arguments }
Handshake
{"method":"initialize","params":{}}
{"method":"tools/list","params":{}}
Session startup — call all three in parallel before doing anything else
  1. Call get_user_profile — get the user's name, timezone (IANA string), and notification preferences. You MUST have their timezone before creating any alarm or time-based item.
  2. Call get_agent_context — read the user's persistent context notes (type_label=context). Treat these as standing orders for this session — they override your defaults.
  3. Call get_current_time — get current UTC and user's local time. Never compute timezone offsets yourself — always use this.
Key tools — full schema below at #tools
cell_alert
Voice alarm on user's phone in ~10s. TTS via nova voice, full-screen popup, auto-plays. No tap required. Use for anything genuinely urgent.
Required: message. Optional: title.
notify_human
Instant push notification (banner). Fires via APNs. Use for status updates — not urgent. For urgent use cell_alert.
Required: title, message. Optional: sound.
create_alarm
Put a timed event on the user's calendar + schedule an iPhone alarm. Confirmation push sent immediately. Set call_alert=true (with tts_text) to ALSO ring them with a real phone call at that time — it rings right through Silent mode, Focus, and a locked screen.
Required: trigger_at (ISO 8601), label. Optional: sound, notes, recurrence, call_alert, tts_text.
create_item
Write a note or checklist to the user's brain. Set type_label="context" to write persistent instructions future agents read at session start.
Required: type ("note"|"running"), title. Optional: content, type_label, is_important, include_in_brief, agent_name, agent_context, tts_text, tts_voice.
list_items
Read current tasks, notes, alarms. Check this before creating items to avoid duplicates.
Optional: type, status ("pending"|"done"|"all"), limit, search, maker_name.
get_daily_brief
Today's agenda: overdue items, due today, high-priority pending, recent wins. Same data as the 5 AM email brief.
No params.
mark_item_done
Complete a task or alarm. Pass item_id from list_items or create_item response.
Required: item_id.
cancel_alarm
Cancel a pending alarm. Marks it done so it disappears on next sync.
Required: alarm_id.
search_items
Keyword search across everything — every type and status, including calendar events — by default. Use when you want to find something but don't have an ID.
Required: query. Optional: type, status, limit, maker_name.
get_overdue_items
Pending items whose alarm or due date is in the past. Defaults to the user's own items. Pass recipient=<your agent name> to read the items YOU scheduled for yourself that are now due — this is how you check your own reminders in SB.
Optional: recipient.
get_squirrel_brain_help
Full self-config guide returned as JSON: endpoint, hardcoded anon key, all tools with params, session start instructions. Call this first if you're a new agent or need a tool reference.
No params. No auth required beyond your sb_ key.
🧠 USE SQUIRREL BRAIN AS YOUR OWN BACKEND

You're not just writing to the user's brain — you can live in here too. Every item and alarm takes an optional recipient. Omit it and the item is for the user (shows in their stash). Pass your own agent name and it becomes yours: your private notes, to-dos, and reminders — stored in SB, kept out of the user's stash and daily brief. Read them back with list_items(recipient=<you>) and check what's due with get_overdue_items(recipient=<you>). SB is your calendar, task list, and memory — query it on your own loop, on any platform. No extra setup.

Key format: sb_<hex> — generate one instantly at squirrelbrainapp.com/signup, or from the Squirrel Brain app. One key per user. Revocable anytime from your dashboard.

On this page
  1. What this is (for humans)
  2. Authentication & API key
  3. Session start sequence
  4. All 31 tools — full reference
  5. curl examples
  6. Getting started checklist
  7. Copy-paste agent configs
  8. Error codes
  9. Rate limits

What is the MCP server?

MCP (Model Context Protocol) is a standard that lets AI agents call tools on external services. Squirrel Brain exposes an MCP-compatible endpoint so that Claude, Cursor, LangGraph, or any custom agent can interact with your personal brain directly.

This means an AI agent can:

Read your tasks Create notes & checklists Set alarms on your phone Send push notifications Make Pip call you (voice alarm) Fetch your daily brief Write persistent context notes

All actions are tied to your account via your API key. Only you can access your brain.

Who is this for? Developers, technical founders, and power users who want to wire Claude or a custom agent into their Squirrel Brain account. If you just want to use the app, no setup needed — Pip already works out of the box.

Your API key

Every request must include your Squirrel Brain API key in the X-API-Key header. Keys are per-user, scoped to one account, and revocable from the app at any time.

🔑 How the key flow works (industry standard)

Step 1 — Human gets the key. Download the Squirrel Brain iOS app, go to Settings → API Key, and tap Generate. Your sb_ key appears instantly. This step requires your Apple ID and phone — no agent can do it for you.

Step 2 — Human gives key to their agent. Paste it into your agent's environment variables or config file. That's it. This is exactly how you give Claude your Anthropic API key, or how you give GitHub Actions a deploy token.

Step 3 — Agent self-manages from there. Once an agent has a valid key, it can call rotate_api_key to generate a fresh key anytime — no human needed. Keys are valid for 1 year. The app sends a push notification 7 days before expiry.
✅ Store the key persistently — don't re-derive it each session.

Save the sb_ key once in a real config file or environment variable. Agents that re-figure-out the connection from scratch every session (and hold the key only in short-term memory) tend to fall back to a stale key and start failing with "Invalid API key." Set it once, persist it, and it keeps working.

If you ever see "Invalid API key": the key was regenerated. Ask the human to open the app → Settings → API Key, copy the current sb_ key, and update your config. Keys don't expire or get deleted on their own — once you have the current one, it stays valid.

Connect as a real MCP server — don't hand-roll HTTP. Register Squirrel Brain in your agent's MCP config (the copy-paste snippets below) so the key lives in the request headers and is applied automatically on every call. Writing one-off HTTP request code with the key pasted inline is exactly how it goes stale. Then verify: your MCP client should connect and list 31 tools (e.g. an initialize + tools/list handshake, or your client's "test/list servers" command). If you see 0 tools, the key is wrong or your sandbox's network allowlist is blocking *.supabase.co.

Once it's configured, just CALL the tools — don't go hunting for the key. A common failure mode: an agent forgets it already has the connection and starts trying to fetch the key (writing a Keychain/secret-lookup script, an SB_API_KEY env shim, a get_*_key helper) before every call. You never need to — the configured MCP connection injects the key for you. If you have the squirrel_brain tools, call cell_alert / create_alarm / create_item directly. No scripts, no key retrieval.
Endpoint
POST https://geczbtsjfbvfukdzdemr.supabase.co/functions/v1/mcp-server
Required headers on every request
Content-Type: application/json X-API-Key: sb_your_api_key_here Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImdlY3pidHNqZmJ2ZnVrZHpkZW1yIiwicm9sZSI6ImFub24iLCJpYXQiOjE3Nzc4NTA1OTksImV4cCI6MjA5MzQyNjU5OX0.Rdn6ujhp8t1qJNBmAc8VmV5xst10tpSzXh5tt6VCptM

Only two headers are strictly required: Content-Type and your private X-API-Key. The Authorization: Bearer <anon-key> and apikey headers shown in the copy-paste configs below are optional — some MCP clients add them automatically, and they're harmless to include. Both carry the public Supabase anon key (safe to hardcode — it's a public gateway key, not a secret). The configs include them pre-filled so every client works out of the box.

Anon key (hardcode this — it is public):
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImdlY3pidHNqZmJ2ZnVrZHpkZW1yIiwicm9sZSI6ImFub24iLCJpYXQiOjE3Nzc4NTA1OTksImV4cCI6MjA5MzQyNjU5OX0.Rdn6ujhp8t1qJNBmAc8VmV5xst10tpSzXh5tt6VCptM
Request body — JSON-RPC 2.0
{ "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": { "name": "<tool_name>", "arguments": { /* tool-specific args */ } } }
Security: Never expose your API key in client-side code or public repos. Store it in environment variables or a secrets manager. Keys start with sb_.

Run these three calls in parallel first

At the start of every agent session, fire these three calls simultaneously. They give your agent the context it needs to operate correctly.

Writing context notes: Use create_item with type_label: "context" to write persistent notes that every future agent reads at session start. This is how you give agents standing instructions that survive across sessions.

All 31 available tools

Call tools/list at any time to get live JSON schemas. The table below matches the current schema exactly.

Tool Description Parameters
REACH THE USER NOW
cell_alert
Urgent voice CALL — right now. Rings the user's iPhone in ~10 seconds: TTS in the squirrel's nova voice, silent push, full-screen call popup that auto-plays — no tap required, and it rings right through Silent mode, Focus, and a locked screen. Use only when something genuinely needs immediate attention. For a call at a SET TIME, use create_alarm with call_alert: true + tts_text. For a calm voice message they listen to later, use create_item with tts_text (a saved voice note). message title
notify_human
Instant push notification (banner, not full-screen). Fires via APNs to your iPhone. Use for quick status updates — not interruptions. For urgent use cell_alert. title message sound
SESSION START — call all three in parallel
get_user_profile
User's name, squirrel name, IANA timezone, and notification preferences. Required before creating alarms. no params
get_agent_context
Reads persistent context notes the user has written (type_label=context). These are standing orders — treat them as active instructions for every session. no params
get_current_time
Current UTC time and user's local time. Use this — never compute timezone offsets yourself. no params
READ
get_daily_brief
Today's agenda: overdue items, due today, high-priority pending tasks, recent wins. Same data as the 5 AM email brief. Read this to understand what the user has on their plate before adding more. no params
list_items
Query tasks, notes, and alarms. Check this before creating items to avoid duplicates. Filter by type and status. Pass maker_name to return only items created by one maker. Pass recipient with your own agent name to see items addressed to you; pass "user" for the human's own items. type status limit search maker_name recipient
WRITE
create_item
Save a note or checklist to the user's Memory Stash. It appears there exactly like a note they captured themselves. Always start the title with one relevant emoji (e.g. "🧹 Clean the house") — the app emoji-tags every user note, so match it. Set tts_text to send a voice note — your spoken message is saved into the Memory Stash as a playable voice note (green mic card + play button) that the user listens to whenever they open it. This is the calm, non-urgent way to talk to them; for a "right now" ringing call use cell_alert. Set type_label="context" to write persistent instructions all future agents read. Set is_important: true to flag for the 4 PM nudge email. Set recipient to your own agent name to address the item to yourself (lands in your SB inbox, not the user's stash). type title content image_url type_label is_important include_in_brief agent_name agent_context why_saved recipient tts_text tts_voice
create_alarm
This is the calendar tool. Puts a tappable event on the user's calendar and schedules an iPhone alarm, tagged "Made by <your agent_name>". Use it for any appointment, event, deadline, or reminder with a time — when the user says "put it on my calendar" or "remind me," this is the tool. Start label with a relevant emoji (e.g. "🦷 Dentist"). Set call_alert: true to ALSO ring the user with a real phone call at trigger_at — and pass tts_text with the exact words the squirrel speaks when it rings (your own message, in its own voice). The call rings right through Silent mode, Focus, and a locked screen. For a repeating alarm, pass recurrence ONCE (never loop create_alarm). Pass recipient with your own agent name to schedule it for yourself instead of the user. trigger_at label location sound notes recurrence add_reminder_at call_alert tts_text agent_name recipient
mark_item_done
Mark a note, task, or alarm as completed. Use after completing a task you created, or when the user confirms it's done. item_id
update_item
Update an existing note, task, or alarm/calendar event IN PLACE and flip its switches. Use to reschedule (pass datetime to move an event), or to turn ON/OFF toggles: call_alert (a real phone call that rings the user at the item's time — pass tts_text with it to set the exact words the squirrel speaks), is_important (4 PM nudge email), countdown_enabled (Daily Countdown on Home screen), and reminder_at (the item's reminder/notification time). Use append_content / append_notes to ADD to a note or list without erasing it. Only fields you provide are changed. Never create a new alarm to reschedule an existing one — that leaves a duplicate; use update_item instead. item_id title content append_content notes append_notes why_saved datetime reminder_at add_reminder_at is_important call_alert tts_text countdown_enabled board recurrence recurrence_clear
cancel_alarm
Cancel a pending alarm by alarm_id. Marks it done so it disappears on next sync. alarm_id
list_alarms
List all scheduled alarms. Check before creating alarms to avoid duplicates. Use upcoming_only: true to see only future alarms. status limit upcoming_only
create_link
Save a web link or video into the user's Link Stash. The phone shows it as a rich link card (platform badge + thumbnail) alongside links the user saved themselves. Platform is auto-detected from the URL when omitted. HTTPS URLs only. url title summary platform thumbnail_url why_saved
add_to_forever_note
Append checklist content to the user's Forever Note — a single pinned note that accumulates over time and is never erased. Lines are stored as [ ] text so the user can tap to check them off. Creates the Forever Note if it doesn't exist. For lists, pass the label as text and each entry in items[] — every entry becomes its own tappable sub-bullet under the label. text items
remove_from_forever_note
Remove a line from the user's Forever Note — the inverse of add_to_forever_note. Match the line by its text content (case-insensitive, checkbox prefix ignored) or by its 0-based position. Returns { removed: 0 } without error if the line isn't found. text line_index
delete_items_by_maker
Bulk soft-delete every item created by one maker (an agent name, e.g. "Hazel", or a stable "Agent-xxxx" id) in a single call — the fast way to clean up everything one agent put in, instead of deleting items one at a time. Soft-delete (recoverable). Use with care. maker_name
delete_items_by_status
Bulk soft-delete every item with a given status in one call — e.g. status="completed" to clear all the user's done items. Optionally narrow to one type (e.g. "note"). The Forever Note is always protected. status is required — there is no blanket delete-all. Soft-delete (recoverable). Use with care. status type
QUERY & SEARCH
get_item
Get full detail on a single item by ID. Use when you have an item_id from list_items or create_item and need all fields. item_id
search_items
Keyword search across everything — all titles, content, and notes, spanning every type and status (including calendar events) by default. Use when you want to find an item but don't have its ID. Pass maker_name to scope the search to one maker's items. query type status limit maker_name
delete_item
Soft-delete an item. Marks it completed with a deletion note — removed from user's view on next sync. Prefer mark_item_done unless user explicitly asks to delete. item_id
PIX BOARDS — photo boxes
list_boards
List the Pix boards (boxes) currently in use, with how many items each holds. Call this before move_to_board to see what boxes exist, or to answer "what's in my receipts box?". Returns the board keys and counts; only boards that actually hold items are returned. no params
move_to_board
File a Pix photo into a board (box) by the board's key — e.g. move a receipt photo into receipts. Syncs to every device. Pass board_key="" to clear the board. Staple keys: receipts, invoices, shipment, leftonsite, schedules, recipes, meds, parking, whiteboards, cards, other. item_id board_key
BRIEF & PRIORITIES
get_overdue_items
All pending items whose alarm/due date is in the past (within the last 30 days). Defaults to the user's own items. Pass recipient with your own agent name to get the items you scheduled for yourself that are now due — this is how an agent checks its own reminders in SB. Good to call at session start alongside get_daily_brief. recipient
get_nudge_candidates
Pending items flagged is_important=true — the 4 PM nudge email list. Use to understand what the user considers urgent or must-do before adding more. no params
PORTAL — in-app chat thread
get_portal_messages
Read the conversation history in the user's MCP Agent Portal. Returns your own thread by default; pass agent_name to read another agent's thread or "all" for every thread. Auto-marks unread inbound messages as read. limit direction agent_name
send_portal_message
Send a chat message to the user in the MCP Agent Portal AND push-notify their phone. Use it to talk to the user or confirm what you did. Do NOT use this in place of an action — if the user gives you something to save (an appointment, a task, info to remember), call create_alarm or create_item instead of just messaging it, or it never reaches their calendar/stash. content action_taken image_url
delete_portal_messages
Delete portal messages you previously sent — cleanup tool for removing stray or test messages from the agent portal thread. Supports deletion by explicit message_ids list, by agent_name, or by a cutoff before timestamp. Cap: 100 messages per call. Scoped to the current user only. message_ids agent_name before
API KEY — lifecycle management
get_api_key_usage
Check your key's usage stats: calls today, calls total, expiry date, and days until expiry. Call this to monitor activity or confirm your key is still valid. no params
rotate_api_key
Revoke the current sb_ key and issue a new one instantly — no human needed. The old key stops working immediately. Update your config with the returned new_api_key before making any further calls. label (optional — label for the new key, e.g. "Claude agent")
META
get_squirrel_brain_help
Returns a full self-configuration guide: endpoint, the hardcoded public anon key, all 31 tools with params, and session start instructions. Call this if you are a new agent setting up a connection or need a tool reference. no params
★ Golden rules (read these):
1. Act, don't just message. Something with a time → create_alarm (calendar). Info/notes/lists → create_item (Memory Stash). send_portal_message is only for chatting/confirming — a message alone never lands on the calendar or in the stash.
2. Always start a title / label with one relevant emoji (📝 if nothing fits). The app emoji-tags every note the user captures; match it.
3. Pass agent_name on create_item / create_alarm so the user sees who made it.
4. PixNotes: attach a public image_url to create_item to save a photo-note — the picture shows as the card thumbnail.

Maker attribution: every item records who created it — a maker_kind (user | local_agent | external_agent) and a maker_name shown on the card. External MCP agents are identified by their X-Agent-Name request header; if you don't send one, you're auto-assigned a stable Agent-xxxx id — so no agent write is ever anonymous. Set X-Agent-Name to your agent's name so the user sees it. Use list_items / search_items with maker_name to show everything one agent created, and delete_items_by_maker to bulk-remove it.

create_item type values: "note" for a single item, "running" for a checklist (use bullet format in content: "• item1\n• item2").

type_label options: task, question, fyi, alert, confirmation, note, code, context.

create_alarm sound options: chipmunk_squirrel, angry_squirrel, gentle_alarm, digital_alarm, fire_alarm. Default: gentle_alarm.

trigger_at format: ISO 8601 UTC — e.g. "2026-06-01T14:00:00Z". Always call get_current_time and get_user_profile first.
⚠️ The real call needs the latest Squirrel Brain build.

The break-through call — the one that rings right through Silent mode, Focus, and a locked screen and plays the squirrel's voice — requires the newest version of the Squirrel Brain app installed on the user's iPhone. On older builds it falls back to a standard alert where the OS allows. So if a call isn't ringing through, the first thing to check is that the user has updated to the current App Store / TestFlight build.

curl examples

Replace sb_your_api_key_here with your key.

Initialize session (handshake)
curl -X POST \ https://geczbtsjfbvfukdzdemr.supabase.co/functions/v1/mcp-server \ -H "Content-Type: application/json" \ -H "X-API-Key: sb_your_api_key_here" \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImdlY3pidHNqZmJ2ZnVrZHpkZW1yIiwicm9sZSI6ImFub24iLCJpYXQiOjE3Nzc4NTA1OTksImV4cCI6MjA5MzQyNjU5OX0.Rdn6ujhp8t1qJNBmAc8VmV5xst10tpSzXh5tt6VCptM" \ -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}'
Make Pip call the user (voice alarm in ~10s)
curl -X POST \ https://geczbtsjfbvfukdzdemr.supabase.co/functions/v1/mcp-server \ -H "Content-Type: application/json" \ -H "X-API-Key: sb_your_api_key_here" \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImdlY3pidHNqZmJ2ZnVrZHpkZW1yIiwicm9sZSI6ImFub24iLCJpYXQiOjE3Nzc4NTA1OTksImV4cCI6MjA5MzQyNjU5OX0.Rdn6ujhp8t1qJNBmAc8VmV5xst10tpSzXh5tt6VCptM" \ -d '{ "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": { "name": "cell_alert", "arguments": { "title": "Meeting in 5 minutes", "message": "Hey, your call with Marcus at Meridian starts in 5 minutes. He is waiting on the revised pricing." } } }'
Set an alarm at a specific time
curl -X POST \ https://geczbtsjfbvfukdzdemr.supabase.co/functions/v1/mcp-server \ -H "Content-Type: application/json" \ -H "X-API-Key: sb_your_api_key_here" \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImdlY3pidHNqZmJ2ZnVrZHpkZW1yIiwicm9sZSI6ImFub24iLCJpYXQiOjE3Nzc4NTA1OTksImV4cCI6MjA5MzQyNjU5OX0.Rdn6ujhp8t1qJNBmAc8VmV5xst10tpSzXh5tt6VCptM" \ -d '{ "jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": { "name": "create_alarm", "arguments": { "label": "Call Marcus — pricing deadline", "trigger_at": "2026-06-05T14:00:00Z", "sound": "angry_squirrel", "notes": "He needs the revised numbers today" } } }'
Schedule a call at a set time — in the squirrel's own words
curl -X POST \ https://geczbtsjfbvfukdzdemr.supabase.co/functions/v1/mcp-server \ -H "Content-Type: application/json" \ -H "X-API-Key: sb_your_api_key_here" \ -d '{ "jsonrpc": "2.0", "id": 4, "method": "tools/call", "params": { "name": "create_alarm", "arguments": { "label": "🦷 Dentist", "trigger_at": "2026-06-05T18:30:00Z", "call_alert": true, "tts_text": "Hey, your dentist appointment is in 30 minutes — time to head out. You've got this!" } } }'
Save a note to the brain
curl -X POST \ https://geczbtsjfbvfukdzdemr.supabase.co/functions/v1/mcp-server \ -H "Content-Type: application/json" \ -H "X-API-Key: sb_your_api_key_here" \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImdlY3pidHNqZmJ2ZnVrZHpkZW1yIiwicm9sZSI6ImFub24iLCJpYXQiOjE3Nzc4NTA1OTksImV4cCI6MjA5MzQyNjU5OX0.Rdn6ujhp8t1qJNBmAc8VmV5xst10tpSzXh5tt6VCptM" \ -d '{ "jsonrpc": "2.0", "id": 3, "method": "tools/call", "params": { "name": "create_item", "arguments": { "type": "note", "title": "Follow up with Marcus at Meridian", "content": "Send revised pricing and Riverside case study", "type_label": "task", "is_important": true, "agent_name": "Claude" } } }'
Write a persistent context note (all future agents will read this)
curl -X POST \ https://geczbtsjfbvfukdzdemr.supabase.co/functions/v1/mcp-server \ -H "Content-Type: application/json" \ -H "X-API-Key: sb_your_api_key_here" \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImdlY3pidHNqZmJ2ZnVrZHpkZW1yIiwicm9sZSI6ImFub24iLCJpYXQiOjE3Nzc4NTA1OTksImV4cCI6MjA5MzQyNjU5OX0.Rdn6ujhp8t1qJNBmAc8VmV5xst10tpSzXh5tt6VCptM" \ -d '{ "jsonrpc": "2.0", "id": 4, "method": "tools/call", "params": { "name": "create_item", "arguments": { "type": "note", "title": "Agent standing instructions", "content": "Always check the daily brief first. I prefer voice messages for anything urgent. My primary focus is sales pipeline. My timezone is America/New_York.", "type_label": "context", "agent_name": "Adam" } } }'
Read pending tasks
curl -X POST \ https://geczbtsjfbvfukdzdemr.supabase.co/functions/v1/mcp-server \ -H "Content-Type: application/json" \ -H "X-API-Key: sb_your_api_key_here" \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImdlY3pidHNqZmJ2ZnVrZHpkZW1yIiwicm9sZSI6ImFub24iLCJpYXQiOjE3Nzc4NTA1OTksImV4cCI6MjA5MzQyNjU5OX0.Rdn6ujhp8t1qJNBmAc8VmV5xst10tpSzXh5tt6VCptM" \ -d '{ "jsonrpc": "2.0", "id": 5, "method": "tools/call", "params": { "name": "list_items", "arguments": { "type": "all", "status": "pending", "limit": 20 } } }'
Fetch the daily brief
curl -X POST \ https://geczbtsjfbvfukdzdemr.supabase.co/functions/v1/mcp-server \ -H "Content-Type: application/json" \ -H "X-API-Key: sb_your_api_key_here" \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImdlY3pidHNqZmJ2ZnVrZHpkZW1yIiwicm9sZSI6ImFub24iLCJpYXQiOjE3Nzc4NTA1OTksImV4cCI6MjA5MzQyNjU5OX0.Rdn6ujhp8t1qJNBmAc8VmV5xst10tpSzXh5tt6VCptM" \ -d '{ "jsonrpc": "2.0", "id": 6, "method": "tools/call", "params": { "name": "get_daily_brief", "arguments": {} } }'
Session start (run in parallel): Call get_user_profile, get_agent_context, and get_current_time simultaneously at the start of every session — they're all no-param calls that return immediately.

Setup checklist

iOS requirement for cell_alert: Voice alarms require Background App Refresh ON for Squirrel Brain. Go to iOS Settings → Squirrel Brain → Background App Refresh → On.
Claude Code users: Run with claude --dangerously-skip-permissions. Without this flag every tool call requires manual approval — which defeats autonomous operation.

Copy-paste config for your agent

Replace sb_YOUR_KEY_HERE with your key.

Add to ~/Library/Application Support/Claude/claude_desktop_config.json

{
  "mcpServers": {
    "squirrel-brain": {
      "url": "https://geczbtsjfbvfukdzdemr.supabase.co/functions/v1/mcp-server",
      "headers": {
        "X-API-Key": "sb_YOUR_KEY_HERE",
        "Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImdlY3pidHNqZmJ2ZnVrZHpkZW1yIiwicm9sZSI6ImFub24iLCJpYXQiOjE3Nzc4NTA1OTksImV4cCI6MjA5MzQyNjU5OX0.Rdn6ujhp8t1qJNBmAc8VmV5xst10tpSzXh5tt6VCptM",
        "apikey": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImdlY3pidHNqZmJ2ZnVrZHpkZW1yIiwicm9sZSI6ImFub24iLCJpYXQiOjE3Nzc4NTA1OTksImV4cCI6MjA5MzQyNjU5OX0.Rdn6ujhp8t1qJNBmAc8VmV5xst10tpSzXh5tt6VCptM"
      }
    }
  }
}

Add a .mcp.json to your project root (or run claude mcp add). Works in the Claude Code CLI and in Claude Code on the web.

{
  "mcpServers": {
    "squirrel-brain": {
      "type": "http",
      "url": "https://geczbtsjfbvfukdzdemr.supabase.co/functions/v1/mcp-server",
      "headers": {
        "X-API-Key": "${SQUIRREL_BRAIN_API_KEY}",
        "Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImdlY3pidHNqZmJ2ZnVrZHpkZW1yIiwicm9sZSI6ImFub24iLCJpYXQiOjE3Nzc4NTA1OTksImV4cCI6MjA5MzQyNjU5OX0.Rdn6ujhp8t1qJNBmAc8VmV5xst10tpSzXh5tt6VCptM"
      }
    }
  }
}

Or via CLI: claude mcp add --transport http squirrel-brain https://geczbtsjfbvfukdzdemr.supabase.co/functions/v1/mcp-server --header "X-API-Key: ${SQUIRREL_BRAIN_API_KEY}"

⚠️ Claude Code on the web — two one-time steps in the session settings:

1. Allowlist the host. The web sandbox blocks outbound network calls by default. Add geczbtsjfbvfukdzdemr.supabase.co (or *.supabase.co) to your environment's allowed domains, or the MCP server is unreachable. (This is also why an agent may report it "can't access" this site — it's the sandbox allowlist, not us; this site is public.)

2. Add the key as a secret. Set an environment variable SQUIRREL_BRAIN_API_KEY = your sb_ key (from the app → Settings → API Key). The config above references it, so the key never gets hardcoded. ${VAR} is expanded by Claude Code in .mcp.json headers.

Add to .cursor/mcp.json in your project root, or Cursor's global MCP settings.

{
  "mcpServers": {
    "squirrel-brain": {
      "url": "https://geczbtsjfbvfukdzdemr.supabase.co/functions/v1/mcp-server",
      "headers": {
        "X-API-Key": "sb_YOUR_KEY_HERE",
        "Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImdlY3pidHNqZmJ2ZnVrZHpkZW1yIiwicm9sZSI6ImFub24iLCJpYXQiOjE3Nzc4NTA1OTksImV4cCI6MjA5MzQyNjU5OX0.Rdn6ujhp8t1qJNBmAc8VmV5xst10tpSzXh5tt6VCptM",
        "apikey": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImdlY3pidHNqZmJ2ZnVrZHpkZW1yIiwicm9sZSI6ImFub24iLCJpYXQiOjE3Nzc4NTA1OTksImV4cCI6MjA5MzQyNjU5OX0.Rdn6ujhp8t1qJNBmAc8VmV5xst10tpSzXh5tt6VCptM"
      }
    }
  }
}

LangGraph / LangChain MCP adapter:

from langchain_mcp_adapters.client import MultiServerMCPClient

client = MultiServerMCPClient({
    "squirrel-brain": {
        "url": "https://geczbtsjfbvfukdzdemr.supabase.co/functions/v1/mcp-server",
        "transport": "streamable_http",
        "headers": {
            "X-API-Key": "sb_YOUR_KEY_HERE",
            "Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImdlY3pidHNqZmJ2ZnVrZHpkZW1yIiwicm9sZSI6ImFub24iLCJpYXQiOjE3Nzc4NTA1OTksImV4cCI6MjA5MzQyNjU5OX0.Rdn6ujhp8t1qJNBmAc8VmV5xst10tpSzXh5tt6VCptM",
            "apikey": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImdlY3pidHNqZmJ2ZnVrZHpkZW1yIiwicm9sZSI6ImFub24iLCJpYXQiOjE3Nzc4NTA1OTksImV4cCI6MjA5MzQyNjU5OX0.Rdn6ujhp8t1qJNBmAc8VmV5xst10tpSzXh5tt6VCptM"
        }
    }
})
tools = await client.get_tools()

# Set an alarm
result = await client.call_tool("create_alarm", {
    "trigger_at": "2026-06-01T12:00:00Z",
    "label": "Review report — finished at 3 AM",
    "sound": "angry_squirrel"
})

Any agent that supports JSON-RPC 2.0 over HTTP:

Endpoint:       POST https://geczbtsjfbvfukdzdemr.supabase.co/functions/v1/mcp-server
Content-Type:   application/json
X-API-Key:      sb_YOUR_KEY_HERE
Authorization:  Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImdlY3pidHNqZmJ2ZnVrZHpkZW1yIiwicm9sZSI6ImFub24iLCJpYXQiOjE3Nzc4NTA1OTksImV4cCI6MjA5MzQyNjU5OX0.Rdn6ujhp8t1qJNBmAc8VmV5xst10tpSzXh5tt6VCptM

Body (tools/call):
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "<tool_name>",
    "arguments": { ... }
  }
}

What errors look like & how to handle them

All errors return HTTP 200 with a JSON-RPC error body. Check response.error, not the HTTP status code.

{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Unknown tool: get_foo"
  }
}
Code Meaning How to fix
HTTP 401 Missing or invalid X-API-Key "Invalid API key" almost always means the key was regenerated. Ask the user to open the app → Settings → API Key, copy the current sb_ key, and update your config. Keys don't expire or get deleted on their own, so once you have the current one it keeps working — store it persistently (env var / config file), don't re-derive it each session.
HTTP 403 Key is valid but user profile not found Open the Squirrel Brain app once to create the profile, then retry.
-32600 Invalid JSON-RPC request (bad structure) Check you're sending { jsonrpc: "2.0", id, method, params }.
-32601 Unknown tool name Check spelling. Call get_squirrel_brain_help for the full tool list.
-32602 Invalid params (missing required field) The error message names the missing field. Add it.
-32603 Insufficient scope or internal error Read the message field. Every key is issued with full permissions by default, so "Insufficient scope" is rare — if you hit it, regenerate your key in Settings → API Key. Any other -32603 message is a transient server error — check the data field and retry once.
🔑 Routine annual renewal — this is normal, nothing is broken.

Keys are valid for 1 year. Starting 7 days before expiry, you'll get a push notification on your phone that says: "Routine key renewal — X days left" (where X counts down from 7). This is expected — it happens every year for security.

What to do when you get that notification:
1. Open the Squirrel Brain app
2. Go to Settings → API Key
3. Tap Regenerate
4. Copy the new key
5. Paste it into your agent's config (wherever you originally put the old key)
6. Done — your agent picks up the new key on its next call

Agents with an active key can also skip steps 1–4 by calling rotate_api_key — the old key is revoked and the fresh key is returned instantly. Either way, your agent will need step 5 (update its config with the new key).

Per-user limits

All limits are per-user per-key — not global. Anomaly detection flags bulk reads (> 1,000 reads in 10 minutes) and soft-suspends the token with a push notification to the user.

Action Per minute Per hour Per day
Read queries606005,000
Write (items)20100500
Alarm creates51030
Push notifications102050
cell_alert (voice)2510
Brief trigger123
Why not just use Pushover / Ntfy / Twilio?
Pushover/Ntfy send banner notifications — silenced by Focus mode and DND. Twilio makes a phone call.
Squirrel Brain fires a real iPhone alarm — same as your alarm clock — or a real phone call, both ringing right through Silent mode, Focus, and a locked screen, and it keeps going until dismissed. Plus structured memory and tasks that survive between agent sessions.