[BUG] Discord plugin: fire-and-forget mcp.notification() silently drops inbound messages on Windows

Resolved 💬 3 comments Opened Apr 6, 2026 by mgzg16 Closed Apr 10, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

When running claude --channels plugin:discord@claude-plugins-official on Windows 11, the Discord bot connects successfully (pairing works, bot sends codes and confirmation), but post-pairing inbound messages are never delivered to the Claude Code session. The bot shows typing indicators and ack reactions, confirming the gate passes and handleInbound() runs — but the mcp.notification() at server.ts:868 silently fails to deliver.

Related to #36837 (Linux gateway issue) but distinct root cause on Windows.

Root Cause Analysis

Traced through server.ts and identified two issues:

1. Fire-and-forget notification (server.ts:868)

mcp.notification({
    method: 'notifications/claude/channel',
    params: { content, meta: { ... } },
}).catch(err => {
    process.stderr.write(`discord channel: failed to deliver inbound to Claude: ${err}\n`)
})

The notification is not awaited. On Windows, the stdio pipe buffer behavior differs from Unix — writes can silently fail if Claude Code is mid-turn or the pipe buffer is under pressure. No retry, no queue, no success logging. If the write fails without throwing (partial write / buffer full), the .catch() never fires and the message is silently lost.

2. Channel cache staleness (server.ts:392) — already identified in #36837 comments

client.channels.fetch(id) without { force: true } returns stale cached partials after idle, causing recipientId to be undefined and the allowlist check to fail on outbound replies.

Evidence

  • Pairing works (bot sends code + confirmation via direct msg.reply()) ✅
  • Gate passes for allowlisted user (typing indicator + ack reaction fire) ✅
  • mcp.notification() called but message never appears in Claude session ❌
  • No stderr errors logged (the .catch() doesn't fire) ❌
  • Manual fetch_messages tool call retrieves messages correctly ✅

The fact that fetch_messages (synchronous tool request) works but mcp.notification() (async push) doesn't confirms the issue is in the notification delivery path, not the gateway or access control.

Suggested Fix

// server.ts:868 — await + retry instead of fire-and-forget
- mcp.notification({
+ await notifyWithRetry(mcp, {
    method: 'notifications/claude/channel',
    params: { ... },
- }).catch(err => {
-   process.stderr.write(`...`)
  })

// Add retry helper
+async function notifyWithRetry(server, payload, maxRetries = 3) {
+  for (let attempt = 1; attempt <= maxRetries; attempt++) {
+    try {
+      await server.notification(payload)
+      return
+    } catch (err) {
+      process.stderr.write(`notification attempt ${attempt}/${maxRetries} failed: ${err}\n`)
+      if (attempt < maxRetries) await new Promise(r => setTimeout(r, 300 * attempt))
+    }
+  }
+}

// server.ts:392 — force-fetch to avoid stale cache (per #36837 comments)
- const ch = await client.channels.fetch(id)
+ const ch = await client.channels.fetch(id, { force: true })

Claude Code Version

Latest (Claude MAX subscription)

Platform

Claude MAX

Operating System

Windows 11 Home 10.0.26200

Terminal/Shell

bash (Git Bash)

Additional Information

  • Plugin version: discord@claude-plugins-official 0.0.4
  • discord.js ^14.14.0
  • Bun runtime
  • Applied the fix locally and testing

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