@cpenned/mcp
v0.8.5
Published
MCP server for Open Brain - a thin adapter over the /v1 HTTP API.
Downloads
1,161
Maintainers
Readme
@cpenned/mcp
MCP server for Open Brain. A thin adapter over the /v1 HTTP API: every tool is
an authenticated call through the same enforced path as any other API consumer,
so the guard layer remains the single write chokepoint.
Configuration
Set via environment variables:
| Variable | Required | Description |
| ------------------------ | -------- | ------------------------------------------------------------------ |
| OPEN_BRAIN_API_URL | yes | Deployment origin, e.g. https://<deployment>.convex.site |
| OPEN_BRAIN_API_KEY | yes | An obr_ API key with the scopes the tools you use require |
| OPEN_BRAIN_CLIENT_TYPE | no | X-Client stamped on the audit log (default mcp) |
The key's scopes gate the tools: resource tools need <resource>:read|write,
review tools reviews:*, settings tools settings:read|write, and
find_tasks / ai_triage need ai:invoke. list_shares/list_shared_tasks
additionally need the key to have been minted with includeGrants: true (via
create_key's includeGrants flag or the web app) - without it, a key only
ever sees the vault's own data, even with *.
The stdio server sends the machine's IANA timezone as X-Timezone on every
request, so relative dates (today, +3d) and views resolve in your zone.
The hosted server does not (it would send the server's zone), so it falls
back to the vault's defaultTimezone.
Run
The package is published to npm, so the simplest path needs no clone or build -
just run it with npx:
OPEN_BRAIN_API_URL=... OPEN_BRAIN_API_KEY=... npx -y @cpenned/mcpThe server speaks MCP over stdio.
Claude Desktop / CLI
{
"mcpServers": {
"open-brain": {
"command": "npx",
"args": ["-y", "@cpenned/mcp"],
"env": {
"OPEN_BRAIN_API_URL": "https://<deployment>.convex.site",
"OPEN_BRAIN_API_KEY": "obr_..."
}
}
}
}Remote (hosted on Vercel)
The repo's Vercel deploy also exposes this tool surface as a remote MCP server
over Streamable HTTP at /api/mcp (see the root README, "Hosted MCP
endpoint"). The hosted variant reuses createServer with
{ localSkills: false }, so install_skills and the skill-install nudge are
local-transport only. Auth is per-request: Authorization: Bearer obr_..., or
/api/mcp/<key> for clients that can't send headers (claude.ai custom
connectors).
From source (development)
Building from the monorepo instead of npm:
npm install
npm run build -w @cpenned/mcp
OPEN_BRAIN_API_URL=... OPEN_BRAIN_API_KEY=... node packages/mcp/dist/index.jsPoint the args at the absolute packages/mcp/dist/index.js path with
"command": "node" if you wire a source build into Claude Desktop.
Tools
- Resources (CRUD, single + batch + multi-get):
create_task,list_tasks,get_task,update_task,delete_task,create_tasks,update_tasks,add_task_tags,remove_task_tags; the*_project,*_garden,*_tagequivalents; project reads includetaskCounts {open, done}andnextTaskId. Task/projectdeferDate/deadlineare calendar days (YYYY-MM-DD); inputs also accept relative tokens liketoday/+3d. Tasks also carryassigneeUserId(settable viacreate_task(s)/update_task(s)as a user id,"me", ornullto unassign - only meaningful in a garden shared with another user, see Mind Meld below);list_tasksfilters byassignee: "me"|"unassigned"|<userId>.create_task(s)andcreate_project(s)accept an initialstatus(backlog|todo|in_progress|done|canceled, defaulttodo). Path ids are validated ([A-Za-z0-9_-]) and URL-encoded. Read tools carryreadOnlyHintand delete/remove/revoke/rotate toolsdestructiveHintannotations. - People (personal CRM):
create_person,list_people(querysearches name, aliases, company, notes, and more),get_person,update_person(null clears fields;archived: falserestores),delete_person(archives),mark_contacted(optionalatbackdates),add_person_links/remove_person_links(link people to tasks, projects, gardens, and other people — person-to-person connections are symmetric and take an optional label like "spouse", plusreadingListItemIdsandhabitIdson either side). People with an elapsed contact cadence appear inget_reviewsandui_review_queue;list_tasksfilters bypersonids. - Reading list:
create_reading_item(onlyurlis required; title/ description are fetched from the page in the background),list_reading_items,get_reading_item,update_reading_item(drives statusunread|reading|read; stamps/clearsreadAt;archived/deletedtoggle independently of status),delete_reading_item(true soft delete, hidden everywhere; restore with{deleted: false}),add_reading_tags/remove_reading_tags. - Habits:
create_habit,list_habits(passcursorfor the next page),get_habit,update_habit,archive_habit,unarchive_habit,complete_habit,remove_habit_completion,reorder_habits,add_habit_tags, andremove_habit_tags. Habits support daily, weekly, monthly, and every-N-days schedules, streak metadata, optional quantity targets, and reversible archive.pausedUntilDay,graceDays,availableFrom,availableUntil, andtargetQuantityacceptnullon update to clear;startDaycan be moved but not cleared. - Strava:
list_strava_activities,get_strava_activity,update_strava_activity(notes/archived/deletedonly — everything else is Strava-authoritative),delete_strava_activity(soft delete; restore with{deleted: false}),add_strava_activity_tags/remove_strava_activity_tags,sync_strava_activities(manual backfill/fallback; real-time ingestion is a webhook). No create tool — activities only arrive via webhook or sync. Requires connecting a Strava account first, from the web app's Settings page. - Calendar (read-only mirror of synced Google Calendar events):
list_calendar_events(startMs/endMsepoch-ms window, optionalcalendarId),list_calendars,sync_calendar. Connect accounts + toggle per-calendar visibility in the web app; link a task to an event withupdate_task'seventId. - Books (a personal library, distinct from the reading list above):
search_books(qtitle/author orisbn),create_book(onlytitlerequired;openLibraryWorkId/isbnschedule background metadata + cover enrichment from Open Library, fill-only-missing),list_books(filter bystatus[]/format[]/tagIds/personIds/query, or multi-get viaids),get_book(tags, people, linked habit, recent sessions),update_book(drives statuswant_to_read|reading|read|dnf; null clears a clearable field;habitId: nullunlinks the page-goal habit;archived/deleted: falserestores),delete_book(soft delete, cover blob kept),add_book_tags/remove_book_tags,log_book_session(retroactive OK, multiple sessions per day, can check off a linked habit for that day - never downgrading a manual completion),remove_book_session,refresh_book_metadata(overwrite?).add_person_links/remove_person_linkstakebookIds. - Attachments (read-only; upload is web/app-only):
list_task_attachments,get_attachment,get_attachment_url(short-lived signed URL, optionalvariantserved/original/thumbnail). Needstasks:read. - Views & reviews:
get_view,get_reviews,review_garden,request_garden_review,mark_task_reviewed,mark_project_reviewed. Views resolve "today" in the timezone of the machine running the server unless you passtz. - Settings:
get_settings,update_settings— the default review period applied to new tasks/projects (2 weeks out of the box;defaultReviewInterval: nulldisables it, andreviewInterval: nulloncreate_task/create_projectopts a single item out).defaultTimezone(IANA string) is also settable - the vault timezone date-only deferDates/ deadlines resolve against.yearlyBookGoalsets the reading-challenge target (books finished this calendar year);nullclears it. - AI:
find_tasks(hybrid search),ai_triage(brain-dump triage). - UI (read-only MCPUI):
ui_view,ui_review_queue,ui_garden_board,ui_habitsreturnui://HTML resources.ui_viewandui_habitstake acursorand say when a page was cut short. - Mind Meld (shared gardens, guest side - sharing/invites/revoke are
web-app-only):
list_shares(gardens shared with the caller: capabilities, owner, participants - empty unless the key hasincludeGrants),list_shared_tasks({shareId, status?, includeCanceled?}, capped at 500). A garden shared from another Open Brain deployment carriesremote: {origin, lastSyncedAt, lastError}and is edited with the normal task tools. In a shared garden, a guest's status moves are gated by the owner's capability grant rather than the usual status machine:completeonly moves an open task todone; any other move (including reopeningdone/canceled) needsedit;canceledneedscancel. - Profile:
get_profile,update_profile(displayName, 1-60 chars; avatar upload is web-only). - Key management:
create_key(optionalincludeGrantsso the minted key can see gardens shared with its owner - only settable if the calling key itself has it),list_keys,rotate_key,revoke_key(require the configured key to holdkeys:manage).rotate_keyandrevoke_keyrefuse the key the server itself is configured with. A key can only grant scopes it itself holds; secrets are returned once. Grantkeys:managedeliberately - it lets the agent mint and revoke keys. - Skills:
install_skillscopies the bundledopen-brain-mcpagent skill into the shared skills directory (see below). Purely local; no API call.
Agent skill
The open-brain-mcp agent skill teaches an assistant how to use these tools
well - Claude Code, or any other agent that reads ~/.agents/skills. It ships
inside this package; install it any of three ways:
npx -y @cpenned/mcp install-skills # into ~/.agents/skills (+ links ~/.claude/skills)
npx -y @cpenned/mcp install-skills --force # overwrite an existing copy
npx -y @cpenned/mcp list-skills # what's bundled
npx -y @cpenned/mcp uninstall-skills- Let the agent do it: when the server starts and the skill isn't installed
yet, the server's instructions ask the connected agent to offer installing it
once via the
install_skillstool. Say yes and restart the agent. - Via the CLI package (bundles the CLI skill too):
npm i -g @cpenned/cli && ob skills install. - Or copy
.agents/skills/open-brain-mcpfrom the repo into~/.agents/skillsby hand.
By default, skills install into the shared ~/.agents/skills directory and
~/.claude/skills is symlinked to that copy, so Claude Code and any other
agent using the shared directory both pick it up. Pass --dir <path> to
install directly into one specific agent's own skills directory instead
(no shared dir, no symlink). Restart your agent after installing.
Publishing
MIT-licensed and publish-ready (files, publishConfig, prepublishOnly
build). To cut a release: bump the version, then npm publish -w @cpenned/mcp
from the repo root (@cpenned is the owner's npm username scope, so no org is
needed; you must be authenticated as that user). prepublishOnly rebuilds
dist first.
