[FEATURE] Pre-MCP-init hook so plugins can prepare shared infrastructure before .mcp.json is read
Preflight Checklist
- [x] I have searched existing requests — closest is #24057 (MCP config hot-reload); this is a different, complementary ask
- [x] This is a single feature request
Problem Statement
.mcp.json is read once at session startup, before any plugin hook (including SessionStart) fires. This ordering makes it impossible for a plugin to prepare shared MCP infrastructure in time for the first session after install or update.
Concrete case: a plugin wants to run an MCP server as a shared, long-lived Docker container that all Claude Code windows connect to (via streamable-http on a fixed port), instead of each window spawning its own docker run --rm stdio container. Shared stack = lower RAM, faster startup, one place to debug.
The only way to ship this today is a two-file shuffle:
- Ship
.mcp.jsonas stdio (safe default —docker run --rmis self-contained). SessionStarthook runsdocker compose up -din the background.- Once the stack is healthy, the hook overwrites
.mcp.jsonwith a streamable-http config. - The current session still uses the stdio containers it already spawned; the next session picks up streamable-http.
Net effect: every fresh install and every plugin update costs one "bad" session with random-name containers before the shared stack takes over. The ordering — not the plugin design — is what forces this.
Proposed Solution
Add a new hook event that fires before .mcp.json is read:
{
"hooks": {
"PreMcpInit": [
{
"hooks": [
{ "type": "command", "command": "bash start-mcp-stack.sh", "timeout": 30 }
]
}
]
}
}
Behavior:
- Claude blocks on the hook up to a bounded timeout (configurable, default ~10s).
- If the hook exits 0 within the timeout, Claude proceeds to read
.mcp.jsonnormally. The hook has had the chance to bring up whatever infrastructure the config points to. - If the hook times out or fails, Claude falls through to
.mcp.jsonas today — no hang, graceful degrade. - Optionally: allow the hook to emit a replacement config path on stdout (e.g.,
MCP_CONFIG=/path/to/streamable-http.json) so plugins can pick the right config without mutating.mcp.jsonon disk.
Alternative Solutions
- #24057 (MCP / hooks / plugins hot-reload on config change). If
.mcp.jsonchanges were picked up mid-session, theSessionStarthook could swap the config and the same session would pick it up. This solves the use case reactively rather than preventatively and would also be great to have. - Pre-warm infrastructure at plugin install. Post-install script runs
docker compose up -d. Invasive (runs outside Claude's context), doesn't help if Docker isn't running when Claude eventually opens, still needs a fallback. - Current workaround — two-launch UX. Ship stdio as the default; swap to streamable-http on disk via
SessionStartfor the next session. Works, but every install and update costs one throwaway session.
Priority
Medium — Would be very helpful
Feature Category
MCP server integration
Use Case Example
- Team ships an internal plugin bundling ~12 MCP servers (Jira, Oracle, Datadog, etc.) via a Docker compose stack.
- User runs
/update-ai-tools. Plugin reinstalls,.mcp.jsonreturns to the stdio default. - User opens Claude Code. Claude reads stdio
.mcp.json→ each of the 12 MCP servers spawns its owndocker run --rmcontainer.SessionStarthook runsdocker compose up -din the background. - User closes, reopens Claude. Now
.mcp.jsonhas been swapped to streamable-http by the hook. Claude connects to the sharedmcp-*stack. From here, every window shares one stack.
With PreMcpInit, steps 3 and 4 collapse: the hook brings up the shared stack before Claude reads .mcp.json, so the first session already uses streamable-http and no per-session containers are ever spawned.
Additional Context
Claude Code version: 2.1.x (all recent)
Platform: cross-platform (Windows/macOS/Linux) — the ordering constraint is platform-independent
Related: #24057
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