Serve time tracks, habits, the journal and calendar periods over MCP by ninyawee · Pull Request #538 · basecamp/hey-cli · GitHub
Skip to content

Serve time tracks, habits, the journal and calendar periods over MCP - #538

Open
ninyawee wants to merge 1 commit into
basecamp:mainfrom
ninyawee:mcp-calendar-domains
Open

ninyawee wants to merge 1 commit into
basecamp:mainfrom
ninyawee:mcp-calendar-domains

Conversation

@ninyawee

@ninyawee ninyawee commented Oct 3, 2026 •

Copy link
Copy Markdown

Part of #537.

hey mcp served calendars and todos, but none of the other calendar work the CLI already does. An agent connected over MCP could not start or stop a time track, tick off a habit, or write the day's journal entry, because those tags were left unmapped (catalog_test.go pinned them that way, as #357 intended: "growing the surface is a one-line change").

hey-sdk models all four groups as plain JSON operations, so the generic dispatcher drives them unchanged. This PR maps them in DomainSpecs:

Tool Tag Actions
hey_timetracks (new) Calendar Time Tracks start_time_track, get_ongoing_time_track, update_time_track (stop by sending ends_at, optionally filing under category_title), create_time_track, list_time_tracks, delete_time_track, list_time_track_categories
hey_habits (new) Calendar Habits create_habit, update_habit, stop_habit, resume_habit, delete_habit, complete_habit, uncomplete_habit
hey_journal (new) Calendar Journal list_journal_entries, get_journal_entry, update_journal_entry
hey_calendar (extended) + Calendar Periods get_calendar_day, get_calendar_week, get_calendar_year, list_calendar_days, list_calendar_weeks: the only reads that expand repeating events and carry habits

The journal blurb warns that a write replaces the whole entry and empty content deletes it, since the action name doesn't say so.

