MCP Server
The Pensum MCP server exposes your vault to AI agents via the Model Context Protocol. Agents can query your tasks, capture new ones, read project state, search across your vault, drive the weekly review, generate calendar exports, and write back when allowed — all with provenance tracking so you can always tell what an agent did vs. what you did.
This is the bridge between Pensum and the rest of your AI workflow. If you use Claude Desktop, Claude Code, or any other MCP-capable agent, the Pensum MCP server lets that agent participate in your productivity loop instead of just observing it.
The fast path: pensum mcp install
Section titled “The fast path: pensum mcp install”The CLI ships a guided install bundle that prints the exact config snippet for your client, with the file path it belongs in and the post-install restart steps:
pensum mcp install --client claude-desktoppensum mcp install --client claude-codepensum mcp install --client cursorAdd --read-only to print a read-only bundle (no writes will be possible even if the agent asks). Add --vault=<name> to pin to a specific vault from your multi-vault config.
The bundle includes the file path for your client’s config, the JSON block to paste under mcpServers, and notes on .pensumignore + the audit log so you know what guard rails are in place from the first run.
Manual config
Section titled “Manual config”If you want to wire things up yourself, run Pensum: Print MCP config in the command palette, or pensum mcp config. Either gives you a JSON snippet ready to drop into your MCP client:
{ "mcpServers": { "pensum": { "command": "pensum", "args": ["mcp-serve"], "env": { "PENSUM_VAULT": "/absolute/path/to/your/vault" } } }}The PENSUM_VAULT env var points the server at the vault you want it to operate on. Use an absolute path.
To start the server in read-only mode, add PENSUM_MCP_MODE=read-only to the env block. The server will accept every read tool but refuse any write tool with a clear error — useful for sessions where you want context-building without any chance of changes.
Drop the snippet into your client
Section titled “Drop the snippet into your client”| Client | Where the config lives |
|---|---|
| Claude Desktop | ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows) — under the mcpServers key |
| Claude Code | ~/.config/claude-code/mcp_servers.json or via the claude mcp add command |
| Cursor | Settings → Features → Model Context Protocol → Add new |
| Other clients | Wherever your client expects MCP server definitions |
Restart the client. The Pensum tools become available to the model.
Multi-vault setup
Section titled “Multi-vault setup”If you have multiple vaults configured in ~/.config/pensum/config.toml (see CLI multi-vault), register one MCP server per vault:
{ "mcpServers": { "pensum-personal": { "command": "pensum", "args": ["mcp-serve", "--vault=personal"] }, "pensum-work": { "command": "pensum", "args": ["mcp-serve", "--vault=work"] } }}This is the recommended pattern: one server per vault, each with its own tool namespace. Agents pick which to call based on context.
Tool naming
Section titled “Tool naming”Pensum’s tools use the form group.action — e.g. plan.today, capture.task, vault.read. The seven groups:
| Group | Purpose |
|---|---|
system.* | Discovery, capabilities, audit, ignore patterns |
plan.* | Task reads, writes, structured queries, the weekly-review digest |
capture.* | Lightweight task and stub creation aimed at agent-driven capture |
curate.* | Wiki entries waiting to be developed |
project.* | Project listing, dashboards, create, frontmatter update |
meet.* | Meeting note list / read / create |
vault.* | Generic file CRUD (read, write, delete, move) + search + ICS export |
Every response is wrapped in a shared envelope with optional workflow.suggested_next hints on success and recovery_hints on error, so agents can chain operations without you teaching them the next step.
Discovery tools
Section titled “Discovery tools”| Tool | Purpose | Args |
|---|---|---|
system.summary | Vault path, entity counts, last scan time | none |
system.capabilities | Server version, permission mode, tool groups, active ignore patterns | none |
system.suggest_next | Context-aware suggestions based on overdue / inbox / stub backlog | none |
system.audit | Tail of the MCP audit log (write operations only). Default 50, max 500. | count?: number |
system.ignore_patterns | The active .pensumignore patterns (defaults + user) | none |
system.suggest_next is the right first call when an agent isn’t sure what to do — it returns a tool list ranked by what currently needs attention.
Plan tools
Section titled “Plan tools”The bulk of Pensum’s task model. Reads are unrestricted; writes are subject to read-only mode.
| Tool | What it does | Args |
|---|---|---|
plan.today | Due / scheduled today + overdue | none |
plan.inbox | Tasks in configured inbox files (default Tasks/Inbox.md) | inbox_paths? |
plan.by_project | Open tasks for one project | project |
plan.overdue | Past-due open tasks | none |
plan.week | Next 7 days | none |
plan.search | Substring search across descriptions; paginated | query, limit?, offset? |
plan.get | Get a task by ULID | id |
plan.waiting | Tasks in waiting status ([w]). Excluded from the other planning views by design. | none |
plan.weekly_review | The five GTD review zones in one digest: inbox, overdue, waiting, stalled projects, wins since the last review | inbox_paths?, since? |
plan.query | Structured query (status, priority, projects, tags, dates, sort, group, limit) | many optional |
plan.search returns { total, offset, limit, count, next_offset, tasks } so agents can walk the result set without re-running the search. next_offset is null on the last page.
Writes
Section titled “Writes”| Tool | What it does | Args |
|---|---|---|
plan.add | Add a task; defaults to agent-suggested-pending provenance so the user reviews it | description, optional file, due_date, scheduled_date, priority, tags, provenance |
plan.complete | Mark a task complete by ULID; recurring tasks auto-create the next occurrence | id, done_date? |
plan.edit | Patch any subset of fields | id, optional description, due_date, scheduled_date, priority, tags |
plan.reschedule | Convenience for date-only changes | id, due_date?, scheduled_date? |
plan.delete | Delete a task line. No undo. | id |
plan.defer | Set the 🛫 start date so the task vanishes from planning until then; pass null to clear | id, date |
plan.add_to_today | Toggle a scheduled date of today | id |
plan.set_status | Change checkbox status (" " / "/" / "w" / "-" / "x"). Prefer plan.complete for x. | id, status |
plan.weekly_review
Section titled “plan.weekly_review”Useful for agent-driven Monday-morning rituals. Returns:
{ "generated_at": "2026-05-17", "inbox": { "count": 4, "tasks": [...] }, "overdue": { "count": 2, "tasks": [...] }, "waiting": { "count": 1, "tasks": [...] }, "stalled_projects": { "count": 1, "projects": [{ "project": "Launch", "open_count": 3, "days_since_last_activity": 21 }] }, "wins_since": { "since": "2026-05-10", "count": 12, "tasks": [...] }}“Stalled” means a project has open work but the last task was completed ≥ 14 days ago (or never). Wins default to a 7-day window; override with since.
Capture tools
Section titled “Capture tools”| Tool | What it does | Args |
|---|---|---|
capture.task | High-level capture into Tasks/Inbox.md. Always lands as agent-suggested-pending. | description, optional project, due_date, priority, tags |
capture.stub | Create a wiki stub in Wiki/. Curate view picks it up. | title, optional tags, source |
capture.task is the right tool when an agent wants to put something on your plate without committing the form of the task. The user accepts, edits, or discards in the Agent Captures view.
Curate tools
Section titled “Curate tools”| Tool | What it does | Args |
|---|---|---|
curate.stubs | Wiki entries, optionally filtered by status (stub / drafted / developed / archived) | status?, limit? |
Project tools
Section titled “Project tools”| Tool | What it does | Args |
|---|---|---|
project.list | All project files in the vault | none |
project.dashboard | Open + overdue + recent completions for one project | project |
project.create | Create a project file with Pensum frontmatter at <folder>/<name>.md | name, optional projects_folder, status, priority, target_date, tags |
project.update | Patch a project file’s frontmatter (status / priority / target_date / tags). Body untouched. | file_path, optional status, priority, target_date, tags |
Meeting tools
Section titled “Meeting tools”| Tool | What it does | Args |
|---|---|---|
meet.list | Meeting files, filterable by date range / project | optional after, before, project, limit |
meet.read | Parsed frontmatter + full body for one meeting | file_path |
meet.create | Create a meeting note with frontmatter scaffold (Agenda / Notes / Actions sections) | title, optional meetings_folder, date, project, attendees, tags |
Vault tools
Section titled “Vault tools”Generic file operations. All vault.* calls are guarded by .pensumignore — if a path matches an ignore pattern the call is refused with an IGNORED error before anything is read or written.
| Tool | What it does | Args |
|---|---|---|
vault.read | Read any file as a string | file_path |
vault.write | Write a file (overwrite by default, creates parent dirs) | file_path, content, optional create_only |
vault.delete | Delete a file. Dry-run by default — pass confirm: true to actually delete. | file_path, confirm? |
vault.move | Rename / move a file | from, to |
vault.search | Full-text search across tasks / projects / meetings / wiki; paginated; optional fragment snippets | query, optional types, limit, offset, fragments, fragment_count, fragment_window |
vault.export_ics | Generate an iCalendar .ics string from tasks; default filter = open + in-progress + waiting + completed in last 30d | optional status, calendar_name |
vault.search with fragments: true returns up to fragment_count snippets of context around each match per file, so an agent can decide whether a file is worth a full vault.read without paying for the full content.
vault.export_ics returns the raw ICS string in data.ics. The matching plugin/CLI command writes it to Pensum/Exports/tasks.ics — for the MCP version, the agent decides where to put the result.
Pagination
Section titled “Pagination”Two tools paginate today: plan.search and vault.search. Both follow the same shape:
{ "total": 142, "offset": 0, "limit": 20, "count": 20, "next_offset": 20, "tasks": [...]}next_offset is null on the last page. To walk a result set, keep re-calling with the previous next_offset.
Provenance
Section titled “Provenance”Every entity returned by an MCP tool includes a provenance field. Possible values:
user-authoredai-suggested-acceptedai-suggested-editedagent-suggested-pendingagent-suggested-acceptedagent-suggested-edited
See provenance for the full meaning of each.
plan.add defaults to agent-suggested-pending, which lands the task in the Agent Captures view for review. To capture directly to active, pass provenance: "user-authored" — usually inadvisable for agent-initiated content.
Permission modes
Section titled “Permission modes”Two server modes, set via the PENSUM_MCP_MODE env var:
| Mode | Set with | Behavior |
|---|---|---|
allow (default) | unset, or PENSUM_MCP_MODE=allow | All tools available. Writes still subject to .pensumignore. |
read-only | PENSUM_MCP_MODE=read-only | Write tools refuse with READ_ONLY and a recovery hint. Reads work normally. |
system.capabilities returns the active mode under permission_mode, so agents can check before they try.
For a stronger guarantee, run a separate stdio server entry (e.g. pensum-readonly) with PENSUM_MCP_MODE=read-only in its env block — the mode is locked at process start.
.pensumignore
Section titled “.pensumignore”A .pensumignore file at the vault root lists paths the MCP server must never read or write. Syntax is a subset of .gitignore:
#comments and blank lines*,**,?wildcards- Trailing
/matches directories only - Leading
/anchors to the vault root - Negation (
!pattern) is not supported — the file is deny-only on purpose, so the security model stays trivially auditable
The server always merges these defaults on top of your file:
.pensum/secrets/****/.git/****/.obsidian/workspace*Use system.ignore_patterns to see the merged list. Any vault.* call against a matched path is refused with an IGNORED error before the call reaches the filesystem.
Audit log
Section titled “Audit log”Every write tool the server exposes appends a one-line JSON entry to .pensum/mcp-audit.jsonl. Read tools are skipped to keep the log small — they’re the bulk of traffic and they don’t change state.
A typical entry:
{"ts":"2026-05-17T15:22:11.043Z","tool":"plan.add","status":"ok","args_summary":{"description":"draft Q3 plan","file":"Tasks/Inbox.md"}}status is one of ok / error / denied. denied covers read-only refusals and .pensumignore matches. args_summary is a trimmed version of the inputs — long strings are truncated, arrays and objects are placeheld so the log stays grep-friendly.
Tail the log from inside an agent session with system.audit (default last 50, max 500). Or just tail -f .pensum/mcp-audit.jsonl from a terminal.
Transport
Section titled “Transport”The MCP server runs over stdio by default. The client launches the server as a subprocess and communicates via stdin/stdout. Every snippet on this page assumes stdio; it’s what every MCP client expects and has no auth surface.
An HTTP transport is also available (localhost-only, token-authenticated) for cases where stdio isn’t workable — e.g. a long-running agent process talking to the same server across multiple sessions, or a containerised agent that can’t spawn the binary itself. Configure under Settings → Agents → Transport.
For v1.0, stdio is recommended. HTTP is there for advanced cases.
The Agent Captures review queue
Section titled “The Agent Captures review queue”When an agent captures a task with agent-suggested-pending provenance (the default for capture.task and plan.add), the task lands in the Agent Captures view rather than going directly into your active task graph.
Open the view: Pensum: Open agent captures. For each pending capture:
- Accept — task moves into active, provenance flips to
agent-suggested-accepted - Edit — open the edit modal, modify, then accept (provenance:
agent-suggested-edited) - Discard — drop the suggestion
This is the safety mechanism for agent-originated content. The expectation: agents capture freely, you triage on your schedule.
To turn off the review queue (allow agent captures to land directly): Settings → Agents → Agent capture review → off. Only do this if you trust your agents to write meaningful tasks; otherwise the review step is valuable.
What agents can do, what they can’t
Section titled “What agents can do, what they can’t”In allow mode with no .pensumignore overrides, agents can:
- Read any file in the vault (
vault.read, allplan.*/project.*/meet.*/curate.*reads) - Add tasks (defaulting to pending review)
- Mark tasks complete, edit them, reschedule, defer, change status, delete
- Create projects, meeting notes, wiki stubs
- Patch project frontmatter
- Write or move arbitrary files
- Delete files only with
confirm: true(default is dry-run)
Agents cannot:
- Touch paths matched by
.pensumignore(default includes.pensum/secrets/**,.git/**, Obsidian workspace state) - Bypass read-only mode once it’s been set in the env
If you want stricter limits, run in read-only mode for sensitive sessions, or add to .pensumignore.
When the server isn’t running
Section titled “When the server isn’t running”If MCP is off (Settings → Agents → Enable MCP server → off), the binary still runs but reports unavailability for tool calls. If the Pensum plugin isn’t loaded, the binary can still read the vault directly (it shares the engine with the CLI). For most users, leave MCP on.
Logging
Section titled “Logging”Server-side logs go to stderr (visible in your MCP client’s logs). For most users this is invisible; if you’re debugging an agent that doesn’t seem to be getting the right responses, check your client’s MCP log.
Versions
Section titled “Versions”The MCP server ships with the Pensum CLI. Update via npm install -g @pensum/cli@latest (or Homebrew if installed that way). The plugin’s MCP integration is decoupled — you can update the CLI without updating the plugin.
system.capabilities returns the running version. Agents can check it if they care about version-specific behavior.