Wire it into your agent
One command does the wiring:
npx foldcase init # or: bunx foldcase-bun initIt adds the server entry below to .mcp.json — choosing bunx or npx by your
lockfile, and setting FOLDCASE_SHOWCASE_DIR=src when src/ exists — and appends the
AGENTS.md block. Both edits are idempotent and merge-safe:
an existing .mcp.json keeps its other servers, a foldcase entry already there is left
alone, and a second run reports kept and changes nothing. By hand, the same entry
(Claude Code and most MCP hosts) is:
{
"mcpServers": {
"foldcase": {
"command": "npx",
"args": ["foldcase", "mcp"],
"env": { "FOLDCASE_SHOWCASE_DIR": "src" }
}
}
}Or in one line: claude mcp add foldcase -e FOLDCASE_SHOWCASE_DIR=src -- npx foldcase mcp.
Under Bun the command is bunx with args ["foldcase-bun", "mcp"].
FOLDCASE_SHOWCASE_DIR (default .) is read by mcp only. A relative value resolves
against the directory the host launches the server in — for Claude Code, the project
root — and becomes the server's root: foldcase_load_catalog resolves relative
directories against that root, never against the currently served one, so no sequence of
loads can walk away from it.
The six tools, all annotated readOnlyHint: true, destructiveHint: false,
openWorldHint: false — a host does not prompt for confirmation to list a catalog:
| Tool | What it does |
|---|---|
foldcase_list_showcases | Enumerate every Showcase — which Schemas it carries, which Messages it dispatches, the directory served — and per-component gaps: the Messages no play dispatches. |
foldcase_get_showcase_schema | Introspect a Showcase's Message union into a JSON Schema document, so the agent builds a valid payload by construction. |
foldcase_get_showcase_model_schema | The same for the Model — the shape a play asserts on, which an agent has to know before it writes one. |
foldcase_run_showcase | Run one Showcase's play — in a fresh subprocess, from the code on disk — and return the typed pass/fail report, naming the file it came from. |
foldcase_run_catalog | Run the whole catalog into one suite report, or the part of it under an id prefix: counter/ runs one component. Fresh from disk, like foldcase_run_showcase. |
foldcase_load_catalog | Refresh the listing after files appear or vanish, or point the server at another directory under the root. Reports how many Showcases came back and which files would not load. A run never needs it. |
The loop an agent runs:
foldcase_list_showcases— which components exist, in which states; thehasMessageSchema/hasModelSchemaflags say which introspection call is worth making, andgapsnames, per component, the Messages no play dispatches — the next Showcase to write.foldcase_get_showcase_schema— the Message union as a draft-2020-12 JSON Schema document: a valid payload by construction, not by reading the source.foldcase_get_showcase_model_schema— the shape aplayasserts on; read it before writing one.Edit the code, or add a Showcase.
foldcase_run_showcasefor one state, orfoldcase_run_catalogwithid_prefix: "counter/"for one component. A run executes in a fresh subprocess and reads the disk, so the edit it is verifying — even a brand-new file — is already in it, no reload needed. A failingplayisstatus: "failed"with a fullSerializedError— data, never a tool error — and a mistyped id returns every available id, so it corrects itself in one round trip.foldcase_load_catalogto refresh the listing after files appear or vanish. The listing and the two schema tools read modules the server already imported, so after an edit inside a loaded file their metadata can lag until the server restarts; the run tools never lag.
No MCP host? The same loop is the CLI: foldcase test --json prints one typed JSON
document on stdout, diagnostics on stderr, and every report names its file.
Foldcase is the static half of a two-server loop.
@foldkit/devtools-mcp
drives the live runtime — it needs a Vite dev server and an open browser tab; Foldcase
needs only a directory of files, so it also runs in CI. The verbs pair up:
| question | live — @foldkit/devtools-mcp | declared — foldcase mcp |
|---|---|---|
| what exists | foldkit_list_runtimes (open tabs) | foldcase_list_showcases |
| Message shape | foldkit_get_message_schema | foldcase_get_showcase_schema |
| the Model | foldkit_get_model (the value now) | foldcase_get_showcase_model_schema (the type) |
| act | foldkit_dispatch_message | foldcase_run_showcase |
devtools-mcp answers what the app is doing right now; Foldcase answers what the app is supposed to do.
Paste into your AGENTS.md
## Showcases (Foldcase)
- Components are described by Showcases: `export const showcases: ReadonlyArray<Showcase>`
in `*.showcase.ts` files. The record is `{ id, play, message?, model?, dispatches? }`;
an id is `component/state`.
- To learn a component, use the `foldcase_*` MCP tools or `npx foldcase test --json` —
do not parse `*.showcase.ts` files or crawl the source for the same facts.
- When you add a component state, add a Showcase for it, and name the Message tags its
play sends in `dispatches` — the listing's `gaps` then says which Messages still have
no Showcase.
- When you change a Message or Model Schema, regenerate the tables: `npx foldcase docs
src docs/schemas`. In CI, `--check` fails on drift instead of writing.
- The run tools execute what is on disk, edits included. Only the listing and schema
tools can lag behind an edit inside a loaded file; restart the server to refresh them.
- Exit 1 means a failed Showcase, an unloadable file, or an empty catalog. All three are
reported as data; one bad file never hides the rest.Last updated Aug 4, 2026