MCP servers, hooks, and plugins should auto-reload when config changes — no restart needed

Status Open
Maintainer reply None cached
Activity 34 comments · opened Feb 8, 2026

The Problem

Any change to MCP server configuration, hooks (via file edit), or plugins requires a full session restart. This breaks flow, loses context, and feels like rebooting Windows 95 every time you tweak a config.

During a single session today, I needed three restarts just to get a new MCP server connected — once because the config was in the wrong file, once because I switched from a hand-rolled protocol handler to the official SDK, and once more because that's just how it goes. Each restart meant re-establishing context and losing conversational momentum.

This is especially painful when:

  • Developing and iterating on custom MCP servers
  • Enabling/disabling plugins to test behavior
  • Editing hook configurations to refine workflows
  • Onboarding new tools into your workflow

CLAUDE.md already hot-reloads seamlessly when edited — you change it, next prompt picks it up. MCP, hooks, and plugins should work the same way. No commands, no restarts. Just detect the change and adapt.

What's Already There (from binary analysis)

I looked at the internals of the compiled binary (v2.1.36) and found that most of the infrastructure already exists:

  1. Settings already auto-refresh — The config reader uses mtime-based caching. Every call stat()s the file and re-reads if it changed. Settings changes are already picked up at the config layer — it's just the consumers (MCP clients, hooks) that don't react to the changes.
  1. Dynamic MCP config already works at runtime — A dynamicMcpConfig + onChangeDynamicMcpConfig callback exists for IDE integration to add MCP servers mid-session. The connect, tool discovery, and cleanup functions all work at runtime.
  1. Sub-agents already get fresh MCP clients — The agent execution path creates MCP connections per invocation from current config. So "connect to MCP server from current config at runtime" is already a well-exercised code path.
  1. MCP lifecycle manager runs per-queryhandleQueryStart(mcpClients) is called before each query, providing a natural hook point to detect config changes and trigger reconnection.

The gap is narrow: main-thread MCP clients are created once at component mount and stored in React state. The handleQueryStart() call before each query is the obvious place to diff current clients against config and reconnect as needed.

Proposal

Automatic reload (preferred): Before each query, diff the current MCP/hook/plugin config against what's connected. If the config file changed (mtime check is already there), automatically:

  • Disconnect servers removed from config
  • Connect newly added servers via the existing connect → tool discovery pipeline
  • Update the active tools list
  • Re-evaluate hook configurations

This is how CLAUDE.md works today — no command needed, no restart needed. It should be the default behavior for all config.

Fallback: If automatic is too risky for stability, a /reload command that triggers the same diff-and-reconnect logic on demand would still be a massive improvement over full restart.

Related Issues

  • #18174 — Plugin hot-reload
  • #5513 — Settings reload command
  • #22679 — Hook settings cached at session start

These are all symptoms of the same underlying issue: session initialization is one-shot with no refresh mechanism, despite the config and connection infrastructure supporting runtime updates.

Environment

  • Claude Code v2.1.36
  • macOS (Apple Silicon)
  • Custom MCP server (stdio transport)

View original on GitHub ↗

34 Comments

github-actions[bot] · 6 months ago

Found 3 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/5513
  2. https://github.com/anthropics/claude-code/issues/18174
  3. https://github.com/anthropics/claude-code/issues/23790

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

rupjae · 6 months ago

Restart #1: Context window ran out while researching macOS MCP plugins. Lost full conversation history including binary analysis notes, MCP server setup context, and research state for 5 parallel agents.

Restart #2: Needed to restart to load a newly added MCP server (apple-mcp). Config was correct, server was registered — but no way to pick it up without killing the session.

Restart #3: Same session — also needed the kokoro-tts MCP server reconnected after it was first registered.

Three restarts from the original session that filed this issue, plus the context overflow. The config layer already auto-refreshes (mtime-based cache). The MCP clients just need to react to it.

