Race observed on first turn: ClaudePlugin emits
notifications/claude/channel before Claude Code finishes registering
the channel handler internally. Claude logs
"MCP server synthesis: Channel notifications registered" ~25ms AFTER
hello_ack arrives. Notifications that arrive earlier are silently
dropped — observed empty session, no turn, curl hangs until timeout.
Fix: on first `inbound` frame after WS hello, wait 800ms before
emitting the MCP notification. Subsequent inbounds skip the wait.
End-to-end verified twice on laptop. Cold-start ~10s, hot path 2-3s.
- WS client to OpenclawPlugin's bridge (auto-reconnect with exponential
backoff)
- On hello: send (openclaw_session, claude_session, pid) — no auth token
- On inbound frame: emit notifications/claude/channel into MCP so Claude
Code opens a new turn
- Single MCP tool `reply(text, final?)` — model calls it to send a
reply back via the bridge. final=false streams progress chunks
- Capability declared under `experimental.claude/channel` (top-level was
silently ignored — bug confirmed against Anthropic's discord plugin)
- Dropped auth handshake + permission_request reverse channel per the
same-machine, full-perms design call
Add .mcp.json so the package is also a valid Claude Code plugin (for
potential plugin: form deployment later).
Stdio MCP server registered as a Claude Code --channels source. Receives
inbound events from SynthesisAgent.OpenclawPlugin and emits
notifications/claude/channel to push them into the running Claude turn loop.
Forwards tools/call requests back to OpenClaw for execution.
Capability declaration uses experimental.claude/channel — required nesting
discovered 2026-05-14 against the official Anthropic discord plugin source.