You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Unify message-list output shape across listy MCP tools #76
Each listy MCP tool returns messages in a slightly different shape:
Tool
Array key
Pagination fields
`total`?
`search`
`results`
`next_before_id`, `next_before_sent_at`
yes
`history`
`results`
`next_after_id`, `next_after_sent_at`
no
`thread`
`messages` ❗
`next_after_id`
no
`recent`
(same as search — deprecated, being removed)
`digest`
`chats[id].messages` ❗
none
no
Field sets per message row also diverge: `thread` drops `message_type` and `forwarded_from_name`, `digest` drops `reply_to_message_id` and `message_type`.
An AI agent that learned the shape of one tool trips on another. It also makes pagination resumption awkward — the cursor key names differ, and tools like `chats`/`contacts` don't expose pagination in the MCP schema at all despite supporting it server-side.
Canonical `MessageRow` shape: every tool returns the same fields (with optional `fields: 'minimal' | 'full'` param for payload control). Default to `full`.
Apply to: `search`, `history`, `thread`, `digest` (shape per chat), and any future listy tools.
Also: expose pagination on `chats` and `contacts`/`address_book` where it's silently capped today (1,648 chats → default `limit: 50` truncates without `has_more` signal).
Migration strategy
Option A (clean break): bump MCP server version, breaking change. One-time pain.
Option B (opt-in): accept `format: 'v1' | 'v2'` param per tool, default v1 for now, switch default to v2 after clients update.
Prefer A since the consumer base is small (primarily the issue author's own Claude Code installs). Call out in SPEC / README.
Acceptance
All listy MCP tools return `{ messages, page: { has_more, next_cursor, total? } }`
Cursor is opaque (AI doesn't assemble `before_id + before_sent_at` manually)
`has_more` always present so AI knows when to stop paginating
`chats` and `address_book` paginate properly
`include_total` param on `search` (default true on first page, false on follow-ups)
Server instructions and tool descriptions updated with new shape
Activity
feat(mcp): unify listy output shape with opaque cursors (#76)
feat(mcp): unify listy output shape with opaque cursors (#76)
feat(mcp): unify listy output shape with opaque cursors (#76) (#81)
chore(gramjs): add gap-fill recovery script + runbook (#84)