`--channels` fails to deliver messages when the plugin is loaded via `--plugin-dir` instead of `enabledPlugins` (origin mismatch: "inline" vs "marketplace")
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?
This is a follow-up to #42413 (multiple sessions loading the Telegram channel plugin simultaneously, SIGTERM poller-theft). We hit exactly that bug: a plugin enabled globally in enabledPlugins gets loaded by every claude session on the machine, not just the one launched with --channels, and the plugin's own MCP server (telegram@claude-plugins-official in our case) evicts any prior poller via unconditional SIGTERM on startup — so opening any ordinary claude session steals the channel session's poller. The documented workaround for that class of bug (see anthropics/claude-plugins-official#1075) is: disable the plugin globally, and load it only for the dedicated session via --plugin-dir. We did exactly that — and it exposes a second, distinct bug, which is what this issue is about.
With the plugin removed from enabledPlugins and loaded via:
claude --channels plugin:telegram@claude-plugins-official --plugin-dir C:\Users\<user>\.claude\plugins\cache\claude-plugins-official\telegram\0.0.6
the full process chain comes up correctly (claude -> bun run -> bun.exe server.ts), the Telegram poller correctly consumes messages from the Bot API (getWebhookInfo shows pending_update_count: 0), but the message is never delivered to the host session. No error is written back to the plugin's server.ts (the mcp.notification({ method: 'notifications/claude/channel', ... }) call is fire-and-forget with no ack), so the plugin has no way to know delivery failed.
With --debug --debug-file <path> (the only combination of debug flags that doesn't itself break --channels — redirecting stdout/stderr directly causes an unrelated crash: Error: Input must be provided either through stdin or as a prompt argument when using --print), we found the actual reason logged once at connection time:
MCP server "plugin:telegram:telegram": Channel notifications skipped: you asked for plugin:telegram@claude-plugins-official but the installed telegram plugin is from inline
So --channels plugin:telegram@claude-plugins-official expects the plugin's origin metadata to say marketplace (or otherwise match the reference string), but --plugin-dir always registers the plugin with origin inline, regardless of whether the directory it points to is byte-identical to the marketplace-installed copy. The host decides not to subscribe to that MCP server's channel notifications at all, once, silently, with no retry for the rest of the session.
Net effect: there is currently no working combination of flags that gives us both (a) isolation from other concurrent claude sessions stealing the plugin's poller (the #42413 bug), and (b) actual message delivery to the --channels session — because (a) requires not using global enabledPlugins, and (b) currently requires using it, since --plugin-dir breaks the origin match. We ended up reverting to global enabledPlugins and mitigating the poller-theft bug with an external watchdog script instead, since that's the only way to get a working system today.
Suggested fix: either (1) --channels plugin:X@marketplace should match against a plugin loaded via --plugin-dir when the resolved path is identical to (or otherwise equivalent to) the marketplace-installed plugin's path, or (2) --channels should accept an inline-origin plugin as satisfying a plugin:X@marketplace reference when no ambiguity exists, or at minimum (3) the mismatch should produce a visible error/warning, not just a debug-log-only skip — today this fails completely silently from the operator's perspective (no error in Telegram, no error in the plugin's own logs, nothing without --debug-file).
What Should Happen?
A --channels session launched with --plugin-dir pointing at an already-installed marketplace plugin should still receive channel messages from that plugin's MCP server, the same way it does when the plugin is enabled via enabledPlugins.
Error Messages/Logs
Environment: Windows 11, Claude Code 2.1.207, plugin telegram@claude-plugins-official v0.0.6.
Broken: claude --channels plugin:telegram@claude-plugins-official --plugin-dir <path-to-installed-plugin-dir>
Working (but reintroduces the SIGTERM poller-theft bug): claude --channels plugin:telegram@claude-plugins-official with the plugin enabled in enabledPlugins
Relevant debug log line (via --debug --debug-file):
MCP server "plugin:telegram:telegram": Channel notifications skipped: you asked for plugin:telegram@claude-plugins-official but the installed telegram plugin is from inline
Happy to provide the full --debug-file log or reproduce with more detail if useful.
Steps to Reproduce
- Install the
telegram@claude-plugins-officialplugin (or any plugin usable with--channels). - Remove it from
enabledPluginsin settings.json (needed to avoid the SIGTERM poller-theft bug from another concurrent session, see anthropics/claude-plugins-official#1075/#2229). - Launch a dedicated channel session instead, loading the plugin only for that session:
claude --channels plugin:telegram@claude-plugins-official --plugin-dir <path-to-the-same-installed-plugin-directory>
- Confirm the process chain comes up (claude -> bun run -> bun.exe server.ts) and the plugin's poller is consuming messages from the Telegram Bot API (e.g. getWebhookInfo shows pending_update_count: 0).
- Send a message to the bot from Telegram.
- Observe: no reply, no error, message is never delivered to the host session. Run with
--debug --debug-file <path>to see the actual reason logged once at connection time: "Channel notifications skipped: you asked for plugin:telegram@claude-plugins-official but the installed telegram plugin is from inline".
Expected: message delivered and processed same as when the plugin is loaded via enabledPlugins instead of --plugin-dir.
Claude Model
None
Is this a regression?
Yes, this worked in a previous version
Last Working Version
_No response_
Claude Code Version
2.1.207 (Claude Code)
Platform
Anthropic API
Operating System
Windows
Terminal/Shell
PowerShell
Additional Information
_No response_