@cpenned/mcp 0.8.4 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/README.md +34 -7
  2. package/dist/client.js +40 -6
  3. package/dist/client.js.map +1 -1
  4. package/dist/config.js +1 -0
  5. package/dist/config.js.map +1 -1
  6. package/dist/server.js +16 -0
  7. package/dist/server.js.map +1 -1
  8. package/dist/tools/api.js +41 -0
  9. package/dist/tools/api.js.map +1 -0
  10. package/dist/tools/attachments.js +43 -0
  11. package/dist/tools/attachments.js.map +1 -0
  12. package/dist/tools/books.js +24 -18
  13. package/dist/tools/books.js.map +1 -1
  14. package/dist/tools/comments.js +63 -0
  15. package/dist/tools/comments.js.map +1 -0
  16. package/dist/tools/gardens.js +8 -7
  17. package/dist/tools/gardens.js.map +1 -1
  18. package/dist/tools/habits.js +26 -18
  19. package/dist/tools/habits.js.map +1 -1
  20. package/dist/tools/index.js +2 -34
  21. package/dist/tools/index.js.map +1 -1
  22. package/dist/tools/keys.js +23 -7
  23. package/dist/tools/keys.js.map +1 -1
  24. package/dist/tools/lists.js +6 -5
  25. package/dist/tools/lists.js.map +1 -1
  26. package/dist/tools/people.js +17 -15
  27. package/dist/tools/people.js.map +1 -1
  28. package/dist/tools/profile.js +18 -6
  29. package/dist/tools/profile.js.map +1 -1
  30. package/dist/tools/projects.js +14 -8
  31. package/dist/tools/projects.js.map +1 -1
  32. package/dist/tools/reading.js +11 -10
  33. package/dist/tools/reading.js.map +1 -1
  34. package/dist/tools/render.js +11 -2
  35. package/dist/tools/render.js.map +1 -1
  36. package/dist/tools/schemas.js +6 -1
  37. package/dist/tools/schemas.js.map +1 -1
  38. package/dist/tools/shares.js +4 -3
  39. package/dist/tools/shares.js.map +1 -1
  40. package/dist/tools/strava.js +13 -9
  41. package/dist/tools/strava.js.map +1 -1
  42. package/dist/tools/tags.js +8 -7
  43. package/dist/tools/tags.js.map +1 -1
  44. package/dist/tools/tasks.js +17 -11
  45. package/dist/tools/tasks.js.map +1 -1
  46. package/dist/tools/ui.js +34 -13
  47. package/dist/tools/ui.js.map +1 -1
  48. package/dist/tools/views.js +12 -10
  49. package/dist/tools/views.js.map +1 -1
  50. package/package.json +1 -1
  51. package/skills/open-brain-mcp/SKILL.md +61 -18
@@ -1,20 +1,22 @@
1
1
  // Opinionated read tools: computed views and the review system. Views are
2
- // timezone-aware (tz overrides the vault default); review tools cover the due
2
+ // timezone-aware (tz overrides the host timezone the server sends); review tools cover the due
3
3
  // queue, garden deep-review, forcing a garden into review, and marking items
4
4
  // reviewed (which restarts their clock).
5
5
  import { z } from "zod";
6
+ import { apiPath } from "../client.js";
6
7
  import { runTool } from "../result.js";
8
+ import { idField } from "./schemas.js";
7
9
  const getViewSchema = z.object({
8
10
  view: z.enum(["today", "upcoming", "overdue"]),
9
11
  tz: z
10
12
  .string()
11
13
  .optional()
12
- .describe("IANA timezone (e.g. America/New_York); defaults to the vault timezone"),
14
+ .describe("IANA timezone (e.g. America/New_York); defaults to the timezone of the machine running this MCP server"),
13
15
  limit: z.number().int().positive().optional(),
14
16
  cursor: z.string().optional(),
15
17
  });
