Skip to content

feat(mcp): live collection board as an MCP App (TASK-4465) - #2520

Merged
xarmian merged 20 commits into
mainfrom
rook/TASK-4465-board
Nov 13, 2026
Merged

xarmian merged 20 commits into
mainfrom
rook/TASK-4465-board

Conversation

@xarmian

@xarmian xarmian commented Nov 13, 2026

Copy link
Copy Markdown
Collaborator

Adds a live board view to the MCP Apps surface, following the item card (#2519).

What changes

  • New read-only tool pad_board, registered only on the remote HTTP /mcp server with MCP Apps on (PAD_MCP_APPS, default on). Stdio is unchanged.
    • show {workspace, collection, parent?}: status columns in schema order with terminal and abandoned flags, a compact per-item projection (no content, no fields blob), at most 300 open items plus 20 per terminal column, truncated, per-column total, unplaced, and the index endpoint's own cursor and access_epoch.
    • changes {workspace, collection, parent?, since, access_epoch}: reads /items-changes and returns upserts, removed_ids (deleted, moved out, other collection, other parent), the endpoint's cursor and epoch, and resync on an epoch change or a full page.
    • Both actions call the existing /collections, /items-index and /items-changes routes through the dispatcher's authed request path. Those endpoints, their cursor logic and their visibility filtering are unchanged. A hidden collection and a missing one get the same not_found.
  • New ui://pad/board resource (text/html;profile=mcp-app, preferred display mode fullscreen). The board HTML is read from an embedded directory, so builds that only create the item card placeholder still compile.
  • Board view (web/src/mcp-app/Board.svelte): columns with status changes via pad_item update with expected_seq (optimistic move, revert and reload on conflict). It polls pad_board changes every 10s only while fullscreen and visible, backs off to 120s on rate limits, re-runs show on resync, and offers Refresh inline. No HTML injection, no links out, no item content shown.
  • Each view now names itself to the host (Pad item card, Pad board) and in its page title.
  • Remote instructions gain a short apps note. ToolSurfaceVersion 0.113 to 0.114 (additive tool).

Tests

  • Go: TestPadBoard_ShowColumns, ShowCaps, ChangesUpsertRemove, RestrictedCursorNoLeak, HiddenVsMissingIdentical, AllowListRefusal, ReadOnly, ParentFilterAndSlugForms, TestMCPApps_BoardRegistration; route parity, read-only and chat-arm census tests now cover the app catalog.
  • Goldens: stdio tools/list unchanged; initialize goldens move only at the version string (remote also gains the apps note); remote tools/list adds pad_board.
  • Web: Board.svelte.test.ts (18), board.test.ts, bridge tests.

https://claude.ai/code/session_01Pa22hHJcmfKEzExwaXJX7T

…row (TASK-4465)

parseBoard and parseChanges keep only well-formed rows from a tool result; boardItemFrom turns a pad_item answer into the board row it replaces, without its content.

Claude-Session: https://claude.ai/code/session_01Pa22hHJcmfKEzExwaXJX7T
Status columns from pad_board show, live deltas from pad_board changes while fullscreen and visible, a Refresh control otherwise, and a per-item status select that writes through pad_item update with expected_seq. No item content, no markup rendering, every call through the bridge.

Claude-Session: https://claude.ai/code/session_01Pa22hHJcmfKEzExwaXJX7T
…tly (TASK-4465)

Collections whose slugs differ only by a trailing s no longer mix in a
board's deltas. Show still accepts singular forms and returns the
canonical slug, which the view passes back to changes.

Claude-Session: https://claude.ai/code/session_01Pa22hHJcmfKEzExwaXJX7T
The Apps surface appends a line saying pad_board is an additional
read-only resource x action tool, thirteen tools in total. The stdio
instructions are unchanged.

Claude-Session: https://claude.ai/code/session_01Pa22hHJcmfKEzExwaXJX7T
…n unseen item (TASK-4465)

A truncated board or one with unplaced items cannot know which column
total an item it does not display was counted in, so needsResync sends
such a delta to a fresh show instead of applyChanges. A complete board
keeps applying deltas. The unplaced-id tracking is gone: an unknown id
on an incomplete board now resyncs.

Claude-Session: https://claude.ai/code/session_01Pa22hHJcmfKEzExwaXJX7T
removed_ids now holds only rows that could have been on the board: this
collection's deletions and parent-filter misses, and moved-out
tombstones (which do not name their source). Live rows in other
collections go to departed_ids; the view drops any it shows and never
re-runs show for them, so unrelated updates no longer resync an
incomplete board. A truncated item that moves away leaves its column
total one too high until the next show, as documented in docs/mcp.md.

Claude-Session: https://claude.ai/code/session_01Pa22hHJcmfKEzExwaXJX7T
…y five minutes (TASK-4465)

Also lists the MCP App directory embed and its board read in the web census allow file.

Claude-Session: https://claude.ai/code/session_01Pa22hHJcmfKEzExwaXJX7T
@xarmian
xarmian merged commit cf860a1 into main Nov 13, 2026
15 checks passed
@xarmian
xarmian deleted the rook/TASK-4465-board branch November 13, 2026 14:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant