Skip to main content

The shape-shifting MCP hub โ€” mount() into any MCP server at runtime. 7 registries. No restart.

Project description

Kitsune MCP

๐ŸŒŠ Kitsune MCP

One MCP entry. 10,000+ servers on demand.
Load only the tools you need. Switch instantly. No restarts.

PyPI Python CI License: MIT Smithery


The problem with static MCP setups

Every server you add to your config loads all its tools at startup โ€” and keeps them there, all session long. Whether your agent uses them or not.

Five servers means 3,000โ€“5,000 tokens of overhead on every request. Your agent sees 50+ tools and has to reason about all of them before it can act.

Kitsune MCP is one entry that replaces all of them.

mount("brave-search", tools=["web_search"])  # only the tool you need
# task done โ€” switch instantly:
unmount()
mount("supabase")                            # different server, no restart
unmount()
mount("@modelcontextprotocol/server-github") # and again

One config entry. Any server across 7 registries. Load only the tools the current task needs โ€” 2 out of 20 if that's all you need. Your agent stays focused and your costs stay low.

Base overhead: 7 tools, ~650 tokens (measured). Each mounted server adds only what you actually load.


Built for two audiences

Adaptive agents

An agent that loads everything upfront burns tokens on tools it never calls โ€” and makes worse decisions because it sees too many options at once. An agent that mounts on demand is leaner, faster, and more focused:

  • Mount only what the current task needs โ€” switch to something else when it's done
  • mount(server_id, tools=[...]) to cherry-pick โ€” load 2 tools from a server that has 20
  • Chain across multiple servers in one session without touching config or restarting
  • Token overhead stays flat: ~650 base + only what you load

Kitsune MCP is designed around the real economics of an agent loop.

MCP developers

Beyond MCP Inspector's basic schema viewer, Kitsune MCP gives you a full development workflow inside your actual AI client:

Need Tool
Explore a server's tools and schemas inspect(server_id)
Quality-score your server end-to-end test(server_id) โ†’ score 0โ€“100
Benchmark tool latency bench(server_id, tool, args) โ†’ p50, p95, min, max
Prototype endpoint-backed tools live craft(name, description, params, url)
Test inside real Claude/Cursor workflows mount() โ†’ call tools natively โ†’ unmount()
Compare two servers side by side mount one, test, unmount, mount the other

No separate web UI. No isolated test environment. Test how your server actually behaves when an AI uses it.


Two modes

kitsune-mcp kitsune-forge
Purpose Adaptive agents, everyday mounting MCP evaluation, benchmarking, crafting
Tools 7 (mount, unmount, search, inspect, call, key, status) All 17
Token overhead ~650 tokens ~1,700 tokens
Use when Agents mounting per task, minimal token budget Discovering, testing, benchmarking, prototyping

Token numbers are measured from actual registered schemas โ€” see examples/benchmark.py.

Both modes from the same package:

{ "command": "kitsune-mcp" }                        โ† lean (default)
{ "command": "kitsune-forge" }                      โ† full suite
{ "command": "kitsune-mcp",
  "env": { "KITSUNE_TOOLS": "mount,unmount,key" } }    โ† custom

How It Fits Together

Kitsune MCP โ€” lean profile

mount() injects tools directly at runtime via FastMCP's live API. Token overhead stays flat regardless of how many servers you explore.

Need the full evaluation suite? kitsune-forge adds execution, connection management, benchmarking, and tool crafting:

Protean Forge โ€” extended suite

Quick Start

pip install kitsune-mcp

Add to your MCP client config โ€” once, globally:

{
  "mcpServers": {
    "kitsune": {
      "command": "kitsune-mcp"
    }
  }
}

Works with Claude Desktop, Claude Code, Cursor, Cline, OpenClaw, Continue.dev, Zed, and any MCP-compatible client. No API keys needed.

Client Global 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
OpenClaw MCP config in OpenClaw settings

Server Sources

