Command Palette

Search for a command to run...

UnylyUnyly
Весь каталог

Kimi Delegate

БесплатноНе проверен

MCP server that lets Claude Code delegate bounded coding tasks to Kimi K2.7-code, optimized for Moonshot prefix caching

GitHubEmbed

Описание

MCP server that lets Claude Code delegate bounded coding tasks to Kimi K2.7-code, optimized for Moonshot prefix caching

README

CI Python 3.10+ License: MIT

An MCP server that lets Claude Code delegate programming work to Kimi K2.7-code (Moonshot AI) — from generating a single file to turning it loose as an autonomous agent that writes code, runs the tests and fixes itself — while Claude stays the orchestrator and decides what gets committed.

Three modes, three levels of trust, chosen per task:

1 · Propose
delegate_to_kimi
2 · Apply
delegate_and_apply
3 · Agent
delegate_agentic
What it does Returns code as text Writes the files, returns a diff Explores, edits, runs, self-corrects
Kimi's reach Nothing — text only Writes inside base_dir Shell, cwd in the project
Runs code? No No Yes
Checks its own work? No No Yes — runs the tests
Review happens Before writing After, on the diff After, on the result
Undo Not needed git checkout git checkout
Typical cost ~$0.003 ~$0.002 $0.016 – $0.13

What each one actually buys you, and what it costs:

Mode The advantage The catch
1 · Propose Nothing reaches disk unread. The only mode with genuine review-before-write The most expensive: applying it means re-emitting the code, so it is billed twice
2 · Apply 82% cheaper on the Claude side — nothing is re-emitted, only a diff is read. Scales with volume Review is after the fact. A mistake is already on disk (recoverable via git)
3 · Agent The only one that closes the loop itself: writes, runs, sees it fail, fixes. Plays to what K2.7 is built for 6–40× dearer. Runs real commands. Takes liberties — it once built a 28 MB virtualenv unasked

resume_delegation is not a mode: it is how you pick mode 3 back up, either when it pauses via ask_claude for something out of its reach or when it runs out of turns. Its advantage is that the agent does not lose the thread — the same session resumes with its context intact.


The agent loop, in plain terms

Modes 1 and 2 are a single exchange: a question goes out, code comes back. Mode 3 is a conversation, and it is worth picturing before reading the rest of this.

Kimi cannot touch your machine. It has no filesystem and no shell — all it can do is ask. So this server sits in the middle and runs a loop:

  1. It describes the task and offers Kimi four things it may ask for: read a file, list files, write a file, run a shell command.
  2. Kimi answers with a request — "read settings.py".
  3. The server carries it out and sends the result back.
  4. Kimi answers with the next one — "run pytest -q".
  5. And on it goes, until Kimi replies with an answer instead of a request.

Each of those round trips is one turn. Reading a file is a turn. Running the tests is a turn. Seeing them fail and writing the fix is two more.

sequenceDiagram
    participant C as Claude
    participant S as This server<br/>on your machine
    participant K as Kimi<br/>Moonshot API

    C->>S: delegate_agentic(task, base_dir)
    S->>K: the task, plus the four tools it may ask for

    loop one turn each
        K->>S: read settings.py
        S->>K: here it is
        K->>S: run pytest -q
        S->>K: 3 failed
        K->>S: write the fix
        S->>K: written
    end

    K->>S: finished, here is what I did
    S->>C: work log, git diff, and the last test output

A well-specified task takes 6 to 11 turns. One with a lot of trial and error can take 40 and still not be finished.

Why there is a turn budget

max_turns caps that loop, at 25 by default. Three reasons it needs one:

The API has no memory. Every turn resends the whole conversation so far, so turn 40 pays for the 39 before it all over again. Cost does not rise with the number of turns, it rises with the square of it. Measured on a real project: an 11-turn task cost $0.036 and a 45-turn task cost $0.242 — four times the turns, seven times the money. (Caching softens this a lot; see Prefix caching. It changes the constant, not the shape.)

A stuck loop looks exactly like a working one. Models will retry the same failing fix with complete conviction. From outside, the only visible difference is the bill.

This is the mode that runs real commands, unattended, in your project.

So the budget is a fuse. Raising it to something enormous does not make problems go away — it removes the one signal that tells you there is a problem.

