mcp-manager · git:20260524.9ad1b1c · 2026-05-24 · sha256 ab84d83182ffac8a

mcp-manager git:20260524.9ad1b1cA

Immutable. This exact content is served forever at /api/v1/blob/ab84d83182ffac8a.

---
name: mcp-manager
description: |
  Manage MCP (Model Context Protocol) servers for openclacky: add, list, probe, remove,
  reconfigure. Edits ~/.clacky/mcp.json so the user never writes JSON by hand.
  Trigger on: add mcp, install mcp, setup mcp, configure mcp, mcp list, mcp remove,
  mcp probe, mcp reconfigure.
argument-hint: "add | list | probe <name> | remove <name> | reconfigure <name>"
allowed-tools:
  - Bash
  - Read
  - Write
  - Edit
  - AskFollowupQuestion
---

# MCP Manager Skill

Manage MCP servers for openclacky. The user's MCP configuration lives at
`~/.clacky/mcp.json` (the same format Claude Desktop and Cursor use). You never
ask the user to edit it by hand — you do it for them through the local clacky
HTTP API.

---

## Command Parsing

| User says | Subcommand |
|---|---|
| `add mcp`, `install mcp`, `connect <something>`, "I want clacky to read my files / access github / query my db / search the web" | `add` |
| `mcp list`, `mcp status`, "what mcps do I have" | `list` |
| `mcp probe <name>`, "what tools does <name> have" | `probe` |
| `mcp remove <name>`, `mcp delete <name>` | `remove` |
| `mcp reconfigure <name>`, `mcp fix <name>` | `reconfigure` |

If the intent is unclear, default to **`add`** — it's the most common ask.

---

## Server Coordinates

All API calls go to the local clacky server. The host and port are exposed via
environment variables:

```bash
HOST="${CLACKY_SERVER_HOST:-127.0.0.1}"
PORT="${CLACKY_SERVER_PORT:-7070}"
BASE="http://${HOST}:${PORT}"
```

All write operations require requests to come from `127.0.0.1` or `::1`. They
will, because we're running locally.

---

## API Cheat Sheet

| Action | Call |
|---|---|
| List configured servers | `curl -s ${BASE}/api/mcp` |
| Add a server | `curl -s -X POST ${BASE}/api/mcp -H 'Content-Type: application/json' -d '{...}'` |
| Update a server | `curl -s -X PUT ${BASE}/api/mcp/<name> -H 'Content-Type: application/json' -d '{...}'` |
| Remove a server | `curl -s -X DELETE ${BASE}/api/mcp/<name>` |
| Probe tools | `curl -s -X POST ${BASE}/api/mcp/<name>/probe` |

Request body for create/update — **stdio** (local process, default):

```json
{
  "name": "filesystem",
  "command": "npx",
  "args": ["-y", "@modelcontextprotocol/server-filesystem", "/Users/me/Documents"],
  "env": { "API_KEY": "xxx" },
  "description": "Read/write files in ~/Documents"
}
```

Request body for create/update — **http** (remote server, streamable-http):

```json
{
  "name": "linear",
  "type": "http",
  "url":  "https://mcp.linear.app/sse",
  "headers": { "Authorization": "Bearer lin_api_xxx" },
  "description": "Linear issues and projects"
}
```

If `type` is omitted but `url` is present, the server treats it as `http`.

---

## Known-Good Server Catalog

When the user describes what they want, match it to one of these and propose it.
Each entry: package, what it does, required params, recommended `description`.

### 1. `filesystem` — read/write local files
- **When**: "read my files", "access my desktop", "browse my code"
- **Command**: `npx`
- **Args**: `["-y", "@modelcontextprotocol/server-filesystem", "<ABSOLUTE_PATH>"]`
- **Required**: absolute directory path (ask user; default to `~/Documents`)
- **Tools**: read_file, write_file, list_directory, search_files, etc.

### 2. `github` — GitHub repos, issues, PRs
- **When**: "access github", "manage my repos", "read my issues"
- **Command**: `npx`
- **Args**: `["-y", "@modelcontextprotocol/server-github"]`
- **Env**: `{ "GITHUB_PERSONAL_ACCESS_TOKEN": "<TOKEN>" }`
- **Required**: PAT from https://github.com/settings/tokens (recommend `repo` scope)

