kitsune-mcp 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +531 -0
- package/bin/kitsune-mcp.js +31 -0
- package/package.json +39 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025โ2026 Kitsune MCP Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,531 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
<img src="https://raw.githubusercontent.com/kaiser-data/kitsune-mcp/main/kitsune-logo.png" alt="Kitsune MCP" width="160" />
|
|
3
|
+
<h1>๐ฆ Kitsune MCP</h1>
|
|
4
|
+
<p><strong>One MCP entry. 10,000+ servers on demand.<br/>Load only the tools you need. Switch instantly. No restarts.</strong></p>
|
|
5
|
+
</div>
|
|
6
|
+
|
|
7
|
+
[](https://pypi.org/project/kitsune-mcp/)
|
|
8
|
+
[](https://pypi.org/project/kitsune-mcp/)
|
|
9
|
+
[](https://github.com/kaiser-data/kitsune-mcp/actions)
|
|
10
|
+
[](LICENSE)
|
|
11
|
+
[](https://smithery.ai/server/@kaiser-data/kitsune-mcp)
|
|
12
|
+
[](https://discord.gg/EYgcf7EX)
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Why Kitsune?
|
|
17
|
+
|
|
18
|
+
In Japanese folklore, the Kitsune (็) is a fox spirit of extraordinary intelligence and magical power. What makes it remarkable is how it grows: with age and wisdom, a Kitsune gains additional tails โ each one representing a new ability it has mastered. It can shapeshift, take on any form it chooses, borrow the powers of others, and just as freely cast them off when the purpose is fulfilled. One fox. Many forms. Total fluidity.
|
|
19
|
+
|
|
20
|
+
This tool works the same way.
|
|
21
|
+
|
|
22
|
+
`shapeshift("brave-search")` โ the fox takes on a new form, its tools appear natively.
|
|
23
|
+
`shiftback()` โ it returns to its true shape, ready to become something else.
|
|
24
|
+
|
|
25
|
+
Each server it shapeshifts into is a new tail. Each capability borrowed and released cleanly. One entry in your config. Every server in the MCP ecosystem, on demand.
|
|
26
|
+
|
|
27
|
+
> *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.*
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## The problem with static MCP setups
|
|
32
|
+
|
|
33
|
+
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.
|
|
34
|
+
|
|
35
|
+
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.
|
|
36
|
+
|
|
37
|
+
**Kitsune MCP is one entry that replaces all of them.**
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
shapeshift("brave-search", tools=["web_search"]) # only the tool you need
|
|
41
|
+
# task done โ switch instantly:
|
|
42
|
+
shiftback()
|
|
43
|
+
shapeshift("supabase") # different server, no restart
|
|
44
|
+
shiftback()
|
|
45
|
+
shapeshift("@modelcontextprotocol/server-github") # and again
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
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.
|
|
49
|
+
|
|
50
|
+
Base overhead: **7 tools, ~650 tokens** ([measured](examples/benchmark.py)). Each mounted server adds only what you actually load.
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Built for two audiences
|
|
55
|
+
|
|
56
|
+
### Adaptive agents
|
|
57
|
+
|
|
58
|
+
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:
|
|
59
|
+
|
|
60
|
+
- Shapeshift into only what the current task needs โ shiftback when done
|
|
61
|
+
- `shapeshift(server_id, tools=[...])` to cherry-pick โ load 2 tools from a server that has 20
|
|
62
|
+
- Chain across multiple servers in one session without touching config or restarting
|
|
63
|
+
- Token overhead stays flat: ~650 base + only what you load
|
|
64
|
+
|
|
65
|
+
Kitsune MCP is designed around the real economics of an agent loop.
|
|
66
|
+
|
|
67
|
+
### MCP developers
|
|
68
|
+
|
|
69
|
+
Beyond MCP Inspector's basic schema viewer, Kitsune MCP gives you a full development workflow inside your actual AI client:
|
|
70
|
+
|
|
71
|
+
| Need | Tool |
|
|
72
|
+
|---|---|
|
|
73
|
+
| Explore a server's tools and schemas | `inspect(server_id)` |
|
|
74
|
+
| Quality-score your server end-to-end | `test(server_id)` โ score 0โ100 |
|
|
75
|
+
| Benchmark tool latency | `bench(server_id, tool, args)` โ p50, p95, min, max |
|
|
76
|
+
| Prototype endpoint-backed tools live | `craft(name, description, params, url)` |
|
|
77
|
+
| Test inside real Claude/Cursor workflows | `shapeshift()` โ call tools natively โ `shiftback()` |
|
|
78
|
+
| Compare two servers side by side | shapeshift into one, test, shiftback, shapeshift into the other |
|
|
79
|
+
|
|
80
|
+
No separate web UI. No isolated test environment. Test how your server actually behaves when an AI uses it.
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Two modes
|
|
85
|
+
|
|
86
|
+
| | `kitsune-mcp` | `kitsune-forge` |
|
|
87
|
+
|---|---|---|
|
|
88
|
+
| **Purpose** | Adaptive agents, everyday mounting | MCP evaluation, benchmarking, crafting |
|
|
89
|
+
| **Tools** | 7 (shapeshift, shiftback, search, inspect, call, key, status) | All 17 |
|
|
90
|
+
| **Token overhead** | ~650 tokens | ~1,700 tokens |
|
|
91
|
+
| **Use when** | Agents mounting per task, minimal token budget | Discovering, testing, benchmarking, prototyping |
|
|
92
|
+
|
|
93
|
+
> Token numbers are measured from actual registered schemas โ see [examples/benchmark.py](examples/benchmark.py).
|
|
94
|
+
|
|
95
|
+
Both modes from the same package:
|
|
96
|
+
|
|
97
|
+
```json
|
|
98
|
+
{ "command": "kitsune-mcp" } โ lean (default)
|
|
99
|
+
{ "command": "kitsune-forge" } โ full suite
|
|
100
|
+
{ "command": "kitsune-mcp",
|
|
101
|
+
"env": { "KITSUNE_TOOLS": "shapeshift,shiftback,key" } } โ custom
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## How It Fits Together
|
|
107
|
+
|
|
108
|
+
<div align="center">
|
|
109
|
+
<img src="https://raw.githubusercontent.com/kaiser-data/kitsune-mcp/main/docs/architecture.svg" alt="Kitsune MCP โ lean profile" width="700"/>
|
|
110
|
+
</div>
|
|
111
|
+
|
|
112
|
+
`shapeshift()` injects tools directly at runtime via FastMCP's live API. Token overhead stays flat regardless of how many servers you explore.
|
|
113
|
+
|
|
114
|
+
Need the full evaluation suite? `kitsune-forge` adds execution, connection management, benchmarking, and tool crafting:
|
|
115
|
+
|
|
116
|
+
<div align="center">
|
|
117
|
+
<img src="https://raw.githubusercontent.com/kaiser-data/kitsune-mcp/main/docs/architecture-forge.svg" alt="Protean Forge โ extended suite" width="700"/>
|
|
118
|
+
</div>
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Quick Start
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
pip install kitsune-mcp
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Add to your MCP client config โ **once, globally**:
|
|
129
|
+
|
|
130
|
+
```json
|
|
131
|
+
{
|
|
132
|
+
"mcpServers": {
|
|
133
|
+
"kitsune": {
|
|
134
|
+
"command": "kitsune-mcp"
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Works with Claude Desktop, Claude Code, Cursor, Cline, OpenClaw, Continue.dev, Zed, and any MCP-compatible client. No API keys needed.
|
|
141
|
+
|
|
142
|
+
| Client | Global config file |
|
|
143
|
+
|---|---|
|
|
144
|
+
| Claude Desktop (macOS) | `~/Library/Application Support/Claude/claude_desktop_config.json` |
|
|
145
|
+
| Claude Desktop (Windows) | `%APPDATA%\Claude\claude_desktop_config.json` |
|
|
146
|
+
| Claude Code | `~/.claude/mcp.json` |
|
|
147
|
+
| Cursor / Windsurf | `~/.cursor/mcp.json` |
|
|
148
|
+
| Cline / Continue.dev | VS Code settings / `~/.continue/config.json` |
|
|
149
|
+
| OpenClaw | MCP config in OpenClaw settings |
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## Server Sources
|
|
154
|
+
|
|
155
|
+
Kitsune MCP searches across 7 registries in parallel โ tens of thousands of servers, no single one required.
|
|
156
|
+
|
|
157
|
+
| Registry | Auth | `registry=` value |
|
|
158
|
+
|---|---|---|
|
|
159
|
+
| [modelcontextprotocol/servers](https://github.com/modelcontextprotocol/servers) | None | `official` |
|
|
160
|
+
| [registry.modelcontextprotocol.io](https://registry.modelcontextprotocol.io) | None | `mcpregistry` |
|
|
161
|
+
| [Glama](https://glama.ai/mcp/servers) | None | `glama` |
|
|
162
|
+
| [npm](https://npmjs.com) | None | `npm` |
|
|
163
|
+
| [PyPI](https://pypi.org) | None | `pypi` |
|
|
164
|
+
| GitHub repos | None | `github:owner/repo` |
|
|
165
|
+
| [Smithery](https://smithery.ai) | Free API key | `smithery` |
|
|
166
|
+
|
|
167
|
+
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).
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## How It Works
|
|
172
|
+
|
|
173
|
+
### The proxy model
|
|
174
|
+
|
|
175
|
+
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:
|
|
176
|
+
|
|
177
|
+
```
|
|
178
|
+
Your AI client
|
|
179
|
+
โ
|
|
180
|
+
โผ
|
|
181
|
+
Kitsune MCP โ the one entry in your config
|
|
182
|
+
โ
|
|
183
|
+
โโโ (on shapeshift) โโโบ filesystem server (spawned subprocess)
|
|
184
|
+
โโโ (on shapeshift) โโโบ brave-search server (spawned subprocess)
|
|
185
|
+
โโโ (on shapeshift) โโโบ remote HTTP server (HTTP+SSE connection)
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
**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.
|
|
189
|
+
|
|
190
|
+
### What shapeshift() does, step by step
|
|
191
|
+
|
|
192
|
+
1. **Connects** to the target server via the right transport (stdio subprocess, HTTP, WebSocket)
|
|
193
|
+
2. **Handshakes** โ sends MCP `initialize` / `notifications/initialized`
|
|
194
|
+
3. **Fetches** `tools/list`, `resources/list`, `prompts/list` from the server
|
|
195
|
+
4. **Registers** each tool as a native FastMCP tool โ a proxy closure with the exact signature from the schema
|
|
196
|
+
5. **Notifies** the AI client (`notifications/tools/list_changed`) so the new tools appear immediately
|
|
197
|
+
|
|
198
|
+
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.
|
|
199
|
+
|
|
200
|
+
`shiftback()` reverses all of it: deregisters the proxy closures, clears resources and prompts, notifies the client.
|
|
201
|
+
|
|
202
|
+
### Resources and prompts
|
|
203
|
+
|
|
204
|
+
`shapeshift()` proxies all three MCP primitives, not just tools:
|
|
205
|
+
|
|
206
|
+
| Primitive | What gets proxied |
|
|
207
|
+
|---|---|
|
|
208
|
+
| **Tools** | Every tool from `tools/list`, registered with its exact parameter schema |
|
|
209
|
+
| **Resources** | Static resources from `resources/list` โ readable via the MCP resources API |
|
|
210
|
+
| **Prompts** | Every prompt from `prompts/list`, with its argument signature |
|
|
211
|
+
|
|
212
|
+
Template URIs (e.g. `file:///{path}`) are skipped โ they require parameter binding that adds complexity with little practical gain. Everything else is proxied.
|
|
213
|
+
|
|
214
|
+
### Transport is automatic
|
|
215
|
+
|
|
216
|
+
| Server source | How it runs |
|
|
217
|
+
|---|---|
|
|
218
|
+
| npm package | `npx <package>` โ spawned locally |
|
|
219
|
+
| pip package | `uvx <package>` โ spawned locally |
|
|
220
|
+
| GitHub repo | `npx github:user/repo` or `uvx --from git+https://...` |
|
|
221
|
+
| Docker image | `docker run --rm -i --memory 512m <image>` |
|
|
222
|
+
| Smithery hosted | HTTP+SSE (requires `SMITHERY_API_KEY`) |
|
|
223
|
+
| WebSocket server | `ws://` / `wss://` |
|
|
224
|
+
|
|
225
|
+
### Why inspect() before shapeshift()
|
|
226
|
+
|
|
227
|
+
`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.
|
|
228
|
+
|
|
229
|
+
Use it to:
|
|
230
|
+
- See exact parameter names and types before committing
|
|
231
|
+
- Check credential requirements upfront (avoid a cryptic error mid-task)
|
|
232
|
+
- Get the measured token cost of the mount so you can budget
|
|
233
|
+
- Verify the server actually starts and responds before a live session
|
|
234
|
+
|
|
235
|
+
```
|
|
236
|
+
inspect("mcp-server-brave-search")
|
|
237
|
+
# โ CREDENTIALS
|
|
238
|
+
# โ โ missing BRAVE_API_KEY โ Brave Search API key
|
|
239
|
+
# โ Add to .env: BRAVE_API_KEY=your-value
|
|
240
|
+
# โ Token cost: ~99 tokens (measured)
|
|
241
|
+
|
|
242
|
+
# Add the key to .env โ picked up immediately, no restart needed
|
|
243
|
+
# Then mount and use in the same session:
|
|
244
|
+
shapeshift("mcp-server-brave-search")
|
|
245
|
+
call("brave_web_search", arguments={"query": "MCP protocol 2025"})
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
## Security
|
|
251
|
+
|
|
252
|
+
Kitsune MCP introduces a trust model for servers you haven't personally audited.
|
|
253
|
+
|
|
254
|
+
### Trust tiers
|
|
255
|
+
|
|
256
|
+
Every `shapeshift()`, `call()`, and `connect()` result shows where the server comes from:
|
|
257
|
+
|
|
258
|
+
| Tier | Sources | Indicator |
|
|
259
|
+
|---|---|---|
|
|
260
|
+
| High | `official` (modelcontextprotocol/servers) | `โ Source: official` |
|
|
261
|
+
| Medium | `mcpregistry`, `glama`, `smithery` | `โ Source: smithery` |
|
|
262
|
+
| Community | `npm`, `pypi`, `github` | `โ ๏ธ Source: npm (community โ not verified)` |
|
|
263
|
+
|
|
264
|
+
### Install command validation
|
|
265
|
+
|
|
266
|
+
Before spawning any subprocess, Kitsune MCP validates the executable name:
|
|
267
|
+
- Blocks shell metacharacters (`&`, `;`, `|`, `` ` ``, `$`) โ prevents injection via a crafted server ID
|
|
268
|
+
- Blocks path traversal (`../`) โ prevents escaping to arbitrary binaries
|
|
269
|
+
|
|
270
|
+
Arguments are passed directly to `asyncio.create_subprocess_exec` (never a shell), so they are not subject to shell interpretation.
|
|
271
|
+
|
|
272
|
+
### Credential warnings
|
|
273
|
+
|
|
274
|
+
`shapeshift()` 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:
|
|
275
|
+
|
|
276
|
+
```
|
|
277
|
+
โ ๏ธ Credentials may be required โ add to .env:
|
|
278
|
+
BRAVE_API_KEY=your-value
|
|
279
|
+
Or: key("BRAVE_API_KEY", "your-value")
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### Process isolation and sandboxing
|
|
283
|
+
|
|
284
|
+
- stdio servers run as separate OS processes โ no shared memory with Kitsune MCP
|
|
285
|
+
- Docker servers run with `--rm -i --memory 512m --label kitsune-mcp=1`
|
|
286
|
+
- `fetch()` blocks private IPs, loopback, and non-HTTPS URLs (SSRF protection)
|
|
287
|
+
- The process pool has a hard cap of 10 concurrent processes and evicts idle ones after 1 hour
|
|
288
|
+
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
## What You Can Access
|
|
292
|
+
|
|
293
|
+
One `kitsune-mcp` entry unlocks any of these on demand โ no config changes, no restart:
|
|
294
|
+
|
|
295
|
+
| Category | Servers | Key needed | Lean tokens |
|
|
296
|
+
|---|---|---|---|
|
|
297
|
+
| **Web search** | Brave Search, Exa, Linkup, Parallel | Free API keys | ~150โ993 |
|
|
298
|
+
| **Web scraping** | Firecrawl, ScrapeGraph AI | Free tiers | ~400 (lean) |
|
|
299
|
+
| **Code & repos** | GitHub (official, 26 tools) | Free GitHub token | ~500 (lean) |
|
|
300
|
+
| **Productivity** | Notion, Linear, Slack | Free workspace keys | ~400 (lean) |
|
|
301
|
+
| **Google** | Maps, Calendar, Gmail, Drive | Free GCP key / OAuth | varies |
|
|
302
|
+
| **Memory** | Mem0, knowledge graphs | Free tiers | ~300 |
|
|
303
|
+
| **No key required** | Filesystem, Git, weather, Yahoo Finance | โ | ~300โ1,000 |
|
|
304
|
+
|
|
305
|
+
The same pattern works for all of them:
|
|
306
|
+
```
|
|
307
|
+
shapeshift("brave") # web search in 2 tools
|
|
308
|
+
call("brave_web_search", arguments={"query": "โฆ"})
|
|
309
|
+
|
|
310
|
+
shapeshift("firecrawl-mcp", tools=["scrape","search"]) # scraping, lean (2 of 9 tools)
|
|
311
|
+
call("scrape", arguments={"url": "https://โฆ"})
|
|
312
|
+
|
|
313
|
+
shapeshift("@modelcontextprotocol/server-github", tools=["create_issue","search_repositories"])
|
|
314
|
+
call("create_issue", arguments={"owner": "โฆ", "repo": "โฆ", "title": "โฆ"})
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
**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](.env.example) for the full key catalog with lean mount hints.
|
|
318
|
+
|
|
319
|
+
### Security note on `.env`
|
|
320
|
+
|
|
321
|
+
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:
|
|
322
|
+
|
|
323
|
+
- Add `.env` to `.gitignore` โ never commit real keys
|
|
324
|
+
- Use project-level `.env` for project-specific keys; `~/.chameleon/.env` for personal global keys
|
|
325
|
+
- Prefer minimal OAuth scopes and fine-grained tokens (e.g. GitHub fine-grained tokens with per-repo permissions)
|
|
326
|
+
- Rotate keys that get exposed; Kitsune MCP picks up the new value immediately without restart
|
|
327
|
+
|
|
328
|
+
---
|
|
329
|
+
|
|
330
|
+
## Why Not Just X?
|
|
331
|
+
|
|
332
|
+
**"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 โ shapeshift into what you need, shiftback when done.
|
|
333
|
+
|
|
334
|
+
**"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.
|
|
335
|
+
|
|
336
|
+
**"What about `mcp-dynamic-proxy`?"** โ It hides tools behind `call_tool("brave", "web_search", {...})` โ always a wrapper. After `receive("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.
|
|
337
|
+
|
|
338
|
+
**"Can FastMCP do this natively?"**
|
|
339
|
+
|
|
340
|
+
| | FastMCP native | Kitsune MCP |
|
|
341
|
+
|---|:---:|:---:|
|
|
342
|
+
| Proxy a known HTTP/SSE server | โ
| โ
|
|
|
343
|
+
| Load tools at runtime | โ
(write code) | โ
`shapeshift()` |
|
|
344
|
+
| Search registries to discover servers | โ | โ
npm ยท official ยท Glama ยท Smithery |
|
|
345
|
+
| Install npm / PyPI / GitHub packages on demand | โ | โ
|
|
|
346
|
+
| Atomic shift back โ retract all shapeshifted tools at once | โ | โ
`shiftback()` |
|
|
347
|
+
| Persistent stdio process pool | โ | โ
|
|
|
348
|
+
| Zero boilerplate โ works after `pip install` | โ | โ
|
|
|
349
|
+
|
|
350
|
+
---
|
|
351
|
+
|
|
352
|
+
## Configuration
|
|
353
|
+
|
|
354
|
+
### Minimal (no API keys)
|
|
355
|
+
|
|
356
|
+
```json
|
|
357
|
+
{
|
|
358
|
+
"mcpServers": {
|
|
359
|
+
"protean": { "command": "kitsune-mcp" }
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
### Optional integrations
|
|
365
|
+
|
|
366
|
+
```json
|
|
367
|
+
{
|
|
368
|
+
"mcpServers": {
|
|
369
|
+
"kitsune": {
|
|
370
|
+
"command": "kitsune-mcp",
|
|
371
|
+
"env": { "SMITHERY_API_KEY": "your-key" }
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
Get a free key at [smithery.ai/account/api-keys](https://smithery.ai/account/api-keys). Without it, Kitsune MCP is fully functional via npm, PyPI, official registries, and GitHub.
|
|
378
|
+
|
|
379
|
+
**Frictionless credentials** โ Kitsune MCP re-reads `.env` on every `inspect()`, `shapeshift()`, and `call()`. Add a key mid-session and it takes effect immediately โ no restart:
|
|
380
|
+
|
|
381
|
+
```
|
|
382
|
+
# .env (CWD, ~/.env, or ~/.chameleon/.env โ all checked, CWD wins)
|
|
383
|
+
BRAVE_API_KEY=your-key
|
|
384
|
+
GITHUB_TOKEN=ghp_...
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
Or use `key()` to write to `.env` and activate in one step:
|
|
388
|
+
|
|
389
|
+
```
|
|
390
|
+
key("BRAVE_API_KEY", "your-key") # writes to .env, active immediately
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
---
|
|
394
|
+
|
|
395
|
+
## All Tools
|
|
396
|
+
|
|
397
|
+
### `kitsune-mcp` โ lean profile (7 tools, ~650 token overhead)
|
|
398
|
+
|
|
399
|
+
| Tool | Description |
|
|
400
|
+
|---|---|
|
|
401
|
+
| `shapeshift(server_id, tools)` | Load a server's tools live. `tools=[...]` for lean shapeshift. |
|
|
402
|
+
| `shiftback(kill)` | Remove shapeshifted tools. `kill=True` terminates the process immediately. |
|
|
403
|
+
| `search(query, registry)` | Search MCP servers across registries. |
|
|
404
|
+
| `inspect(server_id)` | Show tools, schemas, and live credential status (โ/โ per key). |
|
|
405
|
+
| `call(tool_name, server_id, args)` | Call a tool. `server_id` optional when shapeshifted โ current form used. |
|
|
406
|
+
| `key(env_var, value)` | Save an API key to `.env` and load it immediately. |
|
|
407
|
+
| `status()` | Show current form, active connections (PID + RAM), token stats. |
|
|
408
|
+
|
|
409
|
+
### `kitsune-forge` โ full suite (all 17 tools, ~1,700 token overhead)
|
|
410
|
+
|
|
411
|
+
Everything above, plus:
|
|
412
|
+
|
|
413
|
+
| Tool | Description |
|
|
414
|
+
|---|---|
|
|
415
|
+
| `call(tool_name, server_id, args)` | Already in lean profile โ listed here for completeness. |
|
|
416
|
+
| `run(package, tool, args)` | Run from npm/pip directly. `uvx:pkg-name` for Python. |
|
|
417
|
+
| `auto(task, tool, args)` | Search โ pick best server โ call in one step. |
|
|
418
|
+
| `fetch(url, intent)` | Fetch a URL, return compressed text (~17x smaller than raw HTML). |
|
|
419
|
+
| `craft(name, description, params, url)` | Register a custom tool backed by your HTTP endpoint. `shiftback()` removes it. |
|
|
420
|
+
| `connect(command, name)` | Start a persistent server. Accepts server_id or shell command. |
|
|
421
|
+
| `release(name)` | Kill a persistent connection by name. |
|
|
422
|
+
| `setup(name)` | Step-by-step setup wizard for a connected server. |
|
|
423
|
+
| `test(server_id, level)` | Quality-score a server 0โ100. |
|
|
424
|
+
| `bench(server_id, tool, args)` | Benchmark tool latency โ p50, p95, min, max. |
|
|
425
|
+
| `skill(qualified_name)` | Load a skill into context. Persisted across sessions. |
|
|
426
|
+
|
|
427
|
+
---
|
|
428
|
+
|
|
429
|
+
## Usage Examples
|
|
430
|
+
|
|
431
|
+
### Adaptive agent โ multi-server session, zero config
|
|
432
|
+
|
|
433
|
+
```
|
|
434
|
+
# Task 1: read some files
|
|
435
|
+
shapeshift("@modelcontextprotocol/server-filesystem", tools=["read_file"])
|
|
436
|
+
read_file(path="/tmp/data.csv")
|
|
437
|
+
shiftback()
|
|
438
|
+
|
|
439
|
+
# Task 2: search the web
|
|
440
|
+
shapeshift("mcp-server-brave-search")
|
|
441
|
+
brave_web_search(query="latest MCP servers 2025")
|
|
442
|
+
shiftback()
|
|
443
|
+
|
|
444
|
+
# Task 3: run a git query
|
|
445
|
+
shapeshift("@modelcontextprotocol/server-git", tools=["git_log"])
|
|
446
|
+
git_log(repo_path=".", max_count=5)
|
|
447
|
+
shiftback()
|
|
448
|
+
# Three different servers. One session. Zero config edits.
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
### MCP developer workflow โ test your server
|
|
452
|
+
|
|
453
|
+
```
|
|
454
|
+
# Evaluate your server before publishing
|
|
455
|
+
inspect("my-server") # review schemas and credentials
|
|
456
|
+
test("my-server") # quality score 0โ100
|
|
457
|
+
bench("my-server", "my_tool", {}) # p50, p95 latency
|
|
458
|
+
|
|
459
|
+
# Prototype a tool backed by your local endpoint
|
|
460
|
+
craft(
|
|
461
|
+
name="my_tool",
|
|
462
|
+
description="Calls my ranking service",
|
|
463
|
+
params={"query": {"type": "string"}},
|
|
464
|
+
url="http://localhost:8080/rank"
|
|
465
|
+
)
|
|
466
|
+
my_tool(query="test") # call it natively inside Claude
|
|
467
|
+
shiftback()
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
### Same-session usage with call()
|
|
471
|
+
|
|
472
|
+
After `shapeshift()`, use `call()` immediately โ no restart, no server_id needed:
|
|
473
|
+
|
|
474
|
+
```
|
|
475
|
+
shapeshift("@modelcontextprotocol/server-filesystem")
|
|
476
|
+
# โ "In this session: call('tool_name', arguments={...})"
|
|
477
|
+
|
|
478
|
+
call("list_directory", arguments={"path": "/Users/me/project"})
|
|
479
|
+
call("read_file", arguments={"path": "/Users/me/project/README.md"})
|
|
480
|
+
shiftback()
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
### Search, shapeshift, use, shiftback
|
|
484
|
+
|
|
485
|
+
```
|
|
486
|
+
search("web search")
|
|
487
|
+
shapeshift("mcp-server-brave-search")
|
|
488
|
+
key("BRAVE_API_KEY", "your-key") # picked up immediately
|
|
489
|
+
call("brave_web_search", arguments={"query": "MCP protocol 2025"})
|
|
490
|
+
shiftback()
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
### Persistent server with setup guidance
|
|
494
|
+
|
|
495
|
+
```
|
|
496
|
+
connect("uvx voice-mode", name="voice")
|
|
497
|
+
setup("voice") # shows missing env vars
|
|
498
|
+
key("DEEPGRAM_API_KEY", "your-key")
|
|
499
|
+
setup("voice") # confirms ready
|
|
500
|
+
shapeshift("voice-mode")
|
|
501
|
+
speak(text="Hello from Kitsune MCP!")
|
|
502
|
+
shiftback(kill=True) # terminates process, frees RAM
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
---
|
|
506
|
+
|
|
507
|
+
## Installation
|
|
508
|
+
|
|
509
|
+
```bash
|
|
510
|
+
pip install kitsune-mcp # from PyPI
|
|
511
|
+
# or
|
|
512
|
+
git clone https://github.com/kaiser-data/kitsune-mcp && pip install -e .
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
**Requirements:** Python 3.12+ ยท `node`/`npx` (for npm servers) ยท `uvx` from [uv](https://github.com/astral-sh/uv) (for pip servers)
|
|
516
|
+
|
|
517
|
+
---
|
|
518
|
+
|
|
519
|
+
## Contributing
|
|
520
|
+
|
|
521
|
+
```bash
|
|
522
|
+
make dev # install with dev dependencies
|
|
523
|
+
make test # pytest
|
|
524
|
+
make lint # ruff
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
Issues and PRs: [github.com/kaiser-data/kitsune-mcp](https://github.com/kaiser-data/kitsune-mcp)
|
|
528
|
+
|
|
529
|
+
---
|
|
530
|
+
|
|
531
|
+
*MIT License ยท Python 3.12+ ยท Built on [FastMCP](https://github.com/jlowin/fastmcp)*
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
// Thin npm wrapper โ delegates to the Python package via uvx (preferred) or pip fallback.
|
|
5
|
+
// uvx installs kitsune-mcp in an isolated env on first run and caches it.
|
|
6
|
+
|
|
7
|
+
const { spawn } = require('child_process');
|
|
8
|
+
const args = process.argv.slice(2);
|
|
9
|
+
|
|
10
|
+
function run(cmd, cmdArgs) {
|
|
11
|
+
const proc = spawn(cmd, cmdArgs, { stdio: 'inherit', env: process.env });
|
|
12
|
+
proc.on('close', (code) => process.exit(code ?? 0));
|
|
13
|
+
return proc;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Try uvx first (uv's tool runner โ fastest, isolated, no pip install needed)
|
|
17
|
+
const proc = run('uvx', ['kitsune-mcp@latest', ...args]);
|
|
18
|
+
|
|
19
|
+
proc.on('error', () => {
|
|
20
|
+
// uvx not available โ fall back to kitsune-mcp on PATH (pip-installed)
|
|
21
|
+
const fallback = run('kitsune-mcp', args);
|
|
22
|
+
|
|
23
|
+
fallback.on('error', () => {
|
|
24
|
+
process.stderr.write(
|
|
25
|
+
'kitsune-mcp: could not start server.\n' +
|
|
26
|
+
' Option 1 (recommended): install uv โ https://docs.astral.sh/uv/\n' +
|
|
27
|
+
' Option 2: pip install kitsune-mcp\n'
|
|
28
|
+
);
|
|
29
|
+
process.exit(1);
|
|
30
|
+
});
|
|
31
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "kitsune-mcp",
|
|
3
|
+
"version": "0.8.1",
|
|
4
|
+
"description": "The shape-shifting MCP hub โ shapeshift() into 10,000+ MCP servers at runtime. One entry point, no restarts, 7 registries.",
|
|
5
|
+
"mcpName": "io.github.kaiser-data/kitsune-mcp",
|
|
6
|
+
"bin": {
|
|
7
|
+
"kitsune-mcp": "./bin/kitsune-mcp.js"
|
|
8
|
+
},
|
|
9
|
+
"keywords": [
|
|
10
|
+
"mcp",
|
|
11
|
+
"model-context-protocol",
|
|
12
|
+
"claude",
|
|
13
|
+
"anthropic",
|
|
14
|
+
"ai-agents",
|
|
15
|
+
"llm-tools",
|
|
16
|
+
"fastmcp",
|
|
17
|
+
"mcp-server",
|
|
18
|
+
"mcp-hub",
|
|
19
|
+
"mcp-registry",
|
|
20
|
+
"mcp-router",
|
|
21
|
+
"tool-use"
|
|
22
|
+
],
|
|
23
|
+
"author": "kaiser-data",
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "git+https://github.com/kaiser-data/kitsune-mcp.git"
|
|
28
|
+
},
|
|
29
|
+
"homepage": "https://github.com/kaiser-data/kitsune-mcp",
|
|
30
|
+
"bugs": {
|
|
31
|
+
"url": "https://github.com/kaiser-data/kitsune-mcp/issues"
|
|
32
|
+
},
|
|
33
|
+
"engines": {
|
|
34
|
+
"node": ">=18"
|
|
35
|
+
},
|
|
36
|
+
"files": [
|
|
37
|
+
"bin/"
|
|
38
|
+
]
|
|
39
|
+
}
|