https://github.com/kaiser-data/kitsune-mcp
The shape-shifting MCP hub โ shapeshift() into 10,000+ MCP servers at runtime. One entry point, no restarts, 7 registries.
https://github.com/kaiser-data/kitsune-mcp
ai-agents anthropic claude fastmcp llm-tools mcp mcp-hub mcp-registry mcp-server model-context-protocol python smithery
Last synced: about 1 month ago
JSON representation
The shape-shifting MCP hub โ shapeshift() into 10,000+ MCP servers at runtime. One entry point, no restarts, 7 registries.
- Host: GitHub
- URL: https://github.com/kaiser-data/kitsune-mcp
- Owner: kaiser-data
- License: mit
- Created: 2026-02-21T23:09:20.000Z (4 months ago)
- Default Branch: main
- Last Pushed: 2026-05-02T00:06:31.000Z (about 2 months ago)
- Last Synced: 2026-05-02T02:21:49.853Z (about 2 months ago)
- Topics: ai-agents, anthropic, claude, fastmcp, llm-tools, mcp, mcp-hub, mcp-registry, mcp-server, model-context-protocol, python, smithery
- Language: Python
- Size: 3.01 MB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Security: SECURITY.md
Awesome Lists containing this project
README
๐ฆ Kitsune MCP
One config entry. 10,000+ servers on demand. Up to 95% less MCP token overhead.
[](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 gateway MCP server that discovers, installs, and dynamically loads any of 10,000+ MCP servers at runtime. Instead of keeping every server's tools in context permanently, Kitsune mounts tools on demand via `shapeshift()` and releases them when done. Five tools at rest. Thousands available on request. No restarts.
### Why not just shell out to a CLI?
Shelling out to `aws`, `gcloud`, `kubectl`, or `gh` from a Bash tool *also* costs ~0 tokens at rest. So why MCP at all?
**Because long-tail CLI commands fail.** LLMs have great recall on the top ~20 commands of a CLI they've seen in training (`git status`, `gh pr list`, `aws s3 cp`) and steeply degraded recall on everything else. For an API surface the size of `aws` (~9,000 subcommands), first-call success drops to **30โ50%** on long-tail operations โ wrong flag names, singular-vs-plural verbs, case-sensitive enums, and silently-deprecated options. Each miss costs a retry turn, and the worst failures aren't errors but *plausible-looking wrong calls that succeed*.
MCP gives you structured tool schemas the model can read and validate against:
| Approach | Long-tail accuracy | Failure mode | Token cost at rest |
|---|---|---|---|
| CLI fallback | ~30โ50% on rare subcommands | Hallucinated flags, silent wrong calls | ~0 |
| Always-on MCP | ~95% across the whole surface | Schema bloat in every turn | ~10โ15K per server |
| **Kitsune (mount on demand)** | **~95% โ only when you need it** | None โ schemas drop after `shiftback()` | **~965 tokens** |
That's the structural argument for the hub model: **CLI-cheap at rest, MCP-accurate when it matters**. For one-off ops on a CLI the model knows cold, `gh` is fine. For unfamiliar APIs, internal tooling, or any operation where a wrong call has real cost (production AWS changes, billing operations, security flows), Kitsune gives you schema-validated execution without the always-on tax. See [`examples/scenarios/`](./examples/scenarios/) for seven worked use cases.
### Token savings vs always-on
The savings grow with every server you add โ because Kitsune's resting cost stays flat at ~965 tokens (measured: 6 lean-profile tools) no matter how many servers live behind it:
Saving formula: `1 โ (Kitsune base 965 + surgical mount) / always-on total`
| Always-on servers | Always-on/turn | Kitsune per active call | Saved |
|---|---:|---:|---:|
| GitHub (26 tools) | 4,229 | ~1,265 (965 + ~300) | **70%** |
| GitHub + filesystem + git | 8,678 | ~1,265โ1,655 | **81โ85%** |
| Notion + GitHub + filesystem + git + memory | 25,000 | ~1,265โ2,915 | **88โ95%** |
Savings grow because Kitsune's ~965-token baseline is shared across all registered servers โ you only pay it once regardless of how many are behind it.
Fewer tools in context also means more reliable answers. Research consistently shows LLM tool-selection degrades as the visible tool count grows โ Kitsune keeps the model focused on exactly what the current task needs.
---
## Contents
- [Why not just shell out to a CLI?](#why-not-just-shell-out-to-a-cli)
- [Installation](#installation)
- [Quick start](#quick-start)
- [How it works](#how-it-works)
- [Tool reference](#tool-reference)
- [Server sources](#server-sources)
- [GATEWAY: context bloat detection](#gateway-context-bloat-detection)
- [Performance](#performance)
- [Configuration](#configuration)
- [Agent profiles](#agent-profiles)
- [Security](#security)
- [For MCP developers](#for-mcp-developers)
- [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
Add to your MCP client config โ once, globally:
```json
{
"mcpServers": {
"kitsune": { "command": "kitsune-mcp" }
}
}
```
Compatible with Claude Desktop, Claude Code, Cursor, Cline, OpenClaw, Continue.dev, Zed, and any MCP-compatible client.
| 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` |
---
## Quick start
```python
# Find a server
search("web scraping")
# Mount specific tools, use them, release
shapeshift("notion-hosted", tools=["notion-search"])
call("notion-search", arguments={"query": "roadmap"})
shapeshift() # context returns to ~965 tokens
# One-shot via auto() โ use server_hint for reliable routing
auto("current time in Tokyo", server_hint="mcp-server-time")
# Store a credential, then mount
auth("BRAVE_API_KEY", "sk-...")
shapeshift("brave", tools=["brave_web_search"])
call("brave_web_search", arguments={"query": "MCP protocol 2025"})
shapeshift()
```
---
## How it works
Kitsune is a **dynamic MCP proxy**. `shapeshift(server_id)` connects to a target server via the appropriate transport (stdio subprocess, HTTP, WebSocket), fetches its `tools/list`, and registers each tool as a native FastMCP tool with the exact schema from the server. The AI client receives a `notifications/tools/list_changed` event and sees the new tools as first-class โ no wrapper, no indirection.
`shapeshift()` with no args reverses all of it: deregisters the proxy closures, closes the connection, and notifies the client. Context returns to the ~965-token baseline.
### Tool-schema RAG
| Document RAG | Kitsune |
|---|---|
| Index all documents | Registry: 10,000+ servers across 7 sources |
| Query โ retrieve relevant chunks | `search("notion")` โ ranked candidates with token estimates |
| Inject only relevant content | `shapeshift(server, tools=[...])` โ mount only what is needed |
| Model reasons over those chunks | Agent calls those tools natively |
| Evict when done | `shapeshift()` โ context returns to baseline |
### Transport selection
| Server source | Transport |
|---|---|
| npm package | `npx ` โ spawned locally |
| PyPI package | `uvx ` โ spawned locally |
| GitHub repo | `npx github:user/repo` or `uvx --from git+https://...` |
| Smithery hosted | HTTP + SSE (requires `SMITHERY_API_KEY`) |
| WebSocket | `ws://` / `wss://` |
| Docker | `docker run --rm -i --memory 512m ` |
---
## Tool reference
| Tool | Signature | Description |
|---|---|---|
| `status()` | โ | Provider auth state, GATEWAY bloat detection, session performance stats |
| `search()` | `query, registry?, compare?` | Search for servers across 7 registries; `compare=True` shows side-by-side token costs |
| `shapeshift()` | `server_id?, tools=[], server_args=[]` | Mount a server's tools (with ID) or unmount current form (no args). `tools=[...]` for surgical load |
| `call()` | `tool_name, arguments` | Invoke a tool; `server_id` inferred when shapeshifted |
| `auth()` | `server_or_var, value?` | Check or set env vars; trigger OAuth 2.1 browser flow for hosted servers |
| `auto()` | `task, server_hint=, arguments=` | One-shot: search โ mount โ call โ return result |
Context overhead at rest: **~965 tokens** for all 6 lean-profile tools (measured via `examples/benchmark.py`).
> **`auto()` note:** `auto(task, server_hint="server-id")` gives reliable results. Without `server_hint`, routing is best-effort via semantic search and can misfire on ambiguous queries โ use `search()` first when unsure.
---
## Server sources
Kitsune searches 7 registries in parallel. No single registry is required.
| Registry | Auth required | `registry=` value |
|---|---|---|
| [modelcontextprotocol/servers](https://github.com/modelcontextprotocol/servers) | None | `official` |
| [registry.modelcontextprotocol.io](https://registry.modelcontextprotocol.io) | None | `mcpregistry` |
| [Glama](https://glama.ai/mcp/servers) | None | `glama` |
| npm | None | `npm` |
| PyPI | None | `pypi` |
| GitHub repos | None | `github:owner/repo` |
| [Smithery](https://smithery.ai) | Free API key | `smithery` |
`search()` fans out across all no-auth registries by default. Add a `SMITHERY_API_KEY` to include Smithery's hosted catalog (HTTP servers, no local install required).
---
## GATEWAY: context bloat detection
`status()` scans your active MCP client configs and reports what other servers are running on every turn:
```
GATEWAY
โ 1 other server(s) active in claude-desktop (~8 extra tools in context)
Run setup() to harvest their credentials and reduce bloat
โ 1 other server(s) active in claude-code (~8 extra tools in context)
```
To consolidate:
```python
setup() # preview โ shows what can be harvested
setup(action="harvest") # extract API keys โ ~/.kitsune/.env (non-destructive)
setup(action="absorb") # register those servers for shapeshift()
setup(project=True) # write .claude/mcp.json with only Kitsune (this project)
```
Kitsune never modifies existing configs without explicit confirmation.
---
## Performance
### Token overhead: surgical mount vs full mount
Full-mount figures measured live against v0.20.1 via `shapeshift()` probes. Surgical estimates (~) are proportional approximations based on tool count, not individually measured. To measure Kitsune's own profile size: `python examples/benchmark.py`.
Saved = 1 โ (500 base + surgical) / always-on. Surgical estimates (~) are proportional; full-mount figures are measured.
| Server | Tools | Always-on | Surgical example | 500 + surgical | Saved |
|---|---:|---:|---|---:|---:|
| `mcp-server-time` | 2 | 261 | (all tools) | ~761 | โ ยน |
| `mcp-server-git` | 12 | 1,242 | status / diff / log | ~810 | 35% |
| `@modelcontextprotocol/server-memory` | 9 | 2,615 | read_graph / search_nodes | ~1,080 | 59% |
| `@modelcontextprotocol/server-filesystem` | 14 | 3,207 | read / write / edit | ~1,190 | 63% |
| `brave` | 8 | 3,612 | brave_web_search | ~950 | 74% |
| `@modelcontextprotocol/server-github` | 26 | 4,229 | search_repositories | ~800 | 81% |
| `notion-hosted` | 14 | 13,707 | search / fetch | ~2,450 | 82% |
ยน `mcp-server-time`'s full schema (261 tokens) is smaller than Kitsune's base. Kitsune pays off for small servers only when multiple servers share the baseline.
### Multi-server compounding
Kitsune's resting cost (~965 tokens) is constant regardless of how many servers are registered. Always-on cost grows linearly with each server added.
All figures use servers with measured full-mount costs. Kitsune cost = 965 base + surgical mount for whichever server is active. The range reflects the cheapest (git ~310) to most expensive (Notion ~1,950) surgical call.
| Servers always-on | Always-on/turn | Kitsune per active call | Saved |
|---|---:|---|---:|
| GitHub only | 4,229 | ~1,265 | 70% |
| GitHub + filesystem + git | 8,678 | ~1,265โ1,655 | 81โ85% |
| Notion + GitHub + filesystem + git + memory | 25,000 | ~1,265โ2,915 | **88โ95%** |
### Tool-selection reliability
LLM tool-selection degrades as the visible tool count grows โ a finding consistent across multiple tool-use benchmarks (Gorilla, ToolBench). The failure mode is typically adjacent-name confusion: a model that sees `read_file`, `read_text_file`, and `read_media_file` simultaneously is more likely to call the wrong one than a model that sees only the one it needs.
Kitsune holds 6 tools at rest; 7โ9 during active use. A Kitsune-specific benchmark measuring selection accuracy across tool-count conditions does not yet exist โ contributions welcome.
### Connection latency
Kitsune maintains a persistent process pool โ re-attaching to a running server within a session takes 0 ms.
| Transport | Cold start | Warm (pooled) |
|---|---|---|
| HTTP / Smithery hosted | 0โ1.4 s | 0.0 s |
| Local stdio via `npx` | 1.7โ6.3 s | 0.0 s |
| Local stdio via `uvx` | 1.0โ5.2 s | 0.0 s |
---
## Configuration
### Env vars and `.env` files
Kitsune re-reads credentials on every `shapeshift()` and `call()`. Add or update a key mid-session โ no restart needed.
Search order: `CWD/.env` โ `~/.env` โ `~/.kitsune/.env` (last wins).
```bash
# Write a key and activate immediately
auth("BRAVE_API_KEY", "sk-...") # writes to ~/.kitsune/.env
# Or manage .env directly
echo "BRAVE_API_KEY=sk-..." >> ~/.kitsune/.env
```
### Custom tool surface
Expose only specific tools via `KITSUNE_TOOLS`:
```json
{
"mcpServers": {
"kitsune": {
"command": "kitsune-mcp",
"env": { "KITSUNE_TOOLS": "shapeshift,call,auth" }
}
}
}
```
### Smithery
```json
{ "env": { "SMITHERY_API_KEY": "your-key" } }
```
Get a free key at [smithery.ai/account/api-keys](https://smithery.ai/account/api-keys). Without it, Kitsune is fully functional via npm, PyPI, official registry, and GitHub.
---
## Agent profiles
### Research agent โ web search + fetch + memory
```python
shapeshift("brave", tools=["brave_web_search"]) # ~450 tokens
shapeshift("mcp-server-fetch") # ~289 tokens
shapeshift("@modelcontextprotocol/server-memory",
tools=["read_graph", "search_nodes"]) # ~580 tokens
# Peak: ~1,300 tokens vs 6,516 always-on โ 80% reduction
```
### Code agent โ filesystem + git
```python
shapeshift("@modelcontextprotocol/server-filesystem",
tools=["read_file", "write_file", "edit_file"],
server_args=["/path/to/project"]) # ~690 tokens
shapeshift("mcp-server-git",
tools=["git_status", "git_diff", "git_log"]) # ~310 tokens
# Peak: ~1,000 tokens vs 4,449 always-on โ 78% reduction
```
### Notes / PM agent โ Notion + memory
```python
shapeshift("notion-hosted",
tools=["notion-search", "notion-append-block-children"]) # ~1,950 tokens
shapeshift("@modelcontextprotocol/server-memory",
tools=["add_memory", "search_nodes"]) # ~580 tokens
# Peak: ~2,500 tokens vs 16,322 always-on โ 85% reduction
```
---
## Security
### Trust tiers
| Tier | Sources | Label |
|---|---|---|
| High | `official` (modelcontextprotocol/servers) | `โ Source: official` |
| Medium | `mcpregistry`, `glama`, `smithery` | `โ Source: smithery` |
| Community | `npm`, `pypi`, `github` | `โ Source: npm (community โ not verified)` |
Community servers require `confirm=True` on `shapeshift()` โ an explicit acknowledgement before running arbitrary code. Set `KITSUNE_TRUST=community` (via `auth("KITSUNE_TRUST", "community")` or `.env`) to skip the gate globally for servers you already trust.
### Credential handling
- Credentials stored at `~/.kitsune/.env` and `~/.kitsune/oauth/` with mode `0600`
- OAuth 2.1 with PKCE S256 and Dynamic Client Registration (RFC 7591) for hosted servers
- `shapeshift()` warns on missing credentials before any tool call
- `auth("server-id", "logout")` clears cached OAuth tokens
### Process isolation
- stdio servers run as isolated OS subprocesses โ no shared memory with Kitsune
- Docker servers run with `--rm -i --memory 512m`
- `fetch()` blocks private IPs, loopback, and non-HTTPS URLs
- Process pool capped at 10 concurrent servers; idle processes evicted after 1 hour
- Install commands validated against shell metacharacter and path-traversal patterns before execution
---
## For MCP developers
The full evaluation suite is available by setting `KITSUNE_TOOLS=all`:
```json
{ "command": "kitsune-mcp", "env": { "KITSUNE_TOOLS": "all" } }
```
Additional tools:
| Tool | What it does |
|---|---|
| `inspect(server_id)` | Schema review + live credential check (โ/โ per key) + measured token cost |
| `test(server_id)` | Quality score 0โ100 across connectivity, schema correctness, and tool behaviour |
| `bench(server_id, tool, args)` | Latency benchmark โ p50, p95, min, max |
| `compare(query)` | Side-by-side: token cost, tool count, trust tier, credential status |
| `craft(name, description, params, url)` | Register a custom HTTP-backed tool; `shapeshift()` removes it |
Test your server inside real Claude or Cursor sessions โ not in an isolated inspector UI.
---
## Why Kitsune?
In Japanese folklore, the Kitsune (็) is a fox spirit of extraordinary intelligence and magical power. What makes it remarkable is not what it is, but what it can *become*. With age and wisdom, a Kitsune grows new tails โ each one a new ability mastered, a new form borrowed from the world around it. It can shapeshift into anything: a scholar, a warrior, a force of nature. And when the purpose is fulfilled, it casts off that form as easily as it took it on, returning to its true self โ ready to become something else entirely.
One fox. Infinite forms. Every power available. Nothing carried that isn't needed.
`shapeshift("brave-search")` โ the fox takes on a new form. Its tools appear as if they were always there.
`shapeshift()` โ it returns to its true shape. Context drops back to baseline. Ready for the next form.
Each server mounted is a new tail. Each capability borrowed cleanly and released when done. One entry in your config. Every server in the MCP ecosystem, on demand โ summoned, used, and let go.
> *I am not Japanese, and I use this name with the highest respect for the mythology and culture it comes from. The parallel felt too precise to ignore โ a spirit that shapeshifts between forms, gains new powers, and releases them at will. That is exactly what this tool does.*
---
## Contributing
```bash
make dev # install with dev dependencies
make test # pytest
make lint # ruff
```
Issues and PRs: [github.com/kaiser-data/kitsune-mcp](https://github.com/kaiser-data/kitsune-mcp)
See [CHANGELOG.md](CHANGELOG.md) for version history.
---
*MIT License ยท Python 3.12+ ยท Built on [FastMCP](https://github.com/jlowin/fastmcp)*