Kitsune MCP searches across 7 registries in parallel โ€” tens of thousands of servers, no single one required.

Registry Auth registry= value
modelcontextprotocol/servers None official
registry.modelcontextprotocol.io None mcpregistry
Glama None glama
npm None npm
PyPI None pypi
GitHub repos None github:owner/repo
Smithery Free API key smithery

Default search() fans out across all no-auth registries automatically. Add a SMITHERY_API_KEY to extend discovery with Smithery's hosted server catalog (HTTP servers, no local install required).


How It Works

The proxy model

Kitsune MCP is a dynamic MCP proxy. It sits between your AI client and any number of other MCP servers, connecting to them on demand:

Your AI client
    โ”‚
    โ–ผ
Kitsune MCP          โ† the one entry in your config
    โ”‚
    โ”œโ”€โ”€ (on mount) โ”€โ”€โ–บ filesystem server   (spawned subprocess)
    โ”œโ”€โ”€ (on mount) โ”€โ”€โ–บ brave-search server (spawned subprocess)
    โ””โ”€โ”€ (on mount) โ”€โ”€โ–บ remote HTTP server  (HTTP+SSE connection)

Nothing is copied. When you call a mounted tool, Kitsune MCP forwards the call to the original server via JSON-RPC and returns the result. The server's logic always runs on the server โ€” Kitsune MCP only relays the schema and the call.

What mount() does, step by step

  1. Connects to the target server via the right transport (stdio subprocess, HTTP, WebSocket)
  2. Handshakes โ€” sends MCP initialize / notifications/initialized
  3. Fetches tools/list, resources/list, prompts/list from the server
  4. Registers each tool as a native FastMCP tool โ€” a proxy closure with the exact signature from the schema
  5. Notifies the AI client (notifications/tools/list_changed) so the new tools appear immediately

The AI sees read_file, write_file, list_directory as if they were always there. There's no wrapper or call_tool("filesystem", ...) indirection โ€” the tools are first-class.

unmount() reverses all of it: deregisters the proxy closures, clears resources and prompts, notifies the client.

Resources and prompts

mount() proxies all three MCP primitives, not just tools:

Primitive What gets proxied
Tools Every tool from tools/list, registered with its exact parameter schema
Resources Static resources from resources/list โ€” readable via the MCP resources API
Prompts Every prompt from prompts/list, with its argument signature