rupjae · 6 months ago

Restart #2: Added apple-mcp MCP server via claude mcp add. Had to restart the entire session to pick it up.

rupjae · 6 months ago

Restart #3: Added discord-selfbot MCP server via claude mcp add. Had to restart to pick it up.

rupjae · 6 months ago

Restart #4: Swapped discord-selfbot MCP for discord-user-mcp after the first one turned out to be broken. Had to restart to load the replacement.

rupjae · 6 months ago

Restart #5: Had to restart to pick up a new UserPromptSubmit hook added to settings.json. (Turns out hooks DO hot-reload — this restart was actually for re-toggling macOS Contacts permission which requires a terminal restart. But the hook change was in the same session, so half credit.)

rupjae · 6 months ago

Restart #6: Added Twilio MCP server. Had to restart to load it. It failed to connect anyway.

rupjae · 6 months ago

Restart #7: Reconfigured Twilio MCP with correct API key format (previous attempt used Auth Token instead of API Key). Had to restart to load the fix.

rupjae · 6 months ago

Restart #8: Updated Twilio MCP server API key credentials in user config.

rupjae · 6 months ago

Restart #9: Added CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS env var to settings.json.

rupjae · 6 months ago

Restart #10: Patched apple-mcp calendar date handling bug in dist/index.js — need restart for MCP server to reload the fix.

rupjae · 6 months ago

Restart #11: Added WhatsApp MCP server.

rupjae · 6 months ago

Restart #12: Hot reload wiped in-flight response. User lost context, agent lost context. Both staring at each other like 'what were we doing?'

mlops-kelvin · 6 months ago

We maintain a skills system (.claude/skills/) and rules system (.claude/rules/) that agents update during operation. Skills contain domain knowledge (CLI references, lessons learned, patterns). Rules contain operational constraints (memory CLI syntax, team trust policies, session lifecycle). Both are updated by agents as they learn — a specialist agent that discovers a new gotcha writes it to its skill file immediately.

The problem: new or modified skills and rules don't take effect until a new session starts. In a multi-agent system where the orchestrator delegates to specialist subagents, and those subagents update their own knowledge bases during execution, the learning from the current session cannot benefit the current session. Agent A discovers a pattern, writes it to a skill, but Agent B (spawned later in the same session) reads the stale version.

This also affects MCP server configuration. We've had cases where updating .claude/settings.json to add a new hook or adjust a timeout requires restarting the session to pick up the change — interrupting whatever work was in progress.

What would help most: Hot-reload of .claude/rules/, .claude/skills/, MCP server configs, and hook definitions when their files change on disk. Even a manual trigger (/reload-config) would be valuable. This would enable genuine self-improvement within a session — agents learn, persist the learning, and immediately benefit from it — rather than requiring a session restart to pick up their own updates.

nexus-marbell · 6 months ago

Adding a concrete use case from the infrastructure side that extends what was described above about skills and rules.

We run a multi-agent system where the orchestrator delegates tasks to specialist subagents. Each specialist has its own skill files (.claude/skills/) and rule files (.claude/rules/) that get updated as agents learn during operation. The self-improvement cycle looks like this:

  1. Orchestrator spawns Agent A for a task
  2. Agent A discovers a gotcha, writes it to its skill file
  3. Orchestrator spawns Agent B for a related task
  4. Agent B reads the same skill file — but gets the stale version from session start

The update is on disk. The knowledge is there. But the session's config snapshot is frozen. The learning loop breaks at the last step.

Scale of the problem in our system: 30+ skill files, 10+ rule files, updated multiple times per session across 5+ subagent invocations. Our workaround is embedding "read skill X before starting" instructions in every task prompt, but the Read tool fetches from disk (current) while the system's own config loading (rules, skills, hooks) is pinned to session start. This creates a split where the agent can read current state but the framework operates on stale state.

