Gå til hovedinnhold

MCP server

kapi exposes its format-aware content engine as an MCP (Model Context Protocol) server. An assistant connected to it can read the content inside a .docx, a JSON catalog or a Markdown file, ask what the project's own context says about a phrase, edit the content, verify it against the project's checks, and write it back byte-for-byte. Each step is a structured tool call, so the assistant never edits the file's bytes directly.

For the agent-skills path (Claude Code calling the kapi CLI), see Use the Kapi Agent Skills. The two can be used together.

Generated from the server

The tables below are generated by connecting to a real kapi mcp server and asking it for its tools and its resources. A CI drift gate fails the build if they stop matching the binary.

Quick Start​

Start the MCP server:

kapi mcp

This launches a JSON-RPC server on stdio. You don't run it manually; your AI tool starts it as a subprocess. With no flags it serves the writing set; --tools names others.

Setup​

Claude Desktop​

Add to your Claude Desktop config (~/Library/Application Support/Claude/claude_desktop_config.json on macOS, %APPDATA%\Claude\claude_desktop_config.json on Windows):

{
"mcpServers": {
"kapi": {
"command": "kapi",
"args": ["mcp"]
}
}
}

Restart Claude Desktop. Kapi tools will appear in the tool picker.

Claude Code​

Add to your project's .mcp.json file (or create it at the repository root):

{
"mcpServers": {
"kapi": {
"command": "kapi",
"args": ["mcp"]
}
}
}

Claude Code will automatically discover and connect to the kapi MCP server.

VS Code (GitHub Copilot / Copilot Chat)​

Add to your VS Code settings (.vscode/settings.json or user settings):

{
"mcp": {
"servers": {
"kapi": {
"command": "kapi",
"args": ["mcp"]
}
}
}
}

Or add to .vscode/mcp.json in your project:

{
"servers": {
"kapi": {
"command": "kapi",
"args": ["mcp"]
}
}
}

Cursor​

Add to your Cursor MCP config (~/.cursor/mcp.json):

{
"mcpServers": {
"kapi": {
"command": "kapi",
"args": ["mcp"]
}
}
}

Windsurf​

Add to your Windsurf MCP config (~/.windsurf/mcp.json):

{
"mcpServers": {
"kapi": {
"command": "kapi",
"args": ["mcp"]
}
}
}
tips

If kapi is not in your $PATH, use the full path to the binary (e.g. /usr/local/bin/kapi or $HOME/go/bin/kapi).

Available tools​

kapi mcp serves tools in named sets. An assistant reads every tool description it is offered and chooses among them, so a server offers the sets its work needs. --tools takes a comma-separated list, and a name that is not a set is refused with the list of sets:

kapi mcp # the writing set
kapi mcp --tools writing,translation # writing, plus the loop that fills target languages
kapi mcp --tools all # every set

writing is the default: the context:// resources and these 8 tools, which ask what applies, record what the assistant notices, read and edit a file's blocks with its structure kept, and check what it changed.

