[BUG] notifications/claude/channel accepted (notification() resolves) for a backgrounded session are never injected — no queue, no replay on foreground

Status Open
Reported on v2.1.212
Maintainer reply None cached
Activity 0 comments · opened Jul 27, 2026

Summary

notifications/claude/channel notifications sent by a plugin MCP server to a backgrounded interactive session are accepted by Claude Code (the server's notification() resolves successfully) but are never injected into the conversation — not while backgrounded, and not retroactively when the session is foregrounded again. Only notifications that arrive while the session is foreground/active render. There is no error, no queueing, no replay: the notifications are silently eaten.

This is distinct from #61010 (notification after a tool-only turn lands in the prompt buffer — foreground timing issue) and #78028 (dev-channels flag lost on daemon fork-resume — registration issue). Here the channel is registered and proven working in the same session; the loss correlates purely with the session being backgrounded.

Environment

  • Claude Code 2.1.212 (native install), Windows 11 Pro 10.0.26200
  • Node v22.22.0
  • Channel-enabled launch: claude --dangerously-load-development-channels plugin:<name>@<marketplace> (custom marketplace plugin whose MCP server declares capabilities.experimental["claude/channel"])

Repro

  1. Launch an interactive session channel-enabled with a plugin MCP server that pushes notifications/claude/channel (ours pushes a notification per matching Slack message; any server that emits on an external trigger works).
  2. Trigger one notification while the session is foreground → it renders as a <channel> block. Baseline works.
  3. Background the session (switch away from the terminal/session).
  4. Trigger several more notifications.
  5. Foreground the session and send a user message.

Expected: the notifications from step 4 render — either as they arrive, or queued and injected on foreground/next turn.

Actual: none of them ever appear. The session continues as if they never existed.

Evidence that the server side delivered

Our MCP server logs every push. For 5 external events (Slack messages), all 5 completed the full path — the MCP server.notification() call resolved (emit_ok) for every one:

{"ts":"2026-07-27T21:33:02Z","event":"fire_received", ...}   ← rendered (session foreground)
{"ts":"2026-07-27T21:33:02Z","event":"emit_ok", ...}
{"ts":"2026-07-27T21:36:22Z","event":"fire_received", ...}   ← session backgrounded from here on
{"ts":"2026-07-27T21:36:22Z","event":"emit_ok", ...}
{"ts":"2026-07-27T21:36:48Z","event":"fire_received", ...}
{"ts":"2026-07-27T21:36:48Z","event":"emit_ok", ...}
{"ts":"2026-07-27T21:37:07Z","event":"fire_received", ...}
{"ts":"2026-07-27T21:37:07Z","event":"emit_ok", ...}
{"ts":"2026-07-27T21:37:41Z","event":"fire_received", ...}
{"ts":"2026-07-27T21:37:41Z","event":"emit_ok", ...}
{"ts":"2026-07-27T21:38:01Z","event":"fire_received", ...}
{"ts":"2026-07-27T21:38:01Z","event":"emit_ok", ...}

Only the first (foreground) notification was injected into the conversation. The four emit_ok'd while backgrounded never rendered, including after the session was foregrounded and a new user turn started.

Why it matters

The channels feature's main use case is exactly this shape: a session subscribes to an external feed and reacts when something happens. A session that must stay foregrounded to receive pushes can't be left to monitor anything — every backgrounded minute is silent data loss with a success signal (emit_ok) on the sender's side, so the server operator has no way to detect or compensate.

Suggested behavior

Queue channel notifications received while a session is backgrounded and inject them on foreground (or at the start of the next turn), the same way user input typed while the model is running is queued. If dropping is intentional, fail the notification() call (or expose a capability signal) so the emitting server can fall back to polling/retry instead of reporting success.

View original on GitHub ↗