Skip to content

feat(mcp): notifications/claude/channel for push-feel inbox UX - #2433

Merged
HongmingWang-Rabbit merged 1 commit into
stagingfrom
feat/mcp-channel-notifications
May 1, 2026
Merged

HongmingWang-Rabbit merged 1 commit into
stagingfrom
feat/mcp-channel-notifications

Conversation

@HongmingWang-Rabbit

Copy link
Copy Markdown
Contributor

Summary

Adds a notification seam to the universal molecule-mcp wheel so MCP hosts that support push-style notifications (Claude Code today; any compliant client tomorrow) get inbound A2A messages as conversation interrupts instead of having to poll wait_for_message / inbox_peek.

The method name notifications/claude/channel matches the existing contract from the molecule-mcp-claude-channel bun bridge — same wire shape, now native to the universal wheel. Pollers continue to work unchanged for runtimes without notification support.

  • inbox.py — module-level _NOTIFICATION_CALLBACK + set_notification_callback(). Fires from InboxState.record() AFTER lock release with the same dict shape inbox_peek returns. Best-effort: a raising callback never prevents the message from landing in the queue.
  • a2a_mcp_server.py_build_channel_notification() pure helper (unit-testable wire shape) + bridge wiring in main() that schedules notifications via asyncio.run_coroutine_threadsafe (the inbox poller is a daemon thread; the MCP server loop is asyncio).
  • wheel_smoke.py — pin set_notification_callback as a published wheel surface, same regression class as the 0.1.16 main_sync incident.

Test plan

  • tests/test_inbox.py — 6 new tests: callback fires with to_dict() payload, dedupe short-circuits BEFORE fire (no duplicate notifications on backlog overlap), raising callback doesn't crash the inbox, set/None semantics
  • tests/test_a2a_mcp_server.py — 5 new tests: method name pin (matches molecule-mcp-claude-channel server.ts:509), content↔text mapping, meta routing fields, no id field (JSON-RPC notification spec compliance), missing-field tolerance
  • All 59 combined tests pass locally
  • CI green
  • Wheel smoke gate enforces the new pin

Follow-ups

  • Documentation update in molecule-docs to surface the push-UX behavior in runtime-mcp.mdx (separate PR — keeps the docs cross-rebase-able if the wire shape needs tweaking)
  • Live verification on the published wheel after publish-runtime.yml fires

🤖 Generated with Claude Code

Adds a notification seam to the universal molecule-mcp wheel so push-
notification-capable MCP hosts (Claude Code today; any compliant
client tomorrow) get inbound A2A messages as conversation interrupts
instead of having to poll wait_for_message / inbox_peek.

Wire-up:
- inbox.py: module-level _NOTIFICATION_CALLBACK + set_notification_callback()
  Fires from InboxState.record() AFTER lock release, with same dict
  shape inbox_peek returns. Best-effort — a raising callback never
  prevents the message from landing in the queue.
- a2a_mcp_server.py: _build_channel_notification() pure helper +
  bridge wiring in main() that schedules notifications via
  asyncio.run_coroutine_threadsafe (poller is a daemon thread, MCP
  loop is asyncio).
- Method name 'notifications/claude/channel' matches the contract
  documented in molecule-mcp-claude-channel/server.ts:509.
- wheel_smoke.py: pin set_notification_callback as a published name,
  same regression class as the 0.1.16 main_sync incident.

Pollers (wait_for_message / inbox_peek) keep working unchanged for
runtimes without notification support.

Tests: 6 new in test_inbox.py (callback fires once on record, dedupe
short-circuits before fire, raising cb doesn't break inbox, set/clear
semantics), 5 new in test_a2a_mcp_server.py (method name pin, content
mapping, meta routing, no-id JSON-RPC notification spec, missing-
field tolerance). All 59 combined tests pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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