# CLI Management Commands

This document describes the CLI commands for managing MCPProxy upstream servers and monitoring system health.

## Overview

MCPProxy provides two command groups:

1. **`mcpproxy upstream`** - Server management (add, remove, list, logs, enable, disable, restart)
2. **`mcpproxy doctor`** - Health checks and diagnostics

All commands support both **daemon mode** (fast, via socket) and **standalone mode** (direct connection).

## Command Reference

### `mcpproxy upstream list`

List all configured upstream servers with connection status.

**Usage:**
```bash
mcpproxy upstream list [flags]
```

**Flags:**
- `--output, -o` - Output format (table, json) [default: table]
- `--log-level, -l` - Log level (trace, debug, info, warn, error) [default: warn]
- `--config, -c` - Path to config file

**Examples:**
```bash
# List servers with table output
mcpproxy upstream list

# JSON output for scripting
mcpproxy upstream list --output=json

# With debug logging
mcpproxy upstream list --log-level=debug
```

**Output Fields:**
- NAME - Server name
- PROTOCOL - Transport protocol (stdio, http, sse, streamable-http)
- TOOLS - Number of available tools
- STATUS - Unified health status with emoji indicator and summary
- ACTION - Suggested remediation command (if applicable)

**Status Indicators:**
- ✅ Healthy - Server connected and working
- ⚠️ Degraded - Server has warnings (e.g., token expiring soon)
- ❌ Unhealthy - Server has errors or not functioning
- ⏸️ Disabled - Server manually disabled by user
- 🔒 Quarantined - Server pending security approval

**Example Output:**
```
NAME                      PROTOCOL   TOOLS      STATUS                         ACTION
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✅    github-server           http       15         Connected (15 tools)           -
❌    oauth-server            http       0          Token expired                  auth login --server=oauth-server
⏸️    disabled-server         stdio      0          Disabled by user               upstream enable disabled-server
```

---

### `mcpproxy upstream add`

Add a new upstream MCP server to the configuration.

**Usage:**
```bash
# HTTP server
mcpproxy upstream add <name> <url> [flags]

# Stdio server (use -- to separate command)
mcpproxy upstream add <name> -- <command> [args...] [flags]
```

**Flags:**
- `--header` - HTTP header in 'Name: value' format (repeatable)
- `--env` - Environment variable in KEY=value format (repeatable)
- `--working-dir` - Working directory for stdio commands
- `--transport` - Transport type: http or stdio (auto-detected if not specified)
- `--if-not-exists` - Don't error if server already exists
- `--no-quarantine` - Don't quarantine the new server (use with caution)

**Examples:**
```bash
# Add HTTP-based server
mcpproxy upstream add notion https://mcp.notion.com/sse

# Add with authentication header
mcpproxy upstream add weather https://api.weather.com/mcp \
  --header "Authorization: Bearer my-token"

# Add stdio-based server using -- separator
mcpproxy upstream add fs -- npx -y @anthropic/mcp-server-filesystem /path/to/dir

# Add with environment variables and working directory
mcpproxy upstream add sqlite -- uvx mcp-server-sqlite --db mydb.db \
  --env "DEBUG=true" \
  --working-dir /home/user/projects

# Idempotent add (for scripts)
mcpproxy upstream add notion https://mcp.notion.com/sse --if-not-exists
```

**Behavior:**
- New servers are **quarantined by default** for security
- Works in both daemon mode (via API) and standalone mode (direct config file)
- Transport is auto-detected: URL → http, -- separator → stdio

**Output:**
```bash
✅ Added server 'notion'
   ⚠️  New servers are quarantined by default. Approve in the web UI.
```

---

### `mcpproxy upstream remove`

Remove an upstream MCP server from the configuration.

**Usage:**
```bash
mcpproxy upstream remove <name> [flags]
```

**Flags:**
- `--yes, -y` - Skip confirmation prompt
- `--if-exists` - Don't error if server doesn't exist

**Examples:**
```bash
# Remove with confirmation prompt
mcpproxy upstream remove notion

# Skip confirmation (for scripts)
mcpproxy upstream remove notion --yes
mcpproxy upstream remove notion -y

# Idempotent remove (for scripts)
mcpproxy upstream remove notion --yes --if-exists
```

**Interactive Confirmation:**
```bash
$ mcpproxy upstream remove notion
Remove server 'notion'? [y/N]: y
✅ Removed server 'notion'
```