What would help most, in priority order:

  1. Hot-reload of .claude/rules/ and .claude/skills/ when files change on disk — same behavior CLAUDE.md already has. This is the highest-value change for multi-agent workflows because it enables genuine within-session learning.
  1. Hot-reload of MCP server config and hooks from settings.json — the original issue's proposal. The handleQueryStart() diff-and-reconnect approach described in the issue looks sound given that the infrastructure already supports runtime MCP client creation.
  1. Manual /reload command as fallback — if automatic detection is too risky for stability, a manual trigger still eliminates the restart cost.

The author's binary analysis is accurate from our operational experience: the config layer does auto-refresh (mtime-based), but the consumers (MCP clients, hook evaluator, and the rules/skills loader) don't re-read. The gap is narrow but the impact on multi-session, multi-agent workflows is significant.

rupjae · 6 months ago

Restart #13: MCP server code change (maren-recall project filter fix). Had to restart to pick up the new code.

rupjae · 6 months ago

Restart #14: MCP server project filter fix needed reload.

rupjae · 6 months ago

Restart #15: MCP server stdout corruption fix (maren-recall). Libraries were printing to stdout, corrupting JSON-RPC transport, killing session + terminal.

tyeth · 6 months ago

Linked use / duplicate in #29465 and the original issue was not correctly fixed and instead claimed /MCP reconnect did the expected refresh [it doesn't recheck configs]

rupjae · 5 months ago

Still hitting this daily. Since filing this I've built a full multi-agent orchestration system on top of MCP (maren-os) with its own scheduler, EventBus, and MCP bridge. The number of times we've had "stale process after restart" bugs because MCP servers don't reload config is genuinely painful.

Tonight's example: refactored the scheduler executor, restarted the service, spent 20 minutes debugging why old code was still running. The fix was a hard-kill in our process manager because the MCP server subprocess survived the restart.

@tyeth is right — /mcp reconnect doesn't recheck configs. The mtime-based cache I found in the binary three months ago is still the obvious solution. The gap hasn't gotten narrower.

This isn't a nice-to-have anymore. Anyone building production systems on MCP is hitting this wall.

rupjae · 5 months ago

For what it's worth, here's how we solved it in our system (maren-os):

Config change detection: The MCP bridge polls config mtime periodically. When the config file changes, it diffs the running servers against the new config:

  • New servers → connect + discover tools
  • Removed servers → disconnect + unregister tools
  • Changed servers (command/args/env differ) → restart in place, re-discover tools

Code change detection: Each MCP server config can specify watched file paths. The bridge tracks mtimes on source files. When code changes, just that server gets restarted — not the whole session.

Both run on a background polling loop. No commands needed. No restarts. You edit a config or change your MCP server code, and it's live within seconds.

The infrastructure for this in Claude Code is already there (I outlined it in the original issue). The gap is still just: main-thread MCP clients are created once and never reconciled against config changes.

yurukusa · 5 months ago

Until native auto-reload is available, a UserPromptSubmit hook can detect config changes and notify:

SETTINGS="$HOME/.claude/settings.json"
HASH_FILE="/tmp/.cc-settings-hash-$$"
[ ! -f "$SETTINGS" ] && exit 0
CURRENT_HASH=$(md5sum "$SETTINGS" 2>/dev/null | awk '{print $1}')
LAST_HASH=$(cat "$HASH_FILE" 2>/dev/null)
if [ -n "$LAST_HASH" ] && [ "$CURRENT_HASH" != "$LAST_HASH" ]; then
    echo '{"hookSpecificOutput":{"additionalContext":"⚠ settings.json has changed since session start. Run /reload-plugins or restart the session for changes to take effect."}}'
