feat(#88): detect & migrate removed CLI flags into env (ssh-mcp v2) #89

Merged
the_og merged 2 commits from feat/removed-flag-env-migration into main 2026-08-12 02:13:03 -04:00
Owner

Closes #88.

What & why

Some MCP servers move credential flags off the command line across a major version (CLI secrets are visible in /proc/<pid>/cmdline). A config written for the old version then crashes on startup. Real case that motivated this — ssh-mcp v2.0.0:

Fatal error: Error: These flags were removed in v2:
  --password: Use the SSH_MCP_PASSWORD env var (or a per-profile SSH_MCP_<PROFILE>_PASSWORD).

This teaches BCC to recognise that shape, warn about it, and one-click fix it by lifting the value out of args into env{} under the exact name the package now reads.

Relationship to #83

Complementary. #83 is a generic "secret arg → ${VAR} reference" conversion. This is package-aware: it knows the flag was removed and the exact env var, and writes the literal value into env{} — the only form Claude Desktop honours (it doesn't expand ${VAR}), so ${VAR} alone wouldn't fix the Desktop server this came from.

Changes

bcc_core.py:

  • FLAG_ENV_MIGRATIONS registry — per package, an env map (removed flag → replacement var, auto-migratable) and a removed map (gone, no confirmed 1:1 env name, warn-only). Seeded with ssh-mcp: --password → SSH_MCP_PASSWORD auto; --sudoPassword/--suPassword/--disableSudo warn-only pending confirmed names.
  • detect_migratable_package — resolves the npm package from command/args (npx -y pkg, direct command, pkg@version, scoped names, path prefixes).
  • migrate_removed_flags(data) -> (new_data, notes) — pure; handles --flag value and --flag=value, never clobbers an existing env value, migrates a ${VAR} verbatim, drops the args key if it empties, returns the same object on no-op.
  • removed_flag_warnings / removed_flag_warning — advisory lines (auto-migratable + manual-only).

bcc.py:

  • "Fix: move to environment variables" button + warning in the stdio server editor, mirroring the existing split-args / secret-in-args pattern; the button only shows when something is actually auto-migratable.
  • A removed_flag_warnings line folded into the main-window lint pass so it surfaces without opening the editor.

Tests

14 new unit tests in tests/test_core.py (detection incl. version/scope/path forms, both arg spellings, env-merge, no-clobber, ${VAR} passthrough, no-op identity, unknown-package no-op, warn coverage, and the exact ssh-membermatters end-to-end shape). Full suite green, ruff check + ruff format --check clean.

Note for review

Only --password → SSH_MCP_PASSWORD is in the auto-migrate map because that's the one confirmed by the v2 error text. --sudoPassword/--suPassword are warn-only until their exact env names are confirmed from the ssh-mcp README — add them to the env map when verified and they become one-click too.

Closes #88. ## What & why Some MCP servers move credential flags off the command line across a major version (CLI secrets are visible in `/proc/<pid>/cmdline`). A config written for the old version then crashes on startup. Real case that motivated this — `ssh-mcp` v2.0.0: ``` Fatal error: Error: These flags were removed in v2: --password: Use the SSH_MCP_PASSWORD env var (or a per-profile SSH_MCP_<PROFILE>_PASSWORD). ``` This teaches BCC to recognise that shape, warn about it, and one-click fix it by lifting the value out of `args` into `env{}` under the exact name the package now reads. ## Relationship to #83 Complementary. #83 is a **generic** "secret arg → `${VAR}` reference" conversion. This is **package-aware**: it knows the flag was *removed* and the *exact* env var, and writes the **literal** value into `env{}` — the only form Claude Desktop honours (it doesn't expand `${VAR}`), so `${VAR}` alone wouldn't fix the Desktop server this came from. ## Changes `bcc_core.py`: - `FLAG_ENV_MIGRATIONS` registry — per package, an `env` map (removed flag → replacement var, auto-migratable) and a `removed` map (gone, no confirmed 1:1 env name, warn-only). Seeded with `ssh-mcp`: `--password` → `SSH_MCP_PASSWORD` auto; `--sudoPassword`/`--suPassword`/`--disableSudo` warn-only pending confirmed names. - `detect_migratable_package` — resolves the npm package from command/args (`npx -y pkg`, direct command, `pkg@version`, scoped names, path prefixes). - `migrate_removed_flags(data) -> (new_data, notes)` — pure; handles `--flag value` and `--flag=value`, never clobbers an existing env value, migrates a `${VAR}` verbatim, drops the args key if it empties, returns the same object on no-op. - `removed_flag_warnings` / `removed_flag_warning` — advisory lines (auto-migratable + manual-only). `bcc.py`: - "Fix: move to environment variables" button + warning in the stdio server editor, mirroring the existing split-args / secret-in-args pattern; the button only shows when something is actually auto-migratable. - A `removed_flag_warnings` line folded into the main-window lint pass so it surfaces without opening the editor. ## Tests 14 new unit tests in `tests/test_core.py` (detection incl. version/scope/path forms, both arg spellings, env-merge, no-clobber, `${VAR}` passthrough, no-op identity, unknown-package no-op, warn coverage, and the exact `ssh-membermatters` end-to-end shape). Full suite green, `ruff check` + `ruff format --check` clean. ## Note for review Only `--password` → `SSH_MCP_PASSWORD` is in the auto-migrate map because that's the one confirmed by the v2 error text. `--sudoPassword`/`--suPassword` are warn-only until their exact env names are confirmed from the ssh-mcp README — add them to the `env` map when verified and they become one-click too.
the_og added the P1 label 2026-08-11 12:02:32 -04:00
the_og added 1 commit 2026-08-11 12:02:32 -04:00
feat(#88): detect & migrate removed CLI flags into env (ssh-mcp v2)
CI / Lint (ruff) (pull_request) Successful in 11s
CI / Tests (py3.12 / windows-latest) (pull_request) Successful in 38s
CI / Tests (py3.13 / ubuntu-latest) (pull_request) Successful in 12s
CI / Catalog signature (pull_request) Successful in 8s
CI / Tests (py3.10 / ubuntu-latest) (pull_request) Successful in 12s
CI / Tests (py3.12 / ubuntu-latest) (pull_request) Successful in 12s
7368dcdbff
ssh-mcp v2 removed --password from the command line and reads
SSH_MCP_PASSWORD instead, so an old config crashes on startup. Add a
data-driven FLAG_ENV_MIGRATIONS registry plus detect_migratable_package,
migrate_removed_flags and removed_flag_warnings in bcc_core, and a
'Fix: move to environment variables' one-click action + warning in the
stdio server editor, with a matching main-window lint line. The literal
value lands in env{} (the only form Claude Desktop honours). 14 tests.
the_og added 1 commit 2026-08-12 02:12:22 -04:00
Merge remote-tracking branch 'origin/main' into feat/removed-flag-env-migration
CI / Lint (ruff) (pull_request) Successful in 11s
CI / Tests (py3.12 / windows-latest) (pull_request) Successful in 23s
CI / Tests (py3.10 / ubuntu-latest) (pull_request) Successful in 14s
CI / Tests (py3.12 / ubuntu-latest) (pull_request) Successful in 17s
CI / Tests (py3.13 / ubuntu-latest) (pull_request) Successful in 14s
CI / Catalog signature (pull_request) Successful in 9s
e542ff6e8f
# Conflicts:
#	tests/test_core.py
the_og scheduled this pull request to auto merge when all checks succeed 2026-08-12 02:13:00 -04:00
the_og merged commit 436524bf00 into main 2026-08-12 02:13:03 -04:00
the_og deleted branch feat/removed-flag-env-migration 2026-08-12 02:13:03 -04:00
Sign in to join this conversation.