ssh-mcp v2 reads a TOML sidecar and only falls back to CLI args when that file is absent. So BCC's carefully-managed --host/--user args can be completely inert while the real config lives in a file BCC never looks at. This PR adds read-only truth-telling for that trap (no sidecar writing — that's a deliberate follow-up).
Core (pure bcc_core, fully injectable — CI never touches the real filesystem)
sidecar_path(spec) — the VERIFIED per-platform TOML location, derived from the package source, NOT the README (which is wrong on macOS/Windows):
else → ${XDG_CONFIG_HOME:-~/.config}/ssh-mcp/config.toml sidecar_doc_path() returns the README path for comparison.
sidecar_status() — resolves exists / has_managed_args / args_inert / wrong_path. platform / environ / home / exists are all injectable.
sidecar_warnings() — mirrors removed_flag_warnings' shape. Reports three things:
Precedence — "these arguments are inert; the server reads <real path>, edit that instead" (only when the sidecar exists and managed args are present).
Wrong-path — a TOML sitting at the README path that the server never actually reads (macOS/Windows only; on Linux the paths coincide, so no false alarm).
#11 credential scoping — an unprefixed SSH_MCP_PASSWORD shared across 2+ profiles in a multi-profile sidecar.
GUI (minimal, advisory)
A read-only warning label in the stdio editor, mirroring the existing removed-flag label. No fix button — editing the sidecar is a separate, deliberate action. Uses the real platform/env/filesystem so it reflects the user's actual machine. Smoke-tested headlessly with QT_QPA_PLATFORM=offscreen.
⚠️ Heuristic flagged honestly
count_toml_profiles() counts TOML table/array-of-table headers as a 3.10-safe proxy for "how many profiles are defined" (no tomllib on the py3.10 baseline). The exact ssh-mcp multi-profile schema wasn't verifiable from here, so the #11 warning is conservative and documented as best-effort. It only ever advises — it never edits or blocks.
Testing
ruff + format --check clean; pytest green. Added fixture-driven tests: verified paths per platform, args-inert precedence, args-live when absent, wrong-path on macOS + no-false-alarm on Linux, profile counting, and the #11 credential-scoping warning.
Stacked PR — base is feat/90 (this depends on the ServerSpec spine). Review/merge #90 first, then this. Sibling of #92; #93 builds on this. 🤖 Generated with Claude Code
## What (P0 — correctness)
`ssh-mcp` v2 reads a TOML **sidecar** and only falls back to CLI args when that file is **absent**. So BCC's carefully-managed `--host`/`--user` args can be completely **inert** while the real config lives in a file BCC never looks at. This PR adds **read-only truth-telling** for that trap (no sidecar writing — that's a deliberate follow-up).
### Core (pure `bcc_core`, fully injectable — CI never touches the real filesystem)
- **`sidecar_path(spec)`** — the **VERIFIED** per-platform TOML location, derived from the package source, **NOT the README** (which is wrong on macOS/Windows):
- macOS → `~/Library/Application Support/ssh-mcp/config.toml`
- Windows → `%APPDATA%\ssh-mcp\config.toml`
- else → `${XDG_CONFIG_HOME:-~/.config}/ssh-mcp/config.toml`
`sidecar_doc_path()` returns the README path for comparison.
- **`sidecar_status()`** — resolves `exists` / `has_managed_args` / `args_inert` / `wrong_path`. `platform` / `environ` / `home` / `exists` are all injectable.
- **`sidecar_warnings()`** — mirrors `removed_flag_warnings`' shape. Reports three things:
1. **Precedence** — *"these arguments are inert; the server reads `<real path>`, edit that instead"* (only when the sidecar exists **and** managed args are present).
2. **Wrong-path** — a TOML sitting at the README path that the server never actually reads (macOS/Windows only; on Linux the paths coincide, so no false alarm).
3. **#11 credential scoping** — an unprefixed `SSH_MCP_PASSWORD` shared across 2+ profiles in a multi-profile sidecar.
### GUI (minimal, advisory)
A read-only warning label in the stdio editor, mirroring the existing removed-flag label. **No fix button** — editing the sidecar is a separate, deliberate action. Uses the real platform/env/filesystem so it reflects the user's actual machine. Smoke-tested headlessly with `QT_QPA_PLATFORM=offscreen`.
### ⚠️ Heuristic flagged honestly
`count_toml_profiles()` counts TOML table/array-of-table headers as a 3.10-safe proxy for "how many profiles are defined" (no `tomllib` on the py3.10 baseline). The exact ssh-mcp multi-profile schema wasn't verifiable from here, so the #11 warning is conservative and documented as best-effort. It only ever *advises* — it never edits or blocks.
### Testing
`ruff` + `format --check` clean; `pytest` green. Added fixture-driven tests: verified paths per platform, args-inert precedence, args-live when absent, wrong-path on macOS + no-false-alarm on Linux, profile counting, and the #11 credential-scoping warning.
Closes #91. Part of epic #94.
---
**Stacked PR — base is `feat/90`** (this depends on the ServerSpec spine). Review/merge **#90 first**, then this. Sibling of #92; #93 builds on this.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
ssh-mcp v2 reads a TOML sidecar and only falls back to CLI args when that file
is ABSENT — so BCC's managed --host/--user args can be completely inert while
the real config lives in a file BCC never looks at. This adds read-only
truth-telling for that (no sidecar writing).
Core (pure, fully injectable platform/environ/home/exists/read for testing):
- sidecar_path(spec): VERIFIED per-platform TOML location from the package source,
NOT the README (macOS → ~/Library/Application Support/ssh-mcp, Windows → %APPDATA%,
else → ${XDG_CONFIG_HOME:-~/.config}). sidecar_doc_path() is the README path.
- sidecar_status(): resolves exists / has_managed_args / args_inert / wrong_path.
- sidecar_warnings(): mirrors removed_flag_warnings' shape. Reports:
* precedence — "these arguments are inert; the server reads <real path>"
* wrong-path — a TOML at the README path the server never actually reads
* #11 credential scoping — an unprefixed SSH_MCP_PASSWORD shared across 2+
profiles in a multi-profile sidecar (count_toml_profiles is a documented
3.10-safe heuristic; unscoped_credential_warning gates on it).
GUI: a read-only advisory label in the stdio editor (mirrors the removed-flag
label; no fix button — editing the sidecar is a separate deliberate action).
Uses the real platform/env/filesystem so it reflects this machine.
pytest green, ruff + format clean. Closes#91. Part of epic #94.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The CI matrix includes a windows-latest job where str(Path("/Users/…")) renders
with backslashes, so the platform-parameterised sidecar-path assertions failed
there (macOS/Linux passed). Compare .as_posix() instead — separator-normalised
and portable — and note why. Pure test fix; no production-code change.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
What (P0 — correctness)
ssh-mcpv2 reads a TOML sidecar and only falls back to CLI args when that file is absent. So BCC's carefully-managed--host/--userargs can be completely inert while the real config lives in a file BCC never looks at. This PR adds read-only truth-telling for that trap (no sidecar writing — that's a deliberate follow-up).Core (pure
bcc_core, fully injectable — CI never touches the real filesystem)sidecar_path(spec)— the VERIFIED per-platform TOML location, derived from the package source, NOT the README (which is wrong on macOS/Windows):~/Library/Application Support/ssh-mcp/config.toml%APPDATA%\ssh-mcp\config.toml${XDG_CONFIG_HOME:-~/.config}/ssh-mcp/config.tomlsidecar_doc_path()returns the README path for comparison.sidecar_status()— resolvesexists/has_managed_args/args_inert/wrong_path.platform/environ/home/existsare all injectable.sidecar_warnings()— mirrorsremoved_flag_warnings' shape. Reports three things:<real path>, edit that instead" (only when the sidecar exists and managed args are present).SSH_MCP_PASSWORDshared across 2+ profiles in a multi-profile sidecar.GUI (minimal, advisory)
A read-only warning label in the stdio editor, mirroring the existing removed-flag label. No fix button — editing the sidecar is a separate, deliberate action. Uses the real platform/env/filesystem so it reflects the user's actual machine. Smoke-tested headlessly with
QT_QPA_PLATFORM=offscreen.⚠️ Heuristic flagged honestly
count_toml_profiles()counts TOML table/array-of-table headers as a 3.10-safe proxy for "how many profiles are defined" (notomllibon the py3.10 baseline). The exact ssh-mcp multi-profile schema wasn't verifiable from here, so the #11 warning is conservative and documented as best-effort. It only ever advises — it never edits or blocks.Testing
ruff+format --checkclean;pytestgreen. Added fixture-driven tests: verified paths per platform, args-inert precedence, args-live when absent, wrong-path on macOS + no-false-alarm on Linux, profile counting, and the #11 credential-scoping warning.Closes #91. Part of epic #94.
Stacked PR — base is
feat/90(this depends on the ServerSpec spine). Review/merge #90 first, then this. Sibling of #92; #93 builds on this.🤖 Generated with Claude Code
ssh-mcp v2 reads a TOML sidecar and only falls back to CLI args when that file is ABSENT — so BCC's managed --host/--user args can be completely inert while the real config lives in a file BCC never looks at. This adds read-only truth-telling for that (no sidecar writing). Core (pure, fully injectable platform/environ/home/exists/read for testing): - sidecar_path(spec): VERIFIED per-platform TOML location from the package source, NOT the README (macOS → ~/Library/Application Support/ssh-mcp, Windows → %APPDATA%, else → ${XDG_CONFIG_HOME:-~/.config}). sidecar_doc_path() is the README path. - sidecar_status(): resolves exists / has_managed_args / args_inert / wrong_path. - sidecar_warnings(): mirrors removed_flag_warnings' shape. Reports: * precedence — "these arguments are inert; the server reads <real path>" * wrong-path — a TOML at the README path the server never actually reads * #11 credential scoping — an unprefixed SSH_MCP_PASSWORD shared across 2+ profiles in a multi-profile sidecar (count_toml_profiles is a documented 3.10-safe heuristic; unscoped_credential_warning gates on it). GUI: a read-only advisory label in the stdio editor (mirrors the removed-flag label; no fix button — editing the sidecar is a separate deliberate action). Uses the real platform/env/filesystem so it reflects this machine. pytest green, ruff + format clean. Closes #91. Part of epic #94. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>The CI matrix includes a windows-latest job where str(Path("/Users/…")) renders with backslashes, so the platform-parameterised sidecar-path assertions failed there (macOS/Linux passed). Compare .as_posix() instead — separator-normalised and portable — and note why. Pure test fix; no production-code change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>Pull request closed