feat(tui): mcp channel tui render - #2432
Open
godlzr wants to merge 13 commits into
Open
Conversation
…cation factory Extend MCPClient with onChannelMessage and switch StdioMcpClient, HttpMcpClient, and SseMcpClient to build their SDK Client via createMcpSdkClient so all three transports gain the push-channel capability and notification handler. Updates existing MCP test fakes to satisfy the extended interface.
…ent's prompt queue
…nnel prompt origin
…hed content, add observability
The mcp-channel push feature (agent-core-v2) injected pushed messages into the agent's context but never gave the SDK/TUI a discrete signal to render — the domain event carried no message text, and neither protocol's Event/PromptOrigin unions, agent-core's v1-shaped ContextMessage/Event types, nor the TUI's live/replay renderers knew about the mcp_channel origin at all. Only the model's own paraphrase of the pushed content was ever visible. Wires the full chain, mirroring the existing cron.fired path: - protocol: add McpChannelReceivedEvent to the Event union and McpChannelOrigin to PromptOrigin, with matching zod schemas. - agent-core-v2: include the message text in the published mcp.channel.received domain event (previously only server/chatId/ receivedAt). - agent-core: add McpChannelOrigin to the v1-shaped PromptOrigin union (the v2 harness casts its own origins into these types) and handle the new kind in the exhaustive origin switches (compaction handoff, replay turn-boundary detection, session-store visibility checks) — treated like cron: dropped on compaction, doesn't anchor a replay/undo turn boundary. - node-sdk: re-export McpChannelReceivedEvent; the v2->v1 event translator already passes unlisted types through unchanged. - apps/kimi-code: new 'mcp_channel' transcript entry kind and McpChannelMessageComponent (mirrors CronMessageComponent), wired into the live event handler, session replay, kimi-tui's dispatch, and undo's context-entry classification.
🦋 Changeset detectedLatest commit: bf48fcd The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fbeddbf54e
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
…render # Conflicts: # packages/agent-core-v2/docs/state-manifest.d.ts # packages/agent-core-v2/src/index.ts # packages/agent-core-v2/test/mcpCore/connection-manager.test.ts # packages/agent-core-v2/test/mcpCore/fixtures/channel-stdio-server.mjs
origin/main's Workspace-domain refactor replaced session-scoped ISessionMcpService with a workspace-seeded ISessionMcpHandle (plain connectionManager property instead of a method, no ensureMcpReady). Move channel-notification.ts to mcpCore/ alongside the rest of the renamed MCP transport layer, and regenerate the state/wire manifests.
- Project mcp.channel.received into the transcript/web surface too: kap-server's coreEventMap gets a marker case mirroring cron.fired, and kimi-web gets the matching live-event synthesis, turn-building, and a McpChannelNotice.vue renderer (mirrors CronNotice.vue) so a push shows up for web sessions, not just the TUI. - Fix a live/replay text mismatch: replay only stripped the <mcp-channel> envelope without unescaping the <>-escaped body, so restarting a session would show "a < b" where the live render showed "a < b". Unescape mirrors the plugin's escapeXmlTags exactly (only <>, not &/" — matching what the envelope actually encodes) in both the TUI and kimi-web. - Fold two inline JSDoc blocks in client-shared.ts into the file header per the package's comment convention (header-only, external role only). Adds a second changeset for the web-facing half.
MosesDastmard
approved these changes
Jul 30, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Related Issue
Resolves #2431
Problem
See linked issue.
What changed
agent-core-v2already had an MCP "channel push" mechanism (notifications/kimi/channel) so a plugin like a Discord bridge can wake a running session instead of relying on polling, but two gaps made it unusable in practice:mcp.channel.received) never carried the message text — onlyserver/chatId/receivedAt— so there was nothing to render even if something tried.Event/PromptOriginunions that the SDK and TUI are built on (used by both engines — the v2 harness casts its own origins/events into these types) had nomcp_channelmember, so the pushed message was invisible except indirectly, through the model's own paraphrase of what it received in its next turn.This PR closes both gaps, mirroring the existing
cron.firedpath end to end rather than inventing a new pattern:packages/protocol: addMcpChannelReceivedEventto theEventunion andMcpChannelOrigintoPromptOrigin, with matching zod schemas.packages/agent-core-v2: include the message text in the publishedmcp.channel.receiveddomain event.packages/agent-core: addMcpChannelOriginto the v1-shapedPromptOriginunion, and handle the new kind in the exhaustive origin switches it already has (compaction handoff, replay turn-boundary detection, session-store visibility) — treated the same ascron_job: dropped on compaction, doesn't anchor a turn boundary for replay/undo -packages/node-sdk: re-exportMcpChannelReceivedEvent;translator already passes through any type it doesn't explicitly drop or rename, so no translation logic changed.apps/kimi-code: new'mcp_channel'transcript entry kind andMcpChannelMessageComponent(mirrorsCronMessageComponent), wired into the live session-event handler, session replay (so a resumed seo), the TUI's render dispatch, and/undo's context-entryclassification.Tested end-to-end against a real Discord MCP bridge plugin with the experimental v2 engine enabled: a paired DM now wakes the session and renders as a distinct "Message received via discord" block with thenly showing up through the model's own summary. No changeset: every changed code path is either internal
a or only reachable when the CLI is switched onto the experimental v2 engine (KIMI_CODE_EXPERIMENTAL_FLAG`), whied engine yet — no user on the default CLI can perceive this change. Same reasoning applies to docs: nothing user-facinghe default engine.Checklist
gen-changesetsskill, or this PR needs no changgen-docsskill, or this PR needs no doc update.