Skip to content
Back to skills

Mcp Repair

ASecurity

Repair broken MCP: a tool call fails, a server reports "Connection closed", tools that used to exist are gone, a project moved or its venv was rebuilt, junk breaks the stdio stream, or a server answers from the CLI but not from the session. Method: split client / server / environment first, then walk a 5-step ladder (real name → status → logs → CLI reproduction → stdio probe) and fix by category. Use for any "MCP is broken", "the browser tool is not called", "everything broke after the move".

  • 15 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added November 7, 2026
developmentpythongoshellbashsqlbackend

Works with

  • cli
  • mcp

Security analysis

A100/100

Scanned November 7, 2026

npx -y skills add youlianvr/oper-share --skill mcp-repair --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Mcp Repair?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Mcp Repair
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/youlianvr-mcp-repair/badge)](https://www.skillsdirectory.com/skills/youlianvr-mcp-repair)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: mcp-repair
description: >-
  Repair broken MCP: a tool call fails, a server reports "Connection closed",
  tools that used to exist are gone, a project moved or its venv was rebuilt,
  junk breaks the stdio stream, or a server answers from the CLI but not from
  the session. Method: split client / server / environment first, then walk a
  5-step ladder (real name → status → logs → CLI reproduction → stdio probe) and
  fix by category. Use for any "MCP is broken", "the browser tool is not called",
  "everything broke after the move".
---

# MCP-Repair — fix MCP the way we fixed it

A method for taking apart any MCP breakage, built from real incidents: "Connection
closed", `✗ tools.<server>.<tool>`, relocated directories, broken venvs.

**The main principle:** first **split** — is the client, the server or the
environment broken — then fix. Most of the time goes into fixing the wrong one.

## When to use

- A tool call fails inside the session while the server looks configured.
- `MCP server failed: Connection closed`, or the server drops mid-call.
- The model says "tool not found" while the tool should exist.
- After moving or renaming a project directory, or rebuilding a venv/system.
- "research fell over for no reason", "the browser tool does not answer".

## The ladder: steps 0–5

### Step 0 — Resolve the real tool name (never from memory)

In this runtime there is one shape: `search_mcp_tools` finds a tool, then
`call_mcp_tool(server, tool, arguments)` runs it. The server name must match
`~/.agents/mcp.json` exactly; a tool name copied from another client
(`tools.x.y`, `mcp__x__y`, `mcp_x_y`) is the symptom "read from the wrong client",
not a server fault.

### Step 1 — Status: is the server alive at all?

Start with the cheapest read-only tool of that server through the live surface. A
clean answer is health. Two config files matter, and they are not interchangeable:

| File | Shape | Who reads it |
|---|---|---|
| `~/.freebuff/mcp.json` | app consent store: hash-keyed entries, `enabled`, `allowedTools`, approved manifest | the session's own tool surface |
| `~/.agents/mcp.json` | classic `mcpServers` object with `command`/`args`/`env` | `_scripts/mcp-call.py` |

- Tool answers → the server is fine; the problem is the caller (step 2).
- Tool missing from the surface → the server is not enabled for this thread, or its
  entry is broken. Check the consent record before touching the config.
- "Connection closed" → step 3 for the server, then step 5 for the client path.

Do not hand-edit `~/.freebuff/mcp.json`: the app owns that schema. A change goes
through the consent flow.

### Step 2 — The call, not the server

Re-read the tool's schema (`search_mcp_tools` with the server named) and compare it
with the arguments actually sent. Most "internal failure" reports are a missing
required field, a path with the wrong separator, or a query the backend rejects.
Never resend identical invalid arguments: either build one valid request or stop
and report the missing information.

### Step 3 — Reproduce outside the session

The bridge mounts any configured stdio server in the current thread without a
runtime restart:

```bash
python _scripts/mcp-call.py <server> tools
python _scripts/mcp-call.py <server> <tool> '{"query": "test"}'
python _scripts/mcp-call.py <server> <tool> --json          # raw result
```

- **Bridge works** → server and request are fine; the problem is the session's tool
  surface or transport (steps 4–5).
- **Bridge fails** → the server: read the traceback, and look at the raw exception
  before theorising.

### Step 4 — stdio probe: is the protocol clean?

A server that prints anything into stdout before JSON-RPC breaks the stream. Probe
it the same way the bridge does — one `initialize`, then one `tools/list`:

```bash
python - <<'PY'
import asyncio, json
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client

async def main():
    params = StdioServerParameters(command="uv", args=["run", "--project", "<abs>/<server>", "-m", "<server>", "mcp"])
    async with stdio_client(params) as (r, w):
        async with ClientSession(r, w) as s:
            print(json.dumps((await s.initialize()).model_dump())[:300])
            print(len((await s.list_tools()).tools), "tools")

asyncio.run(main())
PY
```

- A clean handshake and a tool count → go to step 5 by category.
- Junk or a hang → the startup wrapper writes into stdout: look for a top-level
  `print()` in the module (outside `def main`), a progress bar, or a shell banner in
  the configured `command`.

### Step 5 — Fix by category

**Server fix (raw exceptions).** If a tool catches only its own errors while
something raw (sqlite, network, a broken page) escapes into the protocol, wrap it and
return a readable error so the connection survives:

```python
except ResearchError as exc:
    raise ValueError(str(exc)) from exc
except Exception as exc:  # noqa: BLE001 — a readable error instead of tearing down stdio
    raise ValueError(f"<tool> failed internally: {type(exc).__name__}: {exc}") from exc
```

Storage degrades gracefully: a sqlite error means cache-less mode plus a warning, not
a crash — the next call must still be able to run.

**Environment fix (after a move or a rebuild).**

1. Editable installs break first: `site-packages/*.pth` and
   `*.dist-info/direct_url.json` hold **absolute** paths (telltale: `ImportError`
   while `python -c "import sys"` works) → rewrite them or reinstall.
2. Console scripts in `bin/` (Windows: `Scripts/`) carry an absolute shebang → reinstall.
3. `pyvenv.cfg` and `bin/python` usually survive a move — check the `.pth` files first.
4. Config entries with absolute paths: prefer `uv run --project <abs>` over a baked
   interpreter path.

**Client fix.** A server that is fine through the bridge but absent in the session is
a consent/thread problem: verify the server is enabled and allowed in
`~/.freebuff/mcp.json`, and let the app's consent flow do the change. A restart of
the thread is the last resort, not the first move.

## Diagnosis vs recovery

| Symptom | First action |
|---|---|
| Tool call "failed internally" | read the schema and the arguments; fix the server's broad except only if it is genuinely hiding a raw error |
| `Connection closed` | bridge reproduction (step 3), then the stdio probe |
| The tool returned, but the result is empty | server log / `err.log`; bridge call with the same arguments |
| Everything fine in the bridge, broken in the session | tool surface/consent; large responses and timeouts |
| After moving the project | `.pth`/`direct_url.json`, config paths, then re-enable |

## Checks after the fix

1. `python _scripts/mcp-call.py <server> tools` lists the expected tools.
2. One real read-only call through the session returns a result, not a bare error.
3. The failing request is repeated once — the error, if any, is now readable.

## References

- `skills/mcp/parts/mcp-usage/` — which server serves which task, and the config rules.
- `_scripts/mcp-call.py` — the bridge; `--json` for raw output, `--timeout` for slow servers.
- `skills/mcp/parts/mcp-repair/` incidents: searchmcp research resiliency (cache degradation +
  broad except), BrowserMCP stdio, relocated venvs.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.