Skip to main content

MCP reference

strauss-kb-mcp speaks stdio and takes no API key and no required environment.

{ "mcpServers": { "strauss-kb": { "command": "strauss-kb-mcp" } } }

Every tool is a projection of the same command table the CLI projects, so the two cannot drift. Thirty-four tools; the one CLI verb with no tool is sync-instructions. STRAUSS_KB_ACTOR names the writer in the log, defaulting to mcp here. Diagnostics go to stderr, because stdout is the JSON-RPC transport.

Shared parameters​

  • bundlePath (string) — absolute path to the base. Required by every tool except kb_schema, kb_types, kb_pins, and kb_context.
  • conceptId (string) — <type>.<slug>, both kebab-case, e.g. decision.cursor-v2.
  • type (enum) — one of fact, requirement, constraint, decision, assumption, open-question, risk, contract, flow, affected-system, source-note.

The tool descriptions the server registers carry the judgment a schema cannot: an unsourced claim is an assumption, a conflict belongs in a risk or a superseding decision, and kb_load is usually the right first call.


Write tools​

Each refuses when the base is pinned --frozen in the workspace.

kb_write​

As CLI write; the record object is the input parameter rather than stdin.

Parameters: bundlePath, type (enum), input (object) — all required. input is the write object — slug, title, why required; sections, anchors, sources, assumption, stale_after, verify, tags, relatedConceptIds, links (max 64), supersedes (max 32), materiality, confidence, owner optional. Unknown keys are rejected, and sections keys must be headings the type defines (see kb_types). links are typed causal edges — { target, rel }, source → target, from the closed eight-rel vocabulary; a self-link is refused.

{
"bundlePath": "/repo/.strauss/kb",
"type": "fact",
"input": {
"slug": "cache-key-includes-region",
"title": "The cache key includes the region",
"why": "A region-less key serves another region's data.",
"sections": { "Claim": "Every key is prefixed with the region." }
}
}

kb_write_decision​

As CLI write-decision. Parameters: bundlePath and input, both required; input is kb_write's object minus sections, plus optional alternative and impact.

{
"bundlePath": "/repo/.strauss/kb",
"input": {
"slug": "cas-not-lock",
"title": "Compare-and-swap rather than a lock",
"why": "A stale lock hold blocks every later writer.",
"alternative": "A lock file, which adds a stale-hold failure mode."
}
}

kb_no_decision​

As CLI no-decision. Parameters: bundlePath and reason (string), both required.

{ "bundlePath": "/repo/.strauss/kb", "reason": "The diff answers it." }

kb_status​

As CLI status. Parameters: bundlePath, conceptId, and status — one of draft, proposed, accepted, open, resolved, rejected, superseded — all required.

{
"bundlePath": "…/kb",
"conceptId": "requirement.export-csv",
"status": "accepted"
}

kb_supersede​

As CLI supersede. Parameters: bundlePath, conceptId, replacementId — all required.

{
"bundlePath": "…/kb",
"conceptId": "decision.cursor-v1",
"replacementId": "decision.cursor-v2"
}

kb_answer​

As CLI answer. Parameters: bundlePath, conceptId, answer (string) — all required.

{
"bundlePath": "…/kb",
"conceptId": "open-question.retry-budget",
"answer": "Three retries with full jitter."
}

kb_verify​

As CLI verify; --note is the note parameter, a non-blank string that must say what the check found. Parameters: bundlePath, conceptId, note — all required.

{
"bundlePath": "…/kb",
"conceptId": "decision.cas-not-lock",
"note": "Re-read KbStore.setStatus; the digest check is still before publish."
}

kb_anchor_resolve​

As CLI anchor-resolve, with the flags as camelCase parameters. Results carry the same per-anchor outcome; only the exit code is CLI-only.

Parameters: bundlePath and conceptId required; repoRoot (string, defaults to the working directory), offline, rebaseline, restamp and check (boolean) optional.

{
"bundlePath": "…/kb",
"conceptId": "decision.cas-not-lock",
"repoRoot": "/repo"
}

kb_anchor_set​

As CLI anchor-set. The object the CLI reads from stdin is the input parameter.

Parameters: bundlePath, conceptId and input required; resolve, offline (boolean) and repoRoot (string) optional, as the CLI flags. input is { reason, anchors }; anchors is the complete new set. Carry an anchor's hash and the rest of its stamp forward to keep drift visible until the new code is read.