### 3. `fetch` — fetch HTTP URLs as markdown
- **When**: "fetch web pages", "read articles by url"
- **Command**: `uvx`
- **Args**: `["mcp-server-fetch"]`
- **Required**: nothing
- **Note**: needs Python `uv` installed (`brew install uv`)

### 4. `memory` — persistent knowledge graph
- **When**: "remember things across sessions", "give clacky long-term memory"
- **Command**: `npx`
- **Args**: `["-y", "@modelcontextprotocol/server-memory"]`
- **Required**: nothing

### 5. `postgres` — query a Postgres database
- **When**: "query my database", "connect to postgres"
- **Command**: `npx`
- **Args**: `["-y", "@modelcontextprotocol/server-postgres", "<DATABASE_URL>"]`
- **Required**: DATABASE_URL like `postgresql://user:pass@host:5432/dbname`

### 6. `slack` — Slack messages
- **When**: "read slack", "send slack messages"
- **Command**: `npx`
- **Args**: `["-y", "@modelcontextprotocol/server-slack"]`
- **Env**: `{ "SLACK_BOT_TOKEN": "xoxb-...", "SLACK_TEAM_ID": "T..." }`
- **Required**: bot token and team id (Slack admin → app config)

### 7. `brave-search` — web search via Brave API
- **When**: "search the web", "give clacky search"
- **Command**: `npx`
- **Args**: `["-y", "@modelcontextprotocol/server-brave-search"]`
- **Env**: `{ "BRAVE_API_KEY": "<KEY>" }`
- **Required**: free API key from https://api.search.brave.com/

### 8. `puppeteer` — browser automation
- **When**: "automate the browser", "scrape with js"
- **Command**: `npx`
- **Args**: `["-y", "@modelcontextprotocol/server-puppeteer"]`
- **Required**: nothing (downloads Chromium on first run)

### Custom (anything else)
If the user names a package or path you don't recognize, take the spec from them
verbatim and pass it through. Always confirm `command`, `args`, and `env` back
in plain language before saving.

### Remote / HTTP servers (streamable-http)
Some MCP servers are hosted services and don't ship as a CLI — you connect over
HTTPS instead. **Trigger when** the user gives you a URL ending in `/mcp`,
`/sse`, or hosted on `*.mcp.*` / `mcp.*.app`, or says "the server is at
https://...".

- **Type**: `http`
- **Required**: `url` (the streamable-http endpoint)
- **Optional**: `headers` — typically `{ "Authorization": "Bearer <token>" }`

Examples of remote MCP servers in the wild:
- Linear: `https://mcp.linear.app/sse` (Bearer API key)
- Cloudflare: `https://<workers-subdomain>.workers.dev/mcp` (Bearer token)
- GitHub Copilot: `https://api.githubcopilot.com/mcp/` (OAuth, advanced)

When the user pastes a URL, ask:
1. What service is this? (so you can pick a `name` and `description`)
2. Does it need an authorization header? If yes, paste the token.

Save with `type: "http"`. The local clacky never spawns a process for these —
it just POSTs JSON-RPC over HTTPS.

> ⚠️ Wrapping a regular CLI tool: if the user gives you a CLI command that is
> **not** a stdio MCP server (e.g. `mcp-cli`, `some-api-cli login`), do NOT save
> it as a stdio MCP entry — it won't speak JSON-RPC over stdin. Tell them: *"This
> looks like a regular CLI, not an MCP server. Does the service offer an HTTPS
> endpoint instead?"*

---

## Subcommand: `add` — the primary flow

Goal: the user describes what they want, you produce a working MCP entry +
confirm it works. Keep questions minimal.

### Step 1 — Identify intent
- If the user's first message already names a server (e.g. "add filesystem"),
  pick that catalog entry directly.
- Otherwise, ask **one** open question: *"What would you like Clacky to be
  able to do? (e.g. read your files, access GitHub, search the web)"*
- Match their answer to the catalog. If multiple match, present 2–3 options
  with one-line descriptions and let them pick.

### Step 2 — Environment preflight
Before asking for parameters, check the runtime is installed:

```bash
# For npx-based servers
which npx >/dev/null 2>&1 || echo "MISSING_NPX"

# For uvx-based servers
which uvx >/dev/null 2>&1 || echo "MISSING_UVX"
```

If missing, tell the user how to install (`brew install node` for npx,
`brew install uv` for uvx) and stop. Do not proceed.