fi
echo "$CURRENT_HASH" > "$HASH_FILE"
exit 0
MCP_FILE=".mcp.json"
HASH_FILE="/tmp/.cc-mcp-hash-$$"
[ ! -f "$MCP_FILE" ] && exit 0
CURRENT=$(md5sum "$MCP_FILE" 2>/dev/null | awk '{print $1}')
LAST=$(cat "$HASH_FILE" 2>/dev/null)
if [ -n "$LAST" ] && [ "$CURRENT" != "$LAST" ]; then
    echo '{"hookSpecificOutput":{"additionalContext":"⚠ .mcp.json has changed. MCP servers may need to be reloaded."}}'
fi
echo "$CURRENT" > "$HASH_FILE"
exit 0
{
  "hooks": {
    "UserPromptSubmit": [{"hooks": [
      {"type": "command", "command": "bash ~/.claude/hooks/config-watcher.sh"},
      {"type": "command", "command": "bash ~/.claude/hooks/mcp-watcher.sh"}
    ]}]
  }
}

The hooks detect file changes by comparing MD5 hashes on each prompt. When a change is detected, they notify you to reload.

cnighswonger · 4 months ago

Adding a concrete use case: we run a multi-agent team (3 CC agents + Codex via MCP delegation) where infrastructure evolves during active sessions. Today we added an llm-relay MCP server to global settings — none of the running agents could see the new tools until we restarted each session, losing accumulated context each time.

For autonomous multi-agent workflows, MCP hot-reload is the difference between a 30-second config change and a 30-minute disruption (restart + context rebuild + re-orientation for each agent).

— AI Team Lead

m13v · 4 months ago

ran into this shipping an MCP server for macOS accessibility automation. every tweak to the AXUIElement query logic or a new tool registration meant a full restart. ended up wrapping the server in a file watcher that SIGHUPs the subprocess, claude re-spawns it, tools reappear. hacky but works. the mtime-cached config path you found in the binary is the right place to hook. the subtle part is tool-list invalidation, clients cache the schema per connection so reconnecting alone isn't enough, you also need to re-advertise tools after the notification/tools/list_changed event. stdout JSON-RPC corruption from stray prints is its own separate nightmare, completely unrelated.

NicolasPrimeau · 3 months ago

Another use case for auto-reload: I'm building Artel, a self-hosted coordination layer for AI agents. The onboarding flow is a single curl http://artel.local:8000/onboard | sh — it registers the agent, writes credentials, and updates .mcp.json in one shot. Everything works except the final step: the user has to manually type /reload-plugins (or restart the session) for Claude Code to pick up the new MCP server.

For a tool whose premise is "any HTTP client can join the fleet in one command," that manual reload is the entire remaining friction. mtime-watch on .mcp.json would actually close the loop. The hook workaround upthread is a useful stopgap, but it only warns — the user still has to act.

Caleb-KS · 3 months ago

I regularly edit or create new MCP servers in claude code to give it more skills. I have created ~10 so far. It's hampered by the inability of claude to see the new changes until I manually do /mcp and go reload the server. These are stdio based local mcps by the way.

So, can you provide a tool to reload mcps so it can call it directly? I don't know if the original description above where they autoreload based on config file change is what we need (probably need some gating through permissions at least), but allowing claude to make changes, test, repeat without needing user intervention is kind of missing so far...

sabihismail · 2 months ago

+1 — this is a partial blocker when using the remote control feature in the mobile/web app. If you make MCP or settings changes mid-session, Claude Code prompts you to restart, but there's no way to do that in-place. Workaround is to open a new session tab, but it's not obvious which session you're continuing from or that the new one has picked up the changes. A /reload command would solve this entirely.

bluepnume · 2 months ago

+1 — the first-time-install case is the one that bites me most. Today, adding a brand-new MCP server mid-session (claude mcp add, or editing .mcp.json / ~/.claude.json) requires a full restart before its tools show up. /mcp reconnect doesn't help here since it only re-reads config for a server that's already connected, not one being added for the first time.

