kitsune-mcp 0.18.1 → 0.20.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.
Files changed (2) hide show
  1. package/README.md +227 -166
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
  <div align="center">
3
3
  <img src="https://raw.githubusercontent.com/kaiser-data/kitsune-mcp/main/kitsune-logo.png" alt="Kitsune MCP" width="160" />
4
4
  <h1>🦊 Kitsune MCP</h1>
5
- <p><strong>One MCP entry. 10,000+ servers on demand.<br/>Load only the tools you need. Switch instantly. No restarts.</strong></p>
5
+ <p><strong>One entry in your config. Any MCP server on demand.<br/>5 tools at rest. Thousands available on request. No restarts.</strong></p>
6
6
  </div>
7
7
 
8
8
  [![PyPI](https://img.shields.io/pypi/v/kitsune-mcp?color=blue&label=pypi)](https://pypi.org/project/kitsune-mcp/)
@@ -17,56 +17,93 @@
17
17
 
18
18
  ---
19
19
 
20
- ## What's new in v0.12.0
20
+ ## What's new in v0.20
21
21
 
22
- Security, reliability, and quality-of-life release.
22
+ - **GATEWAY** — `status()` detects other MCP servers active in your client configs and shows their context cost. `setup()` harvests their API keys and absorbs the servers for `shapeshift()`.
23
+ - **6-tool lean profile** — `status`, `search`, `auth`, `shapeshift`, `call`, `auto`. `auto()` is now first-class in the lean surface, not forge-only.
24
+ - **`auto()` with `server_hint`** — one-shot task execution: `auto("current time in Tokyo", server_hint="mcp-server-time")` infers args and returns the result directly. Arg extraction infers "Tokyo" → "Asia/Tokyo" automatically.
25
+ - **`setup()` wizard** — `setup(action="harvest")` extracts API keys from other servers' configs into `~/.kitsune/.env`. `setup(action="absorb")` registers those servers for `shapeshift()`. `setup(project=True)` writes a lean `.claude/mcp.json` for this project only.
23
26
 
24
- - **SSRF protection** — `fetch()` and `craft()` now block requests to private/loopback addresses (127.x, 10.x, 192.168.x, 169.254.x, localhost), consistent with `skill()`. Set `KITSUNE_ALLOW_LOCAL_FETCH=1` to allow local URLs in dev environments.
25
- - **Parameter aliasing** — `from_timezone` is automatically remapped to `source_timezone`, `to` to `target`, `src`/`dst`/`dest` to `source`/`target`, and language variants. Works transparently for any server with non-intuitive param names (e.g. `mcp-server-time`). Closes #9.
26
- - **Session persistence** — `crafted_tools` and named `connect()` sessions survive server restarts. State is written to `~/.kitsune/state.json` on exit and restored on startup. Crafted tools are re-registered automatically.
27
- - **Registration failures surface** — if `mcp.add_tool()` throws during `shapeshift()`, the error is now shown inline (`⚠️ N tool(s) failed to register`) instead of being silently swallowed.
28
- - **`auto()` prefers free stdio over Smithery HTTP** — `mcp-server-time` (official, local, free) beats a Smithery HTTP equivalent when both match a query.
29
- - **MCP Registry backfill** — all versions back to v0.9.0 are now listed in the MCP Registry (previously silently failing due to an OIDC change in the publisher tool).
30
-
31
- See [CHANGELOG.md](CHANGELOG.md) for the full list plus internal refactors and bug fixes.
27
+ See [CHANGELOG.md](CHANGELOG.md) for the full list.
32
28
 
33
29
  ---
34
30
 
35
- ## Why Kitsune?
36
-
37
- 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.
31
+ ## The problem: static tool loading
38
32
 
39
- This tool works the same way.
33
+ Every MCP server you add to your config loads **all** its tools at startup and keeps them there, every turn, whether used or not.
40
34
 
41
- `shapeshift("brave-search")` the fox takes on a new form, its tools appear natively.
42
- `shiftback()` — it returns to its true shape, ready to become something else.
35
+ Five servers means 3,000–20,000+ tokens of overhead on every request. Research on LLM tool use consistently shows accuracy degrades as the number of visible tools increases — the model has to reason about dozens of options before it can act on any of them.
43
36
 
44
- 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.
37
+ ```
38
+ 20 tools in context → baseline performance
39
+ 50 tools in context → measurable degradation in tool selection accuracy
40
+ 100+ tools in context → significant drop; wrong tools called, arguments hallucinated
41
+ ```
45
42
 
46
- > *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.*
43
+ **The fix isn't a better model it's a smaller menu.**
47
44
 
48
45
  ---
49
46
 
50
- ## The problem with static MCP setups
47
+ ## GATEWAY see what you're paying for
51
48
 
52
- 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.
49
+ Once Kitsune is running, call `status()` to see what other MCP servers your clients are loading:
53
50
 
54
- 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.
51
+ ```
52
+ GATEWAY
53
+ ⚠ 2 other server(s) active in claude-desktop (~16 extra tools in context)
54
+ Run setup() to harvest their credentials and reduce bloat
55
+ ⚠ 1 other server(s) active in claude-code (~8 extra tools in context)
56
+ ```
55
57
 
56
- **Kitsune MCP is one entry that replaces all of them.**
58
+ Kitsune can absorb those servers so you get a single lean config with everything still accessible on demand:
57
59
 
58
60
  ```
59
- shapeshift("brave-search", tools=["web_search"]) # only the tool you need
60
- # task done switch instantly:
61
- shiftback()
62
- shapeshift("supabase") # different server, no restart
63
- shiftback()
64
- shapeshift("@modelcontextprotocol/server-github") # and again
61
+ setup() # preview what can be harvested
62
+ setup(action="harvest") # extract API keys ~/.kitsune/.env (non-destructive)
63
+ setup(action="absorb") # register servers for shapeshift() (non-destructive)
64
+ setup(project=True) # write .claude/mcp.json with only Kitsune (this project only)
65
65
  ```
66
66
 
67
- 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.
67
+ ---
68
+
69
+ ## Kitsune: RAG for your MCP ecosystem
68
70
 
69
- Base overhead: **7 tools, ~650 tokens** ([measured](examples/benchmark.py)). Each mounted server adds only what you actually load.
71
+ Think of Kitsune the same way you think of RAG for documents: instead of loading all your knowledge into context upfront, you retrieve only what's relevant to the current query.
72
+
73
+ Kitsune does the same thing for MCP servers:
74
+
75
+ | RAG for documents | Kitsune for MCP |
76
+ |---|---|
77
+ | Index: all your docs | Registry: 10,000+ MCP servers across 7 sources |
78
+ | Query → retrieve relevant chunks | `search("web scraping")` → find matching servers |
79
+ | Inject only relevant content | `shapeshift("firecrawl", tools=["scrape"])` → mount only needed tools |
80
+ | Clear context when done | `shapeshift()` → unmount, context returns to baseline |
81
+
82
+ **5 tools at rest (~400 tokens). Any server on demand. Load exactly the tools the current task needs — 2 out of 20 if that's all you need.**
83
+
84
+ ```python
85
+ shapeshift("brave-search", tools=["web_search"]) # retrieve: 1 tool, ~300 tokens
86
+ # ... task done ...
87
+ shapeshift() # release: context back to ~400 tokens
88
+ shapeshift("supabase") # next task: different server, no restart
89
+ shapeshift()
90
+ shapeshift("@modelcontextprotocol/server-github") # and again
91
+ ```
92
+
93
+ ---
94
+
95
+ ## Why Kitsune?
96
+
97
+ 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.
98
+
99
+ This tool works the same way.
100
+
101
+ `shapeshift("brave-search")` — the fox takes on a new form, its tools appear natively.
102
+ `shapeshift()` — it returns to its true shape, ready to become something else.
103
+
104
+ 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.
105
+
106
+ > *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.*
70
107
 
71
108
  ---
72
109
 
@@ -76,30 +113,30 @@ Most clients now offer a "connector marketplace" — Notion, Gmail, Drive, Slack
76
113
 
77
114
  Kitsune is lazy and parallel: one entry, every server reachable on demand, only the tools you actively call sit in context.
78
115
 
79
- ### Notion, head to head (numbers measured live in this session)
116
+ ### Notion, head to head (numbers measured live)
80
117
 
81
118
  | Setup | Resting context (every turn) | One Notion search | After cleanup |
82
119
  |---|---:|---:|---:|
83
120
  | Always-on Notion connector | **13,733 tokens** | 13,733 + reply | 13,733 forever |
84
- | Kitsune — full Notion mounted | 3,000 tokens | 16,733 + reply | 3,000 |
85
- | Kitsune — `shapeshift("notion-hosted", tools=["notion-search"])` | 3,000 tokens | **4,540** + reply | 3,000 (after `shiftback`) |
121
+ | Kitsune — full Notion mounted | 400 tokens | ~14,133 + reply | 400 |
122
+ | Kitsune — `shapeshift("notion-hosted", tools=["notion-search"])` | 400 tokens | **~1,940** + reply | 400 (after `shapeshift()`) |
86
123
 
87
124
  Over a 50-turn conversation:
88
125
 
89
126
  - Always-on connector: 50 × 13,733 = **686,650 tokens** of repeated Notion overhead
90
- - Kitsune lean: 50 × 3,000 + 5 turns × 1,540 = **157,700 tokens**
127
+ - Kitsune lean: 50 × 400 + 5 turns × 1,540 = **27,700 tokens**
91
128
 
92
- **77% reduction for the same workflow.** And Notion is just one connector.
129
+ **97% reduction for the same workflow.** And Notion is just one connector.
93
130
 
94
131
  ### The "but it's just one" trap
95
132
 
96
- Real-world enabled-connector token costs (typical hosted MCPs):
133
+ Real-world always-on token costs (typical hosted MCPs):
97
134
 
98
135
  - Notion ~13.7K · Gmail ~8K · Drive ~10K · Slack ~7K · Calendar ~5K
99
136
 
100
- **Five connectors enabled = ~43K tokens per turn**, every turn, whether you mention them or not. Same five via Kitsune lean: ~3K resting, with a brief spike only on the turn where you actually use one.
137
+ **Five connectors enabled = ~43K tokens per turn**, every turn, whether you mention them or not. Same five via Kitsune lean: ~420 tokens resting, with a brief spike only on the turn where you actually use one.
101
138
 
102
- For a 100-turn dev session: 4.3M tokens of waste vs ~310K. **You can have a 14× longer conversation before hitting context limits.**
139
+ For a 100-turn dev session: 4.3M tokens of waste vs ~40K. **You can have a 100× longer conversation before hitting context limits.**
103
140
 
104
141
  ### The killer demo
105
142
 
@@ -119,8 +156,8 @@ For a 100-turn dev session: 4.3M tokens of waste vs ~310K. **You can have a 14×
119
156
  > call("notion-search", {"query": "roadmap"})
120
157
  [results]
121
158
 
122
- > shiftback()
123
- ✓ Released. Context returned to baseline.
159
+ > shapeshift()
160
+ ✓ Released. Context returned to baseline (~400 tokens).
124
161
  ```
125
162
 
126
163
  One tool. On demand. Off again. Same OAuth, same Notion endpoint (`mcp.notion.com/mcp`) — but tokens stay in `~/.kitsune/oauth/`, not on a third-party's servers.
@@ -129,71 +166,56 @@ One tool. On demand. Off again. Same OAuth, same Notion endpoint (`mcp.notion.co
129
166
 
130
167
  ---
131
168
 
132
- ## Built for two audiences
133
-
134
- ### Adaptive agents
135
-
136
- 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:
137
-
138
- - Shapeshift into only what the current task needs — shiftback when done
139
- - `shapeshift(server_id, tools=[...])` to cherry-pick — load 2 tools from a server that has 20
140
- - Chain across multiple servers in one session without touching config or restarting
141
- - Token overhead stays flat: ~650 base + only what you load
142
-
143
- Kitsune MCP is designed around the real economics of an agent loop.
144
-
145
- ### MCP developers
169
+ ## The 6-tool surface
146
170
 
147
- Beyond MCP Inspector's basic schema viewer, Kitsune MCP gives you a full development workflow inside your actual AI client:
171
+ `kitsune-mcp` exposes exactly six tools at rest enough to handle any task autonomously, find, mount, authenticate, call, and monitor any server in the ecosystem:
148
172
 
149
- | Need | Tool |
173
+ | Tool | What it does |
150
174
  |---|---|
151
- | Explore a server's tools and schemas | `inspect(server_id)` |
152
- | Quality-score your server end-to-end | `test(server_id)` score 0–100 |
153
- | Benchmark tool latency | `bench(server_id, tool, args)` p50, p95, min, max |
154
- | Prototype endpoint-backed tools live | `craft(name, description, params, url)` |
155
- | Test inside real Claude/Cursor workflows | `shapeshift()` call tools natively `shiftback()` |
156
- | Compare two servers side by side | shapeshift into one, test, shiftback, shapeshift into the other |
175
+ | `auto(task)` | **Intent router**: describe any task → Kitsune finds the right server, mounts it, and calls the right tool in one step. The front door for new users. |
176
+ | `search(query)` | Find servers across 7 registries. Returns ranked matches with token estimates. |
177
+ | `auth(target, value)` | Store an API key (`auth("BRAVE_API_KEY", "sk-...")`) or trigger OAuth 2.1 (`auth("https://mcp.notion.com/mcp")`). Writes to `~/.kitsune/.env`, active immediately. |
178
+ | `shapeshift(server_id, tools, source)` | **Mount**: server's tools become first-class native tools. **Unmount**: `shapeshift()` with no args releases current form. `tools=[...]` for lean load. |
179
+ | `call(tool_name, arguments)` | Call any tool mounted or not. When shapeshifted, `server_id` is inferred. |
180
+ | `status()` | Current form, active connections (PID + RAM), token overhead, registry health. |
157
181
 
158
- No separate web UI. No isolated test environment. Test how your server actually behaves when an AI uses it.
182
+ **Overhead at rest: ~420 tokens.** Each mount adds only what you load `tools=["web_search"]` is ~300 tokens, not 1,500.
159
183
 
160
- ---
161
-
162
- ## Why MCP — not a CLI skill
163
-
164
- A CLI-based agent skill gives every agent the same surface. An MCP lets you design a completely different surface for each agent — down to the individual tool.
165
-
166
- **1. Surgical token budgets.**
167
- `shapeshift("brave-search", tools=["web_search"])` loads exactly one tool — ~300 tokens — instead of the full server schema. A specialized research agent can be wired to see only the three tools it ever needs. A coding agent sees a different three. Same underlying servers; different, purpose-built surfaces. Token overhead stays flat because context is opt-in, not always-on.
184
+ Need evaluation tools (`inspect`, `test`, `bench`, `craft`, `compare`)? Use `kitsune-forge`:
168
185
 
169
- **2. On-the-fly server creation.**
170
- CLI skills require something to already exist on disk. An MCP can be generated mid-session. An agent can call `craft(name, description, params, url)` to define a new tool backed by any HTTP endpoint — no install, no config change, no restart. One conversation. Any problem. New capability spun up and available to the same agent immediately.
171
-
172
- **3. Fine-tune the surface via the Forge.**
173
- `kitsune-forge` exposes the full toolkit — inspect, benchmark, craft, and test. You can prototype a tool, measure its latency, compare two competing servers, and lock in exactly the shape you want before your production agent ever sees it. The Forge is the workbench; the lean `kitsune-mcp` entry is what the agent runs with after you've dialed it in.
174
-
175
- > The result: agents that carry only the tools they need for the current problem, can extend themselves on demand, and never waste tokens on capability they aren't using.
186
+ ```json
187
+ { "command": "kitsune-forge" }
188
+ ```
176
189
 
177
190
  ---
178
191
 
179
- ## Two modes
192
+ ## Specialized agent profiles
180
193
 
181
- | | `kitsune-mcp` | `kitsune-forge` |
182
- |---|---|---|
183
- | **Purpose** | Adaptive agents, everyday mounting | MCP evaluation, benchmarking, crafting |
184
- | **Tools** | 7 (shapeshift, shiftback, search, inspect, call, key, status) | All 17 |
185
- | **Token overhead** | ~650 tokens | ~1,700 tokens |
186
- | **Use when** | Agents mounting per task, minimal token budget | Discovering, testing, benchmarking, prototyping |
194
+ Because tool context is opt-in, you can wire agents to carry only the surface they ever need:
187
195
 
188
- > Token numbers are measured from actual registered schemas — see [examples/benchmark.py](examples/benchmark.py).
196
+ ### Research agent `search + fetch, ~700 tokens`
197
+ ```json
198
+ { "command": "kitsune-mcp", "env": { "KITSUNE_TOOLS": "search,shapeshift,call,auth,status" } }
199
+ ```
200
+ ```python
201
+ shapeshift("brave-search", tools=["web_search"])
202
+ shapeshift("firecrawl-mcp", tools=["scrape"])
203
+ # Total in-context: ~700 tokens at peak. A GPT-4o request at 700 tokens costs ~$0.0021.
204
+ ```
189
205
 
190
- Both modes from the same package:
206
+ ### Code agent `github + filesystem + git`
207
+ ```python
208
+ shapeshift("@modelcontextprotocol/server-github", tools=["create_issue", "search_repositories"])
209
+ shapeshift("@modelcontextprotocol/server-filesystem", tools=["read_file", "write_file"])
210
+ shapeshift("@modelcontextprotocol/server-git", tools=["git_log", "git_diff"])
211
+ # Each loaded separately when needed — never all 60+ tools at once
212
+ ```
191
213
 
192
- ```json
193
- { "command": "kitsune-mcp" } ← lean (default)
194
- { "command": "kitsune-forge" } ← full suite
195
- { "command": "kitsune-mcp",
196
- "env": { "KITSUNE_TOOLS": "shapeshift,shiftback,key" } } ← custom
214
+ ### Notes agent — `notion + memory, lean`
215
+ ```python
216
+ shapeshift("notion-hosted", tools=["notion-search", "notion-append-block-children"])
217
+ shapeshift("mem0", tools=["add_memory", "search_memory"])
218
+ # ~3,000 tokens peak vs ~22,000 for both always-on
197
219
  ```
198
220
 
199
221
  ---
@@ -206,7 +228,7 @@ Both modes from the same package:
206
228
 
207
229
  `shapeshift()` injects tools directly at runtime via FastMCP's live API. Token overhead stays flat regardless of how many servers you explore.
208
230
 
209
- Need the full evaluation suite? `kitsune-forge` adds execution, connection management, benchmarking, and tool crafting:
231
+ Need the full evaluation suite? `kitsune-forge` adds `inspect`, `test`, `bench`, `craft`, `compare`, and more:
210
232
 
211
233
  <div align="center">
212
234
  <img src="https://raw.githubusercontent.com/kaiser-data/kitsune-mcp/main/docs/architecture-forge.svg" alt="Protean Forge — extended suite" width="700"/>
@@ -243,18 +265,31 @@ Works with Claude Desktop, Claude Code, Cursor, Cline, OpenClaw, Continue.dev, Z
243
265
  | Cline / Continue.dev | VS Code settings / `~/.continue/config.json` |
244
266
  | OpenClaw | MCP config in OpenClaw settings |
245
267
 
268
+ ```
269
+ # One-shot: describe task + pin the server
270
+ auto("current time in Tokyo", server_hint="mcp-server-time")
271
+ auto("search: anthropic news May 2026", server_hint="exa")
272
+
273
+ # Multi-step: inspect / lean-mount / hold mount for several calls
274
+ shapeshift("mcp-server-time")
275
+ call("get_current_time", {"timezone": "Asia/Tokyo"})
276
+ shapeshift()
277
+ ```
278
+
279
+ Use `auto()` with `server_hint` for single-call flows. Use `shapeshift + call` when you want to inspect first, mount specific tools, or run multiple calls on the same server.
280
+
246
281
  ### Using Kitsune alongside existing servers
247
282
 
248
- You can add Kitsune to a config that already has other servers — it works without touching anything else. For the cleanest setup (Kitsune as your sole gateway), `setup()` can extract API keys from your existing server configs into `~/.kitsune/.env` and register those servers so `shapeshift()` can reach them on demand.
283
+ You can add Kitsune to a config that already has other servers — it works without touching anything else.
249
284
 
250
- **Kitsune never deletes or modifies your existing configs without explicit confirmation.** Config changes are always backed up and reversible with `setup(restore=True)`.
285
+ **Kitsune never deletes or modifies your existing configs without explicit confirmation.** Config changes are always backed up and reversible.
251
286
 
252
287
  ### Run Kitsune and standard MCP side-by-side (Claude Code)
253
288
 
254
289
  Claude Code supports per-project MCP configs that override the global one. This means you can run a Kitsune session and a standard multi-server session **simultaneously, with no config changes**:
255
290
 
256
291
  ```bash
257
- # Terminal A — Kitsune-only project (5 tools, clean context)
292
+ # Terminal A — Kitsune-only project (6 tools, clean context)
258
293
  mkdir ~/projects/kitsune-session
259
294
  echo '{"mcpServers":{"kitsune":{"command":"kitsune-mcp"}}}' > ~/projects/kitsune-session/.claude/mcp.json
260
295
  cd ~/projects/kitsune-session && claude
@@ -263,7 +298,7 @@ cd ~/projects/kitsune-session && claude
263
298
  cd ~/projects/any-other-project && claude # uses global ~/.claude/mcp.json
264
299
  ```
265
300
 
266
- Both sessions run in parallel. The Kitsune terminal sees 5 tools; the standard terminal sees everything in your global config. No restarts, no toggling, no risk to either session. This makes it easy to compare workflows or run specialised agent tasks in one terminal while using familiar tools in another.
301
+ Both sessions run in parallel. Terminal A sees 5 tools; Terminal B sees everything in your global config. No restarts, no toggling, no risk to either session. Easy to compare workflows or run specialised agent tasks in one terminal while using familiar tools in another.
267
302
 
268
303
  ---
269
304
 
@@ -314,7 +349,7 @@ Kitsune MCP ← the one entry in your config
314
349
 
315
350
  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.
316
351
 
317
- `shiftback()` reverses all of it: deregisters the proxy closures, clears resources and prompts, notifies the client.
352
+ `shapeshift()` with no args reverses all of it: deregisters the proxy closures, clears resources and prompts, notifies the client.
318
353
 
319
354
  ### Resources and prompts
320
355
 
@@ -339,9 +374,21 @@ Template URIs (e.g. `file:///{path}`) are skipped — they require parameter bin
339
374
  | Smithery hosted | HTTP+SSE (requires `SMITHERY_API_KEY`) |
340
375
  | WebSocket server | `ws://` / `wss://` |
341
376
 
342
- ### Why inspect() before shapeshift()
377
+ ### Cold start latency (typical ranges)
343
378
 
344
- `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.
379
+ | Transport | First call | Subsequent calls |
380
+ |---|---|---|
381
+ | Smithery HTTP / WebSocket | ~100–300 ms | ~50–150 ms |
382
+ | npm (`npx`) — cached | ~1–3 s | reused from pool |
383
+ | npm (`npx`) — cold download | ~5–15 s | cached after first |
384
+ | pip (`uvx`) — cached | ~1–2 s | reused from pool |
385
+ | Docker | ~3–8 s | reused from pool |
386
+
387
+ Kitsune keeps a **persistent process pool** — once a server is started, subsequent `shapeshift()` calls reattach in milliseconds. `shapeshift("brave-search")` the second time is fast.
388
+
389
+ ### Why use `inspect()` before shapeshift()
390
+
391
+ `inspect()` (available in `kitsune-forge`) connects to the server and fetches its schemas — but does **not** register anything. Zero tools added to context, zero tokens consumed by the AI.
345
392
 
346
393
  Use it to:
347
394
  - See exact parameter names and types before committing
@@ -353,11 +400,11 @@ Use it to:
353
400
  inspect("mcp-server-brave-search")
354
401
  # → CREDENTIALS
355
402
  # → ✗ missing BRAVE_API_KEY — Brave Search API key
356
- # → Add to .env: BRAVE_API_KEY=your-value
403
+ # → Add: auth("BRAVE_API_KEY", "your-value")
357
404
  # → Token cost: ~99 tokens (measured)
358
405
 
359
- # Add the key to .env — picked up immediately, no restart needed
360
- # Then mount and use in the same session:
406
+ # Add the key — picked up immediately, no restart needed
407
+ auth("BRAVE_API_KEY", "your-value")
361
408
  shapeshift("mcp-server-brave-search")
362
409
  call("brave_web_search", arguments={"query": "MCP protocol 2025"})
363
410
  ```
@@ -366,11 +413,9 @@ call("brave_web_search", arguments={"query": "MCP protocol 2025"})
366
413
 
367
414
  ## Security
368
415
 
369
- Kitsune MCP introduces a trust model for servers you haven't personally audited.
370
-
371
416
  ### Trust tiers
372
417
 
373
- Every `shapeshift()`, `call()`, and `connect()` result shows where the server comes from:
418
+ Every `shapeshift()` and `call()` result shows where the server comes from:
374
419
 
375
420
  | Tier | Sources | Indicator |
376
421
  |---|---|---|
@@ -378,7 +423,7 @@ Every `shapeshift()`, `call()`, and `connect()` result shows where the server co
378
423
  | Medium | `mcpregistry`, `glama`, `smithery` | `✓ Source: smithery` |
379
424
  | Community | `npm`, `pypi`, `github` | `⚠️ Source: npm (community — not verified)` |
380
425
 
381
- Community servers and `source="local"` installs require `confirm=True` — you're explicitly acknowledging you've reviewed the server before running arbitrary code. To bypass this for servers you already trust, set `KITSUNE_TRUST=community` (via `key("KITSUNE_TRUST", "community")` or your `.env`). This persists across sessions so power users and agents never see the gate again.
426
+ Community servers and `source="local"` installs require `confirm=True` — you're explicitly acknowledging you've reviewed the server before running arbitrary code. To bypass this for servers you already trust, set `KITSUNE_TRUST=community` (via `auth("KITSUNE_TRUST", "community")` or your `.env`). This persists across sessions so power users and agents never see the gate again.
382
427
 
383
428
  ### Install command validation
384
429
 
@@ -390,10 +435,10 @@ Arguments are passed directly to `asyncio.create_subprocess_exec` (never a shell
390
435
 
391
436
  ### OAuth 2.1 for hosted MCP servers
392
437
 
393
- Many hosted MCP servers (Notion, Linear, Cloudflare) authenticate via OAuth 2.1 with Dynamic Client Registration rather than a static API key. Kitsune supports this automatically — pass the server URL directly:
438
+ Many hosted MCP servers (Notion, Linear, Cloudflare) authenticate via OAuth 2.1 with Dynamic Client Registration rather than a static API key. Kitsune supports this automatically:
394
439
 
395
440
  ```python
396
- inspect("https://mcp.notion.com/mcp")
441
+ auth("https://mcp.notion.com/mcp")
397
442
  # First use: browser opens, you approve, tokens are cached.
398
443
  # Subsequent runs: cached token loaded silently, refreshed when expired.
399
444
 
@@ -412,7 +457,7 @@ Headless or no-browser environments: set `KITSUNE_NO_BROWSER=1` to have Kitsune
412
457
  ```
413
458
  ⚠️ Credentials may be required — add to .env:
414
459
  BRAVE_API_KEY=your-value
415
- Or: key("BRAVE_API_KEY", "your-value")
460
+ Or: auth("BRAVE_API_KEY", "your-value")
416
461
  ```
417
462
 
418
463
  ### Process isolation and sandboxing
@@ -442,30 +487,24 @@ The same pattern works for all of them:
442
487
  ```
443
488
  shapeshift("brave") # web search in 2 tools
444
489
  call("brave_web_search", arguments={"query": "…"})
490
+ shapeshift()
445
491
 
446
492
  shapeshift("firecrawl-mcp", tools=["scrape","search"]) # scraping, lean (2 of 9 tools)
447
493
  call("scrape", arguments={"url": "https://…"})
494
+ shapeshift()
448
495
 
449
496
  shapeshift("@modelcontextprotocol/server-github", tools=["create_issue","search_repositories"])
450
497
  call("create_issue", arguments={"owner": "…", "repo": "…", "title": "…"})
498
+ shapeshift()
451
499
  ```
452
500
 
453
501
  **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.
454
502
 
455
- ### Security note on `.env`
456
-
457
- 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:
458
-
459
- - Add `.env` to `.gitignore` — never commit real keys
460
- - Use project-level `.env` for project-specific keys; `~/.kitsune/.env` for personal global keys
461
- - Prefer minimal OAuth scopes and fine-grained tokens (e.g. GitHub fine-grained tokens with per-repo permissions)
462
- - Rotate keys that get exposed; Kitsune MCP picks up the new value immediately without restart
463
-
464
503
  ---
465
504
 
466
505
  ## Why Not Just X?
467
506
 
468
- **"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.
507
+ **"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, release when done.
469
508
 
470
509
  **"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.
471
510
 
@@ -479,7 +518,7 @@ Kitsune MCP re-reads `.env` on every call — which means adding a key instantly
479
518
  | Load tools at runtime | ✅ (write code) | ✅ `shapeshift()` |
480
519
  | Search registries to discover servers | ❌ | ✅ npm · official · Glama · Smithery |
481
520
  | Install npm / PyPI / GitHub packages on demand | ❌ | ✅ |
482
- | Atomic shift back — retract all shapeshifted tools at once | ❌ | ✅ `shiftback()` |
521
+ | Atomic release — retract all shapeshifted tools at once | ❌ | ✅ `shapeshift()` |
483
522
  | Persistent stdio process pool | ❌ | ✅ |
484
523
  | Zero boilerplate — works after `pip install` | ❌ | ✅ |
485
524
 
@@ -492,7 +531,7 @@ Kitsune MCP re-reads `.env` on every call — which means adding a key instantly
492
531
  ```json
493
532
  {
494
533
  "mcpServers": {
495
- "protean": { "command": "kitsune-mcp" }
534
+ "kitsune": { "command": "kitsune-mcp" }
496
535
  }
497
536
  }
498
537
  ```
@@ -512,50 +551,57 @@ Kitsune MCP re-reads `.env` on every call — which means adding a key instantly
512
551
 
513
552
  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.
514
553
 
515
- **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:
554
+ **Frictionless credentials** — Kitsune MCP re-reads `.env` on every `shapeshift()` and `call()`. Add a key mid-session and it takes effect immediately — no restart:
516
555
 
517
556
  ```
518
- # .env (CWD, ~/.env, or ~/.kitsune/.env — all checked, CWD wins)
557
+ # .env (CWD, ~/.env, or ~/.kitsune/.env — all checked, ~/.kitsune/.env wins)
519
558
  BRAVE_API_KEY=your-key
520
559
  GITHUB_TOKEN=ghp_...
521
560
  ```
522
561
 
523
- Or use `key()` to write to `.env` and activate in one step:
562
+ Or use `auth()` to write to `.env` and activate in one step:
524
563
 
525
564
  ```
526
- key("BRAVE_API_KEY", "your-key") # writes to .env, active immediately
565
+ auth("BRAVE_API_KEY", "your-key") # writes to ~/.kitsune/.env, active immediately
566
+ ```
567
+
568
+ ### Custom tool surface
569
+
570
+ ```json
571
+ { "command": "kitsune-mcp",
572
+ "env": { "KITSUNE_TOOLS": "shapeshift,call,auth" } } ← three tools only
527
573
  ```
528
574
 
529
575
  ---
530
576
 
531
577
  ## All Tools
532
578
 
533
- ### `kitsune-mcp` — lean profile (7 tools, ~650 token overhead)
579
+ ### `kitsune-mcp` — lean profile (6 tools, ~420 token overhead)
534
580
 
535
581
  | Tool | Description |
536
582
  |---|---|
537
- | `shapeshift(server_id, tools, source, confirm)` | Load a server's tools live. `tools=[...]` for lean load. `source="local"` forces npx/uvx install; `source="smithery"` forces HTTP. |
538
- | `shiftback(kill, uninstall)` | Remove shapeshifted tools. `kill=True` terminates the process. `uninstall=True` also removes a locally installed package. |
583
+ | `auto(task, tool, args)` | Intent router: describe any task finds server calls tool in one step. Category-aware routing. |
584
+ | `shapeshift(server_id, tools, source, confirm)` | Load a server's tools live. `shapeshift()` with no args unmounts. `tools=[...]` for lean load. `source="local"` forces npx/uvx install; `source="smithery"` forces HTTP. |
539
585
  | `search(query, registry)` | Search MCP servers across registries. |
540
- | `inspect(server_id)` | Show tools, schemas, and live credential status (✓/✗ per key). |
586
+ | `auth(target, value)` | Store an API key (`auth("VAR", "val")`) or trigger OAuth 2.1 (`auth("https://...")`). Writes to `~/.kitsune/.env`, active immediately. |
541
587
  | `call(tool_name, server_id, args)` | Call a tool. `server_id` optional when shapeshifted — current form used. |
542
- | `key(env_var, value)` | Save an API key to `.env` and load it immediately. |
543
588
  | `status()` | Show current form, active connections (PID + RAM), token stats. |
544
589
 
545
- ### `kitsune-forge` — full suite (all 17 tools, ~1,700 token overhead)
590
+ ### `kitsune-forge` — full suite (~1,700 token overhead)
546
591
 
547
592
  Everything above, plus:
548
593
 
549
594
  | Tool | Description |
550
595
  |---|---|
551
- | `call(tool_name, server_id, args)` | Already in lean profile listed here for completeness. |
596
+ | `shiftback(kill, uninstall)` | Explicit unmount. `kill=True` terminates the process. `uninstall=True` also removes a locally installed package. |
597
+ | `inspect(server_id)` | Show tools, schemas, and live credential status (✓/✗ per key). Measures token cost. |
552
598
  | `run(package, tool, args)` | Run from npm/pip directly. `uvx:pkg-name` for Python. |
553
- | `auto(task, tool, args)` | Search → pick best server → call in one step. |
554
599
  | `fetch(url, intent)` | Fetch a URL, return compressed text (~17x smaller than raw HTML). |
555
- | `craft(name, description, params, url)` | Register a custom tool backed by your HTTP endpoint. `shiftback()` removes it. |
600
+ | `craft(name, description, params, url)` | Register a custom tool backed by your HTTP endpoint. `shapeshift()` removes it. |
556
601
  | `connect(command, name)` | Start a persistent server. Accepts server_id or shell command. |
557
602
  | `release(name)` | Kill a persistent connection by name. |
558
603
  | `setup(name)` | Step-by-step setup wizard for a connected server. |
604
+ | `compare(query)` | Compare servers matching a query — token cost, tool count, trust tier, credential status. |
559
605
  | `test(server_id, level)` | Quality-score a server 0–100. |
560
606
  | `bench(server_id, tool, args)` | Benchmark tool latency — p50, p95, min, max. |
561
607
  | `skill(qualified_name)` | Load a skill into context. Persisted across sessions. |
@@ -570,24 +616,24 @@ Everything above, plus:
570
616
  # Task 1: read some files
571
617
  shapeshift("@modelcontextprotocol/server-filesystem", tools=["read_file"])
572
618
  read_file(path="/tmp/data.csv")
573
- shiftback()
619
+ shapeshift() # unmount
574
620
 
575
621
  # Task 2: search the web
576
622
  shapeshift("mcp-server-brave-search")
577
623
  brave_web_search(query="latest MCP servers 2025")
578
- shiftback()
624
+ shapeshift()
579
625
 
580
626
  # Task 3: run a git query
581
627
  shapeshift("@modelcontextprotocol/server-git", tools=["git_log"])
582
628
  git_log(repo_path=".", max_count=5)
583
- shiftback()
629
+ shapeshift()
584
630
  # Three different servers. One session. Zero config edits.
585
631
  ```
586
632
 
587
633
  ### MCP developer workflow — test your server
588
634
 
589
635
  ```
590
- # Evaluate your server before publishing
636
+ # Evaluate your server before publishing (kitsune-forge)
591
637
  inspect("my-server") # review schemas and credentials
592
638
  test("my-server") # quality score 0–100
593
639
  bench("my-server", "my_tool", {}) # p50, p95 latency
@@ -600,40 +646,25 @@ craft(
600
646
  url="http://localhost:8080/rank"
601
647
  )
602
648
  my_tool(query="test") # call it natively inside Claude
603
- shiftback()
649
+ shapeshift()
604
650
  ```
605
651
 
606
- ### Same-session usage with call()
607
-
608
- After `shapeshift()`, use `call()` immediately — no restart, no server_id needed:
652
+ ### Auth then mount in the same session
609
653
 
610
654
  ```
611
- shapeshift("@modelcontextprotocol/server-filesystem")
612
- # → "In this session: call('tool_name', arguments={...})"
613
-
614
- call("list_directory", arguments={"path": "/Users/me/project"})
615
- call("read_file", arguments={"path": "/Users/me/project/README.md"})
616
- shiftback()
617
- ```
618
-
619
- ### Search, shapeshift, use, shiftback
620
-
621
- ```
622
- search("web search")
655
+ auth("BRAVE_API_KEY", "your-key") # written to ~/.kitsune/.env immediately
623
656
  shapeshift("mcp-server-brave-search")
624
- key("BRAVE_API_KEY", "your-key") # picked up immediately
625
657
  call("brave_web_search", arguments={"query": "MCP protocol 2025"})
626
- shiftback()
658
+ shapeshift()
627
659
  ```
628
660
 
629
- ### Local install — no API key needed
661
+ ### OAuth-authenticated hosted server
630
662
 
631
663
  ```
632
- # Force local install via npx/uvx — no Smithery key required
633
- shapeshift("brave", source="local", confirm=True)
634
- # → spawns npx locally, tools appear natively
635
- call("brave_web_search", arguments={"query": "MCP 2026"})
636
- shiftback(uninstall=True) # remove tools AND uninstall the package
664
+ auth("https://mcp.notion.com/mcp") # browser opens, you approve
665
+ shapeshift("https://mcp.notion.com/mcp", tools=["notion-search"])
666
+ call("notion-search", arguments={"query": "roadmap"})
667
+ shapeshift()
637
668
  ```
638
669
 
639
670
  ### Persistent server with setup guidance
@@ -641,11 +672,11 @@ shiftback(uninstall=True) # remove tools AND uninstall the package
641
672
  ```
642
673
  connect("uvx voice-mode", name="voice")
643
674
  setup("voice") # shows missing env vars
644
- key("DEEPGRAM_API_KEY", "your-key")
675
+ auth("DEEPGRAM_API_KEY", "your-key")
645
676
  setup("voice") # confirms ready
646
677
  shapeshift("voice-mode")
647
678
  speak(text="Hello from Kitsune MCP!")
648
- shiftback(kill=True) # terminates process, frees RAM
679
+ shapeshift()
649
680
  ```
650
681
 
651
682
  ---
@@ -666,6 +697,36 @@ npx kitsune-mcp # if you prefer npm (delegates to uvx internally)
666
697
 
667
698
  ---
668
699
 
700
+ ## Built for two audiences
701
+
702
+ ### Adaptive agents
703
+
704
+ 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:
705
+
706
+ - Shapeshift into only what the current task needs — release when done
707
+ - `shapeshift(server_id, tools=[...])` to cherry-pick — load 2 tools from a server that has 20
708
+ - Chain across multiple servers in one session without touching config or restarting
709
+ - Token overhead stays flat: ~400 base + only what you load
710
+
711
+ Kitsune MCP is designed around the real economics of an agent loop.
712
+
713
+ ### MCP developers
714
+
715
+ Beyond MCP Inspector's basic schema viewer, Kitsune MCP gives you a full development workflow inside your actual AI client:
716
+
717
+ | Need | Tool |
718
+ |---|---|
719
+ | Explore a server's tools and schemas | `inspect(server_id)` |
720
+ | Quality-score your server end-to-end | `test(server_id)` → score 0–100 |
721
+ | Benchmark tool latency | `bench(server_id, tool, args)` → p50, p95, min, max |
722
+ | Prototype endpoint-backed tools live | `craft(name, description, params, url)` |
723
+ | Test inside real Claude/Cursor workflows | `shapeshift()` → call tools natively → `shapeshift()` |
724
+ | Compare two servers side by side | `compare("notion")` — token cost, tool count, trust, cred status |
725
+
726
+ No separate web UI. No isolated test environment. Test how your server actually behaves when an AI uses it.
727
+
728
+ ---
729
+
669
730
  ## Contributing
670
731
 
671
732
  ```bash
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kitsune-mcp",
3
- "version": "0.18.1",
3
+ "version": "0.20.1",
4
4
  "description": "The shape-shifting MCP hub — shapeshift() into 10,000+ MCP servers at runtime. One entry point, no restarts, 7 registries.",
5
5
  "mcpName": "io.github.kaiser-data/kitsune-mcp",
6
6
  "bin": {