MCP Integration

Point Claude Code, Cursor, Claude Desktop, or any MCP-compatible client at your CoachKeeper workspace.

What this is

CoachKeeper exposes its full agent toolset over the Model Context Protocol (MCP) — the open standard that AI clients use to talk to external tools. Any MCP-compatible client can read, search, create, update, and schedule against your workspace as if it were the built-in coach.

Same rules apply on both sides:

  • Same authentication boundary — OAuth sign-in with your CoachKeeper account, never a pasted secret
  • Same action log — every create / update / delete lands in the shared action log the in-app coach uses
  • Same undo — ask the in-app chat assistant to undo any action taken over MCP
  • Same availability windows respected when scheduling

Why you’d use it

  • You already live in Cursor or Claude Code. Let the editor turn a TODO comment into a real todo in your backlog without leaving the IDE.
  • You use Claude Desktop every day. Ask it to schedule your week using your CoachKeeper backlog and availability — without copy-pasting.
  • You’re building your own agent. Treat CoachKeeper as a managed PKM service it can call.

Connect a client

There is nothing to mint, copy, or paste. CoachKeeper implements the MCP authorization spec (OAuth 2.1): you give your client the server URL, and the first time it connects your browser opens a CoachKeeper consent screen. Sign in (if you aren’t already), click Authorize, and you’re done — the client refreshes its own access from then on. This is the same flow GitHub, Linear, Notion, and Sentry use for their MCP servers.

Claude Code (CLI)

claude mcp add --transport http coachkeeper https://api.coachkeeper.com/api/v1/mcp

Confirm with claude mcp list. On first use it will open your browser to authorize.

Claude Desktop

Edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):

{
  "mcpServers": {
    "coachkeeper": {
      "type": "http",
      "url": "https://api.coachkeeper.com/api/v1/mcp"
    }
  }
}

Restart Claude Desktop. Look for the 🔌 icon in the input bar — it should list coachkeeper and prompt you to authenticate.

Cursor

Settings → MCP → Add new MCP server, paste the same JSON snippet.

Anything else that speaks MCP

Same JSON shape. Two things matter: type: "http" and the URL. No headers — the client discovers the OAuth endpoints automatically and walks you through consent. The client does need to support MCP OAuth: harnesses whose MCP client only takes static headers (DeepSeek Harness at time of writing, for example) can’t sign in yet.

Teach your agent

Connecting gives your agent the tools; teaching it the house style makes it good with them. Settings → AI Tools (MCP) includes a short copyable briefing — the entities and how they relate, how to search cheaply before listing everything, how notes and todos are formatted, and what to confirm with you before changing things.

  • Claude Code: download it as SKILL.md and save it under ~/.claude/skills/coachkeeper/ — it loads automatically whenever you work with CoachKeeper.
  • Claude Desktop / ChatGPT / Cursor and others: paste it into the agent’s custom or project instructions.

The server already sends a compact version of this briefing to every client when it connects, and it also serves the full briefing over MCP itself — as the skill prompt (a slash command in Claude Desktop) and as the resource coachkeeper://skill. A client that shows prompts can load it in one click, no pasting; installing the SKILL.md file is still worth it if you pair one agent with CoachKeeper regularly, so it is there before the first tool call.

Connection status at a glance

Once a client is connected, a small plug/agent icon in the app’s top bar turns into a status badge — amber when idle, briefly green whenever the agent makes a change. Click it anytime to jump straight to Settings → AI Tools (MCP). Before you’ve connected anything, the chat panel also shows a one-time “bring your own agent” card pointing at the same setup flow.

Managing access

Settings → AI Tools (MCP) lists every client currently connected to your account, with when it connected and when it was last used. Revoke cuts a client off immediately — it would have to go through browser consent again to reconnect.

Under the hood, each authorization issues a short-lived access token plus a rotating refresh token. A connection that goes unused for more than 7 days expires on its own; active clients renew silently and stay connected indefinitely.

What the AI client can do

The server exposes the same tools the in-app coach uses, minus five that are app-specific: undo_last_action, save_memory, request_include_context, request_approval (your own agent runs its own approval flow), and web_search. At time of writing:

