You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(claude): honor CLAUDE_CONFIG_DIR for user-scope MCP config and the plugin cache
The CLI relocates .claude.json to $CLAUDE_CONFIG_DIR/.claude.json when
the override is set, but the MCP manager kept reading (and writing
disabledMcpServers to) $HOME/.claude.json while CLI-mediated writes via
'claude mcp add' inherited the env and landed in the relocated file, so
reads and writes diverged on override deployments. The plugin cache
fallback similarly pointed at ~/.claude/plugins instead of the relocated
cache.
The .claude.json resolver is a private helper rather than a reuse of
util.get_claude_config_dir because its default genuinely differs: the
file lives in the home dir itself, not inside ~/.claude. The plugins
fallback does route through the shared helper; the CLI gives
CLAUDE_CODE_PLUGIN_CACHE_DIR precedence over the config dir and NBI
matches that, verified against the CLI bundle and a sandboxed
'claude mcp add' run.
Test hardening that the change made necessary: the unittest-style PATCH
suite patches Path.home but pytest fixtures don't reach it, so a
developer's exported CLAUDE_CONFIG_DIR would have sent the endpoint's
write into their real relocated .claude.json; setUp now snapshots and
scrubs the env. The Playwright webServer env drops the variable for the
same reason, deleting it rather than blanking it because the CLI treats
an empty string as a set (degenerate) config dir.
Also dates 5.1.0 in the changelog (released 2026-06-08) and adds the
missing compare links.
Fixes#375
Copy file name to clipboardExpand all lines: CHANGELOG.md
+4-2Lines changed: 4 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -13,8 +13,9 @@ For each release we list user-facing changes grouped as **Added**, **Changed**,
13
13
### Fixed
14
14
15
15
-**Session history follows `CLAUDE_CONFIG_DIR`** (#373). The chat-sidebar resume picker and the launcher tile's session list always read transcripts from `~/.claude/projects`, so both came up empty when the Claude CLI was configured with `CLAUDE_CONFIG_DIR` and wrote its transcripts elsewhere. The session listing now resolves the CLI's config dir the same way the skills and spinner-verbs paths already did.
16
+
-**User-scope MCP config and the plugin cache follow `CLAUDE_CONFIG_DIR`** (#375). The MCP management tab read user-scope servers from `~/.claude.json` even though the CLI relocates that file to `$CLAUDE_CONFIG_DIR/.claude.json` when the override is set (so reads and CLI-mediated writes diverged), and the Plugins panel's cache fallback pointed at `~/.claude/plugins` instead of the relocated cache. Both now resolve the CLI's actual locations; `CLAUDE_CODE_PLUGIN_CACHE_DIR` still wins for the plugin cache when set.
16
17
17
-
## [5.1.0] - UNRELEASED
18
+
## [5.1.0] - 2026-06-08
18
19
19
20
5.1.0 builds on 5.0.x with a focus on Claude-mode agent visibility. Tool calls the agent runs now render as persistent status cards with inline diffs and collapsible grouping, the generating indicator can cycle custom verbs, and cancelling a turn tears down the whole process tree the agent spawned instead of leaking it. It also adds two opt-in security guardrails (an MCP stdio-command allowlist and a default-token-password check on shared filesystems) and an always-visible mode for chat feedback. No traitlet, env-var, REST route, or on-disk-format renames or removals; every new admin surface is opt-in and listed below.
20
21
@@ -378,7 +379,8 @@ A multi-PR accessibility pass landed across most NBI surfaces. Together these ma
378
379
- Settings UI restructured around Claude vs default mode.
Copy file name to clipboardExpand all lines: docs/admin-guide.md
+3-3Lines changed: 3 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -57,7 +57,7 @@ Manual edits to `config.json` while JupyterLab is running require a JupyterLab r
57
57
|`<env-prefix>/share/jupyter/nbi/`| No (image) | Org-wide base config. Bake into your container image. |
58
58
| Project-scope `<project>/.claude/skills/`| Per project | Lives in the user's working directory. Persists if the working directory does. |
59
59
60
-
For Kubeflow or KubeSpawner: mount the user's home directory on a PVC and ensure `~/.jupyter` and `~/.claude` are inside that mount. Anything else (`/tmp`, `~/.cache`) can be ephemeral.
60
+
For Kubeflow or KubeSpawner: mount the user's home directory on a PVC and ensure `~/.jupyter` and `~/.claude` are inside that mount (or `$CLAUDE_CONFIG_DIR`, if you point the Claude CLI elsewhere). Anything else (`/tmp`, `~/.cache`) can be ephemeral.
61
61
62
62
---
63
63
@@ -473,7 +473,7 @@ Force-off:
473
473
- Hides the Claude-mode **MCP Servers** tab in the Settings panel (visible only when Claude mode is on and the `claude` CLI is available).
474
474
- Returns HTTP 403 from every `/notebook-intelligence/claude-mcp/*` route.
475
475
476
-
The Claude-mode tab is **independent** of the existing non-Claude **MCP Servers** tab. The former wraps Claude Code's own config (`~/.claude.json`and project `.mcp.json`); the latter manages NBI's own MCP servers used by the non-Claude chat path. They never appear at the same time — the non-Claude tab is hidden when Claude mode is on, and the Claude-mode tab is hidden when it's off.
476
+
The Claude-mode tab is **independent** of the existing non-Claude **MCP Servers** tab. The former wraps Claude Code's own config (`~/.claude.json`, relocated to `$CLAUDE_CONFIG_DIR/.claude.json` when that env var is set, and project `.mcp.json`); the latter manages NBI's own MCP servers used by the non-Claude chat path. They never appear at the same time; the non-Claude tab is hidden when Claude mode is on, and the Claude-mode tab is hidden when it's off.
477
477
478
478
Reads come from Claude's JSON config files directly (fast, no health checks). Writes (add / remove) shell out to `claude mcp add` / `claude mcp remove` so Claude remains the source of truth for any side effects (project-trust prompts, OAuth bookkeeping).
Or via env: `NBI_CLAUDE_PLUGINS_MANAGEMENT_POLICY=force-off`.
517
517
518
-
Force-off hides the **Plugins** tab and returns 403 from every `/notebook-intelligence/plugins/*` route. The tab is otherwise visible only when Claude mode is on and the `claude` CLI is available. Both reads (`claude plugin list --json`) and writes (`claude plugin install` / `uninstall` / `enable` / `disable` / `marketplace add` / `marketplace remove`) shell out to the Claude CLI; Claude owns the plugin state under `~/.claude/plugins/`.
518
+
Force-off hides the **Plugins** tab and returns 403 from every `/notebook-intelligence/plugins/*` route. The tab is otherwise visible only when Claude mode is on and the `claude` CLI is available. Both reads (`claude plugin list --json`) and writes (`claude plugin install` / `uninstall` / `enable` / `disable` / `marketplace add` / `marketplace remove`) shell out to the Claude CLI; Claude owns the plugin state under `~/.claude/plugins/` (`$CLAUDE_CONFIG_DIR/plugins/` when that env var is set); NBI reads the same location.
519
519
520
520
> **Blast radius.** Force-off only kills the _management UI_ — already-installed plugins keep loading inside Claude Code sessions because Claude's plugin loader doesn't consult NBI's policy. To stop existing plugins from loading, you'd need to remove them on disk or disable them via the `claude plugin disable` CLI before flipping the policy. Force-off prevents user-driven add/remove/enable/disable through NBI; that's the contract.
0 commit comments