From 79fe7ce02091efa560d5f6ffe4f12b430b9b2630 Mon Sep 17 00:00:00 2001 From: Cuihtlauac ALVARADO Date: Wed, 23 Sep 2026 10:03:48 +0200 Subject: [PATCH] feat(plugin): package as a Claude Code plugin and marketplace Add .claude-plugin/plugin.json (registers the sudo-proxy MCP server inline and ships a skill) and .claude-plugin/marketplace.json (a single-plugin marketplace named "tarides"), so the repo can be added and installed with: /plugin marketplace add tarides/sudo-proxy /plugin install sudo-proxy@tarides Declare mcpServers inline in plugin.json rather than shipping a root .mcp.json: a project-root .mcp.json auto-loads whenever the repo itself is opened in Claude Code, prompting every developer for MCP approval. Inline registration loads the server only when the plugin is installed. The plugin does not install the sudo-proxy-mcp binary; that stays a documented prerequisite, since a human-consent tool should not install itself silently. The skill tells the model to reach for sudo-proxy only for privileged or remote work, start the server before executing, and write a clear per-command description for the approval prompt. Also add plugin.json to the version-bump checklist in CLAUDE.md alongside the pre-existing hardcoded version strings in server.json and the mcpb manifest. Co-Authored-By: Claude Opus 4.8 (1M context) --- .claude-plugin/marketplace.json | 14 +++++++ .claude-plugin/plugin.json | 17 ++++++++ CLAUDE.md | 10 ++++- README.md | 21 ++++++++++ skills/run/SKILL.md | 71 +++++++++++++++++++++++++++++++++ 5 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 .claude-plugin/marketplace.json create mode 100644 .claude-plugin/plugin.json create mode 100644 skills/run/SKILL.md diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json new file mode 100644 index 0000000..c99154e --- /dev/null +++ b/.claude-plugin/marketplace.json @@ -0,0 +1,14 @@ +{ + "name": "tarides", + "owner": { + "name": "Tarides", + "url": "https://github.com/tarides" + }, + "plugins": [ + { + "name": "sudo-proxy", + "source": "./", + "description": "Human-approved sudo for agents — run privileged commands locally or over SSH, with a TUI keypress required on every one and no credential ever stored." + } + ] +} diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json new file mode 100644 index 0000000..e4c40f1 --- /dev/null +++ b/.claude-plugin/plugin.json @@ -0,0 +1,17 @@ +{ + "name": "sudo-proxy", + "version": "1.1.0", + "description": "Run privileged commands locally or over SSH, with a human keypress approving each one", + "author": { + "name": "Tarides" + }, + "homepage": "https://github.com/tarides/sudo-proxy", + "repository": "https://github.com/tarides/sudo-proxy", + "license": "MIT", + "keywords": ["sudo", "ssh", "privileged", "human-in-the-loop", "approval"], + "mcpServers": { + "sudo-proxy": { + "command": "sudo-proxy-mcp" + } + } +} diff --git a/CLAUDE.md b/CLAUDE.md index 607e2e9..8e2a141 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -11,6 +11,14 @@ cargo build --release --no-default-features # core only (no MCP server) The version in `Cargo.toml` must match the git tag. When bumping the version: 1. Update `version` in `Cargo.toml` -2. Tag the commit: `git tag v` +2. Update the hardcoded version strings in the packaging metadata so they + don't drift from `Cargo.toml`: + - `server.json` (the `version` field and the `mcpb` package identifier URL) + - `packaging/mcpb/manifest.json` + - `.claude-plugin/plugin.json` +3. Tag the commit: `git tag v` All binaries read the version from `Cargo.toml` at compile time via `env!("CARGO_PKG_VERSION")`. +The JSON files above carry the string separately because they are consumed by +external tooling (the MCP registry, mcpb, the Claude Code plugin loader) before +any binary runs. diff --git a/README.md b/README.md index 2ce649b..0a1e1a2 100644 --- a/README.md +++ b/README.md @@ -128,6 +128,27 @@ Point your MCP client at the server — add to the project's `.mcp.json` or } ``` +### Install as a Claude Code plugin + +The repo is also a Claude Code [plugin](https://code.claude.com/docs/en/plugins) +and its own marketplace. Instead of editing `.mcp.json` by hand: + +``` +/plugin marketplace add tarides/sudo-proxy +/plugin install sudo-proxy@tarides +``` + +The plugin registers the `sudo-proxy` MCP server and ships a skill that +tells the model to reach for sudo-proxy only for privileged or remote +work, to start the server before executing, and to write a clear +description for each command so the approval prompt is easy to judge. It +does **not** install the `sudo-proxy-mcp` binary — that must already be on +your `PATH` (see the `cargo install` / `cargo binstall` steps above). A +tool whose whole point is explicit human consent should not install +itself silently. + +### Run commands + Then the model starts a server (opening a terminal with the approval TUI) and runs commands through it: diff --git a/skills/run/SKILL.md b/skills/run/SKILL.md new file mode 100644 index 0000000..4933633 --- /dev/null +++ b/skills/run/SKILL.md @@ -0,0 +1,71 @@ +--- +name: run +description: Run a privileged (sudo) or remote-over-SSH command through sudo-proxy, which shows the user a single-keypress TUI approval prompt before anything executes. Use when a task needs to install packages, edit system files, manage services, or run any command on a remote host — NOT for ordinary unprivileged work in the current directory. +--- + +# sudo-proxy: run + +sudo-proxy runs a command through a human-approval gate: every `execute` +pops a single-keypress Y/N prompt in the user's terminal (and, when +privileged, a live `sudo` password prompt) before the command runs. No +credential is stored; there is no auto-approve mode. It works for local +commands and for commands on a remote host reached over an SSH tunnel. + +The `sudo-proxy-mcp` binary must already be on the user's `PATH` +(`cargo install sudo-proxy` or `cargo binstall sudo-proxy`). This plugin +launches the server; it does not install the binary. + +## When to use it — and when not to + +Use sudo-proxy only when the command genuinely needs it: + +- **Privilege escalation** — installing packages, editing system files, + managing services, anything that needs `sudo`. +- **A remote host** — running a command on another machine over SSH. + +For everything else — reading files, building, running tests, git, any +unprivileged command in the working tree — keep using the ordinary Bash +tool. sudo-proxy adds a human-approval round-trip on *every* call, so +routing routine work through it just slows the user down. + +## How to call it + +1. **Start the server first.** Call `start_server` before the first + `execute`. With no arguments it opens a local terminal with the + approval TUI; pass `host` to open an SSH-tunnelled session to a remote + machine. If a server is already running it returns immediately, so + calling it again is cheap and safe. + +2. **Execute with a clear description.** Every `execute` takes an `argv` + array and should carry a `description`. That description is what the + user reads in the approval prompt, so make it specific and honest — + "Install nginx" or "Restart the ci-runner service", not "run command". + A good description is the difference between an easy `y` and a puzzled + deny. + +3. **Match the host.** Pass the same `host` to `execute` that you passed + to `start_server`; omit it for localhost. Set `privileged: false` for + commands that should run as the current user but still behind the Y/N + gate. + +```jsonc +start_server() +execute({ "argv": ["apt", "install", "nginx"], "description": "Install nginx" }) + +// remote host +start_server({ "host": "ci-runner" }) +execute({ "argv": ["systemctl", "restart", "buildkite"], + "host": "ci-runner", + "description": "Restart the Buildkite agent on ci-runner" }) +``` + +Expect denials: the user may press `N`. Treat a denied command as a +deliberate choice, report it plainly, and do not try to route around the +gate. + +## Reference + +- Tools (`start_server`, `execute`, `status`, `stop_server`, + `update_host`): https://github.com/tarides/sudo-proxy/blob/main/docs/mcp.md +- Security model and threat model: + https://github.com/tarides/sudo-proxy/blob/main/docs/security.md