What happens as it runs low

A fuse that blew silently, mid-edit, would leave the working tree broken. So the budget is a slope, not a cliff:

  • Once a fifth of it is left, every turn carries a countdown into the conversation — "3 turns left before you are cut off. Stop opening new fronts. Get what you have already written into a state that compiles and passes."

  • On the last turn it is told to stop calling tools altogether and to summarise instead: what is done, what is left, what it left half-finished.

  • If it runs out anyway, the run is not lost. The entire conversation is saved, and the result hands you the line that continues it:

    resume_delegation(session_id="d07358a952...", result="<what to finish first>")
    

    result is your guidance, not an answer to a question — read the diff first, since a cut-off run may have left something half-written. extra_turns=N sets how much more rope it gets; leaving it out grants the same budget it started with.

Continuing is far cheaper than starting over, because a fresh delegation re-pays for exploring the project from nothing — and that exploration is most of what makes turns expensive in the first place.

Requirements

  • Python 3.10+
  • Claude Code
  • git — the write-capable tools require a clean working tree, and use it as the undo path
  • A Moonshot API key (pay-as-you-go; see below)

Setup

1. Get an API key

Sign up at platform.kimi.ai, open API Keys, and create one. It is shown only once — copy it somewhere safe.

Billing is pay-as-you-go: $0.95 per million input tokens ($0.19 cached), $4.00 per million output. A small delegation costs well under a cent; the loops in delegate_agentic run to a few cents. A few dollars of credit goes a long way.

Those three figures, and every cost quoted further down, are a snapshot taken on 2026-08-24. The copy the server actually bills against lives in PRICE_IN_PER_M, PRICE_CACHED_PER_M and PRICE_OUT_PER_M at the top of server.py, and nothing checks either copy against Moonshot. If the prices move, change the constants first — the numbers this tool reports are read and trusted, so a wrong one is worse than none.

Never put the key in this repository. It is passed as an environment variable at registration time (step 3) and stored in Claude Code's own config, outside the repo. .gitignore already excludes .env and key files, but the server never reads a key from disk in the first place — only from the MOONSHOT_API_KEY environment variable.

2. Install

git clone <this-repo-url>
cd kimi-delegate-mcp
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt

3. Register with Claude Code

Use absolute paths — Claude Code launches this as a subprocess and does not resolve relative ones:

claude mcp add kimi-delegate -s user \
  -e MOONSHOT_API_KEY=your-key-here \
  -- "$(pwd)/.venv/bin/python" "$(pwd)/server.py"

-s user makes it available in every project. Use -s local to limit it to the current one.

4. Restart Claude Code, then verify

claude mcp list

You should see kimi-delegate: ... - ✔ Connected.

The restart is not optional. Claude Code starts MCP servers when the session begins. A server registered mid-session does not appear — not even in /mcp — and edits to server.py or to its environment are not picked up until you restart. To test changes without restarting, import server.py in a script and call the function directly, bypassing the MCP layer.

Connected means registered, not working. It says the process started and spoke MCP — not that your key is valid or that Moonshot answered. Spend a fraction of a cent confirming the whole path:

