> ## Documentation Index
> Fetch the complete documentation index at: https://botmesh.afaya.com.co/llms.txt
> Use this file to discover all available pages before exploring further.

# MCP server

> @botmesh/mcp is a Model Context Protocol server over stdio. It gives an AI coding agent (or an editor) the project's deterministic pieces so a flow document can be written, validated, compiled, drawn, linted, migrated and diffed without starting a bot: no phone, no credentials, no network.

Every tool is a function of its arguments. The server has **no third-party dependencies** (the JSON-RPC transport is implemented in the package), never evaluates code and never writes to disk.

## Run it

MCP clients start it with `npx`; nothing to install up front:

```bash theme={null}
npx -y @botmesh/mcp --help        # usage; --version prints the version
```

### Register it in your client

**Claude Code**:

```bash theme={null}
claude mcp add botmesh -- npx -y @botmesh/mcp
```

or, shared with the project, `.mcp.json`:

```json theme={null}
{ "mcpServers": { "botmesh": { "command": "npx", "args": ["-y", "@botmesh/mcp"] } } }
```

**Cursor** (`.cursor/mcp.json`) and **Claude Desktop** (`claude_desktop_config.json`) use the same `mcpServers` shape. **VS Code** (`.vscode/mcp.json`):

```json theme={null}
{ "servers": { "botmesh": { "type": "stdio", "command": "npx", "args": ["-y", "@botmesh/mcp"] } } }
```

On Windows, a client that cannot start `npx` directly needs `"command": "cmd", "args": ["/c", "npx", "-y", "@botmesh/mcp"]`.

### Documentation tools

`--docs <dir>` (or `BOTMESH_DOCS_DIR`; the pre-rename `BOTWA_DOCS_DIR` is still read) points at a local Markdown tree, such as the `docs/` folder of a clone of the repository; the guides are not bundled in the package. Without it the two docs tools are **not** advertised in `tools/list`, so a client never sees a tool that cannot work.

### From a checkout

```bash theme={null}
pnpm build                                     # packages resolve through lib/

node packages/mcp/lib/bin.js --docs docs       # flow tools + docs_search / docs_page
node packages/mcp/lib/bin.js                   # flow tools only
```

In VS Code the repo already ships `.vscode/mcp.json`: run `pnpm build` once, then start the *botmesh* server from the MCP view.

### Programmatically

```ts theme={null}
import { createMcpServer, serveStream } from '@botmesh/mcp'

const server = createMcpServer({ docsDir: 'docs' })
await serveStream(process.stdin, { server, write: (line) => { process.stdout.write(`${line}\n`) } })
```

The main entry (`createMcpServer`, `serveStream`, `runStdio`, the protocol revisions, the server identity and `EXAMPLE_FLOW_DOCUMENT`) is covered by semver; the JSON-RPC framing, the tool catalogue and the docs search live in `@botmesh/mcp/internal`, with no semver guarantee.

## Tools

| Tool | Input | Returns |
| - | - | - |
| `flow_validate` | `document` | `{ valid, issues: [{ path, message }], summary? }` — issues carry the JSON Pointer of the offending node. |
| `flow_analyze` | `document`, `subflows?`, `format?`, `direction?` | Validates, compiles, renders the graph (`mermaid` by default, `graph` with `format: "json"`) and returns the `lintFlows` diagnostics. |
| `flow_migrate` | `document`, `target?` | `{ document, from, to, applied, issues }`. A document without `version` is read as 0. |
| `flow_diff` | `left`, `right` | `{ changed, metadata, added, removed, changedSteps, before, after }` (the last two are digests). |
| `flow_digest` | `document` | `{ digest, version }` — `sha256` over canonical JSON, so key order and formatting never change it. |
| `flow_schema` | — | The draft 2020-12 schema, `limits` and `stepKinds` (derived from the schema itself). |
| `flow_example` | — | A canonical document that validates and lints clean. |
| `docs_search` | `query`, `limit?` | Sections with `path`, `title`, `heading`, `snippet` and `score` (only with a docs directory). |
| `docs_page` | `path` | The markdown of one page (only with a docs directory). |

