Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@ Or if you already have [uv](https://docs.astral.sh/uv/): `uv tool install crux-c

## Get started in three steps

**1. Build your registry** — add MCP servers and skills from any source:
**1. Build your registry** — add MCP servers and skills from any source. Packages are installed and validated automatically:

```bash
crux add mcp filesystem --npx @modelcontextprotocol/server-filesystem
crux add mcp filesystem --npm @modelcontextprotocol/server-filesystem
crux add mcp wikijs --github jaalbin24/wikijs-mcp-server
crux add skill autoresearch --github user/autoresearch-skill
```
Expand Down
14 changes: 14 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,20 @@ All notable changes to Crux are documented here.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Changed

- **`crux mcp add --npm`** now runs `npm install -g` to install packages globally before registering. Catches missing packages, build failures, and platform incompatibilities at registration time instead of agent runtime.
- **`crux mcp add --uv`** now runs `uv tool install` to permanently install Python tools before registering. Catches yanked versions, missing packages, and build errors immediately.
- **`crux mcp add --github`** now auto-detects project type and installs dependencies after cloning: `package.json` triggers `npm install` (+ `npm run build` if build script exists), `pyproject.toml` triggers `uv sync`, `requirements.txt` triggers `uv venv && uv pip install -r requirements.txt`.
- **`crux mcp add --local`** now runs the same dependency auto-detection and installation as `--github`.
- Renamed CLI flags: `--npx` is now `--npm`, `--uvx` is now `--uv`.

### Added

- **`--skip-validation` flag** for `crux mcp add`: bypasses installation and dependency checks. Useful for MCPs that require auth before installation, offline registration, or private registries.

## [1.0.0] - 2026-03-16

### Added
Expand Down
65 changes: 50 additions & 15 deletions docs/cli/mcp-add.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# crux mcp add

Register a new MCP server in the global registry.
Install and register a new MCP server in the global registry.

When you add an MCP, Crux installs its dependencies before registering it. This catches broken packages, missing dependencies, and build failures immediately — not when an agent tries to use the server mid-task.

## Usage

Expand All @@ -18,34 +20,67 @@ crux mcp add <name> [options]

| Option | Description |
|--------|-------------|
| `--npx <package>` | npm package to run via npx |
| `--uvx <package>` | PyPI package to run via uvx |
| `--github <user/repo>` | GitHub repository to clone |
| `--local <path>` | Local directory path |
| `--npm <package>` | npm package (runs `npm install -g` to install globally) |
| `--uv <package>` | PyPI package (runs `uv tool install` to install permanently) |
| `--github <user/repo>` | GitHub repository (clones and auto-installs dependencies) |
| `--local <path>` | Local directory path (copies and auto-installs dependencies) |
| `--command <cmd>` | Command to run the MCP server |
| `--args <args>` | Arguments for the command (space-separated) |
| `--tags <tags>` | Comma-separated tags |
| `--keychain <vars>` | Comma-separated env var names for keychain auth (prompts inline) |
| `--build-cmd <cmd>` | Build command to run after cloning |
| `--skip-validation` | Skip package installation and dependency checks |

## What happens during `mcp add`

### npm packages (`--npm`)

Runs `npm install -g <package>` to install the package globally. If the package doesn't exist (E404), fails to download, or is incompatible with your platform, the error is reported immediately and the MCP is not registered.

### PyPI packages (`--uv`)

Runs `uv tool install <package>` to permanently install the tool. If the package doesn't exist, all versions are yanked, or it fails to build (e.g., C extension on wrong Python version), the error is reported immediately.

### GitHub repos (`--github`)

Clones the repo, then auto-detects the project type and installs dependencies:

- `package.json` found: runs `npm install`, then `npm run build` if a build script exists
- `pyproject.toml` found: runs `uv sync`
- `requirements.txt` found: runs `uv venv && uv pip install -r requirements.txt`

If dependency installation fails, the cloned directory is cleaned up and the MCP is not registered.

### Local directories (`--local`)

Copies the directory to `~/.crux/mcps/<name>/`, then runs the same dependency auto-detection as GitHub repos.

### `--skip-validation`

Bypasses installation and dependency checks entirely. The MCP is registered with just the metadata. Use this when:

- The MCP requires authentication before it can be installed
- You're working offline and will install later
- You're using a private registry that Crux can't access

## Examples

```bash
# npm package
crux mcp add filesystem --npx @modelcontextprotocol/server-filesystem
# npm package — installs globally, then registers
crux mcp add filesystem --npm @modelcontextprotocol/server-filesystem

# PyPI package — installs via uv tool, then registers
crux mcp add my-tool --uv my-mcp-tool

# GitHub repo with build step
crux mcp add wikijs --github jaalbin24/wikijs-mcp-server \
--build-cmd "npm install && npm run build"
# GitHub repo — clones, installs deps, builds, then registers
crux mcp add wikijs --github jaalbin24/wikijs-mcp-server

# With keychain auth (prompts for credentials inline)
crux mcp add github --npx @modelcontextprotocol/server-github \
crux mcp add github --npm @modelcontextprotocol/server-github \
--keychain GITHUB_TOKEN
# → Prompts: Enter GITHUB_TOKEN: ****
# → ✓ Stored GITHUB_TOKEN

# PyPI package
crux mcp add my-tool --uvx my-mcp-tool
# Skip installation (register only)
crux mcp add my-private-mcp --npm @private/mcp-server --skip-validation

# Local path
crux mcp add dev-server --local /path/to/server
Expand Down
2 changes: 1 addition & 1 deletion docs/getting-started/concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Understanding Crux's architecture and key abstractions.
The **registry** (`~/.crux/registry.json`) is your personal catalog of all MCP servers and skills you've registered. It's machine-wide — shared across all your projects.

```bash
crux add mcp filesystem --npx @modelcontextprotocol/server-filesystem
crux add mcp filesystem --npm @modelcontextprotocol/server-filesystem
crux add mcp wikijs --github jaalbin24/wikijs-mcp-server
crux list
```
Expand Down
12 changes: 6 additions & 6 deletions docs/getting-started/quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@ Set up a project with scoped MCP access in 30 seconds.

## 1. Add MCPs to Your Registry

Register MCP servers from npm, PyPI, GitHub, or local sources. You only do this once per MCP — they're available across all your projects.
Register MCP servers from npm, PyPI, GitHub, or local sources. Crux installs and validates each package before registering it. You only do this once per MCP — they're available across all your projects.

```bash
# npm packages
crux add mcp filesystem --npx @modelcontextprotocol/server-filesystem
# npm packages (installs globally via npm install -g)
crux add mcp filesystem --npm @modelcontextprotocol/server-filesystem

# GitHub repos
# GitHub repos (clones and auto-installs dependencies)
crux add mcp wikijs --github jaalbin24/wikijs-mcp-server

# PyPI packages
crux add mcp my-tool --uvx my-mcp-tool
# PyPI packages (installs via uv tool install)
crux add mcp my-tool --uv my-mcp-tool
```

See what's available in the official registry:
Expand Down
16 changes: 12 additions & 4 deletions docs/guides/authentication.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,21 @@ Crux supports several authentication methods depending on how an MCP server expe
| `bearer` | HTTP Bearer tokens passed in request headers |
| `oauth` | OAuth 2.0 flows managed by Crux |

Declare the auth type when adding an MCP. When `--keychain` is used, you are prompted for credentials inline:
Declare the auth type when adding an MCP. When `--keychain` is used, Crux installs the package first, then prompts for credentials:

```bash
crux mcp add github --npx @modelcontextprotocol/server-github --keychain GITHUB_TOKEN
crux mcp add github --npm @modelcontextprotocol/server-github --keychain GITHUB_TOKEN
# → Installing @modelcontextprotocol/server-github via npm install -g...
# → Enter GITHUB_TOKEN: ****
# → ✓ Stored GITHUB_TOKEN
# → ✓ Authenticated 'github'
# → ✅ Registered MCP 'github'
```

If an MCP requires authentication before it can be installed, use `--skip-validation` to register first, then authenticate:

```bash
crux mcp add private-mcp --npm @corp/private-mcp --keychain API_KEY --skip-validation
crux mcp auth private-mcp
```

To re-authenticate or rotate credentials later, use `crux mcp auth`:
Expand Down Expand Up @@ -64,7 +72,7 @@ Crux opens the authorization URL in your browser, handles the redirect, and stor
For MCPs that delegate to an external CLI for authentication (e.g., the GitHub CLI):

```bash
crux mcp add github --npx @modelcontextprotocol/server-github --external-cli "gh auth token"
crux mcp add github --npm @modelcontextprotocol/server-github --external-cli "gh auth token"
```

No separate `crux mcp auth` call is needed — the external command is called at MCP startup.
Expand Down
24 changes: 16 additions & 8 deletions docs/guides/registry.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,33 +6,41 @@ The registry is your personal catalog of MCP servers and skills. Add once, use i

Register MCP servers from different sources:

=== "npm (npx)"
=== "npm"

Installs the package globally via `npm install -g`, then registers it:

```bash
crux mcp add filesystem --npx @modelcontextprotocol/server-filesystem
crux mcp add github --npx @modelcontextprotocol/server-github
crux mcp add filesystem --npm @modelcontextprotocol/server-filesystem
crux mcp add github --npm @modelcontextprotocol/server-github
```

=== "PyPI (uvx)"
=== "PyPI"

Installs the tool permanently via `uv tool install`, then registers it:

```bash
crux mcp add my-tool --uvx my-mcp-package
crux mcp add my-tool --uv my-mcp-package
```

=== "GitHub"

Clones the repo and auto-detects dependencies (`package.json`, `pyproject.toml`, or `requirements.txt`):

```bash
crux mcp add wikijs --github jaalbin24/wikijs-mcp-server
```

GitHub sources are cloned to `~/.crux/mcps/`. If the MCP needs a build step:
GitHub sources are cloned to `~/.crux/mcps/`. Dependencies are installed automatically. Use `--build-cmd` only for custom build steps beyond what auto-detection handles:

```bash
crux mcp add wikijs --github jaalbin24/wikijs-mcp-server --build-cmd "npm install && npm run build"
crux mcp add custom --github user/repo --build-cmd "make build"
```

=== "Local"

Copies the directory and auto-detects dependencies:

```bash
crux mcp add my-local-mcp --local /path/to/mcp-server
```
Expand All @@ -52,7 +60,7 @@ This tells Crux that `wikijs` expects the `WIKIJS_API_KEY` environment variable.
Organize your MCPs with tags:

```bash
crux mcp add filesystem --npx @modelcontextprotocol/server-filesystem --tags "core,filesystem"
crux mcp add filesystem --npm @modelcontextprotocol/server-filesystem --tags "core,filesystem"
```

## Adding Skills
Expand Down
4 changes: 2 additions & 2 deletions docs/overrides/home.html
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@ <h2>How it works</h2>
<div class="crux-step__num">1</div>
<div class="crux-step__body">
<h3>Build your registry</h3>
<p>Add MCP servers and skills from any source. You do this once&nbsp;&mdash;&nbsp;they&rsquo;re available to every project.</p>
<pre><code>crux mcp add filesystem --npx @modelcontextprotocol/server-filesystem
<p>Add MCP servers and skills from any source. Packages are installed and validated automatically. You do this once&nbsp;&mdash;&nbsp;they&rsquo;re available to every project.</p>
<pre><code>crux mcp add filesystem --npm @modelcontextprotocol/server-filesystem
crux mcp add wikijs --github jaalbin24/wikijs-mcp-server
crux skill add autoresearch --github user/autoresearch-skill</code></pre>
</div>
Expand Down
22 changes: 11 additions & 11 deletions docs/superpowers/plans/2026-03-19-cli-restructuring.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,8 @@ def main() -> None:

p = mcp_sub.add_parser("add", help="Register a new MCP server")
p.add_argument("name", help="Name for the MCP")
p.add_argument("--uvx", help="PyPI package to run via uvx")
p.add_argument("--npx", help="npm package")
p.add_argument("--uv", help="PyPI package to run via uvx")
p.add_argument("--npm", help="npm package")
p.add_argument("--github", help="GitHub repo (e.g. user/repo)")
p.add_argument("--local", help="Local directory path")
p.add_argument("--command", help="Command to run the MCP")
Expand Down Expand Up @@ -307,7 +307,7 @@ Note the `elif entry_type == "skill"` branch in `cmd_add`, the skill handling in
- [ ] **Step 2: Create `commands/skill.py`**

Extract skill-specific code:
- `cmd_skill_add` — skill registration from `cmd_add`'s skill branch (GitHub/local only, no --npx/--uvx/--keychain)
- `cmd_skill_add` — skill registration from `cmd_add`'s skill branch (GitHub/local only, no --npm/--uv/--keychain)
- `cmd_skill_remove` — only searches `skill_definitions`
- `cmd_skill_list` — only shows skills table

Expand Down Expand Up @@ -834,14 +834,14 @@ git commit -m "refactor: cmd_setup -> cmd_init, remove MCP setup branch, remove
- [ ] **Step 2: Update `preflight.py`**

Update fix hint strings:
- Line 66-67: `f"Fix: crux add mcp {name} --npx <package>"` → `f"Fix: crux mcp add {name} --npx <package>"`
- Line 66-67: `f"Fix: crux add mcp {name} --npm <package>"` → `f"Fix: crux mcp add {name} --npm <package>"`
- Line 102-103: `f"Fix: crux secret set {name} {var} <value>"` → `f"Fix: crux mcp auth {name}"`
- Line 138: `f"Fix: crux add skill {name} --github <repo>"` → `f"Fix: crux skill add {name} --github <repo>"`

- [ ] **Step 3: Update `registry.py` (core)**

Read the file, find `suggest_crux_add` function. Update the command strings it generates:
- `f"crux add mcp {safe_name} --npx {pkg}"` → `f"crux mcp add {safe_name} --npx {pkg}"`
- `f"crux add mcp {safe_name} --npm {pkg}"` → `f"crux mcp add {safe_name} --npm {pkg}"`
- Same for `--github` variant

- [ ] **Step 4: Verify syntax for all three files**
Expand Down Expand Up @@ -911,7 +911,7 @@ Crux is a CLI tool for managing MCP servers, skills, and agent tasks.

### MCP Servers
- `crux mcp search <query>` — Search the MCP Registry
- `crux mcp add <name> --npx <pkg>` — Register an MCP server
- `crux mcp add <name> --npm <pkg>` — Register an MCP server
- `crux mcp remove <name>` — Unregister an MCP server
- `crux mcp list` — List registered MCP servers
- `crux mcp upgrade` — Update cloned MCP repos
Expand Down Expand Up @@ -1119,16 +1119,16 @@ def _load_registry(root):
class TestMcpAdd:
def test_add_npx_mcp(self, crux_env):
env, root = crux_env
result = run_crux("mcp", "add", "new-mcp", "--npx", "@test/new-mcp", "--tags", "test", env=env)
result = run_crux("mcp", "add", "new-mcp", "--npm", "@test/new-mcp", "--tags", "test", env=env)
assert result.returncode == 0
assert "Registered MCP" in result.stdout
reg = _load_registry(root)
assert "new-mcp" in reg["mcp_definitions"]

def test_add_duplicate_fails(self, crux_env):
env, root = crux_env
run_crux("mcp", "add", "dup", "--npx", "@test/dup", env=env)
result = run_crux("mcp", "add", "dup", "--npx", "@test/dup", env=env)
run_crux("mcp", "add", "dup", "--npm", "@test/dup", env=env)
result = run_crux("mcp", "add", "dup", "--npm", "@test/dup", env=env)
assert result.returncode != 0
assert "already exists" in result.stdout

Expand All @@ -1142,7 +1142,7 @@ class TestMcpAdd:
class TestMcpRemove:
def test_remove_existing(self, crux_env):
env, root = crux_env
run_crux("mcp", "add", "to-remove", "--npx", "@test/pkg", env=env)
run_crux("mcp", "add", "to-remove", "--npm", "@test/pkg", env=env)
result = run_crux("mcp", "remove", "to-remove", env=env)
assert result.returncode == 0
assert "Removed" in result.stdout
Expand Down Expand Up @@ -1359,7 +1359,7 @@ python -m crux_cli.cli.main task --help
- [ ] **Step 3: Verify old commands no longer work**

```bash
python -m crux_cli.cli.main add mcp test --npx test 2>&1 | grep -q "invalid choice"
python -m crux_cli.cli.main add mcp test --npm test 2>&1 | grep -q "invalid choice"
python -m crux_cli.cli.main secret set test KEY 2>&1 | grep -q "invalid choice"
python -m crux_cli.cli.main run list 2>&1 | grep -q "invalid choice"
python -m crux_cli.cli.main init 2>&1 | grep -q "Setup complete" # crux init = env setup, not project create
Expand Down
Loading
Loading