{
"bundlePath": "…/kb",
"conceptId": "decision.export-retention",
"input": {
"reason": "Reviewed the refactor: isExportExpired replaces shouldDeleteExport; retentionDays owns the shared setting.",
"anchors": [
{
"file": "src/cleanup.mjs",
"symbol": "isExportExpired",
"hash": "sha256:5c7242b8…",
"hash_kind": "ast",
"resolved_at": "2026-09-17T20:06:25.829Z",
"lines": 3,
"resolver": "tree-sitter"
},
{ "file": "src/retention.mjs", "symbol": "retentionDays" }
]
}
}

Returns { conceptId, reason, changes, anchors, baseline, note }. baseline is always "unchanged": moving a pointer is not accepting the code behind it. Call kb_anchor_resolve next to check the new pointers, with rebaseline to accept them, and kb_verify only for a reading someone actually did.

kb_reassess​

As CLI reassess, with the flags as camelCase parameters. Reach for it when a drift warning names a record, or when a supersession leaves you asking whether the records around it still hold.

Parameters: bundlePath and conceptId required; repoRoot (string, defaults to the working directory) and withDiff (boolean) optional.

{
"bundlePath": "…/kb",
"conceptId": "fact.region-key",
"withDiff": true
}

Returns { conceptId, packet, rebaselined, cosmetic }; packet is null when the record has neither drift nor an unresolved reference. packet.references holds outgoing — what this record's strauss_links point at that no longer holds — and incoming, who still points at it, answered for a record that has itself stopped holding. It rebaselines moved anchors and does nothing else to the record — never verified[], never standing, never a link.


Read tools​

kb_load, kb_catalog, kb_query, kb_pack, and kb_trace are the only supported ways to read a base: a raw file read bypasses supersession resolution.

kb_load​

As CLI load, with the flags as camelCase parameters. Usually the right first call.

Parameters: bundlePath required; type (enum, narrows to one record type), budgetTokens (positive integer, default 25000), all (boolean — bypasses the budget, mutually exclusive with budgetTokens), and repoRoot (string, default cwd, for the drift check) optional. Superseded records arrive as name, replacement and date stubs — pass the id to kb_trace for the history.

Refuses over budget rather than truncating, message naming the next rung.

Every result — refused or not — carries a digest, the base's content stamp (see the load digest).

Place this output in the stable prefix

kb_load's result belongs in the stable prefix — the system prompt, or the first turn — and should be reloaded only when the returned digest changes. A prompt cache matches a prefix byte-for-byte, so one volatile result placed ahead of a stable load prices the whole base at full rate on every later call.

{ "bundlePath": "/repo/.strauss/kb", "type": "decision" }

kb_catalog​

As CLI catalog: every record as one line — concept id, type, title, standing, stale flag — at roughly thirty tokens each. Parameters: bundlePath required, type and tags (string array) optional.

The tier-one listing, and what to reach for when kb_load refuses: alone among the read tools it has no ceiling and never refuses. Bodies are not here.

{ "bundlePath": "/repo/.strauss/kb", "type": "open-question" }

kb_query​

As CLI query; the query text is text, and this surface adds type and includeNonCurrent.

Parameters: bundlePath required; text (string), type (enum), tags (string array), includeNonCurrent (boolean — the CLI always sets this), and repoRoot (string, default cwd, for the drift check) optional.

These results are volatile per call

Place them at the tail of the context, not the stable prefix kb_load's output belongs in, or every query invalidates a prompt cache that would otherwise hold.

{ "bundlePath": "/repo/.strauss/kb", "text": "cache key region" }

kb_pack​

As CLI pack, with the flags as camelCase parameters. Emits markdown. Parameters: bundlePath and conceptId (the root) required; hops (default 2), maxNodes (default 20) and budgetTokens (default 25000) optional positive integers.

{ "bundlePath": "/repo/.strauss/kb", "conceptId": "decision.cursor-v2" }

kb_trace​

As CLI trace; the edge names are the edges array, and this surface adds depth.

Parameters: bundlePath and conceptId (the seed) required; edges (array of typed-link, supersession, anchor, source; default all four) and depth (positive integer, default 3) optional. typed-link follows only the causal rels — related_to is excluded because a bibliography floods a blast radius.

{
"bundlePath": "…/kb",
"conceptId": "decision.cursor-v2",
"edges": ["supersession"]
}

kb_impact​

As CLI impact: the transitive set of dependants of a record.

Parameters: bundlePath and conceptId (the root) required; depth (positive integer, unbounded by default — a walk it cuts reports truncated: true) and rels (array of causal rels, default every rel but related_to) optional.

