diff --git a/server.ts b/server.ts index 5964533..72efba4 100644 --- a/server.ts +++ b/server.ts @@ -98,6 +98,7 @@ mcp.setRequestHandler(CallToolRequestSchema, async req => { let ws: WebSocket | null = null let backoff = 1000 const outbox: unknown[] = [] +let firstInboundDelivered = false function bridgeSend(frame: unknown): void { if (ws && ws.readyState === WebSocket.OPEN) { @@ -147,6 +148,16 @@ async function handleBridge(frame: any): Promise { log(`hello_ack received`) return case 'inbound': + // Race guard: Claude Code's internal "Channel notifications registered" + // log line appears ~25ms AFTER we send hello_ack — if we push the + // notification before then, claude silently drops it. Buffer the + // first inbound briefly to dodge this. Subsequent inbounds don't + // need the wait (channel is registered for the lifetime of the + // session). + if (!firstInboundDelivered) { + await new Promise(r => setTimeout(r, 800)) + firstInboundDelivered = true + } await mcp.notification({ method: 'notifications/claude/channel', params: {