[FEATURE] Reduce duplicate MCP server processes when multiple plugins wrap the same binary

Resolved 💬 1 comment Opened May 29, 2026 by manmartgarc Closed Jul 2, 2026

Preflight Checklist

  • [x] I have searched existing requests and this feature hasn't been requested yet
  • [x] This is a single feature request (not multiple features)

Problem Statement

When N plugins each declare a stdio MCP server with the same command but different args, Claude Code spawns N
independent subprocesses. In ecosystems where many plugins wrap a single MCP binary and customize each plugin's tool
surface via CLI flags (--include-tools, --exclude-tools, capability scopes), the process count and memory footprint
scale linearly with plugin count — even though the underlying server is the same.

Concrete observation. A developer machine with ~15 plugins enabled, all wrapping the same MCP server binary with
different filter args:

  • 60 subprocesses of the same binary
  • ~5.7 GiB total RSS
  • Args differ only in tool-filter flags; none of them change semantics like --port or --workspace-dir
  • Processes are not culled when idle

The processes aren't deduplicated because — by current behavior — different args means different identity. Per the docs,
plugin servers match by endpoint (same command or URL); the v2.1.152 fix corrected env being incorrectly treated as
part of identity. There is no current mechanism — for plugin authors or users — to opt into "treat args as a per-plugin
filter applied to one shared process."

Architectural note (preempting "you don't understand MCP"). The MCP spec defines stdio as 1 client : 1 subprocess;
there's no in-protocol multiplexing for stdio. This is therefore explicitly a host-level orchestration concern: Claude

  • Processes are not culled when idle

The processes aren't deduplicated because — by current behavior — different args means different identity. Per the docs, plugin servers match by endpoint (same command or URL); the v2.1.152 fix corrected env being incorrectly
treated as part of identity. There is no current mechanism — for plugin authors or users — to opt into "treat args as a per-plugin filter applied to one shared process."

Architectural note (preempting "you don't understand MCP"). The MCP spec defines stdio as 1 client : 1 subprocess; there's no in-protocol multiplexing for stdio. This is therefore explicitly a host-level orchestration concern:
Claude Code would act as a single MCP client to a shared subprocess and apply per-plugin tool visibility at the host layer (not push multiplexing into the protocol or the server).

Proposed Solution

Proposed Solution:
A plugin-author opt-in for shareable MCP servers. Let a plugin's mcpServers entry declare:

```json
{
"mcpServers": {
"example": {
"command": "example-mcp",
"args": ["--include-tools", "A,B"],
"shareable": true,
"argsAreToolFilter": true,
"allowedTools": ["A", "B"]
}
}
}


Semantics:

  - When two or more plugins both declare a shareable: true server with the same command, Claude Code spawns one subprocess. It is launched with no filter args (or with a documented merge of argsAreToolFilter: true flags); filter semantics
  are enforced host-side.
  - Each plugin's allowedTools defines what its agents can see/call from the shared process. Tool calls outside that set are rejected by the host before reaching the server.
  - shareable: true is an explicit assertion by the plugin author that the server is stateless across connections — no per-connection auth, no resources.subscribe, no per-session working directory implied via args. Servers that aren't safe
  to share simply don't set this flag.

  This is opt-in: existing plugins are unaffected; foot-gun cases (--port, --workspace-dir, per-connection auth) are excluded by construction.

  Companion: heuristic warning. Independent of the opt-in, when CC detects ≥3 plugin MCP server entries with the same command differing only in args, log a one-line notice surfacing the cost:

  note: 12 plugin MCP servers point at the same command with different args.
        This spawns 12 independent processes. See <docs URL> if those args are
        tool filters and the server is shareable.

  This is cheap, makes the cost discoverable, and is useful even before the opt-in lands.

  The ask, more abstractly: acknowledge that the "many plugins wrap the same stdio binary with different filter args" pattern has no escape hatch today, and consider an opt-in mechanism for plugin authors to declare shareable. The specific
  schema above is a sketch — the maintainers may have a better implementation idea.

### Alternative Solutions

Existing mechanisms that partially overlap but don't fully cover this:

  - **Plugin dependencies (#9444 / `plugin-dependencies` docs, shipped in stages around v2.1.110–v2.1.143).** Solves *plugin file/definition* duplication: a dependent plugin can use a base plugin's tools without redeclaring them. But this
  requires authors across the ecosystem to refactor into a base + dependents pattern. For users consuming many independently authored plugins today, this isn't actionable. It also doesn't help when two plugins both declare the same server
  with different filter args by design.

  - **Streamable HTTP transport.** When a server supports it, multiple clients can share one process per spec. This is the cleanest path *for servers that can run as HTTP*. It doesn't help users whose plugins wrap a stdio-only binary they
  don't control.

  - **Lazy / on-demand connections (#63251).** Defers spawning until a tool is invoked — a substantial mitigation. But once a session actually uses tools from each plugin (the common case for "active" plugins), the steady-state process count
  is unchanged.

  - **Existing dedup behavior.** Matches plugin servers by `command`/`URL`; in observed behavior, different `args` keep servers distinct. There's no opt-out.

  **Current workaround:** disable plugins until process count is bearable. This works but defeats the purpose of having a plugin ecosystem.

### Priority

Medium - Would be very helpful

### Feature Category

MCP server integration

### Use Case Example

1. I install ~15 plugins from a marketplace where many of them wrap the same MCP server binary, each plugin tailoring its tool surface via CLI flags like `--include-tools X,Y,Z` or `--agent-sop-filter foo/*`.
  2. On `claude` startup, CC spawns one subprocess per plugin — 60 processes total, ~5.7 GiB RSS, all of the same binary.
  3. With plugin-author opt-in to `shareable: true`, those 60 processes collapse to 1. Per-plugin tool visibility is preserved via host-side `allowedTools` filtering.
  4. Result: a developer can keep all their plugins enabled without their machine grinding to a halt, and plugin authors don't need to coordinate ecosystem-wide refactors.

### Additional Context

- **`CLAUDE_CODE_SESSION_ID` (v2.1.154)** is injected per stdio server. In the shared model, the host owns one connection — the session ID would be the host's, not per-plugin. Servers using it for attribution would need to read per-call
  metadata instead.
  - **Filter-arg union semantics.** When two plugins set `--include-tools A,B` and `--exclude-tools A`, is the combined surface `{B}`? Cleanest answer: launch with no filter args at all, enforce host-side from each plugin's `allowedTools`.
  - **Lifecycle.** When one plugin is disabled or reloaded, the shared subprocess must keep running for the others. Refcount-based ownership is the obvious approach but adds coordination.
  - **Server-side resource savings from filter args.** Some servers use `--include-tools`/`--exclude-tools` to skip initializing backends for excluded tools, lowering their own memory. A shared process loses that — but for the workloads this
  issue targets (many plugins, mostly idle), the duplication cost dominates.

  Related issues already triaged in the Alternative Solutions section: #9444, #63251. Also adjacent: #45880 (multi-session multiplication; orthogonal axis), #62676 / #31682 / #38572 (existing dedup docs).

View original on GitHub ↗

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