Template URIs (e.g. file:///{path}) are skipped โ€” they require parameter binding that adds complexity with little practical gain. Everything else is proxied.

Transport is automatic

Server source How it runs
npm package npx <package> โ€” spawned locally
pip package uvx <package> โ€” spawned locally
GitHub repo npx github:user/repo or uvx --from git+https://...
Docker image docker run --rm -i --memory 512m <image>
Smithery hosted HTTP+SSE (requires SMITHERY_API_KEY)
WebSocket server ws:// / wss://

Why inspect() before mount()

inspect() connects to the server and fetches its schemas โ€” but does not register anything. Zero tools added to context, zero tokens consumed by the AI.

Use it to:

  • See exact parameter names and types before committing
  • Check credential requirements upfront (avoid a cryptic error mid-task)
  • Get the measured token cost of the mount so you can budget
  • Verify the server actually starts and responds before a live session
inspect("mcp-server-brave-search")
# โ†’ CREDENTIALS
# โ†’   โœ— missing  BRAVE_API_KEY โ€” Brave Search API key
# โ†’   Add to .env:  BRAVE_API_KEY=your-value
# โ†’ Token cost: ~99 tokens (measured)

# Add the key to .env โ€” picked up immediately, no restart needed
# Then mount and use in the same session:
mount("mcp-server-brave-search")
call("brave_web_search", arguments={"query": "MCP protocol 2025"})

Security

Kitsune MCP introduces a trust model for servers you haven't personally audited.

Trust tiers

Every mount(), call(), and connect() result shows where the server comes from:

Tier Sources Indicator
High official (modelcontextprotocol/servers) โœ“ Source: official
Medium mcpregistry, glama, smithery โœ“ Source: smithery
Community npm, pypi, github โš ๏ธ Source: npm (community โ€” not verified)

Install command validation

Before spawning any subprocess, Kitsune MCP validates the executable name:

  • Blocks shell metacharacters (&, ;, |, `, $) โ€” prevents injection via a crafted server ID
  • Blocks path traversal (../) โ€” prevents escaping to arbitrary binaries

Arguments are passed directly to asyncio.create_subprocess_exec (never a shell), so they are not subject to shell interpretation.

Credential warnings

mount() probes tool descriptions for unreferenced environment variable patterns. If a tool mentions BRAVE_API_KEY and that variable isn't set, you get a warning immediately โ€” before you call anything:

โš ๏ธ  Credentials may be required โ€” add to .env:
  BRAVE_API_KEY=your-value
  Or: key("BRAVE_API_KEY", "your-value")

Process isolation and sandboxing

  • stdio servers run as separate OS processes โ€” no shared memory with Kitsune MCP
  • Docker servers run with --rm -i --memory 512m --label kitsune-mcp=1
  • fetch() blocks private IPs, loopback, and non-HTTPS URLs (SSRF protection)
  • The process pool has a hard cap of 10 concurrent processes and evicts idle ones after 1 hour

What You Can Access

One kitsune-mcp entry unlocks any of these on demand โ€” no config changes, no restart:

Category Servers Key needed Lean tokens
Web search Brave Search, Exa, Linkup, Parallel Free API keys ~150โ€“993
Web scraping Firecrawl, ScrapeGraph AI Free tiers ~400 (lean)
Code & repos GitHub (official, 26 tools) Free GitHub token ~500 (lean)
Productivity Notion, Linear, Slack Free workspace keys ~400 (lean)
Google Maps, Calendar, Gmail, Drive Free GCP key / OAuth varies
Memory Mem0, knowledge graphs Free tiers ~300
No key required Filesystem, Git, weather, Yahoo Finance โ€” ~300โ€“1,000

The same pattern works for all of them:

mount("brave")                                    # web search in 2 tools
call("brave_web_search", arguments={"query": "โ€ฆ"})

mount("firecrawl-mcp", tools=["scrape","search"]) # scraping, lean (2 of 9 tools)
call("scrape", arguments={"url": "https://โ€ฆ"})

mount("@modelcontextprotocol/server-github", tools=["create_issue","search_repositories"])
call("create_issue", arguments={"owner": "โ€ฆ", "repo": "โ€ฆ", "title": "โ€ฆ"})

Token cost scales with what you load, not what exists. A 26-tool GitHub server costs ~500 tokens if you only mount 3 tools. See .env.example for the full key catalog with lean mount hints.

Security note on .env

Kitsune MCP re-reads .env on every call โ€” which means adding a key instantly activates it. That convenience comes with a responsibility: .env is the single place all your API keys live. A few practices worth following:

  • Add .env to .gitignore โ€” never commit real keys
  • Use project-level .env for project-specific keys; ~/.chameleon/.env for personal global keys
  • Prefer minimal OAuth scopes and fine-grained tokens (e.g. GitHub fine-grained tokens with per-repo permissions)
  • Rotate keys that get exposed; Kitsune MCP picks up the new value immediately without restart

Why Not Just X?

"Can't I just add more servers to mcp.json?" โ€” Every configured server starts at launch and exposes all tools constantly. You can't add or remove mid-session without a restart. With 5+ servers you're burning thousands of tokens on every request for tools rarely needed. Kitsune MCP keeps the tool list minimal โ€” mount what you need, unmount it when done.

"What about MCP Inspector?" โ€” MCP Inspector is a standalone web UI that connects to one server and lets you inspect schemas and call tools manually. It's useful for basic debugging but isolated from real AI workflows. Kitsune MCP tests servers inside actual Claude or Cursor sessions โ€” how an AI really uses them. It adds test() scoring, bench() latency numbers, side-by-side server comparison, and craft() for live endpoint prototyping. It also discovers and installs servers on demand; Inspector requires you to already have one running.

"What about mcp-dynamic-proxy?" โ€” It hides tools behind call_tool("brave", "web_search", {...}) โ€” always a wrapper. After mount("mcp-server-brave-search"), Kitsune MCP gives you a real native brave_web_search with the actual schema. It also can't discover or install packages at runtime.

"Can FastMCP do this natively?"

FastMCP native Kitsune MCP
Proxy a known HTTP/SSE server โœ… โœ…
Mount tools at runtime โœ… (write code) โœ… mount()
Search registries to discover servers โŒ โœ… npm ยท official ยท Glama ยท Smithery
Install npm / PyPI / GitHub packages on demand โŒ โœ…
Atomic shed โ€” retract all morphed tools at once โŒ โœ… unmount()
Persistent stdio process pool โŒ โœ…
Zero boilerplate โ€” works after pip install โŒ โœ…

Configuration

Minimal (no API keys)

{
  "mcpServers": {
    "protean": { "command": "kitsune-mcp" }
  }
}

Optional integrations

{
  "mcpServers": {
    "kitsune": {
      "command": "kitsune-mcp",
      "env": { "SMITHERY_API_KEY": "your-key" }
    }
  }
}

Get a free key at smithery.ai/account/api-keys. Without it, Kitsune MCP is fully functional via npm, PyPI, official registries, and GitHub.

Frictionless credentials โ€” Kitsune MCP re-reads .env on every inspect(), mount(), and call(). Add a key mid-session and it takes effect immediately โ€” no restart:

# .env (CWD, ~/.env, or ~/.chameleon/.env โ€” all checked, CWD wins)
BRAVE_API_KEY=your-key
GITHUB_TOKEN=ghp_...

Or use key() to write to .env and activate in one step:

key("BRAVE_API_KEY", "your-key")   # writes to .env, active immediately

All Tools

kitsune-mcp โ€” lean profile (7 tools, ~650 token overhead)

Tool Description
mount(server_id, tools) Inject a server's tools live. tools=[...] for lean morph.
unmount(release) Remove morphed tools. release=True kills the process immediately.
search(query, registry) Search MCP servers across registries.
inspect(server_id) Show tools, schemas, and live credential status (โœ“/โœ— per key).
call(tool_name, server_id, args) Call a tool. server_id optional when mounted โ€” current form used.
key(env_var, value) Save an API key to .env and load it immediately.
status() Show current form, active connections (PID + RAM), token stats.

kitsune-forge โ€” full suite (all 17 tools, ~1,700 token overhead)

Everything above, plus:

Tool Description
call(tool_name, server_id, args) Already in lean profile โ€” listed here for completeness.
run(package, tool, args) Run from npm/pip directly. uvx:pkg-name for Python.
auto(task, tool, args) Search โ†’ pick best server โ†’ call in one step.
fetch(url, intent) Fetch a URL, return compressed text (~17x smaller than raw HTML).
craft(name, description, params, url) Register a custom tool backed by your HTTP endpoint. unmount() removes it.
connect(command, name) Start a persistent server. Accepts server_id or shell command.
release(name) Kill a persistent connection by name.
setup(name) Step-by-step setup wizard for a connected server.
test(server_id, level) Quality-score a server 0โ€“100.
bench(server_id, tool, args) Benchmark tool latency โ€” p50, p95, min, max.
skill(qualified_name) Load a skill into context. Persisted across sessions.

Usage Examples

Adaptive agent โ€” multi-server session, zero config

# Task 1: read some files
mount("@modelcontextprotocol/server-filesystem", tools=["read_file"])
read_file(path="/tmp/data.csv")
unmount()

# Task 2: search the web
mount("mcp-server-brave-search")
brave_web_search(query="latest MCP servers 2025")
unmount()

# Task 3: run a git query
mount("@modelcontextprotocol/server-git", tools=["git_log"])
git_log(repo_path=".", max_count=5)
unmount()
# Three different servers. One session. Zero config edits.

MCP developer workflow โ€” test your server

# Evaluate your server before publishing
inspect("my-server")               # review schemas and credentials
test("my-server")                  # quality score 0โ€“100
bench("my-server", "my_tool", {})  # p50, p95 latency

# Prototype a tool backed by your local endpoint
craft(
    name="my_tool",
    description="Calls my ranking service",
    params={"query": {"type": "string"}},
    url="http://localhost:8080/rank"
)
my_tool(query="test")   # call it natively inside Claude
unmount()

Same-session usage with call()

After mount(), use call() immediately โ€” no restart, no server_id needed:

mount("@modelcontextprotocol/server-filesystem")
# โ†’ "In this session: call('tool_name', arguments={...})"

call("list_directory", arguments={"path": "/Users/me/project"})
call("read_file", arguments={"path": "/Users/me/project/README.md"})
unmount()

Search, mount, use, unmount

search("web search")
mount("mcp-server-brave-search")
key("BRAVE_API_KEY", "your-key")   # picked up immediately
call("brave_web_search", arguments={"query": "MCP protocol 2025"})
unmount()

Persistent server with setup guidance

connect("uvx voice-mode", name="voice")
setup("voice")                      # shows missing env vars
key("DEEPGRAM_API_KEY", "your-key")
setup("voice")                      # confirms ready
mount("voice-mode")
speak(text="Hello from Kitsune MCP!")
unmount(release=True)                  # kills process, frees RAM

Installation

pip install kitsune-mcp        # from PyPI
# or
git clone https://github.com/kaiser-data/kitsune-mcp && pip install -e .

Requirements: Python 3.12+ ยท node/npx (for npm servers) ยท uvx from uv (for pip servers)


Contributing

make dev     # install with dev dependencies
make test    # pytest
make lint    # ruff

Issues and PRs: github.com/kaiser-data/kitsune-mcp


MIT License ยท Python 3.12+ ยท Built on FastMCP

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

kitsune_mcp-0.8.0.tar.gz (283.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

kitsune_mcp-0.8.0-py3-none-any.whl (322.4 kB view details)

Uploaded Python 3

File details

Details for the file kitsune_mcp-0.8.0.tar.gz.

File metadata

  • Download URL: kitsune_mcp-0.8.0.tar.gz
  • Upload date:
  • Size: 283.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for kitsune_mcp-0.8.0.tar.gz
Algorithm Hash digest
SHA256 49c80d9a0d0c97810523e2e11b06d64b05701d433876e9d43c41e39e91c5c5c9
MD5 e797200df1001d18b5e7d0d010d1bf94
BLAKE2b-256 ae374448d22267d3c1c1a2ca2ec41fd95e5fd629554a9e9248e704778c741760

See more details on using hashes here.

Provenance

The following attestation bundles were made for kitsune_mcp-0.8.0.tar.gz:

Publisher: publish.yml on kaiser-data/kitsune-mcp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file kitsune_mcp-0.8.0-py3-none-any.whl.

File metadata

  • Download URL: kitsune_mcp-0.8.0-py3-none-any.whl
  • Upload date:
  • Size: 322.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for kitsune_mcp-0.8.0-py3-none-any.whl
Algorithm Hash digest
SHA256 6ae0841ee44a36197493b3fee47667c9abb4d13b89decc4a78cdc40420288c2b
MD5 270d9acf442991746e3f40c0a9db1d36
BLAKE2b-256 a5cbcc765a86a3fbb2e8cdc2ecbb57865279bedf1e34096c69a0d89d81b030e6

See more details on using hashes here.

Provenance

The following attestation bundles were made for kitsune_mcp-0.8.0-py3-none-any.whl:

Publisher: publish.yml on kaiser-data/kitsune-mcp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page