`flow_analyze` runs the **same** `describeFlows()` and `lintFlows()` that `bot.describe()` and `bot.lint()` use, and `flow_*` wraps `@botmesh/flow-schema`, so the server can never disagree with the runtime or the deployment gate.

### Valid or invalid is a result, not an error

An invalid document is a **successful** call whose payload says `valid: false` with the issues:

```json theme={null}
{ "jsonrpc": "2.0", "id": 2, "result": { "content": [{ "type": "text", "text": "{\n  \"valid\": false,\n  \"issues\": [{ \"path\": \"/steps/0/text\", \"message\": \"must be a string of 1-4096 characters\" }]\n}" }] } }
```

`isError: true` is reserved for the **request** (missing or mistyped arguments, an unmigratable version, a path outside the docs root), so an agent can tell "my document needs work" from "my call was wrong".

The arguments are checked against the `inputSchema` that `tools/list` advertises, before the tool runs: an unknown key, a missing required one, a value outside an `enum` or a range (`format`, `direction`, `target` up to the current document version, `limit` from 1 to 25) or a value nested more than 64 levels deep fails with one sentence that names it, for example `invalid arguments for flow_validate: unknown argument "doc" (accepted: "document")`. Error texts never carry absolute paths: a missing page answers `page not found: guide/x.md`.

## Protocol

* `initialize` answers with `capabilities: { tools: { listChanged: false } }`, the package version and an `instructions` block that states the invariants that are expensive to get wrong (the v1 API does not exist, documents are data, a handler must not `await` a conversation it starts, ids are opaque).
* Supported revisions: `2025-06-18`, `2025-03-26`, `2024-11-05`. A client asking for another one is answered with `2025-06-18` and decides what to do.
* Every tool carries `annotations` (`readOnlyHint: true`, `destructiveHint: false`, `idempotentHint: true`, `openWorldHint: false`), so a client may run them without asking for confirmation.
* `ping`, `tools/list` and `tools/call`; anything else (`resources/*`, `prompts/*`, `logging/setLevel`) answers `-32601`, because those capabilities are not advertised.
* **Notifications are never answered** (JSON-RPC forbids it), including `notifications/initialized`.
* A response sent by the client (a message with `result` or `error` and no `method`) is ignored, never answered.
* One JSON message per line. A malformed line answers `-32700`, a line longer than `maxMessageLength` (16 Mi characters by default, `DEFAULT_MAX_MESSAGE_LENGTH`) answers `-32600` without being buffered, and the session continues. A JSON array is a batch (revision `2025-03-26`): it is answered with an array of responses, notifications left out.
* Nothing but protocol messages is written to stdout; diagnostics go to stderr. If the client closes the pipe, the server stops writing and exits when stdin ends, without an unhandled `EPIPE`. A `--docs` directory that does not exist is reported on stderr at start-up.

## Documentation search

With `--docs`, `docs_search` indexes every `.md` under the directory except generated output (`api/`, `dist/`, `.vitepress/`) and the internal design notes (`superpowers/`), and splits them into heading-delimited sections (a `#` inside a fenced code block is not a heading).

Ranking is deterministic and deliberately simple: accent- and case-insensitive terms, **inverse document frequency** so a rare identifier (`appendLog`) outranks a word that appears on every page (`durabilidad`), presence instead of raw counts, a doubled weight for heading hits, a coverage bonus and an exact-phrase bonus. English and Spanish pages are indexed together, so one query reaches both.

`docs_page` only reads `.md` files and rejects any path that escapes the docs root.

## Tests

`pnpm --filter @botmesh/mcp test` covers the framing (messages split across chunks, `\r\n`, a last line without a newline, UTF-8 chunks, batches, oversized lines, a seeded fuzz of raw chunks), the argument checks, every tool with valid and invalid input, the 14 step kinds, subflow resolution, migration of a versionless document, a bilingual search over a temporary tree (including `../` rejection) and the version lockstep with `package.json`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.