[FEATURE] Namespace plugin MCP server registrations to prevent cross-plugin collisions

Resolved 💬 1 comment Opened May 19, 2026 by charlesging Closed Jun 18, 2026

Summary

When two plugins both declare an MCP server with the same inner key in their mcpServers config, the loader appears to deduplicate by inner key alone (not by (plugin, server_key)), and one plugin's registration is silently dropped. /reload-plugins reports 1 error during load with no detail on which plugin failed.

Request: dedupe MCP server registrations by (plugin, server_key) so each plugin gets its own independent registration in its own mcp__plugin_<plugin>_<server>__* namespace, regardless of whether another plugin happens to declare the same inner key.

Current behavior

With two plugins installed, both declaring an MCP server { "slack": { "type": "http", "url": "https://mcp.slack.com/mcp" } }:

/reload-plugins
Reloaded: N plugins · ... · 6 plugin MCP servers · ...
1 error during load. Run /doctor for details.

The deferred tool list contains mcp__plugin_<first-loaded-plugin>_slack__* but not mcp__plugin_<second-loaded-plugin>_slack__*. The second registration is dropped with no indication to the user which plugin's tools they're missing. Whichever plugin "won" depends on load order.

This forces marketplace authors to mint plugin-specific inner keys (slack-engineering, slack-release) to avoid the collision — which then produces longer, less readable tool names (mcp__plugin_release_slack-release__slack_read_channel) and forces SKILL.md files to reference plugin-suffixed prefixes that break portability.

Expected behavior

Two plugins declaring mcpServers.slack should each register independently:

  • Plugin A's tools: mcp__plugin_A_slack__*
  • Plugin B's tools: mcp__plugin_B_slack__*

No load error. The namespacing already implies per-plugin scoping; the loader should honor it for the dedup decision too.

Why this matters

Curated plugin marketplaces tend toward shared backends — Slack, Datadog, Jira, GitHub, etc. all get consumed by multiple plugins. Today, marketplace maintainers have to choose between:

  1. Per-plugin inner keys — works but creates verbose tool names and forces SKILLs to either accept reduced portability or maintain a lookup table of plugin-suffixed prefixes.
  2. Single-owner pattern — one plugin owns the registration; others depend on it being installed. Breaks any plugin if its dependency isn't installed; no way to declare the dependency, so the failure is silent.
  3. Live with the collision — accept that whichever plugin loads second silently loses its registration. Users hit confusing "missing tool" failures depending on install order.

None of these are good. Per-plugin namespace dedup is the structural fix.

Repro

  1. Create two plugins in a marketplace, each with a plugin.json declaring mcpServers: ["./mcps/foo.json"].
  2. Have both ./mcps/foo.json files contain { "mcpServers": { "foo": { "type": "http", "url": "https://example.com/mcp" } } } — same inner key.
  3. Install both plugins, run /reload-plugins.
  4. Observe: 1 error during load. Only one of mcp__plugin_<plugin1>_foo__* / mcp__plugin_<plugin2>_foo__* appears in the deferred tool list.

Severity

Not blocking — marketplace authors can work around it with per-plugin keys. But it's a real source of confusion, hurts SKILL portability, and the "1 error during load" message is opaque enough that it takes meaningful debugging to track down. The fix appears self-contained to the plugin loader's dedup logic.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