**Behavior:**
- Works in both daemon mode (via API) and standalone mode (direct config file)
- Removes server from running daemon and config file
- Clears server's tool index entries

---

### `mcpproxy upstream add-json`

Add an upstream server using a JSON configuration object.

**Usage:**
```bash
mcpproxy upstream add-json <name> '<json>'
```

**JSON Fields:**
- `url` - Server URL (for HTTP transport)
- `command` - Command to run (for stdio transport)
- `args` - Command arguments (array)
- `headers` - HTTP headers (object)
- `env` - Environment variables (object)
- `working_dir` - Working directory (for stdio)
- `protocol` - Transport type (auto-detected if not specified)

**Examples:**
```bash
# Add HTTP server with headers
mcpproxy upstream add-json weather '{"url":"https://api.weather.com/mcp","headers":{"Authorization":"Bearer token"}}'

# Add stdio server with environment
mcpproxy upstream add-json sqlite '{"command":"uvx","args":["mcp-server-sqlite","--db","mydb.db"],"env":{"DEBUG":"1"}}'

# Complex configuration
mcpproxy upstream add-json complex-server '{
  "command": "node",
  "args": ["./server.js"],
  "env": {"NODE_ENV": "production", "PORT": "3000"},
  "working_dir": "/opt/mcp-server"
}'
```

**Behavior:**
- Useful for complex configurations or when copying from JSON config files
- Protocol is auto-detected from `url` (→ http) or `command` (→ stdio)
- New servers are quarantined by default

---

### `mcpproxy upstream logs <name>`

Display recent log entries from a specific server.

**Usage:**
```bash
mcpproxy upstream logs <server-name> [flags]
mcpproxy upstream logs --server <server-name> [flags]
```

**Flags:**
- `--server, -s` - Server name (alternative to positional argument)
- `--tail, -n` - Number of lines to show [default: 50]
- `--follow, -f` - Follow log output (requires daemon)
- `--log-level, -l` - Log level [default: warn]
- `--config, -c` - Path to config file

**Examples:**
```bash
# Show last 50 lines (either form works)
mcpproxy upstream logs github-server
mcpproxy upstream logs --server github-server
mcpproxy upstream logs -s github-server

# Show last 200 lines
mcpproxy upstream logs github-server --tail=200

# Follow logs (Ctrl+C to stop)
mcpproxy upstream logs github-server --follow
```

**Behavior:**
- **Daemon mode**: Fetches logs via API from running server
- **Standalone mode**: Reads directly from log file (read-only)
- **Follow mode**: Requires running daemon, polls for new lines

---

### `mcpproxy upstream enable <name|--all>`

Enable a disabled server or all disabled servers.

**Usage:**
```bash
mcpproxy upstream enable <server-name>
mcpproxy upstream enable --server <server-name>
mcpproxy upstream enable --all [--force]
```

**Flags:**
- `--server, -s` - Server name (alternative to positional argument)
- `--all` - Enable all disabled servers
- `--force` - Skip confirmation prompt (for automation)

**Requirements:**
- Daemon must be running

**Examples:**
```bash
# Enable single server (either form works)
mcpproxy upstream enable github-server
mcpproxy upstream enable --server github-server
mcpproxy upstream enable -s github-server

# Enable all servers (interactive confirmation)
mcpproxy upstream enable --all

# Enable all servers (skip prompt)
mcpproxy upstream enable --all --force
```

**Interactive Confirmation:**
```bash
$ mcpproxy upstream enable --all
⚠️  This will enable 5 server(s). Continue? [y/N]: _
```

**Non-interactive mode requires --force:**
```bash
$ echo "y" | mcpproxy upstream enable --all
Error: --all requires --force flag in non-interactive mode
```

---

### `mcpproxy upstream disable <name|--all>`

Disable a server or all enabled servers.

**Usage:**
```bash
mcpproxy upstream disable <server-name>
mcpproxy upstream disable --server <server-name>
mcpproxy upstream disable --all [--force]
```

**Flags:**
- `--server, -s` - Server name (alternative to positional argument)
- `--all` - Disable all enabled servers
- `--force` - Skip confirmation prompt

**Requirements:**
- Daemon must be running

**Examples:**
```bash
# Disable single server (either form works)
mcpproxy upstream disable github-server
mcpproxy upstream disable --server github-server
mcpproxy upstream disable -s github-server

# Disable all servers (interactive confirmation)
mcpproxy upstream disable --all

# Disable all in script
mcpproxy upstream disable --all --force
```

