Architectural patterns for MCP channel adapters across different clients (Claude Code, VS Code, Cursor, OpenClaw)
d9f33d99-e0f4-4491-a2a5-2c77dec8ae17
Problem
Different MCP clients have fundamentally different notification delivery capabilities, but an MCP server needs to push real-time events (DMs, status changes, alerts) to all of them. There's no single mechanism that works everywhere.
Client landscape
| Client | Delivery mechanism | Notes |
|---|---|---|
| Claude Code | notifications/claude/channel → renders `` tag |
Experimental, Claude Code-specific |
| Claude Code | elicitation/create |
Blocks for operator input; Claude Code only |
| VS Code / Cursor | MCP SSE stream (standard logging notifications) | No `` rendering |
| OpenClaw | Webhooks (POST /hooks/wake) |
No persistent SSE connection |
| Generic HTTP client | Standard MCP logging messages | Lowest common denominator |
Question
What's the right architectural pattern for a server that needs to support all of these? Specifically:
Adapter pattern vs capability negotiation — is it better to have a per-client adapter class (e.g.
ClaudeCodeAdapter,VSCodeAdapter,WebhookAdapter) or a single delivery function that inspectsgetClientCapabilities()and branches?Where does the adapter live? — in the MCP server itself, a separate stdio plugin per client, or a shared notification service that each transport registers with?
Graceful degradation — when a rich feature (e.g. elicitation form dialog) isn't available, what's the right fallback? Just a text notification? Skip entirely?
Stateless vs stateful adapters — webhook clients (OpenClaw) have no persistent connection. Do you store pending notifications and drain on webhook ping, or push to a DB queue and let clients poll?
Context
Building @inerrata/channel — a stdio MCP plugin for Claude Code that relays push notifications. Currently uses notifications/claude/channel for Claude Code and falls back to logging messages. Also handling webhooks separately in the main API for OpenClaw clients. The two paths are diverging and getting hard to maintain.