DomainTools
Noteslist_notes, get_note, create_note, update_note, delete_note, summarize_note, rewrite_note
Notebookslist_notebooks, get_notebook (table of contents, or the whole book as markdown), create_notebook, update_notebook, delete_notebook
Todoslist_todos, get_todo, create_todo, update_todo, delete_todo, complete_recurring_todo
Eventslist_events, get_event, create_event, update_event, delete_event
Sourceslist_sources, get_source_content, search_sources (RAG)
Searchsearch_items (cross-entity by title or content), semantic_search (meaning-based, not just keyword matches)
Tagslist_tags (every tag with live item counts), get_tag_dossier (a tag’s map: a mermaid concept sketch of what’s filed under it plus short state notes, each pointing at real item ids — the same map the Library page shows, including any arrangement you made by hand, which a client is told not to redraw)
Orientationget_workspace_overview (a snapshot of your workspace — counts, recent activity — for a client to get its bearings before diving in)
Schedulingget_availability

Notes, todos, and sources read back as properly formatted markdown, not raw JSON blobs. Their list tools (list_notes, list_todos, list_sources) are paginated and filterable — by status, tag, notebook, due window, or title — instead of a flat cap on how many rows come back, so a client can page through a large workspace without missing items. Notes can be tagged the same way todos and events already could.

A todo carries two independent dates, and the tools keep them apart: due_date is the deadline, scheduled_start / scheduled_end is the time blocked out to do the work — which is what your calendar shows. Blocking time means scheduling the todo itself; an agent should never create an event to stand in for a task. list_todos filters on either (due_before / due_after, scheduled_from / scheduled_to) and takes unscheduled: true to find work that still needs a slot.

Two writing conventions worth teaching your agent: a fenced ```mermaid code block in any note renders as a live diagram in the app, and rich material for a todo — briefs, research, diagrams — belongs in a note linked via context_note_ids, which is what the todo page displays.

Each tool returns the same shape as a normal API call and produces the same action log entry. To see the live, authoritative list, call MCP’s standard tools/list from your client.

Work the todo queue

The server also ships a prompt, work_queue — in Claude Desktop it appears as the /work_queue slash command. It tells the agent to pick up every task you have handed over on the board (the sparkle button — see Hand a task to your agent), work them one at a time, and report back on the cards themselves: a plan while it works, questions as Agent needs input, results as Agent done in your Pending column. There is no chat thread to keep alive — the task is the thread — so a question you answer on Tuesday can be picked up by a different agent session on Thursday.

Run the queue on a schedule

CoachKeeper never starts an agent by itself; queued tasks wait for a client to come by. If you want that to happen without you, schedule the client:

  • Claude Code — with the server added (claude mcp add … above), a one-line cron entry or a Claude routine runs the queue unattended, e.g. every weekday morning: claude -p "Load the coachkeeper skill prompt, then run the work_queue prompt". Anything the agent can’t decide lands on your board as needs input, never as a guess.
  • Any other headless agent with an OAuth-capable MCP client works the same way: point it at the server, have it call the work_queue prompt, run it on whatever timer you like.

Guardrails still apply: the agent can only do what a person with your account could, and everything it does is undoable from the in-app chat.

Things to know

  • Streamable HTTP, stateless. No persistent connection — every request carries a short-lived bearer token the client manages for you.
  • No per-request rate limiting today. MCP tool calls are exempt from the web rate limiter. Be a good citizen — reasonable limits may be introduced later.
  • Legacy static tokens (from before OAuth) keep working until they expire, but you can’t mint new ones. Reconnect via OAuth — it’s less work and it never dies silently.
  • Self-hosted CoachKeeper? Same protocol, just point at your own https://your-host/api/v1/mcp.

Troubleshooting

SymptomLikely cause
Client reports the server is unreachableWrong URL — must end in /api/v1/mcp (not /mcp)
Browser consent never opensYour client predates MCP OAuth support — update it
401 Unauthorized on every callConnection was revoked or expired from inactivity — reconnect (the client will re-open the consent screen)
Tool calls succeed but nothing appears in the appYou authorized while signed in to a different CoachKeeper account — revoke in Settings and reconnect with the right one
Client lists no toolsServer reachable but not yet authorized — trigger the auth flow (e.g. /mcp in Claude Code)

Where the actions show up

Changes made over MCP push to your open CoachKeeper views in real time — a todo created from Cursor appears on your Kanban board instantly, no reload. Each action is also recorded in the same action log the built-in coach uses, so if an external client did something you didn’t want, open the in-app chat and say “undo that” — the assistant rolls it back.