### Step 3 — Collect parameters
Ask only for the **business-meaningful** params from the catalog entry:
- For `filesystem`: which directory? Default offer: `~/Documents`. Resolve `~`
  to an absolute path before saving.
- For `github`/`brave-search`/`slack`: tell them where to get the token, then
  ask them to paste it.
- For `postgres`: ask for the connection URL.

Never invent values. If you don't have a sensible default, ask.

### Step 4 — Confirm
Show the user the spec you're about to save, in plain language:

> I'll add a server called **filesystem** that runs `npx -y @modelcontextprotocol/server-filesystem /Users/me/Documents`. It'll let me read and write files in your Documents folder. OK?

For secrets (tokens, passwords), echo only the last 4 characters: `***...abcd`.

### Step 5 — Save
For stdio:
```bash
curl -s -X POST ${BASE}/api/mcp \
  -H 'Content-Type: application/json' \
  -d '{
        "name":        "filesystem",
        "command":     "npx",
        "args":        ["-y", "@modelcontextprotocol/server-filesystem", "/Users/me/Documents"],
        "description": "Read/write files in ~/Documents"
      }'
```

For http:
```bash
curl -s -X POST ${BASE}/api/mcp \
  -H 'Content-Type: application/json' \
  -d '{
        "name":        "linear",
        "type":        "http",
        "url":         "https://mcp.linear.app/sse",
        "headers":     { "Authorization": "Bearer lin_api_xxx" },
        "description": "Linear issues and projects"
      }'
```

If the response has `"ok": false`, show the error and ask the user how to
proceed (retry, edit, abort).

### Step 6 — Probe
Immediately verify the server starts and exposes tools:

```bash
curl -s -X POST ${BASE}/api/mcp/filesystem/probe
```

- **`ok: true`**: extract `tools[]`, summarize for the user. Example:
  > Done. **filesystem** is working — Clacky now has 11 new tools (read_file, write_file, list_directory, ...). Try asking me to *list files in your Documents folder*.
- **`ok: false`**: show the error verbatim and offer common fixes:
  - "command not found" → wrong runtime, suggest re-running with correct one
  - "ENOENT" / "no such file" → bad path, ask for a valid one
  - timeout → package may be downloading on first run; suggest retrying
  - auth-related → token wrong/expired, offer `reconfigure`

### Step 7 — Hint at next steps
End with a one-line nudge: how the user can use the new MCP next. Examples:
- filesystem: "Try: *list the files in my Documents folder*"
- github: "Try: *show me my open PRs*"
- fetch: "Try: *fetch https://news.ycombinator.com and summarize*"

---

## Subcommand: `list`

```bash
curl -s ${BASE}/api/mcp
```

Render as a short table. If `configured: false`, say so and offer to run `add`.

```
| Name         | Command | Args summary           | Has env |
|--------------|---------|------------------------|---------|
| filesystem   | npx     | @modelcontextprotocol… | no      |
| github       | npx     | @modelcontextprotocol… | yes     |
```

Don't show full args if they contain absolute paths — collapse them with `…`.

---

## Subcommand: `probe <name>`

```bash
curl -s -X POST ${BASE}/api/mcp/<name>/probe
```

If `ok: true`, list every tool with a one-line description. If `ok: false`, run
the same error-fixing flow as in `add` step 6.

---

## Subcommand: `remove <name>`

1. Confirm with the user first: *"Remove **<name>**? Its tools will no longer
   be available to Clacky. (Y/n)"*
2. On yes:
   ```bash
   curl -s -X DELETE ${BASE}/api/mcp/<name>
   ```
3. Confirm completion in one line.

---

## Subcommand: `reconfigure <name>`

1. Fetch current spec from `/api/mcp` and show it back.
2. Ask which fields to change (path / token / args).
3. Build the new spec and `PUT /api/mcp/<name>`.
4. Probe to verify, same as `add` step 6.

---

## General Rules

- **Never write directly to `~/.clacky/mcp.json`.** Always go through the API.
- **Never echo full secrets.** Mask all but last 4 chars of tokens/URLs.
- **One question at a time.** Don't dump a form on the user.
- **Stop on errors.** Don't proceed past a failed preflight or probe.
- **Quote real error messages.** Don't paraphrase API errors — users may need to
  google them.
- **Stay in scope.** If the user wants to write/edit a non-MCP file or do
  unrelated work, hand back to the main agent.