16
18
  export function getView(client, args) {
17
- return client.get(`/v1/views/${args.view}`, {
19
+ return client.get(apiPath `/v1/views/${args.view}`, {
18
20
  tz: args.tz,
19
21
  limit: args.limit,
20
22
  cursor: args.cursor,
@@ -27,20 +29,20 @@ const getReviewsSchema = z.object({
27
29
  export function getReviews(client, args) {
28
30
  return client.get("/v1/reviews", { gardenId: args.gardenId, limit: args.limit });
29
31
  }
30
- const gardenIdSchema = z.object({ gardenId: z.string() });
32
+ const gardenIdSchema = z.object({ gardenId: idField });
31
33
  export function reviewGarden(client, args) {
32
- return client.get(`/v1/gardens/${args.gardenId}/review`);
34
+ return client.get(apiPath `/v1/gardens/${args.gardenId}/review`);
33
35
  }
34
36
  export function requestGardenReview(client, args) {
35
- return client.post(`/v1/gardens/${args.gardenId}/request-review`);
37
+ return client.post(apiPath `/v1/gardens/${args.gardenId}/request-review`);
36
38
  }
37
- const markTaskReviewedSchema = z.object({ taskId: z.string() });
39
+ const markTaskReviewedSchema = z.object({ taskId: idField });
38
40
  export function markTaskReviewed(client, args) {
39
- return client.post(`/v1/tasks/${args.taskId}/reviewed`);
41
+ return client.post(apiPath `/v1/tasks/${args.taskId}/reviewed`);
40
42
  }
41
- const markProjectReviewedSchema = z.object({ projectId: z.string() });
43
+ const markProjectReviewedSchema = z.object({ projectId: idField });
42
44
  export function markProjectReviewed(client, args) {
43
- return client.post(`/v1/projects/${args.projectId}/reviewed`);
45
+ return client.post(apiPath `/v1/projects/${args.projectId}/reviewed`);
44
46
  }
45
47
  export function registerViewTools(server, client) {
46
48
  server.registerTool("get_view", {
@@ -1 +1 @@
1
- {"version":3,"file":"views.js","sourceRoot":"","sources":["../../src/tools/views.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"views.js","sourceRoot":"","sources":["../../src/tools/views.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cpenned/mcp",
3
- "version": "0.8.4",
3
+ "version": "0.9.0",
4
4
  "description": "MCP server for Open Brain - a thin adapter over the /v1 HTTP API.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -122,7 +122,9 @@ pre-guessing constraints.
122
122
  `assignee: "me"|"unassigned"|<userId>` filters the home vault by assignee),
123
123
  `get_task`, `update_task` (drives status), `delete_task`, batch
124
124
  `create_tasks`/`update_tasks`, `add_task_tags`/`remove_task_tags`.
125
- `create_task`/`update_task` accept `eventId` to link a synced calendar event
125
+ `create_task`/`create_tasks` accept an initial `status` (default `todo`;
126
+ e.g. `backlog` to park it). `create_task`/`update_task` accept `eventId` to
127
+ link a synced calendar event
126
128
  (read-only mirror); `eventId: null` on update unlinks it.
127
129
  `create_task`/`create_tasks`/`update_task`/`update_tasks` also accept
128
130
  `assigneeUserId` (a user id, `"me"`, or `null` to unassign) - only
@@ -132,6 +134,7 @@ pre-guessing constraints.
132
134
  `sharedFrom` marker).
133
135
  - **Projects**: `create_project`, `list_projects`, `get_project`,
134
136
  `update_project`, `delete_project`, `create_projects`/`update_projects`.
137
+ `create_project(s)` accept an initial `status` (default `todo`).
135
138
  Project reads carry `taskCounts {open, done}` (canceled in neither) and
136
139
  `nextTaskId` (first open task by manual order; `get_task` it to see what's
137
140
  next), so progress needs no extra task listing.
@@ -145,8 +148,8 @@ pre-guessing constraints.
145
148
  (null clears a field, e.g. `contactInterval: null`; `archived: false`
146
149
  restores), `delete_person` (archives, links kept), `mark_contacted`
147
150
  (optional `at` backdates the touch), `add_person_links`/`remove_person_links`
148
- (`{id, taskIds?, projectIds?, gardenIds?, readingListItemIds?, bookIds?,
149
- people?}` — `people` is `[{id, label?}]` for person-to-person connections;
151
+ (`{id, taskIds?, projectIds?, gardenIds?, readingListItemIds?, habitIds?,
152
+ bookIds?, people?}`: `people` is `[{id, label?}]` for person-to-person connections;
150
153
  symmetric, shown on both people, re-link with a new label to change it or
151
154
  `label: null` to clear it; unlink takes the same shape, ids only for
152
155
  `people`). `create_task(s)` accept `personIds` inline; `list_tasks` filters
@@ -159,9 +162,10 @@ pre-guessing constraints.
159
162
  `archived`/`deleted` toggle independently of status), `delete_reading_item`
160
163
  (true soft delete, hidden everywhere; restore with `update_reading_item
161
164
  {deleted: false}`), `add_reading_tags`/`remove_reading_tags`.
162
- - **Habits**: `create_habit`, `list_habits`, `get_habit`, `update_habit`,
165
+ - **Habits**: `create_habit`, `list_habits` (pages; pass `cursor`), `get_habit`, `update_habit`,
163
166
  `archive_habit`/`unarchive_habit`, `complete_habit` (`quantity?`, `durationMinutes?`,
164
- `force?` skips time window), `remove_habit_completion` (by `completionId` or `day`),
167
+ `force?` skips time window), `remove_habit_completion` (by `completionId` or `day`;
168
+ a `day` lookup reaches back through the newest 200 check-ins),
165
169
  `reorder_habits`, `add_habit_tags`/`remove_habit_tags`.
166
170
  Schedules: `{kind: daily}`, `{kind: weekly, times, byWeekday?}`, `{kind: monthly, times}`,
167
171
  `{kind: every_n_days, interval}`. Optional `graceDays` (daily streak tolerance),
@@ -191,20 +195,37 @@ pre-guessing constraints.
191
195
  `delete_book` (soft delete, cover blob kept, restore with `{deleted:
192
196
  false}`), `add_book_tags`/`remove_book_tags`, `log_book_session` (`day?`,
193
197
  `pagesRead?`, `minutes?`, `endPage?`, `notes?`; retroactive OK, multiple
194
- sessions per day), `remove_book_session` (never retroactively un-satisfies
198
+ sessions per day; `pagesRead` alone continues from the current page and
199
+ moves it forward), `remove_book_session` (never retroactively un-satisfies
195
200
  a habit day), `refresh_book_metadata` (`overwrite?` to replace non-empty
196
201
  fields). Person links via `add_person_links`/`remove_person_links` with
197
202
  `bookIds`.
198
203
  - **Saved lists** (named, reusable task-list filters): `list_saved_lists`,
199
204
  `create_saved_list`, `update_saved_list`, `delete_saved_list`.
200
- - **Views & reviews**: `get_view` (today/upcoming/overdue, timezone-aware),
205
+ - **Comments**: `list_task_comments {taskId}` (oldest first, max 200, plus
206
+ `participants`: the people in the task's garden who can be @mentioned,
207
+ `{userId, displayName, avatarUrl, role}`), `add_task_comment {taskId, body,
208
+ mentions?}`, `edit_task_comment {taskId, commentId, body, mentions?}`
209
+ (author only), `delete_task_comment {taskId, commentId}` (author or garden
210
+ owner). Each comment has `body` (Markdown with mention tokens), `text`
211
+ (tokens rendered as `@Name`), `mentions` (user ids), `canEdit`,
212
+ `canDelete`, and `editedAt` once edited. Tasks carry `commentCount`
213
+ (omitted when 0). Needs `tasks:read` / `tasks:write`.
214
+ - **Attachments** (read-only; upload is web/app-only): `list_task_attachments
215
+ {taskId}`, `get_attachment {id}` (metadata), `get_attachment_url {id,
216
+ variant?}` (short-lived signed URL; `variant` is `served` (default),
217
+ `original`, or `thumbnail`). Needs `tasks:read`.
218
+ - **Views & reviews**: `get_view` (today/upcoming/overdue, timezone-aware;
219
+ without `tz` it uses the timezone of the machine running the MCP server),
201
220
  `get_reviews` (due queue), `review_garden` (deep review),
202
221
  `request_garden_review`, `mark_task_reviewed`, `mark_project_reviewed`.
203
222
  - **AI**: `find_tasks` (hybrid keyword + semantic search), `ai_triage`
204
223
  (brain dump → garden-assigned tasks, recurring habits, reading-list
205
224
  saves/edits/cancels, and books - see Workflows).
206
- - **UI (read-only)**: `ui_view`, `ui_review_queue`, `ui_garden_board` return
207
- `ui://` HTML resources.
225
+ - **UI (read-only)**: `ui_view`, `ui_review_queue`, `ui_garden_board`,
226
+ `ui_habits` return `ui://` HTML resources. `ui_view` and `ui_habits` take a
227
+ `cursor`; when a page is cut short the result adds a text note with the
228
+ cursor for the next page.
208
229
  - **Settings**: `get_settings`, `update_settings` (the default review period
209
230
  applied to new tasks/projects; `defaultReviewInterval: null` disables it;
210
231
  `defaultTimezone`, an IANA string, is also settable - it's what date-only
@@ -216,11 +237,15 @@ pre-guessing constraints.
216
237
  owner, participants - empty unless the key has `includeGrants`),
217
238
  `list_shared_tasks {shareId, status?, includeCanceled?}` (that garden's
218
239
  tasks, capped at 500).
219
- - **Profile**: `get_profile` (user id, display name, avatar URL),
220
- `update_profile {displayName}` (1-60 chars; avatar upload is web-only).
240
+ - **Profile**: `get_profile` (user id, display name, avatar URL,
241
+ `notifications: {emailOnMention, emailOnAssign}`), `update_profile
242
+ {displayName?, notifications?: {emailOnMention?, emailOnAssign?}}` (pass at
243
+ least one; display name 1-60 chars; avatar upload is web-only).
221
244
  - **Keys**: `create_key` (optional `includeGrants` to let the new key see
222
245
  gardens shared with its owner - only settable if the calling key itself
223
- has it), `list_keys`, `rotate_key`, `revoke_key`.
246
+ has it), `list_keys`, `rotate_key`, `revoke_key`. `rotate_key` and
247
+ `revoke_key` refuse the key this MCP server itself authenticates with (it
248
+ would lock the server out); rotate or revoke that one from the CLI or web app.
224
249
 
225
250
  ## Workflows
226
251
 
@@ -235,16 +260,20 @@ pre-guessing constraints.
235
260
  archives it, reversibly, independent of status) — it matches existing
236
261
  items by exact title, so an unmatched or ambiguous reference comes back as a
237
262
  reading-list clarification rather than a silent no-op or a task.
238
- - **Plan today** → `get_view today`. Pass the user's IANA `tz` if known so the
239
- day boundary is correct.
263
+ - **Plan today** → `get_view today`. It defaults to this machine's timezone;
264
+ pass the user's IANA `tz` if they are somewhere else so the day boundary is
265
+ correct.
240
266
  - **Add a task** → need a garden: `list_gardens` first, then `create_task` with
241
267
  `gardenId`. Set `deadline` for "today"/hard dates — that's what lands it in
242
268
  the Today view. `create_task`/`create_tasks` accept `tagIds`, `recurrence`,
243
269
  `deferDate`, `deadline`, and `habitId` (completing the task checks in the
244
270
  habit) **inline** — set them at creation, never create-then-patch.
245
271
  `deferDate`/`deadline` are calendar days `"YYYY-MM-DD"` (no timezone); inputs
246
- also accept relative tokens (`"today"`, `"tomorrow"`, `"+3d"`), so no
247
- client-side date math. Returned values are always `"YYYY-MM-DD"`.
272
+ also accept relative tokens (`"today"`, `"tomorrow"`, `"+3d"`, `"friday"`,
273
+ `"next week"`; a weekday is its next occurrence after today), so no
274
+ client-side date math. The local (stdio) server sends the machine's
275
+ timezone, so relative tokens resolve in the user's zone; the hosted server
276
+ falls back to the vault timezone. Returned values are always `"YYYY-MM-DD"`.
248
277
  - **Recurring task** → set `recurrence` at creation:
249
278
  `{mode, frequency, interval, byWeekday?}`. `mode`: `on_schedule` (next = prior
250
279
  due + interval; self-heals missed days) or `on_completion` (next = completed +
@@ -281,6 +310,19 @@ pre-guessing constraints.
281
310
  pagesRead}` as pages are read (auto-promotes `want_to_read` to `reading`)
282
311
  → `update_book {id, status: "read"}` when finished (stamps `finishedDay`
283
312
  and force-completes a linked page-goal habit for that day).
313
+ - **Comment on a task / loop someone in** → `list_task_comments {taskId}` to
314
+ read the thread and see who can be mentioned, then `add_task_comment {taskId,
315
+ body, mentions: ["Sam"]}`. `mentions` takes participant user ids or display
316
+ names (case-insensitive, leading `@` ok): a plain `@Sam` already in the
317
+ body becomes a mention token, otherwise the token is prepended; an unknown
318
+ name is a 400, so check `participants` first. You can also write the token
319
+ inline: `@[Display Name](userId)`; a token for someone outside the task's
320
+ garden becomes plain `@Name` text. Anyone who can see the task can comment,
321
+ including watch-only guests of a shared garden (the key needs
322
+ `includeGrants` for shared tasks). Mentioned people, and people newly
323
+ assigned a task, get an email from the server (never the caller), unless
324
+ they turned it off via `update_profile {notifications: {emailOnMention:
325
+ false}}` (or `emailOnAssign`).
284
326
  - **Find something** → `find_tasks` (handles fuzzy/semantic queries; narrow to a
285
327
  due window with `deadlineBefore` / `deadlineAfter`, inclusive day bounds,
286
328
  e.g. `"2026-07-10"` or `"+1w"`).
@@ -298,8 +340,9 @@ pre-guessing constraints.
298
340
  `people:read|write`, settings tools `settings:read|write`, reading list tools
299
341
  `reading:read|write`, Strava tools `strava:read|write`, book tools
300
342
  `books:read|write`, calendar tools `calendar:read|write`), review tools
301
- `reviews:*`, `find_tasks`/`ai_triage` need
302
- `ai:invoke`, the `*_key` tools need `keys:manage`. A missing scope returns a
343
+ `reviews:*`, `find_tasks` needs `ai:invoke` + `tasks:read`, `ai_triage` needs
344
+ `ai:invoke` + `tasks:write`, `reading:write`, `habits:write`, and
345
+ `books:write` (it can create any of those), the `*_key` tools need `keys:manage`. A missing scope returns a
303
346
  403 tool error. Keys minted before a feature shipped won't carry its scope
304
347
  unless they hold `*`. There is no upload tool here (cover uploads are a
305
348
  web-only flow, `POST /v1/uploads` before setting `coverStorageId`), but a