Skip to content

Latest commit

 

History

History
226 lines (172 loc) · 7.57 KB

File metadata and controls

226 lines (172 loc) · 7.57 KB

Kitsune MCP — Real-Time Demo Script

Three acts, each showing something native Tool Search cannot do, because each needs code executed at runtime, not just tool schemas deferred:

  1. Developing an MCP server live — edit → reload → test, no restart
  2. Executing a long-tail server — Glama / Smithery, nothing pre-installed
  3. The guardrails holding — running unknown code, with honest limits

Every block is a real tool call. Outputs are representative — abbreviated for the screen, and the exact trust/error strings match Kitsune's real messages. Times are for a screen recording; trim to taste.

Setup for the whole demo. Every call below runs on the default install — the MCP REPL trio (connect, release, reload) now ships in the lean profile, so no KITSUNE_TOOLS=all is needed. One config entry:

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

Act 1

Real-time MCP development — the MCP REPL (≈ 45 s)

The pain we're killing: every edit to a work-in-progress MCP server normally needs a client restart to take effect. Restart → lose session → re-establish context → test one line → repeat.

[SCREEN — split: editor left, agent session right]

You're building my-mcp-server. It has a summarize tool that's returning junk.

# Start the work-in-progress server as a pooled process, then mount its tools
connect("uvx --from . my-mcp-server", name="dev")
shapeshift("dev")
Connected: dev (PID 40213)
Tools (3): search, fetch, summarize
⚠️  Source: pool connection (local — verify command before use)
call("summarize", arguments={"url": "https://example.com"})
"Example Domain Example Domain Example Domain …"   ← bug: it's repeating

[CUT to editor] — fix the bug in summarize(), save.

[BACK to session] — one call reloads the edit. reload() kills the stale process, starts fresh code, and remounts live — so the client sees the new schemas without a restart, and there's no "connect handed back the old process" trap:

reload("dev")
Reloaded: dev (was PID 40213 — killed, restarted, remounted)

Connected: dev (PID 40271)          ← new PID = new code
Tools (3): search, fetch, summarize

Remounted:
Registered 3 tools: search, fetch, summarize

CAPTION: One call: release → connect → remount. Never the stale-process trap.

call("summarize", arguments={"url": "https://example.com"})
"This domain is for use in illustrative examples in documents."   ← fixed

TITLE CARD: Edit → reload → test. Same session. Zero restarts. That's an MCP REPL.


Act 2

Executing a long-tail server — Glama & Smithery (≈ 40 s)

The pain we're killing: you need a capability that lives in one of 130,000+ servers you were never going to add to your config. Native deferral can't help — the server isn't configured. Kitsune discovers and runs it on demand.

[SCREEN — agent session]

# Search a specific registry
search("pdf extraction", registry="glama")
1. mcp-pdf-tools        ⚠ glama (community)   ~7 tools   npx
2. pdf-reader-mcp       ⚠ npm (community)     ~4 tools   npx
   (2 community sources gated — pass confirm=True to run)

Community source, so Kitsune asks for one explicit confirm before it executes anything (see Act 3 for why):

shapeshift("mcp-pdf-tools", confirm=True)
Registered 7 tools: extract_text, extract_tables, get_metadata, …
⚠️  Source: glama via local npx/uvx (community — not verified by official MCP registry) (2.1s  — warm calls will be instant)
call("extract_text", arguments={"path": "q3-report.pdf"})
shapeshift()  # done — process released, tools dropped

[CUT] — now a hosted server via Smithery (HTTP, no local install; needs a free SMITHERY_API_KEY):

search("web search", registry="smithery")
shapeshift("exa")  # medium trust — no confirm needed
call("web_search_exa", arguments={"query": "MCP registry growth 2026"})
shapeshift()

CAPTION: Local npx server and a remote hosted server — same three calls. Neither was in your config. Neither needed a restart.

TITLE CARD: 130,000+ servers. Summoned, used, released.


Act 3

The guardrails holding — running unknown code, with limits (≈ 40 s)

The point: "run anything on demand" raises the obvious question — what stops a malicious server? This act shows the guardrails refusing the unsafe path, and is honest about where they stop: they reduce risk, they are not a full sandbox.

[SCREEN — agent session]

Guard 1 — trust gate. A community server won't run on a bare mount:

shapeshift("some-random-npm-server")
⚠️  'some-random-npm-server' is from npm (community — not verified by the
    official MCP registry).
To proceed: shapeshift('some-random-npm-server', confirm=True)
To always trust community: the user sets KITSUNE_TRUST=community in ~/.kitsune/.env

CAPTION: No arbitrary code runs without an explicit, logged consent.

Guard 2 — command injection blocked. A malicious server id can't smuggle a shell command into the spawn:

connect("uvx legit-server ; rm -rf ~", name="evil")
Error: Shell metacharacter in command: 'uvx legit-server ; rm -rf ~'

CAPTION: Install commands are validated before a subprocess is ever spawned.

Guard 3 — SSRF blocked. A server (or a redirect it follows) can't pivot to your internal network. Requests are HTTPS-only, and any host that resolves to a private, loopback, or otherwise non-public address is refused — including on redirect hops, which are each re-validated:

call("fetch", arguments={"url": "https://10.0.0.5/admin"})
Blocked: 'https://10.0.0.5/admin' resolves to a private/loopback address.
Set KITSUNE_ALLOW_LOCAL_FETCH=1 to allow.

CAPTION: No cloud-metadata theft, no localhost pivots — even via redirect.

Guard 4 — isolation + caps. When a server does run, it's constrained (but note: stdio isolation is not a security sandbox — the process runs as your user):

• stdio servers  → separate OS subprocess (isolated from Kitsune's memory,
                   but runs with YOUR permissions — files, network, env)
• docker servers → docker run --rm -i --memory 512m --pids-limit 512
                   --cap-drop ALL --security-opt no-new-privileges
                   --read-only --tmpfs /tmp   (hardened by default)
• versions       → npm/pypi pinned at resolution (npx pkg@1.2.3 / uvx pkg==1.2.3)
• pool           → max 10 processes, idle ones evicted after 1h
• credentials    → ~/.kitsune/.env at mode 0600, warned-on before use

TITLE CARD: Reach the whole ecosystem — with eyes open about the limits.

For a demo, say the honest line: these guards stop the classic attacks (injection, SSRF, silent execution), but a local server still runs with your permissions. For untrusted servers, use Docker and restrict credentials. Don't run this unattended against production admin credentials.


Closing (≈ 10 s)

pip install kitsune-mcp

VOICEOVER: "Tool Search made your configured servers cheap. Kitsune makes every server you didn't configure reachable — built live and run on demand, with guardrails you understand. One config entry. No restarts."


Companion to the launch script in demo-script.md. Commands reflect the real tool surface; see ../README.md for the authoritative reference.