delegate_to_kimi("Write a Python function clamp(value, low, high) that bounds
value to [low, high] and raises ValueError if low > high. Nothing else.")

A code block plus a cost footer means it works end to end. An auth error means the key never reached the server — check env in the registration command, not the code.


The tools

Code you can verify yourself

A delegated model that finishes when its own tests go green is marking its own homework — and cheap models are known to write tests that pass without testing anything. So all three modes require injectable seams rather than trusted tests: pure functions where possible, side effects (network, disk, clock, randomness) behind parameters instead of buried in the logic, no hidden global state.

delegate_agentic also leaves the test infrastructure standing and must report the exact command to run the tests, the seams it left, and what stayed hard to test.

Verified on a task with real side effects — "fetch the weather for a city and report it with a timestamp". It produced:

def report(city: str, *, fetch=None, now=None) -> str:

plus a conftest.py with a fake-HTTP factory and a frozen clock. Six independently written tests — covering cases it had not anticipated, such as the results key being absent rather than empty, and URL-encoding of accented city names — all passed against those seams, without touching its code.

It holds up where it matters most, too. Given an ESP32 blink-in-morse task with no board attached, it pulled the logic into a MorsePlayer<IO> template with the I/O injected, stubbed the Arduino API, and left five host-side tests — timing assertions included — that run on a development machine with no hardware present. For embedded work that is the difference between testable and not.

When the domain is enumerable, do better than reading its tests. Build an oracle the model never saw and sweep the whole input space. Asked to implement to_roman(n) for 1..3999, it reported "21 tests pass" — true, but its tests check only what it thought to check. Two independent properties settle it:

# 1. an inverse the model never wrote
from_roman(to_roman(n)) == n
# 2. canonical form — a naive round-trip would accept IIII and VIIII
re.match(r"^M{0,3}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$", to_roman(n))

All 3,999 values passed. That is not "the tests are green", it is "no valid input exists where this fails". The technique works wherever a property can be checked without reimplementing the logic: inverse pairs (parse/serialise, encode/decode), invariants (a sorted list is still a permutation of its input), or an obviously-correct slow version checked against the fast one.

Reporting

All three report tokens in/out, how many were cache hits, how many went to the model's reasoning, and the estimated cost:

_Kimi K2.7-code · 1572 tokens in (1536 cached) / 460 tokens out, 101 reasoning · ~$0.00065_

delegate_agentic reports the same totals across the whole loop, with the cache hit rate as a percentage — the number worth watching there, since a loop resends its history on every turn.

delegate_to_kimi(task, file_paths=[], extra_context="")

Returns Kimi's proposed code as text. Review it, then apply it yourself.

Safest, but it has a cost trap: applying the code means re-emitting it through Write/Edit, so the same code is billed twice — once as Kimi output at $4/M, again as Claude output at $10/M. Over a whole project that inversion can make delegating more expensive than not delegating at all.

delegate_and_apply(task, base_dir, file_paths=[], extra_context="")

Writes the files itself and returns only a compact diff. Claude never re-emits the code, so the second charge disappears — measured 82% lower Claude-side cost on a two-file task, and the gap widens on edits to large existing files.

Review moves from before the write to after it. Use it on a clean git tree.

Because nothing is executed in this mode, a file that does not even parse would otherwise land on disk reported as a success. So every written file is checked before the run is allowed to claim success:

Written in /path/to/project:
  A utils/slug.py (new, 19 lines)

⚠️ **Written but broken** — review before trusting it:
  ⚠ utils/slug.py: does not parse — unmatched '}' (line 19)

That is a real example: the model emitted an otherwise correct function and appended a stray }. The file is still written — git remains the undo path — but the run cannot pass silently.

Extension Check
.py ast.parse
.json json.loads
.xml, .svg, .xsd, .xsl, .xslt, .plist, .pom ElementTree.fromstring
.toml tomllib.loads
.kt, .java, .ts, .js, .go, .c, .cpp, .cs, .swift, .scala, .groovy, .php brackets counted, literals and comments skipped
anything else none

The bracket count is not a parser and does not pretend to be one. It reports only what no valid file can contain — a closer with nothing open, something still open at the end, an unterminated string or block comment — and gives up silently the moment it meets something it does not model. Rust is deliberately excluded: a lifetime opens with the same character as a char literal, so fn f<'a>(x: &'a str) pairs the two apostrophes into a "literal" that swallows the (. Telling those apart needs a real parser, and cargo check is one. A checker that cries wolf is one nobody reads.

The model's output is untrusted input — it chooses these paths — so every one is resolved and checked before anything is written:

Path from model Result
ok/file.py written
../escape.py refused — outside base_dir
/etc/passwd, ~/x.py refused — absolute
.env, a/credentials.json refused — sensitive filename
ANSI codes or markdown around the path stripped, then checked
empty after cleaning refused — would resolve to base_dir itself

Subdirectories are fine at any depth — tests/stubs/Arduino.h is written, and missing parent directories are created. The check is not "does it contain ..?" but "does the resolved path still land inside base_dir?", so a .. that stays within (src/sub/../other.py) is allowed and one that escapes is not.

Known limitation: symlinks pointing outside are refused. Resolving a path follows symlinks, so a vendor/ inside the project that links to a library above it lands outside base_dir and is rejected. That is deliberate — a symlink would otherwise be the obvious way around the confinement — but it also catches legitimate cases like linked monorepo packages. The clean fix is to pass a base_dir high enough to contain both, not to loosen the check.

delegate_agentic(task, base_dir, extra_context="", max_turns=25)

Kimi gets four tools — read_file, write_file, list_files and run_bash (with cwd set to base_dir) — and runs its own loop: explore, edit, run the tests, see them fail, fix, repeat.

This is what K2.7-code is actually built for; it scores above Opus 4.8 on tool-use benchmarks, and one-shot generation wastes that.

State the finish condition in the task ("until pytest passes"), and give it a clean git tree.

Commits, pushes and publishing are refused — those belong to the human and to Claude, not to a delegated agent. So are the git commands that would destroy the working tree the whole design relies on for undo:

Command Result
pytest -q, python -m pytest allowed
git status, git diff, git log allowed — read-only git
git commit, git push, gh pr create refused
ls && git push origin main refused — chained commands are caught
git reset --hard, git checkout, git clean refused
npm publish, twine upload refused

⚠️ This is a workflow guard, not a sandbox. run_bash takes a shell string and the cwd confinement is a convenience, not a cage — a command can leave the directory with an absolute path. It stops accidents, not attacks. Only point it at projects where that is acceptable.

Before the loop starts, the server probes the environment once — interpreter version, whether pytest is importable, any existing venv, project files, tests already present — and states it in the prompt, so the agent does not spend turns rediscovering it (see Why loops cost more for what that buys).

Other limits: aborts unless the tree is clean, caps the loop at max_turns, times commands out at 120 s, clips tool output to 4,000 characters — keeping both ends for shell output, since test runners put the verdict on the last line — and returns git diff --stat plus any new untracked files at the end.

Every call comes back with what it did, not just what it tried. An attempt reads the same whether the agent is converging or going round in circles, so the log carries the outcome beside it:

Kimi worked in /path/to/project — 6 tool calls:
   1. write_file(app/Foo.kt) → 2 lines
   2. run_bash(gradlew test) → exit 1
   3. write_file(app/Foo.kt) → 3 lines
   4. run_bash(gradlew test) → exit 1
   5. read_file(app/Foo.kt) → 3 lines read
   6. run_bash(gradlew test) → exit 1

Same file, same command, same failure, three times: that run is stuck, and you can see it without opening anything. The log is written by the server from what happened — never by the agent about itself, since a summary from a stuck model is a claim by the least reliable witness at its least reliable moment.

The last thing it ran comes back verbatim. Whatever command looked like a test suite or a linter is echoed with its raw output, because "all 14 tests pass" is a claim and this is the evidence — and they have differed:

Last verification it ran, verbatim — not its summary of it:
    $ python -m pytest -q
    [exit 127]

    [stderr]
    /bin/sh: 1: python: not found

If it ran commands but never checked anything, or never ran a command at all, the result says so instead. Closing that loop is the whole point of this mode, so not closing it is worth knowing about.

The turn cap warns before it bites, and does not end the run. Once a fifth of the budget is left, every turn carries a countdown into the conversation:

TURN BUDGET: 3 turns left before you are cut off. Stop opening new fronts. Get
what you have already written into a state that compiles and passes, then
summarise.

and the final turn is told not to call any more tools. Without that the loop just stopped mid-edit — the failure that prompted this was a run that hit the cap having written a test file that did not compile, leaving the tree broken. If it is cut off anyway, the session is saved exactly as a pause is, and the result tells you how to continue rather than making you start over.

Expect it to take liberties. In testing it created a 28 MB virtualenv inside the project, unprompted, to install pytest after the system one was missing. That was reasonable and it got the tests passing — but review the directory, not just the diff.

resume_delegation(session_id, result, extra_turns=0)

Confined to one directory and barred from committing, the agent would otherwise have no way to handle work that needs the outside world — flashing a board, reading a serial port, someone looking at an LED. It would only be able to give up or invent a result.

So it gets a fifth tool of its own, ask_claude. Calling it suspends the loop: state is written to ~/.cache/kimi-delegate/sessions/, and the request comes back to you along with the work so far and the diff. Do the thing, then call resume_delegation with what you observed — the same session continues with its context intact.

The same door reopens a run that hit max_turns. There is no question to answer there, so result is guidance instead — what to finish first, what to leave alone — and extra_turns sets how much more rope it gets, defaulting to the budget it started with. Read the diff before you write that guidance: a cut-off run can have left something half-written. Continuing costs a fraction of a fresh delegation, which would re-pay for exploring the project from scratch — and that exploration is most of what makes turns expensive.

flowchart TD
    K["Agent working"] --> N{"needs something<br/>out of reach?"}
    N -->|No| K
    N -->|Yes| ASK["ask_claude('flash it and<br/>tell me what the LED does')"]
    ASK --> SAVE["State saved to ~/.cache<br/>under a session_id"]
    SAVE --> C["You get the request<br/>+ work log + git diff"]
    C --> DO["You do it<br/>asking a human if it is hardware,<br/>credentials, or irreversible"]
    DO --> RES["resume_delegation(session_id, result)"]
    RES --> K

Note that the agent does not gain any reach here — it gains a way to ask. You stay the gate.

Be literal in result: paste the real output, or describe exactly what is visible. Saying you couldn't do it is also a useful answer — it lets the agent try another route instead of waiting.

How far a request travels depends on what it needs:

Request Chain
Run a command — flash, read a serial port, run something outside the project agent → you → agent
Observe something physical — "is the LED blinking SOS?", "is the board plugged in?", "press reset" agent → you → a human → you → agent
Commit or push agent → you → human approves → you → agent

Many requests you can settle yourself. But hardware, credentials and anything irreversible are worth confirming with a person first — reflashing someone's board is not a decision to take on their behalf.

Expect more than one pause. Each resume can end in another, under a new session id. In the ESP32 test it paused twice: asked to be flashed, got an answer, made a change, and asked to be re-verified.

Answer carefully, and check the work log first. Given a report that contradicts its own correct code, this model does not push back — it improvises. In testing, a deliberately false observation ("dots and dashes look the same length") had it "fixing" the LED polarity, which has nothing to do with duration, on code whose timings were already correct and covered by a passing test it had written. If your answer contradicts what it has built, say so explicitly rather than letting it guess.

Session ids are generated server-side and validated on the way back in, since they return as an argument. Sessions expire after 24 hours, and the saved file is removed on resume so the same pause cannot be answered twice.


How it works

The first two tools differ in who writes the file, and that is where the cost is decided:

flowchart TD
    T["Claude delegates"] --> D{"Which tool?"}

    D -->|delegate_to_kimi| A1["Kimi generates code<br/>output · 4 $/M"]
    A1 --> A2["Code enters Claude's<br/>context in full<br/>input · 2 $/M"]
    A2 --> A3["Claude reviews<br/>BEFORE any write"]
    A3 --> A4["Claude RE-EMITS the code<br/>via Write / Edit<br/>output · 10 $/M"]
    A4 --> A5["File on disk"]

    D -->|delegate_and_apply| B1["Kimi generates code<br/>output · 4 $/M"]
    B1 --> B2["Server validates<br/>paths and writes"]
    B2 --> B3["File on disk"]
    B3 --> B4["Claude receives only<br/>a compact diff<br/>input · 2 $/M"]
    B4 --> B5["Claude reviews<br/>AFTER the write<br/>git = undo"]

The box that explains everything is "Claude RE-EMITS the code": on the review-first path the same code is billed twice. The direct-write path removes the second charge entirely.

delegate_agentic works differently — a loop, not a reply:

flowchart TD
    S["Claude starts delegate_agentic<br/>with a goal"] --> CHK{"clean git tree?"}
    CHK -->|No| AB["Aborts, touching nothing"]
    CHK -->|Yes| L["Kimi picks its next step"]
    L --> TOOL{"which tool?"}
    TOOL -->|read_file / list_files| R["Reads the project"]
    TOOL -->|write_file| W["Writes files"]
    TOOL -->|run_bash| G{"commit, push<br/>or publish?"}
    G -->|Yes| DENY["REFUSED<br/>that is Claude's job"]
    G -->|No| EXEC["Runs · cwd = base_dir"]
    R --> L
    W --> L
    DENY --> L
    EXEC --> L
    L -->|stops asking for tools| DONE["Summary + git diff --stat<br/>back to Claude"]

Prefix caching

Moonshot bills repeated prompt prefixes at $0.19/M instead of $0.95/M — an 80% discount on input. Caching is automatic (no cache_id to manage; the explicit POST /v1/caching API is legacy moonshot-v1 only), but it only works if the prefix is genuinely stable:

  • The prompt must exceed 256 tokens or nothing is cached.
  • Matching is by prefix, aligned to 256-token blocks. One changed byte and everything after it stops being cached.

So the prompt is built stable first, variable last:

flowchart TB
    S["1 · SYSTEM_PROMPT<br/>byte-for-byte identical every call<br/>cached almost always"]
    F["2 · File context<br/>sorted, so the order is stable<br/>cached when the same files repeat"]
    T["3 · The task<br/>different every call<br/>never cached"]
    S --> F --> T --> R["Kimi responds"]

Put the task first and the prefix diverges on the third token, so nothing is ever cached. Measured, two calls sharing a file context:

Tokens in Cached Cost
Call 1 (cold) 1,573 0 $0.00184
Call 2 (same prefix) 1,572 1,536 (98%) $0.00065

The discount applies to input only. On small one-off tasks the output dominates the bill, so caching barely helps; it pays off across several delegations over the same large context.

Why loops cost more

The API is stateless: every call resends the whole conversation, so a loop's input grows each turn and the earliest tokens end up billed ten times over. A one-shot delegation runs about $0.003; an agentic loop runs $0.02–0.03. Not that the agent does ten times the work — there are just many more, and progressively larger, requests.

Prefix caching is doing a lot of work here, because that repeated history is exactly what it is for. Measured on a real loop: 18,432 of 22,948 input tokens cached (80%), which took the run from $0.034 to $0.020 — a 41% saving.

So do not trim the history to save money. It is the obvious instinct and it backfires: cutting from the middle changes the prefix, and everything after the cut stops being cached.

Where the money actually is, once caching is applied:

Cost Share
Input (80% cached) $0.0078 39%
Output $0.0121 61%

Output is the larger half and caching does not touch it. The only real lever left is spending fewer turns — each turn costs its own output (reasoning included) and then rides along in every later request. Hence the environment probe: on one run, four of eleven turns went on discovering that python was not on PATH, that pytest was missing, and building a virtualenv. Handing that over up front, on the same task:

Before After
Tool calls 11 8 −27%
Tokens in 22,948 18,604 −19%
Tokens out 3,035 2,291 −25%
Cost $0.0199 $0.0161 −19%

No loss of quality — 19 generated tests, all passing. The environment block sits ahead of the task so it stays inside the cacheable prefix.

Runs that pause and resume are the expensive case: each resume restarts from the whole accumulated history. The ESP32 session above reached $0.127 over 24 calls — still small change, but roughly six times a straightforward loop.

Model behaviour worth knowing

Verified against the live API, not just the docs:

Reality Consequence
Thinking Always on, cannot be disabled Billed as output and counts against max_tokens
Temperature Ignored — fixed sampling Nothing to tune
reasoning_effort K3 only Not applicable
Output ceiling Accepts ≥131,072 The budget here is 32,000

Reasoning is not a rounding error: on a moderate task it was 2,314 of 3,635 completion tokens (64%). A budget sized for the code alone therefore truncates the reply — and a truncated reply leaves its last file block unclosed, so a naive parser drops it silently. Both write-capable tools check finish_reason and refuse to apply a truncated reply.

That overhead also dominates small tasks, and it is not predictable. The same six-line clamp request, sent twice, spent 691 of 752 completion tokens on reasoning ($0.0033) and then 73 of 239 ($0.0011) — a 3× cost spread on an identical prompt. Since thinking cannot be disabled and its length cannot be steered, that variance is simply the price of entry.

The usable rule is therefore about the floor, not the average: a trivial delegation costs somewhere in the fractions-of-a-cent range regardless of how little work it is, and you cannot predict where in that range it lands. If the task fits comfortably in a single edit, do it yourself. Delegation pays off on volume, not on errands.

Multi-turn tool loops must feed the assistant turn back including reasoning_content, or Moonshot rejects the following request.


Tests

They run offline and on every push; see CHANGELOG.md for what changed between versions.

The server confines a model's writes and blocks it from publishing, so its guards are worth testing. They are:

.venv/bin/pip install pytest
MOONSHOT_API_KEY=dummy .venv/bin/python -m pytest tests/ -q

72 tests, no network: _call_kimi is the single network seam and every test that needs a reply injects one — the same rule this server asks delegated code to follow, applied to itself. They cover path confinement (including the documented symlink limitation), the command guard, session-id validation, output clipping, prompt ordering for cache stability, and delegate_and_apply end to end against canned replies.

Passing tests are not the same as tests that bite, which is this project's whole suspicion of delegated work — so the guards were checked by breaking them on purpose:

Guard disabled Tests that failed
Command guard (commits/pushes allowed) 16
base_dir confinement (escapes allowed) 4
finish_reason check (truncated replies applied) 1
Syntax checks (Python, JSON, XML, TOML, brackets) 1–2 each
The bracket scanner's bail-outs (false positives allowed back in) 1 each
Turn-cap session saving 4
Turn-budget warnings 5
Fresh budget on resume 2
Verification echo 1
Outcome labels in the work log 2
Prices declared once (a literal re-added by hand) 1
Windows-path hint on base_dir 5
session_id validation 8

Notes on model choice

Kimi K2.7-code is the cheap-model pick here, not a claim that it beats better models. It doesn't: Sonnet 5 leads it on SWE-bench Verified (85.2% vs a self-reported 60.4%) and on SWE-bench Pro. K2.7's published gains over K2.6 come entirely from Moonshot's own benchmarks with no independent verification — and its SWE-bench Verified score is actually lower than K2.6's.

What earns it the slot is that in independent testing K2.6 was the one cheap model that wrote tests that actually tested something, rather than mocking classes that don't exist. K2.7-code is its coding-specialist fine-tune. Treat its benchmark numbers as provisional; treat review as mandatory.

Data residency

Moonshot does not specify a hosting country, and its policy permits training on submitted data with no documented opt-out. Everything the model reads leaves your machine irreversibly — and in agentic mode, it chooses what to read.

Do not point this at code covering other people's personal data. Under GDPR that is an international transfer to a country with no adequacy decision.

Troubleshooting

Symptom Cause
Tool doesn't appear in Claude Code Server registered mid-session — restart Claude Code
MOONSHOT_API_KEY is not set in the MCP process environment Key missing from the registration; re-run claude mcp add with -e
Edits to server.py have no effect The running session still has the old subprocess — restart
ABORTED before starting: ... Uncommitted changes, often just __pycache__. Commit, stash, or gitignore them
base_dir does not exist ... That is a Windows path The server runs inside WSL. Pass the /mnt/c/... form it suggests
ABORTED: Kimi's reply was cut off ... finish_reason='length' The task was too big for one reply. Split it up
No paused delegation with id ... The session expired (24 h) or was already resumed. Start a fresh delegation
(unfinished: hit the N-turn cap) Not a dead end: the session is saved. Read the diff, then resume_delegation(session_id, result="<what to finish first>")
that session is not waiting for an answer The run neither paused nor ran out of turns, so there is nothing to resume

License

MIT

from github.com/JMcordobamendez/kimi-delegate-mcp

Установка Kimi Delegate

У этого сервера нет опубликованного пакета — он собирается из исходников. Открой репозиторий и следуй инструкции в README.

▸ github.com/JMcordobamendez/kimi-delegate-mcp

FAQ

Kimi Delegate MCP бесплатный?

Да, Kimi Delegate MCP бесплатный — установка в пару кликов через Unyly без оплаты.

Нужен ли API-ключ для Kimi Delegate?

Нет, Kimi Delegate работает без API-ключей и переменных окружения.

Kimi Delegate — hosted или self-hosted?

Self-hosted: сервер запускается локально на твоей машине командой из раздела установки.

Как установить Kimi Delegate в Claude Desktop, Claude Code или Cursor?

Открой Kimi Delegate на unyly.org, выбери вкладку своего клиента (Claude Desktop, Claude Code, Cursor) и нажми Install — конфиг сгенерируется автоматически, без правки JSON.

Похожие MCP

Compare Kimi Delegate with

Не уверен что выбрать?

Найди свой стек за 60 секунд

Автор?

Embed-бейдж для README

Похожее

Все в категории development