ToolWhat it does
apply_editsApply a kapi.change/v1 change set: the one write verb. Each content operation addresses one edition of one block with at, the ref read_blocks reports, and carries if_match, the rev you read. Several operations may name one block, each with the rev you read. set_content replaces the text (keep the <x id="…"/> placeholders; with if_match "absent" and an edition it creates that translation, which is how a translation's file is written), replace_text changes part of it by find (placeholder text, as read_blocks shows it), by start and end, or by range, set_attribute changes an inline code's attribute such as a link's href (code, name, value), mark wraps text in a new code such as fmt:bold, and remove_edition drops a translation. A plural or select branch is the operation's path. In a JSON, YAML or ARB catalog, insert_block adds a key (doc, name, after or before, and its text per language in editions) and delete_block removes one with its translations (at, and if_match mapping the catalog's own language to the rev you read). describe_format says which operations a format supports. A refused change set writes nothing: an edition that moved since you read it is refused as stale with its current revision and text, an edit that drops, invents or unbalances an inline code or flattens a plural is refused as guard, an edit that introduces a failing term or voice finding is refused as gate_failed with the findings (rewrite the wording they name and resend; only a person can override), and every other operation reports not_applied. Each refusal carries a code and the field at fault: re-read, fix the operation and resend. Status partial means some of it landed: a write interrupted after some documents were written (docs says which), or a store operation refused after the content was written, which carries its error. Re-read the documents before you send more. mode preview computes and checks the change set and returns a diff per document without writing. A source edit lists the translations it made stale under invalidates. Every operation is recorded as yours, the calling agent's, in this server's session. Writing a term, a content-memory pair or a recipe field and deciding a review are a person's: those operations are refused as not_permitted. Record a term rule as a suggestion with context_note, with from and to for wording you changed. Each document's findings say what the commit check found on the edit; run check_file after a native write, or for what the commit check does not run.
check_fileCheck a file you changed against the voice and terms in force at its location, in any format kapi reads (Markdown, JSON, Word, XLIFF and more). Run it on every file you changed and fix what it reports before you say the work is done. To check only what a change touched, pass diff, diff_against (a git revision), staged, or diff_range (A..B). Returns a kapi.check/v2 report: findings, and which analyzers covered the content. A pass is not semantic approval.
context_noteRecord what you noticed about how this project writes, as soon as you notice it, including what your own text does not use: a product, feature or plan name as written, the spelling variety, or a word chosen over a common alternative. For a name or word, pass `term` with the form the files use and `instead_of` with the form they avoid: the split form of a one-word name, the other spelling, or the other word. kapi adds the spacing, hyphen and case variants. Say anything else, such as the spelling variety, in `text`. Give `path` and `quote` from a file that was there before you started. Leave alone, with no note, a word the files write more than one way, an interface label, and wording taken from your task. When the person changes your wording, pass `from` (what you wrote), `to` (what they wrote) and `path`, and set `suggest` to also suggest the rule it implies. To take back a note of your own recorded wrongly, pass its id in `withdraw`. Every note is a suggestion: checks report it, none fails on it, and it holds only where you saw it until a person decides about it in review.
context_readRead everything that applies to one file: the voice in full, the words to use and to avoid, the old names that stay correct there, and what has been suggested but not yet established. kapi's section of AGENTS.md and CLAUDE.md states the same rules, so call this for a file no section covers or when you need the full answer. `path` is project-relative, e.g. `docs/guide.md`, or `profile/<name>` for a named profile. Set `comments` before writing a comment in a source file: the answer is then for the file's comments. The same text the context://<path> resource returns.
context_searchAsk what this project says about one word or phrase: what it is called here, whether it is discouraged and what to say instead, and wording the project has already approved. For everything that applies to a file, call context_read instead. An empty answer means nothing is recorded about the word; if the files always write it one way, record that with context_note, and leave it alone, with no note, if they write it more than one way. `attention` says what a person must act on, such as context files nobody has imported.
context_session_summaryReport what this session recorded with context_note, and what the hooks' check runs found in it (the edit hook's run on each edited file, and the Stop hook's ship gates): `checked` runs, the `failing` findings the runs left, the `caught` findings and the `files` the session edited. A finding is caught when a hook run reported it and the next run on the same file no longer found it. The hook records its runs under the assistant host's session id. Without `session`, it summarizes the session with the project's latest check run, or the session that recorded last when none ran a check, and names it in `chosen`. Call it only if you recorded a note, and end your report with what it says, including the command a person reviews the session with.
describe_formatSay what apply_edits can do in a format: whether the format keeps a document's translations in one file or one per file, and for each content operation what it accepts (the content forms of set_content, the code types a writer can create, the attributes set_attribute can change per code type), or null where the format refuses the operation as unsupported. Name a format, or a document to describe the format kapi reads it in. apply_edits' input schema gives each operation's fields; on the command line, kapi apply --schema OP prints one operation's schema.
read_blocksRead a document's blocks, a page at a time: the read leg of apply_edits. Each block carries ref (doc, block and edition) to copy into an operation's at, rev to send as its if_match, and text with inline codes as <x id="…"/> placeholders, which an edit keeps. codes lists each code by the id its placeholder shows, with its type and attributes; structures lists each plural or select with the path that reaches a branch and the branch's text; editions lists the block's translations with their revision, text and status; ops lists the operations the block accepts. A page holds up to limit blocks: pass next back as cursor for the following page. A cursor from a document that changed since is refused as stale; read it again from the start. Reads the document as apply_edits writes it, through the format and configuration the project binds.

content works on content directly:

ToolWhat it does
check_textCheck a draft snippet with deterministic content rules. Before drafting, read the context://<project-relative-path> resource for the applicable guidance. Supply context_path to check with that destination's voice and terms; without it, project guidance is not resolved. Explicit profile_pack/profile_file are available only without context_path. Returns a kapi.check/v2 Report with findings, analyzer coverage and configuration warnings, which never change pass; pass is not semantic approval. After saving edits, use check_file to verify the actual file.
detect_formatDetect the file format from a file path based on its extension
redactReplace sensitive spans with protected placeholders before processing
term-checkTerminology Check
voice_checkScore text against a voice profile using deterministic vocabulary rules; returns a 0-100 compliance score and findings
voice_rewriteRewrite text to comply with a voice profile by substituting forbidden/competitor terms (deterministic, offline). A rule that names no replacement, and a match on an inflected form of a term, are left in place and listed under skipped with the term, its list, severity and reason; rewrite those by hand and verify with voice_check.

translation runs the loop that fills target languages:

ToolWhat it does
statsSize files before processing them. Reports per-file and total content metrics: blocks (translatable and not), words, characters (with and without spaces, plus the unique-character inventory), segments when available, and a by-role breakdown. Works on any supported format (Word, PowerPoint, JSON, XLIFF, Markdown, HTML, …) and returns the same JSON `kapi stats --json` emits.
translateTranslate content with an LLM or machine-translation provider (select an engine, then a provider)
upBring a kapi project up to date against its ship gates: re-extract drifted sources, run the default flow (content memory reuse then AI translate) over every target language, concurrently per language, loop until every gated locale is shippable or waits for review, and run the project's bound checks each pass. In a project connected to a Bowrain server the run happens there (push, converge on the org's keys and shared content memory, pull the results); pass local to run the loop on this machine instead. Never fails on pending target work: blocks waiting for review are reported, not thrown. Returns the structured result (per-locale standing, locales waiting for review, materialized files). Use up_plan first to see the pending work and token estimate.
up_planDry-run the catch-up work for a kapi project: per (collection, locale), the blocks missing a target, exact-content-memory leverage, the remaining AI work, and a rough token estimate. No provider calls, nothing written. The pre-flight for the up tool.

review is the review queue and the review picture of one block, with apply_edits from the writing set, which records a pre-review:

ToolWhat it does
review_blockRead one block's review picture: ref and rev, the reference and revision of the edition under review, and the block itself, under block: source and target text, ladder status, the last recorded decision (with identity), and the context the decision is made in: the point governing the file (voice guidance, term rules, coordinates), the blocks before and after it as run sequences, the prior approved version and the content-memory match with its wording, the check findings with their run anchors, and the AI pre-review score. Address it with the ref a review_queue row carries, or a ref read_blocks reports with the translation's edition. A block in the project's source language is read from its source file and returns its authoring rung with no target half. To record a pre-review, send apply_edits a decide operation with at set to ref, if_match set to rev, outcome advise, a score from 0 to 100 and your reasons: it is bound to the wording you read, a later edit drops it, and it never approves the block.
review_queueList the review queue: every block awaiting a person, each with ref, the reference review_block reads it by ({doc, block, edition}: the source document, the block key and the translation's language; no edition for a source block). One queue holds every language, the project's source language among them: a translated block not yet approved is one row, and a source block held below the project's translate_after level is another, marked `isSource`. The result also carries `languages`, the pending count per language. Filter with language, locale and/or collection. Read-only, derived from the content files and the project state store; blocks annotated by an AI pre-review carry their score. Lean by design: call review_block for a block's context (the point governing it, its neighbourhood, its prior version, its findings).

Project scoping applies on top. Started inside a kapi project (discovered by a git-style upward walk, exactly as the CLI discovers it), the tool set is narrowed to the sources the recipe declares and the project's first target language becomes the default for the translating tools.

Tools from installed plugins​

An installed plugin adds its own tools to this surface. kapi mcp starts each plugin's server once per session and passes calls through, so the tools a plugin brings answer on the same connection that serves the loop verbs. Configure one MCP server, not one per plugin.

A plugin contributes the tools its manifest declares. A plugin that is not installed adds nothing, one that fails to start is left off with a note on stderr while the rest of the surface keeps working, and a plugin tool whose name kapi already uses is skipped so the kapi tool keeps the name.

Widening the surface​

Two flags on kapi mcp add tools no set holds, for debugging and for callers who really are assembling a pipeline by hand:

  • kapi mcp --all-tools adds every CLI-visible processing tool, plus the listing verbs: case-transform, create-target, diff-leverage, dnt-check, encoding-detect, entity-extract, inline-codes-remove, list_formats, list_tools, media-refine, placeholder-check, pseudo-translate, pseudo_translate, qa, recycle, remove-target, review, search-replace, segmentation, term-extract, translate-after, unredact, voice-check, voice-infer, whitespace-correct, xml-validation.
  • kapi mcp --all-flows adds the flow-running verbs: list_flows, run_flow.
  • kapi mcp --all serves every set and adds both.

Two tools are withheld from every surface, including the widened ones: external-command and script run arbitrary commands and JavaScript, which is a different class of decision from "show me every tool". Both remain available through kapi exec.

Available resources​

Retrieval comes in two shapes, a tool and a resource. Asking what a word means is a call with arguments, so it is the context_search tool. Asking what applies at a location is reading something that already exists at an address, so it is a resource:

AddressRenders asWhat it answers
context://profile/{name}{?format,project}text/markdownWhat applies when you write at one place: the voice, the words to use and to avoid, and what has been suggested but not yet established. kapi's section of AGENTS.md and CLAUDE.md states the same rules, so read it for a file no section covers or for the full answer. An answer with nothing recorded says so. Returns markdown; append `?format=json` for the structured answer, which also names the point, the project and the revision that answered. Names a profile instead of a file, e.g. `context://profile/marketing`.
context://{+path}{?format,project,comments}text/markdownWhat applies when you write at one place: the voice, the words to use and to avoid, and what has been suggested but not yet established. kapi's section of AGENTS.md and CLAUDE.md states the same rules, so read it for a file no section covers or for the full answer. An answer with nothing recorded says so. Returns markdown; append `?format=json` for the structured answer, which also names the point, the project and the revision that answered. The path is project-relative, e.g. `context://docs/guide.md`; `?project=<path>` reads another project.

The two addresses are one primitive. A path answers what applies here; a profile name answers the same question for a caller with no file in hand (an ad-hoc run, or a starter pack). The markdown is the brief a writer reads: the voice, one list of words to use and to avoid, and what has been suggested but not yet established, as kapi context <path> prints it. The JSON adds the point the location resolved to, the full voice guide, the terms, the governance windows and the provenance.

The suggestions list is reported apart from everything in force. Each entry carries its status, suggested or contested (with contested_by naming the other side), the rule or note it states, who suggested it, in which session and the evidence behind it, with the operation id a person keeps it by. A check reports every suggestion and fails on none of them.

The server offers these addresses as resource templates, and many clients list no resources from a template, so an assistant there cannot discover them on its own. context_read returns exactly the same text as a tool, the server's instructions name the address, and kapi context <path> prints the same text for an assistant that can run a shell command.

The rendering is a property of the read. ?format=json returns the same answer as application/json (the document kapi context <path> --json prints) and everything else returns text/markdown. An unrecognised format is refused, so a program never receives prose it cannot parse.

context://docs/guide.md # markdown, for a model to read
context://docs/guide.md?format=json # the same answer, for a program
context://profile/marketing # a named profile, no location needed

The CLI half is kapi context <path>, which calls the same host function and prints the same markdown. A conformance test holds the two surfaces to the same answer.

Example conversations​

"How many words need translating?"​

How many translatable words are in src/locales/en.json?

The assistant calls stats with the file path and returns a structured answer with word, block, character, and segment counts.

"What do we call this here?"​

Is "sign-in" the term we use, and how do we say it in French?

The assistant calls context_search. One question reaches every store the project binds (its terms, its content memory, its voice profile) and the answer says what the project calls the thing, whether it is discouraged and what to say instead, and any wording already approved. Asking before writing is cheaper than learning the same fact from a failing check afterwards.

Every answer carries notes, and the first of them says whether the context, the terms or the decisions moved since this session last read them. What a person must act on, such as a checkout whose context nobody has imported, is also in attention, and it is the part of the notes the text answer shows. The comparison is against what the project last observed of its server, held on disk, so it costs a small file read and no round trip, and it reports rather than resolves: an assistant told the terms moved asks again before continuing, because the wording it had settled on was chosen against a context that has since changed.

"Show me the content of this file"​

Show me the translatable strings in messages.json

The assistant calls read_blocks with the document's path and returns a page of blocks: each block's reference and revision, its text with inline codes as <x id="…"/> placeholders, the codes and their attributes, and the operations the block accepts.

"Edit the content, then check it"​

Tighten the intro paragraph in report.docx, keeping it on brand

The assistant reads the blocks with read_blocks, rewrites the text itself (no second model), and sends a change set through apply_edits: one replace_text or set_content operation per block, addressed by the ref the read reported and guarded by its rev. kapi writes it through the format's writer, keeping the document's structure and inline codes, then the assistant calls check_file to confirm the gate passes, looping until it does.

"Catch the project up"​

What translation work is outstanding, and how much would it cost?

The assistant calls up_plan, a dry run reporting, per collection and locale, the blocks missing a target, the content-memory leverage, the remaining AI work and a rough token estimate. Nothing is written and no provider is called. up then does the work: re-extract what drifted, reuse the content memory, translate the rest, run the project's checks, and loop until every gated locale is shippable or waits for review.

"Review this translation"​

Show me the French blocks waiting for review, and pre-review them for me

The assistant calls review_queue, reads each candidate with review_block using the ref its row carries (the result holds the block's text, status and review context under block), and records a pre-review through apply_edits: a decide operation at that ref, with if_match set to the rev review_block returned, outcome advise, a score from 0 to 100 and its reasons. The pre-review is bound to the wording the assistant read and recorded under the identity agent/<client>, so a later edit drops it. It decides nothing: the block stays in the queue until a person approves or rejects it, and an assistant's establish is refused.

review_queue returns one queue across the project's languages. Each row carries language and, when that language is the project's source, isSource: true and a status on the authoring ladder; languages counts the pending blocks per language, so an assistant can narrow with the language argument to one that has work. review_block reads a source-language block the same way it reads a translation, from the source file, and returns its point and neighbourhood with no target half.

Tool reference​

context_read​

Read everything that applies to one file: the voice in full, the words to use and to avoid, the old names that stay correct there, and what has been suggested but not yet established. kapi's section of AGENTS.md and CLAUDE.md states the same rules, which an assistant loads without a call (rules files), so an assistant calls this for a file no section covers, or when it needs the full answer. It returns exactly the text the context://<path> resource returns, for a client that lists no resources from a template. path is project-relative, or profile/<name> for a named profile; comments answers for the comments in the file instead of its content.

ParameterTypeRequiredDescription
pathstringyesthe project-relative file you are about to write, or profile/<name>
commentsbooleannoanswer for the comments in the file rather than its content
formatstringnomarkdown (default) or json
projectstringnothe project this call acts on: its kapi.yaml recipe, its root directory, or any path inside it (default: the project the MCP server started in)

A word somebody has suggested a rule or a note about comes back under suggestions, apart from the terms in force.

ParameterTypeRequiredDescription
querystringyesthe word or phrase to ask about
limitintegernomax results per group (default 10)
localestringnonarrow results to one language (e.g. en, fr)
memorystringnopath to a standalone content memory (default: the project's own store)
projectstringnothe project this call acts on: its kapi.yaml recipe, its root directory, or any path inside it (default: the project the MCP server started in)
termsstringnopath to a standalone terms store (default: the project's own store)

context_note​

Record what the files do every time, or what the person changed. Use text for a note, or term and instead_of for a suggested term rule: kapi adds the spacing, hyphen and case variants of a compound, so Quickcast instead of Quick cast also avoids Quick-cast and QuickCast. The lower-case spelling is never added; name it in instead_of when the project avoids it. For wording the person changed, pass from, to and path; suggest also records the rule the change implies. A term rule and a change need path. Pass withdraw with an id this session recorded to take that note back; a person handles established rules and notes from other sessions.

The result is a suggestion: every check reports it, and none fails on it until a person keeps it in kapi context review. It holds only where the assistant saw it, the part of the project path belongs to, until a person applies it more widely. It is the same recording as kapi context note on the command line.

ParameterTypeRequiredDescription
advisorybooleannowith suggest: the rule should only report once a person keeps it; unset, a kept rule fails a check
blockstringnothe ref.block that read_blocks or kapi inspect reports
fromstringnofor a change a person made: the wording that was there
instead_ofarraynoforms the project avoids for term, e.g. Quick cast; spacing, hyphen and case variants are added for you
pathstringnothe project-relative file you saw it in, or the person changed it in
pointobjectnonarrows where the note holds, axis to value, within the point the file it was seen in sits at, such as market set to no; it may narrow and never widen
projectstringnothe project this call acts on: its kapi.yaml recipe, its root directory, or any path inside it (default: the project the MCP server started in)
quotestringnothe wording you saw, quoted from the file
suggestbooleannowith from and to: also record the rule the change implies, so the next use of the old wording is reported
termstringnothe form this project uses for a name or word, e.g. Quickcast
textstringnothe fact, in one sentence, in your own words
tostringnofor a change a person made: the wording that replaced it
valid_fromstringnothe note holds from this date (2006-01-02) or RFC3339 instant on
valid_tostringnothe note holds until this date (2006-01-02) or RFC3339 instant, not including it
whystringnowhat the person said about the change, or what was wrong with the note withdrawn
withdrawstringnothe id of a note this session recorded wrongly, to take it back

context_session_summary​

An assistant calls it only after it recorded a note. It returns what this session recorded and what became of it, counted as observed, corrected, suggested, contested, established, withdrawn, dropped and reset, with the sentence to end a task report on. The report ends with the kapi context review --session <id> command a person reviews the session's suggestions with.

It also returns what the hooks' check runs found in the session: the edit hook's run on each file an edit wrote, and the Stop hook's run of the ship gates:

FieldCounts
checkedthe runs the hooks recorded
failingthe failing findings the runs left, each file as the latest run that checked it found it
caughtthe findings a run reported that the next run on the same file no longer found
filesthe files the session's turns edited

Each field is present at zero, so checked: 0 means no run was recorded. Each hook records a run under the assistant host's session id, and the MCP server records a note under its own.

Without session, the tool summarizes the session whose latest check run is the project's most recent, so a note written after a hook run leaves the run's outcomes in view. When no session holds a check run, it summarizes the session that recorded last. chosen names the session, the rule that applied and when the session last recorded. When the log holds no session's operations, the answer is one line in report saying that the edit hook records one each time it checks an edited file, and the Stop hook each time it runs the project's checks. Pass session to read another session.

ParameterTypeRequiredDescription
projectstringnothe project this call acts on: its kapi.yaml recipe, its root directory, or any path inside it (default: the project the MCP server started in)
sessionstringnothe session to summarize (default: the latest session with a check run, named in chosen)

Keeping, dropping, widening, resetting and syncing are reserved for people, through kapi context review, reset and sync or Kapi Desktop, and are excluded from the MCP tools. See Growing context.

read_blocks​

Read a document's blocks, a page at a time. Each block carries ref, the reference an operation names (doc, block and, for a translation, edition), and rev, the revision of the edition the read showed, which an operation sends as if_match. text holds the content with inline codes as <x id="…"/> placeholders, which an edit keeps; codes names what each placeholder stands for, and structures lists the branches of a plural or a select with the path that reaches each. Pass next back as cursor for the following page. Inside a project, doc is a path relative to the project's root, and the file of a translation reads that edition of its source. The format is the one the project's recipe binds to the file, or the one kapi detects, and apply_edits writes the file in the same format. A source code file whose comments kapi checks is refused as unsupported with the capability comment: edit a comment in the file itself, then run check_file on it.

ParameterTypeRequiredDescription
docstringyesthe document: a path inside the project, relative to its root or absolute, or outside a project a path under the server's working directory; container!entry names an archive member; the file of a translation reads that edition of its source
blocksarraynoonly these blocks, by the block key a read reports; empty reads every block
cursorstringnocontinue a read: the next value of the page before
editionsarraynotranslations kept in files of their own to show beside each block, such as fr or de; the editions the document holds itself are always shown
limitintegernothe most blocks a page holds (default 100, at most 1000)
projectstringnothe project this call acts on: its kapi.yaml recipe, its root directory, or any path inside it (default: the project the MCP server started in)

apply_edits​

The write verb. apply_edits takes a kapi.change/v1 change set, the contract every kapi surface sends (E-09), plus the per-call project.

ParameterTypeRequiredDescription
opsarrayyesthe operations, applied in order; a position names the content as read, and an empty list changes nothing. Several operations may name one block, each sending the rev you read, since every if_match is checked against the content the change set began with
evidencearraynowhere the wording behind the change was seen
gatestringnoenforce (the default): a failing finding the change introduces refuses it; report: the change lands with its findings
modestringnoapply (the default), or preview: compute and check, write nothing
notestringnoone line a person reads in history and review
projectstringnothe project this call acts on: its kapi.yaml recipe, its root directory, or any path inside it (default: the project the MCP server started in)
require_basisbooleannorefuse a derived-edition write whose authoritative edition moved since it was read
schemastringno
OperationWhat it changes
set_contentan edition's whole text, keeping its placeholders; with if_match: "absent" and an edition, it creates that translation, adding its key to a JSON, YAML or ARB translation file that lacks it
replace_textpart of the text, named by find (the text as a read shows it, a <x id="…"/> placeholder naming a code), by start and end, or by range; a path names the plural form or select case it is in
remove_editiondrops a translation: from a bilingual file such as PO, or with its key from a JSON, YAML or ARB translation file
insert_blockadds a key to a JSON, YAML or ARB catalog, with its text in each language
delete_blockremoves a key from such a catalog and from each translation's file
decidea pre-review: outcome advise, with a score and reasons

describe_format lists what each format supports; an operation the format refuses is refused as unsupported and writes nothing.

{
"note": "Name the handbook",
"ops": [
{
"op": "replace_text",
"at": { "doc": "docs/guide.html", "block": "p" },
"if_match": "r:3f9a1c0e7b2d4a55",
"edits": [{ "find": "shop guide", "text": "handbook" }]
}
]
}

A refused change set writes nothing. An edition that changed since it was read is refused as stale, and the refusal carries its current revision and text, so the assistant can rebase without another read. An edit that drops, invents or unbalances an inline code, or flattens a plural or select, is refused as guard. A reference that names no block is not_found, and so is a find that matches nothing, with the text it searched. A block the format reads as not translatable, such as a code block, is unsupported. Each document in docs carries the findings the edit introduced, failing or not, an empty list when the check found nothing; a failing one refuses the change as gate_failed, and the finding names the wording a term rule asks for. Every other operation of a refused change set reports not_applied, and the result is an error. The status partial is an error too: some of the change set landed. Either a write stopped after some files were written, and docs names them, or the content was written and a decision recorded after it was refused, and that operation carries the error. The assistant reads the documents again before it sends more. mode: "preview" computes the result and a diff per document and writes nothing. A source edit lists the translations it made stale under invalidates.

apply_edits sends every change set as the calling agent in the server's session; a change set has no field that names its sender. Writing a term, a content-memory pair or a field of kapi.yaml is a person's decision, so a change set holding a term, memory or recipe operation, an if_match of * or gate: "report" is refused as not_permitted and writes nothing. The assistant records a term rule as a suggestion with context_note, with from and to for wording it changed, and a person keeps it. A review decision is a person's too: an assistant's decide takes only the outcome advise, with the score it gives. A person sends the same operations with kapi apply in a terminal.

describe_format​

What apply_edits can do in a format: whether the format keeps a document's translations in one file (in-file) or one per file (one-per-file), and for each operation what it accepts, or null where the format refuses it.

ParameterTypeRequiredDescription
docstringnoa document, to describe the format kapi reads it in; give this or format
formatstringnoa format name, such as html, markdown or po
projectstringnothe project this call acts on: its kapi.yaml recipe, its root directory, or any path inside it (default: the project the MCP server started in)

check_file​

ParameterTypeRequiredDescription
diffstringnounified diff text (git diff output); only the content blocks it touches are checked
diff_againststringnogit revision to diff the working tree against, read-only, with untracked files as added; only the content blocks changed are checked
diff_rangestringnotwo commits as A..B, or A...B for the change B made since its merge base with A; each file is read from B and nothing from the working tree; only the content blocks changed are checked
dntarraynodo-not-translate terms that must survive verbatim into the target
filestringnopath to the file whose content should be checked; with diff, diff_against, staged or diff_range it narrows the scope to this file, and may be omitted
forbidarraynoregex that must NOT appear in the content
max_charsintegernoflag content longer than this many characters (0 = off)
max_wordsintegernoflag content with more than this many words (0 = off)
profile_filestringnoexplicit voice override loaded from YAML; bypasses the file-scoped project voice and channel; omit to use project guidance
profile_packstringnoexplicit voice override; omitting profile_pack and profile_file preserves the file-scoped project voice and channel
projectstringnothe project this call acts on: its kapi.yaml recipe, its root directory, or any path inside it (default: the project the MCP server started in)
requirearraynoregex that MUST appear in the content
stagedbooleannocheck the changes staged for commit: the index diffed against HEAD, with each file read from the index, leaving out unstaged edits and untracked files; only the content blocks changed are checked
targetstringnotranslated target file to check against the source (enables the bilingual source-against-target checks)
target_langstringnolocale of the target file (e.g. de)
validatestringnoreader structure/encoding validation: off|report|strict (report folds structure.*/encoding.* findings into the report; strict also fails on a Major+ structure/encoding problem). Default off.

check_text​

ParameterTypeRequiredDescription
textstringyesthe text to verify
context_pathstringnoproject-relative destination whose voice and terms govern this draft; may not exist yet; requires a project; cannot combine with profile_pack or profile_file
forbidarraynoregex that must NOT appear in the content
max_charsintegernoflag content longer than this many characters (0 = off)
max_wordsintegernoflag content with more than this many words (0 = off)
profile_filestringnopath to a voice profile YAML
profile_packstringnobuilt-in profile pack to check vocabulary against (e.g. marketing-blog)
projectstringnothe project this call acts on: its kapi.yaml recipe, its root directory, or any path inside it (default: the project the MCP server started in)
requirearraynoregex that MUST appear in the content

stats​

ParameterTypeRequiredDescription
filesarrayyespaths of the files to summarize
formatstringnoinput format override applied to every file (default: auto-detect by extension/content)

up_plan​

ParameterTypeRequiredDescription
no_checksbooleannoplan the run up makes with no_checks: a language that only fails the project's bound checks gets no pass, so the plan prices none for it
projectstringnothe project this call acts on: its kapi.yaml recipe, its root directory, or any path inside it (default: the project the MCP server started in)

up​

ParameterTypeRequiredDescription
jobsintegernohow many languages to catch up concurrently per pass (0 = project default, else 4)
localbooleannoin a server-connected project, run the loop on this machine and push the results, instead of running it on the server
materializebooleannoafter the loop, write the target-language files for every shippable locale (overrides the recipe's materialize policy)
no_checksbooleannoskip the project's bound checks inside the loop (failing blocks then count as translated)
passesintegernomaximum reconciliation passes (0 = loop until up to date or waiting for review; 1 = single pass)
projectstringnothe project this call acts on: its kapi.yaml recipe, its root directory, or any path inside it (default: the project the MCP server started in)

detect_format​

ParameterTypeRequiredDescription
pathstringyesFile path to detect format from

How it works​

Kapi MCP uses the same machinery as the CLI commands: the format registry for detection, the executor for flow orchestration, and the same built-in tools. The MCP server exposes them as typed, discoverable tools over the Model Context Protocol stdio transport.

No server process, ports, or authentication needed. Your AI tool launches kapi mcp as a child process, communicates over stdin/stdout, and shuts it down when the session ends.

merknad

Most tools here are rule-based and need no API key: context_search, check_text, check_file, voice_check, voice_rewrite, stats, read_blocks, apply_edits, describe_format, the context write tools and the review tools all run offline. The ones that reach a language model (translate, and up when there is work the content memory cannot cover) need a provider credential, which they read from the same credential store the CLI uses (kapi credentials add).