Calendar Events stays unmapped. The model has only its two deletes. Create and update are hey-sdk's "phase-2: calendar events" excluded routes, which the CLI reaches through hand-written form posts the catalog can't see. docs/agents.md now says so and points at hey event add / edit. Event writes (#537's second ask) need hey-sdk to model those routes first; basecamp/hey-sdk#230's open-world trait seems relevant there, since --invite sends mail.

Changes

  • internal/mcpserver/domains.go: three new domains, plus Calendar Periods in calendar
  • catalog_test.go, server_test.go, cmd/mcp_test.go: 10 tools; unmapped list now Attachments, Bulk Reply, Calendar Events, Clips, …
  • hey mcp --help and docs/agents.md: name the new domains and the event gap

Testing

  • make check is green: fmt, vet, golangci-lint (0 issues), unit tests, surface and lockstep checks.
  • Live, against a real account, through the built hey mcp over stdio:
    • Reads succeeded: list_time_tracks (paginated, next_page returned), list_time_track_categories, get_ongoing_time_track (404 when nothing is running, as documented), get_calendar_day, get_calendar_week, list_calendar_weeks, get_calendar_year, list_journal_entries, get_journal_entry.
    • Writes succeeded: create_habit → complete_habit → uncomplete_habit → delete_habit on a throwaway habit, confirmed gone from the week afterwards.
    • Not exercised live: time-track and journal writes, which would have touched real data.

🤖 Generated with Claude Code


Summary by cubic

Adds MCP tools for the calendar work hey mcp was missing: time tracks, habits, journal, and calendar periods. An agent can now start and stop time tracks, tick off habits, and read or write journal entries over MCP.

  • New gateway tools hey_timetracks, hey_habits, and hey_journal, plus Calendar Periods (day, week, year) under hey_calendar — the only reads that expand repeating events and carry habits.
  • A journal write replaces the whole entry, so read it first; empty content deletes the entry.
  • Calendar Events stays unmapped because the SDK model only covers its deletes; docs/agents.md now directs to hey event add/edit.

Part of #537.

Written for commit 6812e95. Summary will update on new commits.

Review in cubic

hey mcp served calendars and todos, but none of the other calendar work
the CLI already does: an agent connected over MCP could not start or stop
a time track, tick off a habit, or write the day's journal entry. Those
tags were left unmapped, and catalog_test pinned them that way.

hey-sdk models all four groups as plain JSON operations, so the generic
dispatcher drives them unchanged. This maps them in DomainSpecs:

- hey_timetracks: Calendar Time Tracks (start, ongoing, stop via
  update_time_track's ends_at, create, list, edit, delete, categories)
- hey_habits: Calendar Habits (create, update, stop, resume, delete,
  complete and uncomplete a day)
- hey_journal: Calendar Journal (list, read and write a day's entry)
- hey_calendar gains Calendar Periods: a day, week or year as HEY draws
  it, the only read that expands repeating events and carries habits

Calendar Events stays unmapped. The model has only its two deletes;
create and update are hey-sdk's "phase-2: calendar events" excluded
routes, reached by the CLI through hand-written form posts the catalog
cannot see. docs/agents.md says so and points at hey event add/edit.

Refs basecamp#537

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ninyawee
ninyawee requested a review from a team as a code owner October 3, 2026 00:14
Copilot AI balanced review requested due to automatic review settings October 3, 2026 00:14

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 6 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="internal/mcpserver/domains.go">

<violation number="1" location="internal/mcpserver/domains.go:43">
P2: This implies year reads also include expanded occurrences and habits, but `GetCalendarYear` returns only the year grid and spanning events. Scope the occurrence and habit details to day/week reads, and describe the year response as a grid.</violation>

<violation number="2" location="internal/mcpserver/domains.go:48">
P3: The timetracks blurb promises "list, edit or delete completed tracks and categories", but the API model offers no create/update/delete actions for categories — the only category operation is `ListTimeTrackCategories` (`GET /calendar/time_tracks/categories.json`). An agent reading the tool description could attempt a category delete/edit action that does not exist. Reword so edit/delete applies only to tracks.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Tags: []string{"Calendars"},
Blurb: "HEY Calendars: list calendars, read their recordings (todos and events — the todo read path), and toggle calendar visibility.",
Tags: []string{"Calendars", "Calendar Periods"},
Blurb: "HEY Calendars: list calendars, read their recordings (todos and events — the todo read path), toggle calendar visibility, and read a day, week or year as HEY draws it (repeating events expanded into occurrences, plus habits).",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: This implies year reads also include expanded occurrences and habits, but GetCalendarYear returns only the year grid and spanning events. Scope the occurrence and habit details to day/week reads, and describe the year response as a grid.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At internal/mcpserver/domains.go, line 43:

<comment>This implies year reads also include expanded occurrences and habits, but `GetCalendarYear` returns only the year grid and spanning events. Scope the occurrence and habit details to day/week reads, and describe the year response as a grid.</comment>

<file context>
@@ -40,8 +39,23 @@ var DomainSpecs = []catalog.DomainSpec{
-		Tags:  []string{"Calendars"},
-		Blurb: "HEY Calendars: list calendars, read their recordings (todos and events — the todo read path), and toggle calendar visibility.",
+		Tags:  []string{"Calendars", "Calendar Periods"},
+		Blurb: "HEY Calendars: list calendars, read their recordings (todos and events — the todo read path), toggle calendar visibility, and read a day, week or year as HEY draws it (repeating events expanded into occurrences, plus habits).",
+	},
+	{
</file context>
Suggested change
Blurb: "HEY Calendars: list calendars, read their recordings (todos and events — the todo read path), toggle calendar visibility, and read a day, week or year as HEY draws it (repeating events expanded into occurrences, plus habits).",
Blurb: "HEY Calendars: list calendars, read their recordings (todos and events — the todo read path), toggle calendar visibility, read days and weeks with repeating events expanded into occurrences and habits, and read a year as HEY draws its grid.",

{
Key: "timetracks",
Tags: []string{"Calendar Time Tracks"},
Blurb: "HEY Calendar time tracks: start tracking, read the ongoing track, stop it (update_time_track with ends_at, optionally filing it under a category_title), record a finished stretch, and list, edit or delete completed tracks and categories.",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: The timetracks blurb promises "list, edit or delete completed tracks and categories", but the API model offers no create/update/delete actions for categories — the only category operation is ListTimeTrackCategories (GET /calendar/time_tracks/categories.json). An agent reading the tool description could attempt a category delete/edit action that does not exist. Reword so edit/delete applies only to tracks.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At internal/mcpserver/domains.go, line 48:

<comment>The timetracks blurb promises "list, edit or delete completed tracks and categories", but the API model offers no create/update/delete actions for categories — the only category operation is `ListTimeTrackCategories` (`GET /calendar/time_tracks/categories.json`). An agent reading the tool description could attempt a category delete/edit action that does not exist. Reword so edit/delete applies only to tracks.</comment>

<file context>
@@ -40,8 +39,23 @@ var DomainSpecs = []catalog.DomainSpec{
+	{
+		Key:   "timetracks",
+		Tags:  []string{"Calendar Time Tracks"},
+		Blurb: "HEY Calendar time tracks: start tracking, read the ongoing track, stop it (update_time_track with ends_at, optionally filing it under a category_title), record a finished stretch, and list, edit or delete completed tracks and categories.",
+	},
+	{
</file context>
Suggested change
Blurb: "HEY Calendar time tracks: start tracking, read the ongoing track, stop it (update_time_track with ends_at, optionally filing it under a category_title), record a finished stretch, and list, edit or delete completed tracks and categories.",
Blurb: "HEY Calendar time tracks: start tracking, read the ongoing track, stop it (update_time_track with ends_at, optionally filing it under a category_title), record a finished stretch, and list, edit or delete completed tracks, and list their categories.",

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟢 Approved

The mappings reuse the existing dispatcher; remaining feedback concerns minor description corrections and optional regression coverage.

Review effort: Balanced
Findings: 2 Low severity

Open (2)
What changed in this PR

Expands hey mcp to expose existing calendar capabilities through the SDK-backed dispatcher, addressing part of #537.

Changes:

  • Adds time-track, habit, and journal tools.
  • Adds calendar-period reads to hey_calendar.
  • Updates tool-count tests, help, and documentation; event creation/editing remains outside MCP.

[!TIP]
If you aren't ready for review, convert to a draft PR.
Click "Convert to draft" or run gh pr ready --undo.
Click "Ready for review" or run gh pr ready to reengage.

File Description
internal/​mcpserver/​server_test.go Expects ten gateway tools.
internal/​mcpserver/​domains.go Maps new domains and calendar-period reads.
internal/​mcpserver/​catalog_test.go Updates tools and unmapped-tag expectations.
internal/​cmd/​mcp.go Expands command help.
internal/​cmd/​mcp_test.go Updates integration tool count.
docs/​agents.md Documents added tools and event-write limitations.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Tags: []string{"Calendars"},
Blurb: "HEY Calendars: list calendars, read their recordings (todos and events — the todo read path), and toggle calendar visibility.",
Tags: []string{"Calendars", "Calendar Periods"},
Blurb: "HEY Calendars: list calendars, read their recordings (todos and events — the todo read path), toggle calendar visibility, and read a day, week or year as HEY draws it (repeating events expanded into occurrences, plus habits).",

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants