mirror of
https://github.com/PerpetualSoftware/pad.git
synced 2026-09-23 11:03:41 +00:00
e90ee18907
* feat(mcp): pad mcp install / uninstall / status (TASK-948)
One-shot config writers for the three MCP-capable client apps:
pad mcp install claude-desktop # ~/.config/Claude/claude_desktop_config.json (linux)
pad mcp install cursor # ~/.cursor/mcp.json
pad mcp install windsurf # ~/.codeium/windsurf/mcp_config.json
pad mcp install --all # all three
pad mcp uninstall cursor # remove
pad mcp status # report install state
Implementation:
- internal/mcp/install.go (new) — Agent registry with per-OS path
resolvers (PathFor takes (home, goos) so tests inject); AddPadEntry
/ RemovePadEntry / HasPadEntry primitives that read-modify-write
JSON, preserving every entry except mcpServers.pad. Installer
façade with Home/GOOS overrides for tests.
- cmd/pad/mcp.go — three new cobra subcommands wired into mcpCmd:
install (no-args = status, --all = batch), uninstall, status.
Binary path resolved via os.Executable().
DOD coverage:
- Existing entries preserved (TestAddPadEntry_PreservesOtherServers
asserts both other mcpServers and unrelated top-level keys survive).
- Idempotent install (binary unchanged → modified=false).
- Update install (binary changed → modified=true).
- Idempotent uninstall (missing file / missing entry → no-op).
- Per-platform path resolution tested for linux + darwin.
- 16 unit tests including edge cases: empty/whitespace files,
malformed JSON rejected (no silent overwrite), case-insensitive
agent aliases.
Live verified end-to-end:
- HOME=/tmp/fakehome pad mcp install cursor → writes valid JSON
- pad mcp status → shows [x] Cursor with command path
- pad mcp uninstall cursor → leaves mcpServers:{} skeleton
Config file perms: 0600 (configs may hold credentials for OTHER
MCP servers; tighten on principle).
Parent: PLAN-942.
* fix(mcp): tighten install argument validation + chmod existing configs (Codex round 1)
Two findings on PR #338:
1. `pad mcp install` had no Args validator so cobra silently accepted
extras: `pad mcp install cursor windsurf` only installed Cursor.
Added cobra.MaximumNArgs(1) plus an explicit guard rejecting
`--all` combined with an agent name (those flows are
mutually exclusive).
2. os.WriteFile(path, data, 0o600) only honors the mode when CREATING
the file. A pre-existing 0644 config kept 0644 after the install,
defeating the security-tightening claim in the comment. Added an
explicit os.Chmod(path, 0o600) after writing; chmod failures are
stderr warnings, not hard errors (the data write already
succeeded; perms hardening is best-effort defense-in-depth).
New test TestAddPadEntry_TightensExistingFilePerms locks the
0600-after-install contract; live verified the cobra guards reject
both error cases with clean messages.
Parent: PLAN-942.
* fix(mcp): tighten perms on idempotent install path too (Codex round 2)
Codex caught: AddPadEntry's no-op early-return (when desired config
matches existing) skipped the chmod step from round 1's fix. So an
already-up-to-date 0644 config retained 0644 after re-running
`pad mcp install`.
Extracted tightenPerms() as a helper called from BOTH paths:
- writeJSONConfig (modified path) — chmod after write
- AddPadEntry's no-op return — chmod even when content is unchanged
Best-effort: chmod failures still emit a warning rather than failing
the install (the user's intent already succeeded; perms tightening is
defense-in-depth, not core functionality).
New test TestAddPadEntry_TightensPermsOnIdempotentNoop locks the
no-op-path contract.
Parent: PLAN-942.