The walk follows each rel in whichever direction its dependence runs. Naming related_to — or an unknown rel — in rels is an error, not an empty result.

{
"bundlePath": "…/kb",
"conceptId": "fact.region-key",
"rels": ["depends_on", "satisfies"]
}

via holds each edge as { source, target, rel } — the edge as written, not as walked. For one flat hop of every rel, use kb_backlinks.

kb_match​

As CLI match, except that the diff always arrives as files — there is no --git or --stdin here. Reach for it when you have code in hand and want what is attached to it; use kb_answer when you have a question and want whatever addresses it.

Parameters: bundlePath and files ([{ filePath, hunks: [{ startLine, endLine, side? }] }], where a hunk's optional side is "old" or "new" and picks which half of the change its lines number — only an anchor on the same side lands on it) required; symbolRanges ([{ file, symbol, startLine, endLine }], resolved from repoRoot when omitted), repoRoot (string), offline (boolean) and includeNonCurrent (boolean) optional.

{
"bundlePath": "…/kb",
"files": [
{
"filePath": "src/order.service.ts",
"hunks": [{ "startLine": 118, "endLine": 131 }]
}
],
"repoRoot": "/repo"
}

kb_classify​

As CLI classify, except that the diff always arrives as files — there is no --git or --stdin here. Reach for it to decide what in a change needs reading; kb_match says what is attached to it.

Parameters: bundlePath and files required — each file { filePath, hunks: [{ startLine, endLine, side?, lines? }], renamedFrom?, similarity? }, where lines are the hunk's changed lines and feed the boilerplate and banner rules; repoRoot (string) optional, and the file's first lines and any symbol-scoped override are resolved from it; offline (boolean) optional, which keeps that resolution off the network.

{
"bundlePath": "…/kb",
"files": [
{
"filePath": "src/protocol/generated/index.ts",
"hunks": [{ "startLine": 4, "endLine": 4, "lines": ["// @generated"] }]
}
],
"repoRoot": "/repo"
}

As CLI backlinks: every inbound typed link, one hop, every rel including related_to, each with its rel and the standing of the record that made it. Parameters: bundlePath, conceptId.

{ "bundlePath": "/repo/.strauss/kb", "conceptId": "fact.region-key" }

kb_list​

As CLI list: every record, optionally narrowed to one type or tag. Parameters: bundlePath required, type and tags (string array) optional.

tags is the CLI's repeatable --tag, and is the same field on kb_query and kb_catalog — see tags.

{ "bundlePath": "/repo/.strauss/kb", "type": "open-question" }

kb_index​

As CLI index: the index, rebuilt if it disagrees with the records — the cheap re-orientation call after compaction. Parameter: bundlePath.

{ "bundlePath": "/repo/.strauss/kb" }

kb_log​

As CLI log: what touched what, and when. Malformed lines are reported rather than repaired, and conflicted says the log still carries merge markers, which the read skips past. Parameter: bundlePath.

{ "bundlePath": "/repo/.strauss/kb" }

kb_stamp​

As CLI stamp: the base's digest, counts, and a digest per record, and drifted: how many records have an anchor whose code no longer matches its hash — no bodies. Parameters: bundlePath optional (omit it to stamp every pinned base), since optional (a digest, or a path to a prior stamp, which also names the changed ids). Empty means nothing moved.

Ask it when a reload hook said a base changed, or before trusting a kb_load result from earlier in the session.

{ "bundlePath": "/repo/.strauss/kb", "since": "9f2c…" }

Promotion and export tools​

kb_promote​

As CLI promote, with the flags as camelCase parameters. Reach for it at merge, to lift what a review base settled into the base that outlives the pull request.

Parameters: bundlePath required — the base being promoted from; conceptIds (string[]) and to (the target base) required unless list is true; source (string, usually the pull request URL) and force (boolean, overwrite what the target already holds) optional.

{
"bundlePath": "/repo/.strauss/review",
"conceptIds": ["decision.cursor-v2"],
"to": "/repo/.strauss/kb",
"source": "https://github.com/org/repo/pull/59"
}

Returns { mode: "promote", to, promoted } with { conceptId, droppedLinks } per record, or { mode: "list", candidates } with { conceptId, type, title, why } per candidate. Copies land without the review tags; links to records left behind are dropped and reported. The originals stay put.

kb_export​

As CLI export. Reach for it when a repository keeps ADRs of its own and the base is where its decisions are actually written.

Parameters: bundlePath, format ("madr") and to (the directory) all required.

{ "bundlePath": "/repo/.strauss/kb", "format": "madr", "to": "docs/adr" }

Returns { to, format, exported, foreign }, each exported entry { conceptId, file, status }. Numbering is keyed by slug, so a re-run rewrites content in place.


Format tools​

kb_validate​

As CLI validate: cross-record checks over supersession pointers, typed-link rels and targets, and assumptions that cite sources. Parameter: bundlePath.

{ "bundlePath": "/repo/.strauss/kb" }

Returns an array of { check, conceptId, note, severity }. Only errors fail the check; the non-zero exit is CLI-only.

kb_doctor​

As CLI doctor, with the flags as camelCase parameters. Read-only — every finding names a record for a person to repair.

Parameters: bundlePath required; expiringDays (default 30), unverifiedDays (default 90), agingDays (default 90), repoRoot (default cwd, for drifted), offline (boolean, read foreign anchors from the repo cache only), strict (boolean — turns an expired record into a non-zero CLI exit, with no effect on the report), drifted (boolean — report only drift, as a kb_reassess packet per record) and withDiff (boolean, with drifted) optional.

The checks are expired, expiring, unverified, aging, orphaned, broken-supersession, superseded-but-cited, drifted, and unchecked — see the CLI reference for what each detects. Every group is reported even when empty.

{ "bundlePath": "/repo/.strauss/kb", "unverifiedDays": 30 }

Returns { bundlePath, checkedAt, recordCount, thresholds, counts, groups, findingCount, healthy }, where each group is { check, headline, count, findings } and each finding is { conceptId, title, status, note }. A superseded-but-cited finding also carries reference: { from, target, targetStanding, rels, replacedBy }. Under drifted it also carries packets and rebaselinable.

kb_sweep​

As CLI sweep: deletes records carrying tag that are also resolved, rejected or superseded — see the one deletion. Parameters: bundlePath and tag required, terminal (must be true, naming the only scope it deletes) required, dryRun (boolean) optional.

{ "bundlePath": "/repo/.strauss/kb", "tag": "review", "terminal": true }

Returns { tag, dryRun, deleted, candidates, skipped, failed }, where skipped is { conceptId, heldBy } per record a surviving record still points at, and failed is { conceptId, reason } per id the run could not remove.

kb_schema​

As CLI schema: JSON Schema for the frontmatter, the write input, and log entries. Takes no parameters.

{}

kb_types​

As CLI types: every record type with its purpose, body sections, and starting status. Read this before writing rather than guessing headings. Takes no parameters.

{}

Workspace pin tools​

kb_pin​

As CLI pin; the base to pin is bundlePath rather than a positional, and the layer flags become one layer parameter. Idempotent.

Parameters: bundlePath required; optional mode (full: always emit this base's records whole, still under the block budget — index: never upgrade — absent: the profile's full-under threshold decides), profiles (string[], the context profiles this pin surfaces in; absent means all), layer (project | local | user, default project, the committed .strauss/kb-pins.json), and frozen (boolean: true concludes the base so writes against it refuse, false lifts the freeze).

{ "bundlePath": "/repo/docs/adr", "mode": "full", "layer": "project" }

kb_unpin​

As CLI unpin: remove a base from every manifest layer that holds it, reporting which were touched. Parameter: bundlePath.

{ "bundlePath": "/repo/docs/adr" }

kb_pins​

As CLI pins: every pinned base across the layers, each with its layer and whether it currently resolves to readable records. Takes no parameters.

{}

kb_context​

As CLI context, with the flags as camelCase parameters. Emits nothing when nothing is pinned, and refuses with the list of bases and their sizes rather than truncating past its budget. Takes no bundlePath.

All parameters are optional: budgetTokens (ceiling on the whole block, default 4000), fullUnderTokens (per-base threshold applied before the budget: a base whose complete load fits under it arrives as full records; off by default), profile (named budget set — built-ins session-start (full-under 1500), compact and turn (budget 2500); an unknown name falls through to defaults), excludeTags (string array — records carrying one stay out of the block, the base still pinned and still readable through the tools), format (markdown | json — the CLI envelope for hook protocols requiring strict JSON on stdout; MCP callers omit it, the block itself is identical), and event (string, the hookEventName stamped into that envelope, only meaningful with format: "json").

Budgets and exclusions resolve most-specific-first: explicit parameters, then the workspace manifests' context tables (per profile, over their default), then the built-in profile, then package defaults. No profile excludes a tag by default.

{ "profile": "session-start" }