---

### `mcpproxy upstream restart <name|--all>`

Restart a server or all enabled servers.

**Usage:**
```bash
mcpproxy upstream restart <server-name>
mcpproxy upstream restart --server <server-name>
mcpproxy upstream restart --all
```

**Flags:**
- `--server, -s` - Server name (alternative to positional argument)
- `--all` - Restart all enabled servers

**Requirements:**
- Daemon must be running

**Examples:**
```bash
# Restart single server (either form works)
mcpproxy upstream restart github-server
mcpproxy upstream restart --server github-server
mcpproxy upstream restart -s github-server

# Restart all servers (no confirmation needed)
mcpproxy upstream restart --all
```

**Note:** Restart does not require confirmation as it's non-destructive.

**Locally-launched HTTP/SSE upstreams:** when a server is configured with both
`command` and an HTTP/SSE `url` (see [docs/configuration.md](configuration.md#locally-launched-http--sse-servers)),
`restart` stops the spawned child (`SIGTERM` → grace → `SIGKILL`) before
re-running Connect. The grace timeout is fixed at 5s today; the next start
won't begin until the previous child is fully reaped, so you can rely on the
port being free after the command returns. Stop ordering is: close MCP client
→ stop launched child → release per-server state.

---

### `mcpproxy doctor`

Run comprehensive health checks to identify issues.

**Usage:**
```bash
mcpproxy doctor [flags]
```

**Flags:**
- `--output, -o` - Output format (pretty, json) [default: pretty]
- `--log-level, -l` - Log level [default: warn]
- `--config, -c` - Path to config file
- `--server` - Limit health checks to a single upstream server by name (Spec 044)

**Requirements:**
- Daemon must be running

**Examples:**
```bash
# Pretty output with issue categorization
mcpproxy doctor

# JSON output for scripting
mcpproxy doctor --output=json

# Only show issues for a single server
mcpproxy doctor --server=github
```

**Health Checks:**
- Upstream server connection errors
- OAuth authentication requirements
- Missing secrets (unresolved references)
- Runtime warnings
- Docker isolation status

**Output:**
- Total issue count
- Categorized issues with actionable remediation steps
- Exit code 0 even if issues found (for scripting)

---

### `mcpproxy doctor fix <CODE>` (Spec 044)

Run a registered diagnostics fixer for a specific (server, code) pair.
By default the fix runs as a non-destructive dry_run; pass `--execute`
to apply mutating changes.

**Usage:**
```bash
mcpproxy doctor fix <CODE> --server <name> [--execute] [--fixer-key <key>] [flags]
```

**Flags:**
- `--server` - Upstream server name (required)
- `--fixer-key` - Override the auto-resolved fixer_key (rare; needed only
  when a code defines multiple button-type fix steps)
- `--execute` - Apply the fix (default behaviour is dry_run)
- `--output, -o` - Output format (pretty, json) [default: pretty]

**Requirements:**
- Daemon must be running

**Examples:**
```bash
# Dry-run an OAuth re-login for the github server
mcpproxy doctor fix MCPX_OAUTH_REFRESH_EXPIRED --server github

# Actually re-run the OAuth flow (destructive)
mcpproxy doctor fix MCPX_OAUTH_REFRESH_EXPIRED --server github --execute

# JSON output for scripting / CI
mcpproxy doctor fix MCPX_STDIO_SPAWN_ENOENT --server my-stdio -o json
```

**Error code reference:** run `mcpproxy doctor list-codes` for the full
catalog with associated fix steps and fixer keys.

---

## Common Workflows

### Debugging Server Connection Issues

```bash
# 1. Run health check to see all issues
mcpproxy doctor

# 2. Check specific server status
mcpproxy upstream list

# 3. View logs for failing server
mcpproxy upstream logs failing-server --tail=100

# 4. Restart server
mcpproxy upstream restart failing-server

# 5. Verify fix
mcpproxy upstream list
```

### Monitoring Server Health

```bash
# Follow logs in terminal 1
mcpproxy upstream logs github-server --follow

# In terminal 2, trigger operations
mcpproxy call tool --tool-name=github:get_user --json_args='{"username":"octocat"}'

# Watch logs update in real-time
```

### Bulk Server Management

```bash
# List all servers first
mcpproxy upstream list

# Disable all for maintenance
mcpproxy upstream disable --all --force

# Perform maintenance...

# Re-enable all
mcpproxy upstream enable --all --force

# Verify
mcpproxy upstream list
```

---

## Daemon Mode vs Standalone Mode

### Daemon Mode (Preferred)
- **Detection**: Socket file exists at `~/.mcpproxy/mcpproxy.sock`
- **Behavior**: Uses HTTP API via Unix socket
- **Speed**: Fast (reuses existing connections)
- **Requirements**: `mcpproxy serve` running

### Standalone Mode (Fallback)
- **Detection**: No socket file found
- **Behavior**: Direct connection to servers or file reading
- **Speed**: Slower (establishes new connections)
- **Limitations**: Some commands unavailable (enable, disable, restart, follow, doctor)

### Command Availability

| Command | Daemon Mode | Standalone Mode | Notes |
|---------|-------------|-----------------|-------|
| `upstream add` | ✅ Via API | ✅ Config file | Both modes supported |
| `upstream remove` | ✅ Via API | ✅ Config file | Both modes supported |
| `upstream add-json` | ✅ Via API | ✅ Config file | Both modes supported |
| `upstream list` | ✅ Full status | ✅ Config only | Standalone shows "unknown" |
| `upstream logs` | ✅ Via API | ✅ File read | Follow requires daemon |
| `upstream enable` | ✅ | ❌ | Requires daemon |
| `upstream disable` | ✅ | ❌ | Requires daemon |
| `upstream restart` | ✅ | ❌ | Requires daemon |
| `doctor` | ✅ | ❌ | Requires daemon |

---

## Safety Considerations

### Security Quarantine for New Servers

All servers added via `upstream add` or `upstream add-json` are **quarantined by default**:

- Quarantined servers are visible but not connected
- No tool calls are proxied to quarantined servers
- Approve servers via the web UI to unquarantine
- This protects against Tool Poisoning Attacks (TPA)

```bash
# Add server (automatically quarantined)
mcpproxy upstream add notion https://mcp.notion.com/sse

# View quarantine status
mcpproxy upstream list
# 🔒 notion  http  0  Pending approval  Approve in Web UI

# Approve in web UI or via API:
curl -X POST "http://localhost:8080/api/v1/servers/notion/unquarantine" \
  -H "X-API-Key: your-key"
```

### Bulk Operations Warning

⚠️  **Safety Warning: Bulk Operations**

The `--all` flag affects all servers simultaneously:

- `disable --all` - Stops all upstream connections (reversible with `enable --all`)
- `enable --all` - Activates all servers (may trigger API calls, OAuth flows)
- `restart --all` - Reconnects all servers (may cause brief service disruption)

**Best practices:**
- Use `upstream list` first to see affected servers
- Test with single server before using `--all`
- Use `--force` in automation only when appropriate

### Interactive Confirmation

Confirmation prompt shows count:

```bash
⚠️  This will disable 12 server(s). Continue? [y/N]:
```

Shows what will be affected before proceeding.

---

## Tool Management (`mcpproxy tools`)

Global view and per-tool enable/disable across all configured servers.

### `mcpproxy tools list`

List tools from upstream servers. Without `--server`, lists every tool across
all servers from the consolidated endpoint (requires daemon). With `--server`,
lists tools from that specific server only (daemon or standalone).

**Usage:**
```bash
mcpproxy tools list [flags]
```

**Flags:**
- `--server, -s` - Server name (optional; omit for global list)
- `--status` - Filter by state: `enabled`, `disabled`, `config-denied`
- `--risk` - Filter by risk level: `read`, `write`, `destructive`
- `--approval` - Filter by approval: `approved`, `pending`, `changed`
- `--output, -o` - Output format: `table`, `json`, `yaml`
- `--log-level, -l` - Log level [default: info]
- `--config, -c` - Path to config file
- `--timeout, -t` - Connection timeout [default: 30s]
- `--trace-transport` - Enable HTTP/SSE frame-by-frame tracing

**Examples:**
```bash
# Global list (all servers) — requires daemon
mcpproxy tools list
mcpproxy tools list -o json | jq '.[0]'

# Filtered list
mcpproxy tools list --status disabled
mcpproxy tools list --risk read
mcpproxy tools list --approval pending

# Server-scoped debug listing (daemon or standalone)
mcpproxy tools list --server=github-server
mcpproxy tools list --server=github-server --log-level=trace
```

**Output Columns (global view):**
- NAME, SERVER, STATE (enabled/disabled/config-denied), APPROVAL, USAGE, LAST USED, DESCRIPTION

---

### `mcpproxy tools enable <server:tool> [...]`

Enable one or more tools. Requires daemon.

**Usage:**
```bash
mcpproxy tools enable <server:tool> [<server:tool>...]
```

**Examples:**
```bash
mcpproxy tools enable github:create_issue
mcpproxy tools enable github:create_issue github:list_repos memory:create_entities
```

**Behavior:**
- Each `server:tool` is parsed by splitting on the first `:` (tool names may contain `:`)
- All targets are attempted independently; invalid targets are reported without aborting others
- Prints `OK <server:tool>: enabled` or `FAILED <server:tool>: <reason>` per target
- Exits non-zero if any target failed (enabling partial failure detection in scripts)

---

### `mcpproxy tools disable <server:tool> [...]`

Disable one or more tools. Requires daemon.

**Usage:**
```bash
mcpproxy tools disable <server:tool> [<server:tool>...]
```

**Examples:**
```bash
mcpproxy tools disable github:create_issue
mcpproxy tools disable everything:echo memory:foo
echo "exit: $?"   # non-zero if any failed
```

**Behavior:**
- Same per-target processing and exit-code semantics as `tools enable`
- Config-denied tools fail individually (server rejects) without aborting other targets

---

### `mcpproxy tools approve [<server:tool>...]`

Approve tools pending tool-level quarantine (Spec 032), clearing `pending` /
`changed` tools for use without the Web UI or MCP. Requires daemon.

**Usage:**
```bash
mcpproxy tools approve <server:tool> [<server:tool>...]
mcpproxy tools approve --server <name> <tool> [<tool>...]
mcpproxy tools approve --server <name> --all
```

**Flags:**
- `-s, --server <name>` - Scope bare tool names to this server (required with `--all`)
- `--all` - Approve every pending/changed tool for `--server`

**Examples:**
```bash
mcpproxy tools approve github:create_issue
mcpproxy tools approve github:create_issue github:list_repos
mcpproxy tools approve --server github create_issue list_repos
mcpproxy tools approve --server github --all
mcpproxy tools approve --server github --all -o json
```

**Behavior:**
- Targets are either `<server>:<tool>` pairs (the colon form wins) or bare tool
  names scoped via `--server`; bare names without `--server` are rejected
- Targets are grouped per server; each server group is processed independently
- `--all` requires `--server` and cannot be combined with explicit targets
- Prints `OK <server>: approved N tool(s)` per server group; exits non-zero if
  any server group failed
- `-o json|yaml` (or `MCPPROXY_OUTPUT`) emits a structured per-server result array

---

### `mcpproxy tools reject [<server:tool>...]`

Reject (block) tools pending tool-level quarantine (Spec 032). Reject maps to
the **block** action: the tool is atomically approved **and** disabled (hidden),
so it is never left in the approved+enabled state — mirroring the Web UI "Block"
button. Requires daemon.

**Usage:**
```bash
mcpproxy tools reject <server:tool> [<server:tool>...]
mcpproxy tools reject --server <name> <tool> [<tool>...]
mcpproxy tools reject --server <name> --all
```

**Flags:**
- `-s, --server <name>` - Scope bare tool names to this server (required with `--all`)
- `--all` - Reject every pending/changed tool for `--server`

**Examples:**
```bash
mcpproxy tools reject github:delete_repo
mcpproxy tools reject --server github delete_repo force_push
mcpproxy tools reject --server github --all
```

**Behavior:**
- Same target parsing, per-server grouping, exit-code, and output-format
  semantics as `tools approve`
- Prints `OK <server>: blocked N tool(s)` per server group

---

## Exit Codes

- `0` - Success
- `1` - Execution failure (API error, connection failure, user declined confirmation)
- `2` - Invalid arguments or configuration (non-interactive without --force)

---

## Implementation Notes

### Architecture
- Commands in `cmd/mcpproxy/*_cmd.go`
- Client library in `internal/cliclient/client.go`
- API endpoints in `internal/httpapi/server.go`

### Adding New Commands
1. Create command file in `cmd/mcpproxy/`
2. Add methods to `internal/cliclient/client.go`
3. Register in `cmd/mcpproxy/main.go`
4. Follow existing patterns for daemon detection
5. Support both daemon and standalone modes where possible

### Testing
All commands support manual testing:
```bash
go build -o mcpproxy ./cmd/mcpproxy
./mcpproxy <command> [args]
```
