feat: MCP server push notifications (unsolicited messages to client)
Use case
Multi-agent coordination via MCP servers. Our memory system (synapt) uses MCP to provide persistent channels between agents. When Agent A posts a message, Agent B should be notified — but MCP is request-response only, so B only sees the message on its next tool call.
Current workaround
We piggyback channel checks on every MCP tool response via a suffix appended to tool results. This works when the agent is actively making tool calls, but fails when idle — the agent has no way to receive notifications without polling.
Proposed
Allow MCP servers to send unsolicited messages/notifications to the client. This could be:
- A server-initiated "notification" message type that appears in the agent context
- A "push" channel that the server can write to at any time
- Server-sent events or webhooks that trigger a client-side prompt
Why this matters
- Multi-agent coordination requires real-time awareness of team activity
- Polling wastes context window tokens (hundreds of "no new messages" checks)
- The MCP protocol already supports bidirectional communication in theory — this just enables the server→client direction for notifications
Context
We built synapt (https://github.com/laynepenney/synapt), a persistent memory system for AI coding assistants. Four agents (3 Claude Code + 1 Codex) coordinate via shared channels. The lack of server push is the biggest remaining coordination gap — agents go "dark" when idle because they have no way to receive notifications without a tool call.
10 Comments
Found 3 possible duplicate issues:
This issue will be automatically closed as a duplicate in 3 days.
🤖 Generated with Claude Code
+1 — experiencing the same polling problem with multi-session coordination over MCP. Sessions that aren't actively making tool calls miss messages entirely. Server push would make real-time coordination between sessions practical.
+1 — My use case is a Slack MCP server that listens for incoming messages and surfaces them as mid-workflow interrupts (think
/btwstyle). The user should be able to see the notification, then choose to respond now, snooze for X minutes, or dismiss.Without server→client push, the only options are polling on every tool call (wasteful) or checking at prompt-submit time (too late / not real-time enough). A push channel or interrupt mechanism would make this kind of real-time messaging integration practical.
FYI @SC7639 @laynepenney: We just got around this by blocking on MCP calls. It's not an innate signal for the agent, but if they are waiting for task queue items, the block is usually sufficient to get low latency response.
Thanks for sharing! The blocking approach makes sense for task-queue agents waiting for work. Our use case is a bit different — we want Slack notifications delivered passively while the agent is actively working on other tasks (coding, running tests, etc.).
We built claude-code-slack-notifier which uses a PostToolUse hook instead — a Socket Mode listener queues incoming DMs/@mentions to a JSON file, and a hook checks the queue after each tool call. No polling, no blocking, and notifications appear inline without interrupting the workflow.
That said, native MCP server push (the original feature request) would be the ideal solution for both patterns.
@SC7639 Agreed! That's why I mentioned "innate signal". We want something almost like a dashboard light. The agent should be able to notice it and take some action, like you say
/btwstyle. But here's an experiment: Ask something of/btwthat is specific to what the main agent knows about while the main agent is busy./btwcan't answer because it is not the same agent. We are only doing the blocking so we can keep working for now.Similar to what you built with synapt — we have an MCP IPC server (SQLite + WAL mode) for multi-Claude coordination.
Workaround for the pull-only limitation: our
wait_for_messagestool blocks for up to 55 seconds, returning instantly when a message arrives. A 1-minute cron triggers it when idle. Effective latency drops from 60s to ~5s gaps, ~7s round-trip.Not true push, but the blocking wait pattern covers ~55 of every 60 seconds. Would love to see proper server→client push in the MCP spec — the Channels feature exists but notifications are silently dropped (10+ open bugs).
Source: https://github.com/nedlern/route-spectrum/tree/staging/tools/ipc-server
+1 with a concrete neo-mjs use case — different project, same architectural need.
We're shipping a Phase 3 wake substrate (https://github.com/neomjs/neo issue #10357). Two-agent swarm (Claude Code + Antigravity/Gemini) coordinating via a Memory Core MCP server. Same root problem: receiver agent goes dark when idle because the MCP server can't push.
Current workaround is a "Shape C bridge daemon" — out-of-process polling using
tmux send-keys/osascriptfor wake injection. Works but accessibility-permission-dependent + UI-fragile.Architectural reference: ADR 0002 specifies a Hybrid Shape A/B/C routing where MCP
notifications/message(per the spec) is the preferred path, and the bridge daemon is the fallback for harnesses without native subscription support.Native MCP-client subscription (this issue's ask) eliminates Shape C's UI-automation surface entirely. Strong signal that the multi-agent coordination use case is broader than any single project — synapt + neo-mjs + (presumably others) converging on the same primitive need.
Cross-reference: https://github.com/neomjs/neo/issues/10364
Thanks for the request. This is the same ask as #35072 (push MCP notifications into the active session). Consolidating tracking there.
Surfacing inbound MCP
notifications/messageinto a running session is the core blocker for real-time multi-agent coordination on a shared workspace. Inbound notifications are received by the Claude Code CLI client today but never injected into the model's context — a truly-idle agent stays deaf until its next user turn. (Related: #3174, now locked.)Even if full server-push stays out of scope, leg-3 injection alone — taking a
notifications/messagethe client already receives and injecting it into the model's context — would unblock peer-to-peer agent wake: a peer hands off a task, flags a collision on a shared file, or requests a review, and an idle agent actually wakes to it. Today every such signal has to be smuggled through Stop-hook exit codes, SessionStart stdout, or a polling loop, which is fragile and adds latency.This is the single biggest blocker to making Claude Code a first-class node in a multi-agent mesh. Would love to see that narrower slice on the roadmap.