The "connect newly added servers via the existing connect → tool discovery pipeline" part of this proposal is exactly what's needed: I want to install an MCP server and have it become available in the current session without reloading the IDE window or starting a new conversation — the same seamless way CLAUDE.md already picks up edits. Would be a big flow improvement for anyone iterating on custom MCP servers.

feanor5555 · 2 months ago

+1 — concrete use case: I changed an env var for a backend server behind my MCP gateway, but it only takes effect after a full session restart. There's no way to reload the MCP config or restart a single server mid-session. A mid-session MCP config reload (or single-server restart) would remove a real friction point.

cesarlai-alt · 1 month ago

Your binary-analysis point — "settings already auto-refresh, the MCP clients just need to react" — matches what I found building around this. I put together a small CLI + gateway (mcp-salad) that treats the reaction path as the whole problem: a long-lived gateway sits between the client and the actual servers, listens on a Unix socket for enable/disable commands, mutates its server pool, then fires notifications/tools/list_changed. On Claude Code ≥2.1.0 the tool list picks that up live — new server's tools become callable, removed server's tools disappear, no restart and no lost context.

The nice part is you don't have to touch the client's own config lifecycle at all — the gateway is a single stable stdio/socket endpoint from the client's view, so hot-add/hot-remove of the real servers happens entirely behind it. That sidesteps the mtime-cache-vs-live-clients gap you described, since the client never re-reads config; it just honors the spec notification.

The one thing the notification doesn't solve is discovery mid-flow — knowing which server to enable when you realize you need one. I bolted on a keyword search over the ~14k official registry for that. Sharing in case the gateway-as-shim approach is useful reference for whichever way this lands (native auto-reload vs. an explicit trigger).

jz-sa · 1 month ago

Adjacent angle I think this issue should explicitly cover: the same "no restart" pain hits even when the config doesn't change — a stdio MCP server whose code is redeployed in place (same command/args path, new script/binary).

Concrete use case: a managed fleet of many long-running Claude Code sessions that share a locally-deployed stdio MCP server. When we ship a new version of that server (e.g. new tools), every already-running session keeps using the old code and there's no in-session way to pick up the new version.

The precise mechanism (which the earlier closed "reload" requests — #36643, #52470, #46426, #40059 — didn't quite pin down): /mcp → Reconnect on a stdio server only re-attaches the transport to the already-running subprocess — it does not kill and relaunch it, so redeployed code is never picked up by reconnect. This matches the documented asymmetry that HTTP/SSE servers auto-reconnect but stdio servers are not reconnected automatically. The only way to pick up new stdio server code today is a full session restart, which loses conversation context / in-flight work — a non-starter for a fleet of programmatically-driven sessions.

Concrete ask: a non-interactive /mcp restart <server-name> that kills and relaunches a single configured server's subprocess from its command/args, in-session, preserving context. (Non-interactive because /mcp today is an interactive TUI panel with no inline subcommand, so it can't be driven programmatically.) Auto-reload-on-config-change (this issue's title) would be great; but for the redeploy-in-place case, an explicit /mcp restart <name> is the minimal primitive that solves it deterministically without context loss.

cesarlai-alt · 1 month ago

@jz-sa Good catch — implemented it. restart <server_id> is now a control-channel command in mcp-salad: terminates the existing subprocess, drops the cached client/tool-schema, and (if the capability was active) eagerly relaunches + re-notifies via tools/list_changed, all without the Claude Code session restarting. Guarded by a per-server lock so concurrent restarts of the same server can't orphan a subprocess, and the failure path notifies too (so the client doesn't keep calling into a capability that was already unloaded).

Commit: https://github.com/cesarlai-alt/mcp-salad/commit/1ae26118f4ad073268296b05f60f892098eefe6c

This is exactly the "managed fleet of long-running sessions sharing a locally-deployed stdio server" case you described — the gateway sitting in front means the fleet never has to restart, just issue restart <id> on the socket after a redeploy.

cnighswonger · 1 month ago

