Background
The History screen lists past MCP traffic as HistoryEntry cards. Each card already renders Replay and Pin / Unpin buttons (clients/web/src/components/groups/HistoryEntry/HistoryEntry.tsx:131-139), but neither does anything yet — the handlers are stubbed all the way up the tree.
Current state
The callbacks bubble: HistoryEntry → HistoryListPanel → HistoryScreen (onReplay / onTogglePin, pinnedIds) → InspectorView (onReplayHistory / onTogglePinHistory, pinnedHistoryIds) → App.
At the top:
App.tsx:1997-1998 wires both onReplayHistory and onTogglePinHistory to todoNoop.
App never passes pinnedHistoryIds, so InspectorView.tsx:618 falls back to new Set() — pinned state is always empty and the Pin button has no visible effect.
So clicking Replay or Pin today is a no-op.
Proposal
Implement both handlers in App.tsx and thread the pinned set down.
Pin / Unpin
Replay
onReplayHistory(id) looks up the MessageEntry by id and re-issues its original request. MessageEntry.message is the original JSON-RPC request (core/mcp/types.ts:171), so dispatch by method:
tools/call → resolve the Tool by params.name from the tools list, then inspectorClient.callTool(tool, params.arguments).
prompts/get → getPrompt(params.name, params.arguments).
resources/read → readResource(params.uri).
- Define behavior for other request methods (subscribe, completion, logging/setLevel, …) — replay or ignore with a notice.
- Replay responses are surfaced history-locally. Rather than routing the user to the originating screen (Tools/Prompts/Resources), a replay re-issues the request and shows the fresh result inline on the History screen — i.e. the replayed call produces a new
MessageEntry in the history list (and/or updates the originating entry's expanded result view), so the user stays in History and can compare runs in place. The replay still goes through InspectorClient, so the normal traffic is logged as usual.
Open questions
- Pinned-entry treatment: protected from Clear All, sorted to the top, and/or visually marked beyond the Unpin label?
- Should pinned ids persist only for the session, or across reconnects/restarts (storage)?
- Replay scope: just the three "actionable" request types above, or every request method?
- History-local surfacing detail: does a replay append a brand-new entry, update the existing entry in place, or both?
Acceptance criteria
Background
The History screen lists past MCP traffic as
HistoryEntrycards. Each card already renders Replay and Pin / Unpin buttons (clients/web/src/components/groups/HistoryEntry/HistoryEntry.tsx:131-139), but neither does anything yet — the handlers are stubbed all the way up the tree.Current state
The callbacks bubble:
HistoryEntry→HistoryListPanel→HistoryScreen(onReplay/onTogglePin,pinnedIds) →InspectorView(onReplayHistory/onTogglePinHistory,pinnedHistoryIds) →App.At the top:
App.tsx:1997-1998wires bothonReplayHistoryandonTogglePinHistorytotodoNoop.Appnever passespinnedHistoryIds, soInspectorView.tsx:618falls back tonew Set()— pinned state is always empty and the Pin button has no visible effect.So clicking Replay or Pin today is a no-op.
Proposal
Implement both handlers in
App.tsxand thread the pinned set down.Pin / Unpin
Set<string>of pinned entry ids inApp;onTogglePinHistory(id)toggles membership and passes the set down aspinnedHistoryIds(already plumbed throughInspectorView→HistoryScreen→HistoryListPanel→HistoryEntry.isPinned).historyUi/ per-screen persistence work in Persist per-screen selection and search/filter across tab navigation; clear only on user action or disconnect #1417 / Extract resetSessionScopedUiState() helper as App.tsx per-session state grows #1394).Replay
onReplayHistory(id)looks up theMessageEntryby id and re-issues its original request.MessageEntry.messageis the original JSON-RPC request (core/mcp/types.ts:171), so dispatch by method:tools/call→ resolve theToolbyparams.namefrom the tools list, theninspectorClient.callTool(tool, params.arguments).prompts/get→getPrompt(params.name, params.arguments).resources/read→readResource(params.uri).MessageEntryin the history list (and/or updates the originating entry's expanded result view), so the user stays in History and can compare runs in place. The replay still goes throughInspectorClient, so the normal traffic is logged as usual.Open questions
Acceptance criteria
isPinnedtrue) and Unpin clears it; the state is reflected immediately and persists across tab navigation within a session.pinnedHistoryIdsis supplied byApp(no longer defaulting to an empty set inInspectorView).tools/call/prompts/get/resources/readentry re-issues the original request with its recorded params.todoNoopwiring is removed for these two handlers.