π¦ Kitsune MCP
The agent harness for MCP.
One config entry. Borrow any of 130,000+ servers mid-session β develop live, reach the long tail, try community code contained β then shift back.
Session survives.
[](https://pypi.org/project/kitsune-mcp/)
[](https://www.npmjs.com/package/kitsune-mcp)
[](https://registry.modelcontextprotocol.io/v0/servers?search=io.github.kaiser-data%2Fkitsune-mcp)
[](https://pypi.org/project/kitsune-mcp/)
[](https://github.com/kaiser-data/kitsune-mcp/actions)
[](https://codecov.io/gh/kaiser-data/kitsune-mcp)
[](LICENSE)
[](https://smithery.ai/server/@kaiser-data/kitsune-mcp)
[](https://glama.ai/mcp/servers/kaiser-data/kitsune-mcp)
[](https://discord.gg/EYgcf7EX)
---
Kitsune is a **runtime MCP proxy**: one always-on gateway your agent uses to reach the rest of the ecosystem. `search` finds a server across 7 registries. `shapeshift(id)` mounts its tools in the current turn. `shapeshift()` drops them. No config edit. No client restart.
```text
search β shapeshift β call β shapeshift() # reach, use, release
connect β shapeshift β edit β reload β call # MCP REPL (default install)
```
**Install for reach and live execution β not for token savings.** Native Tool Search already defers schemas for servers you've configured. Kitsune covers what Tool Search cannot: servers you've never set up, servers you're writing right now, and community packages you want to try without wiring them into `mcp.json` forever.
| | Loop | Why it wins |
|---|---|---|
| **MCP REPL** | edit β `reload` β `call` | Iterate on your own server without killing the session |
| **Long-tail reach** | `search` β `shapeshift` β `call` | One-offs and obscure APIs with no pre-install |
| **Try-before-you-trust** | `confirm=True` + Docker cage on by default + TOFU pins | Community catalog without blind always-on installs |
| Use Kitsune when⦠| Skip it when⦠|
|---|---|
| You're building an MCP and need an edit/reload loop | You only need 1β3 trusted servers (configure them natively) |
| A task needs a server that isn't in your config | Every turn hits the same server (keep it always-on) |
| CLI flag-guessing on a long-tail API is too risky | You want cheaper tokens β floor is **~1,774 tokens/turn**, additive on modern clients |
| You want to evaluate community MCP code safely | Unattended prod admin/billing/security keys ([Safety](#safety-model)) |
| You're consolidating a crowded MCP config ([GATEWAY](#gateway-consolidate-always-on-servers)) | You need sub-second first call (cold mount ~1β15s β `prewarm` or always-on) |
Worked high-stakes flows (IAM, IR, audits): [`examples/scenarios/`](./examples/scenarios/). CLI vs MCP accuracy argument lives there too β short version: models nail common CLI commands and fail on the long tail; Kitsune mounts schemas only while you need them.
---
## Contents
- [Installation](#installation)
- [Quick start](#quick-start)
- [Developing an MCP server live](#developing-an-mcp-server-live)
- [How it works](#how-it-works)
- [Tool reference](#tool-reference)
- [Server sources](#server-sources)
- [Safety model](#safety-model)
- [GATEWAY: consolidate always-on servers](#gateway-consolidate-always-on-servers)
- [Performance](#performance)
- [Configuration](#configuration)
- [Mount patterns](#mount-patterns)
- [For MCP developers](#for-mcp-developers)
- [Why Kitsune?](#why-kitsune)
- [Contributing](#contributing)
---
## Installation
```bash
pip install kitsune-mcp # recommended
# or
uvx kitsune-mcp # isolated env via uv, no venv setup
# or
npx kitsune-mcp # npm (delegates to uvx internally)
```
**Requirements:** Python 3.12+ Β· `node`/`npx` for npm-based servers Β· `uvx` from [uv](https://github.com/astral-sh/uv) for PyPI-based servers Β· Docker optional (sandbox)
Add once to your MCP client config:
```json
{
"mcpServers": {
"kitsune": { "command": "kitsune-mcp" }
}
}
```
| Client | Config file |
|---|---|
| Claude Desktop (macOS) | `~/Library/Application Support/Claude/claude_desktop_config.json` |
| Claude Desktop (Windows) | `%APPDATA%\Claude\claude_desktop_config.json` |
| Claude Code | `~/.claude/mcp.json` |
| Cursor / Windsurf | `~/.cursor/mcp.json` |
| Cline / Continue.dev | VS Code settings / `~/.continue/config.json` |
Also works with OpenClaw, Zed, and any MCP-compatible client.
Lean profile at rest: **9 tools Β· ~1,774 tokens/turn** (`status`, `search`, `auth`, `shapeshift`, `call`, `auto`, plus the `connect` / `release` / `reload` REPL trio) β measured via `python examples/benchmark.py`.
---
## Quick start
**Borrow a server you never configured:**
```python
search("web scraping")
shapeshift("firecrawl", tools=["scrape_url"]) # surgical: one tool, not the whole surface
call("scrape_url", arguments={"url": "https://example.com"})
shapeshift() # drop form β session stays up
```
**Community / long-tail (confirm; caged by default):**
```python
search("pdf", registry="glama")
shapeshift("mcp-pdf-tools", confirm=True) # npm/PyPI caged in Docker by default (when available)
call("extract_text", arguments={"path": "report.pdf"})
shapeshift("mcp-pdf-tools", confirm=True, sandbox=False) # opt out of the cage
shapeshift()
```
**Hosted (Smithery HTTP β needs a free `SMITHERY_API_KEY`):**
```python
search("exa", registry="smithery")
shapeshift("exa")
call("web_search_exa", arguments={"query": "MCP registry growth 2026"})
shapeshift()
```
**Credentials mid-session:**
```python
auth("BRAVE_API_KEY", "sk-...")
shapeshift("brave", tools=["brave_web_search"])
call("brave_web_search", arguments={"query": "MCP protocol 2026"})
shapeshift()
```
**One-shot** β pass `server_hint` when you know the id (`auto` without it is best-effort and can misfire):
```python
auto("current time in Tokyo", server_hint="mcp-server-time")
```
Full live walkthrough: [`docs/demo-realtime.md`](docs/demo-realtime.md).
---
## Developing an MCP server live
Building an MCP normally means: edit β restart client β lose session β re-test. Kitsune turns that into an **MCP REPL** in one session β and `connect` / `release` / `reload` are in the **default lean profile**, so this works on a plain `pip install` with no `KITSUNE_TOOLS=all`.
```python
connect("uvx --from . my-mcp-server", name="dev") # start child process
shapeshift("dev") # mount tools β client sees them
call("summarize", arguments={"url": "https://example.com"})
# β¦ edit the tool in your editor β¦
reload("dev") # release β restart fresh code β remount, one call
call("summarize", arguments={"url": "https://example.com"})
```
`reload("dev")` folds the whole cycle β kill the stale process, start your edited code, remount so the client sees the new schemas β into a single call. It also removes the classic footgun: calling `connect()` again after an edit *without* releasing first hands you back the **old** process; `reload` always releases first.
Local `connect()` targets are untrusted (`confirm` / `KITSUNE_TRUST` apply). Process isolation β security sandbox β see [Safety model](#safety-model). Companion skill: `kitsune-dev`.
---
## How it works
`shapeshift(server_id)` picks a transport (stdio / HTTP+SSE / WebSocket / Docker), connects, fetches `tools/list`, and registers each tool as a native FastMCP tool with the server's real schema. The client gets `notifications/tools/list_changed` and sees first-class tools β no wrapper indirection.
`shapeshift()` with no args deregisters proxies, closes the connection, and returns to the lean baseline.