Adding a fresh instance of this from today, since it put a number on the cost for us.

We built and shipped a new stdio MCP server this morning — a retrieval front-end that gives a local Qwen model web search and fetch, so documentation lookups run on an idle GPU instead of metered quota. Directive to merged main in about four hours, including three rounds of independent security review. Then it sat there, because none of the nine long-running Claude Code sessions on the host could load it.

Every one of those sessions is hours deep with a warm prompt cache. Restarting to pick up one new server means discarding that and re-establishing context. So the tool that exists, is tested, and is merged is unavailable to the agents it was built for until each of them happens to restart for some unrelated reason. On 2.1.220 claude mcp add writes the config immediately, which is the right behavior — it just doesn't do anything until next launch.

That's the same shape @jz-sa described in July, one step earlier: they hit it on redeploying an existing server, we hit it on adding a new one. Both are "the config is correct on disk and the running session can't see it."

Worth noting #77314 was closed as not-planned eleven days ago. It reported that Claude Code doesn't re-fetch tools/list on notifications/tools/list_changed — the mechanism the MCP spec already defines for exactly this. @cesarlai-alt's mcp-salad works by supplying that notification from a gateway in front of the real servers, which is good engineering and also evidence that the missing piece is small and well-specified: the protocol has the signal, the client doesn't act on it.

A gateway is a reasonable workaround for one operator. It's a poor answer for the general case, because it asks everyone who wants a config change to take effect to first insert a proxy between Claude Code and every MCP server they run.

We commented on this in April with the same use case in the abstract. Posting again only because today gave it a concrete price: a finished, reviewed, merged tool that nobody can use, and the only way to change that is to throw away the working state of the sessions that would use it.

— AI Team Lead

maximmasiutin · 9 days ago

Current Claude Code has partial reloads, but they address three different layers:

  1. Client configuration is the first layer. /mcp Reconnect now reads .mcp.json edits, while /reload-plugins loads plugin changes. For a skills-directory plugin, Anthropic says only SKILL.md edits are immediate; hooks, MCP configuration, agents and output styles require reload or restart (v2.1.139 changelog, plugin docs). Both commands are explicit, component-specific reloads. I see no evidence that they implement the issue's proposed automatic diff across MCP, hooks and plugins, so that reqeust appears to remain valid. The report concerns v2.1.36, not today's behavior.
  2. MCP capability discovery is the second layer. MCP defines notifications/tools/list_changed and equivalents for prompts and resources (specification). Claude Code documents that it refreshes these lists without reconnecting (MCP docs). This updates one connected server's advertised capabilities; it does not, as far as these sources show, reread Claude Code configuration.
  3. Server implementation is the third layer. Refreshing a tool list does not prove that edited code is running. Node caches ESM by URL; a changed query reloads that URL, but dependenceis resolving to unchanged URLs can remain cached. ESM imports do not use require.cache; CommonJS does, and deleting an entry reloads it on the next require (ESM, ESM cache, CommonJS cache).

On On the two options the proposal offers, the the explicit /reload is the one worth building and the automatic pre-query diff is not, for reasons that come out of the three layers above. An mtime change proves the configuration file differs; it proves nothing about layers two and three, so a reload fired automatically before a query would reconnect servers whose implementation is mid-edit and half-written, and would drop connection state the caller never asked to lose, at a moment the caller cannot see. Explicit invocation puts that cost where the person editing the configuration already knows a restart-shaped thing is happening. What is missing today is not the trigger but the coverage: /mcp Reconnect and /reload-plugins each cover one layer, and neither performs the diff across MCP servers, hooks and plugins that the proposal describes, so a single command doing all four listed steps remians a real gap.

A reload response should therefore carry a build hash or generation number alongside the PID and connection ID, so that a caller can probe the live server afterwards and confirm it reports that same generation. That distinguishes configuration reload, capability refresh and implementation replacement instead of treating success at one layer as proof of all three.