Conversation
Covers 19 new CLI commands and 13 new MCP tools across mail, mailbox, calendar, identity, vacation, and thread operations to achieve full CRUD parity with the Fastmail JMAP/CardDAV/CalDAV API surface. Includes 5-phase implementation plan. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix MCP tool count (15 new, not 13) and mark 5 unwired tools - Clarify mail search needs new query parser, not existing Search() - Add GetFull() for mail show (existing Get() lacks display properties) - Fix is:unread mapping to notKeyword (not negated hasKeyword) - Note Identity type field fixes needed (ReplyTo/BCC are wrong type) - Add CapVacationResponse capability requirement - Document calendar DAV client pattern (follows contacts.go) - Note existing builders for Mailbox/Identity (reduce scope) - Note EmailSetBuilder already supports Update() for keywords Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…tant Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Detailed bite-sized implementation plan covering 5 phases: - Phase 1: Mailbox + Mail Read (tasks 1-10) - Phase 2: Mail Write Operations (tasks 11-13) - Phase 3: Calendar CLI (tasks 14-16) - Phase 4: Identity, Vacation, Thread (tasks 17-22) - Phase 5: MCP Catch-up (tasks 23-25) Each task follows TDD workflow: write failing test → implement → verify → commit. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add builder pattern for JMAP Mailbox/set method supporting create, update, and destroy operations, along with MailboxSetResponse type for deserializing server responses. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add MailboxService to pkg/fastmail wrapping JMAP Mailbox/get and Mailbox/set operations. Includes Mailbox() accessor on Client and full test coverage for all four operations plus error paths. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add Cobra subcommands for mailbox management with text and JSON output, --force confirmation for delete, and required flag/arg validation. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Register mailbox MCP tools (list, create, rename, delete) following the existing tool handler pattern. Wire registerMailboxTools into RegisterMailTools and add tests for tool registration and argument validation. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add MailService.GetFull method that requests full display properties (from, to, cc, bcc, bodyValues, textBody, htmlBody, attachments) with fetchTextBodyValues enabled. Add Attachment type to both JMAP and domain layers, along with convertFullEmail and address/attachment conversion helpers. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…rieval Add DownloadBlob method to jmap.Client that downloads a blob using the session's downloadUrl template with proper auth headers. Add GetRaw method to MailService that fetches an email's blobId then downloads the raw RFC 5322 source via DownloadBlob. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add `mail show EMAIL_ID` command that displays a single email with formatted headers, body, and attachments. Supports `--raw` flag for RFC 5322 source output, plus `--json` and `--quiet` global flags. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implements a lightweight search query parser that converts human-readable query strings into JMAP FilterCondition maps. Supports prefix tokens (from:, to:, subject:, has:, is:, in:, before:, after:) and free text, with automatic AND-wrapping for compound queries. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Refactor Search to delegate to new SearchWithFilter method that accepts a pre-built JMAP FilterCondition map, enabling the search parser to pass structured filters directly instead of plain text queries. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Wire up `mail search QUERY...` subcommand that parses query args via search.Parse() and delegates to SearchWithFilter. Includes --limit/-n flag (default 25) and reuses outputEmails for consistent output. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add `mail move EMAIL_ID --folder FOLDER` to move emails between mailbox folders and `mail delete EMAIL_ID --force` with a required confirmation flag. Both commands include JSON/quiet output support and corresponding CLI tests for argument and flag validation. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… tool Add support for setting email keywords (read/unread, flagged/unflagged) across all three layers: MailService.SetKeywords uses JMAP Email/set with keyword patch paths, `mail flag` CLI command with --read/--unread/--flagged/ --unflagged boolean flags, and mail_flag MCP tool for AI agent access. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add 6 calendar subcommands (list, show, create, update, delete, calendars) following the contacts CLI pattern. Extend config with CalDAV endpoint/username fields and auto-derivation from the JMAP endpoint. Add NewCalendarService constructor to the public API. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace duplicated inline tool registration in cli/mcp.go with a single call to mcp.RegisterMailTools, wiring up contacts and calendar adapters. Extend CalendarAdapter with Get/Update/Delete/ListCalendars function pointers and add calendar_get, calendar_update, calendar_delete, and calendar_calendars MCP tools with full handler implementations and tests. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…er RFC 8620 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…onse Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implement IdentityService with List method, CLI `identity list` command, and `identity_list` MCP tool. Fix gofmt alignment in jmap.Identity struct and add dupl nolint directives for shared JMAP service List pattern. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add VacationService with Get/Set methods wrapping the JMAP VacationResponse/get and VacationResponse/set endpoints. Wire up CLI commands (vacation show, vacation set) with --enable/--disable, --from, --to, --subject, --body flags. Register vacation_get and vacation_set MCP tools for AI agent access. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add ThreadService.Get that performs Thread/get then Email/get to fetch all emails in a conversation. Wire up `thread show THREAD_ID` CLI command and `thread_get` MCP tool. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add two new MCP tools for contact management: - contacts_update: updates an existing contact by fetching it first and merging provided fields (name, email, phone) - contacts_delete: deletes a contact by ID Includes registration tests and handler validation tests for nil contacts client and missing ID arguments. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
VacationService.Set now decodes VacationSetResponse and checks NotUpdated["singleton"], matching the pattern used by all other Set methods. The CLI vacation set command now validates that at least one flag is provided before making the API call. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Resources defined in mcp/resources.go were never registered with the MCP server, making them dead code. Add RegisterResources() to iterate the ResourceRegistry and register each resource with the server. Also log contacts and calendar client errors to stderr instead of silently swallowing them, so users can diagnose DAV configuration issues. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Log a warning to stderr when ReceivedAt fails RFC3339 parsing instead of silently producing zero time. Reject contradictory --read/--unread and --flagged/--unflagged flag combinations with a clear error. Also adds inMailbox resolution for SearchWithFilter so folder names in search queries are resolved to mailbox IDs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Refuse to delete mailboxes with protected roles (inbox, drafts, sent, trash, junk) even when --force is specified, preventing accidental destruction of standard JMAP mailboxes. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
PR #5 Review Summary: "Design: Full API parity for CLI and MCP"Scope: 50 files, +8700/-219 lines — CLI commands, JMAP protocol, MCP tools/resources, service layer, search parser Critical Issues (3)1.
|
| Gap | Severity |
|---|---|
| MCP tool handlers are schema-only tests (no handler invocation) | High |
CalendarService has zero tests (pkg/fastmail/calendar.go) |
High |
SetKeywords only tests true values, not keyword removal |
High |
MCP mail_flag with contradictory flags untested |
Medium |
VacationService.Set with empty options untested |
Medium |
Search parser: is:read, is:draft, is:answered unhandled |
Low |
Strengths
- Well-structured three-layer architecture (internal → pkg → cli/mcp)
- Thorough JMAP builder + response deserialization tests
- Excellent error-path coverage at service layer (NotCreated/NotUpdated/NotDestroyed)
- Smart two-stage delete (move to Trash, then permanent if already in Trash)
- Protected mailbox deletion prevents deleting inbox/drafts/sent/trash/junk
- Search parser is clean and extensible with solid test coverage
Recommended Action
- Fix critical issues first — keyword removal bug (feat(cli): add mail read command (fc-h2at) #1) and delete-on-transient-error (feat(cli): add mail read command (fc-h2at) #2) affect data integrity
- Add MCP handler invocation tests — the schema-only tests leave significant integration gaps
- Address important validation gaps (Improve auth handling and CardDAV defaults #4, Design: Full API parity for CLI and MCP #5) before MCP goes to production
- Consider the suggestions for a follow-up PR
🤖 Generated with Claude Code using pr-review-toolkit
Critical fixes (P0): - SetKeywords sends nil (JSON null) instead of false to remove keywords per RFC 8621 §4.1.1 - Delete propagates transient resolveMailbox errors instead of silently falling through to permanent destroy - MCP argument helpers return type-mismatch errors instead of silently returning defaults Important fixes (P2): - Vacation --enable/--disable enforced as mutually exclusive - MCP mail_flag validates read/unread and flagged/unflagged mutual exclusivity - MCP resources return actual errors instead of fake success with error text in body - SearchWithFilter deep-copies filter map to avoid caller mutation - convertEmails returns ([]Email, error) instead of writing to stderr - mailbox delete without --force returns error (matches mail delete) Suggestions (P3): - Move removes redundant Get call before Email/set - internal/jmap/ migrated from fmt.Errorf to samber/oops - All 22 getAccountID call sites wrapped with operation context Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Comprehensive design for full CRUD parity between CLI and MCP server with Fastmail JMAP/CardDAV/CalDAV APIs.
Includes 19 new CLI commands, 13 new MCP tools, 4 new resources, and 5-phase implementation plan starting with mailbox and mail operations.