Skip to content
GitHub

bino mcp

bino mcp runs a Model Context Protocol server over stdio, exposing bino's introspection, validation, authoring, and build surface to AI agent clients such as Claude Code, Claude Desktop, and Cursor.

Because a bino report is plain-text YAML + SQL, an agent can author it directly — and bino's schema and validation become the guardrails that tell the agent precisely whether what it wrote is correct.

bino mcp [--work-dir DIR]

Most agent clients are configured with a command, so bino mcp is the entrypoint you register once. Under the hood:

  • Proxy mode — if a bino daemon is already running for the project (for example because VS Code is open), bino mcp connects to that daemon's /mcp endpoint and forwards to it, so the agent reuses the daemon's already-loaded DuckDB session and file watcher instead of starting a second one.
  • Standalone mode — with no daemon running, bino mcp loads the project itself and serves the MCP directly.

Flags:

  • --work-dir, -w – report bundle directory (default: .).
  • --no-proxy – always run standalone, even if a daemon is running.
  • --allow-publish – also expose the registry_publish tool (see Security). When bino mcp proxies to a running daemon, the daemon's --mcp-allow-publish flag decides instead.

Clients that speak MCP over HTTP can instead point straight at a running daemon's endpoint (http://127.0.0.1:<port>/mcp; the port is recorded in .bino/daemon.json). The daemon mounts /mcp by default on loopback — pass bino daemon --mcp=false to disable it.

claude mcp add bino -- bino mcp --work-dir /path/to/report

Add an entry to the client's MCP config (Claude Desktop: claude_desktop_config.json; Cursor: .cursor/mcp.json):

{
  "mcpServers": {
    "bino": {
      "command": "bino",
      "args": ["mcp", "--work-dir", "/path/to/report"]
    }
  }
}

Read-only context an agent can pull in:

URIContents
bino://schemaThe full merged JSON Schema for all manifest kinds (built-in + plugin).
bino://schema/{kind}The self-contained spec schema for one kind (e.g. bino://schema/Table).
bino://kindsEvery manifest kind and its capability category (data / layout / embeddable / artefact / config).
bino://documentsThe project index: every document → {kind, name, file, position}.
bino://packagesThe project's registry packages: bino.lock merged with bino.toml [dependencies], with installed state.
ToolWhat it does
list_kindsEvery manifest kind with its capability category.
outline_kind(kind)A compact outline of one kind's spec: every field with its path, type, required flag, enum, default and description. Layout kinds report the allowed child kinds as childKinds. Start here.
scaffold_kind(kind)A minimal YAML document for one kind with every required spec field pre-filled.
describe_kind(kind)The full spec JSON Schema for one kind. Large (up to ~20k tokens for layout kinds); prefer outline_kind.
describe_project()All documents in the project.
describe_document(file)The documents declared in one file.
get_columns(name)Column names of a DataSet or DataSource (prefix $ to force a DataSource).
get_rows(name, limit?)A sample of rows from a DataSet or DataSource.
graph_deps(kind, name, direction?, max_depth?)Dependencies (out), dependents (in), or both.
ToolWhat it does
validate_project(execute_queries?)Validate the project on disk; optionally execute datasets for data-validation warnings.
validate_draft(yaml)Validate manifest YAML in memory (no disk write) — the pre-write guardrail.
introspect_source(spec, sheet?, limit?)Probe a not-yet-registered CSV/Excel/DB source: columns, sample rows, sheets, detected CSV options.
ToolWhat it does
create_manifest(kind, name, spec, ...)Create any manifest from a spec object; validated and written atomically, auto-placed by project convention.
write_manifest(file, yaml, append?)Persist a full manifest document, validated before writing.
edit_manifest(file, position, patch)Edit one document in place via dotted-path edits, preserving comments and key order.
scaffold_source(dataSource, dataSet?)Scaffold a DataSource and an optional typed DataSet in one step.
init_bundle(...)Bootstrap a new starter report bundle.

Every write validates against the merged JSON Schema before persisting, so an agent cannot write a structurally invalid manifest. Writes are atomic (temp file + rename).

ToolWhat it does
build(artefacts?, out_dir?)Render artefacts by running bino build — streams progress and returns the exit code, output, and produced artefacts. Subject to the usual engine-compatibility check.
ToolWhat it does
registry_packages()The project's dependencies, offline: bino.lock merged with bino.toml [dependencies], whether each is installed under .bino/registry/, and the params each package declares.
registry_search(query, kinds?, scopes?, tags?, page?, per_page?)Search the registry for published packages (network). Use it before authoring a component from scratch.
registry_info(spec)Resolve one package spec (@scope/name, optionally @version or @tag): version, kinds, files, dependencies, and the installed version when the project already locks it.
registry_auth_status()The resolved registry URL, whether a credential is available, and where credentials are stored. Never returns the token.
registry_add(specs)Add packages as dependencies: resolves the transitive closure, verifies every download, then writes bino.toml, bino.lock and .bino/registry/. Reports name collisions with local documents.
registry_update(packages?)Re-resolve tag-following dependencies to their newest versions and rewrite bino.lock; exact pins are held.
registry_remove(packages)Remove dependencies from bino.toml and delete every locked package no longer reachable (offline).
registry_install()Re-materialize .bino/registry/ exactly as pinned in bino.lock, without re-resolving.
registry_publish(bump?, dry_run?, visibility?)Run bino publish --json for the project's [package]. Only registered when the server was started with the opt-in flag — see Security.
1. outline_kind({kind:"Table"})       → the Table spec fields, types, enums, defaults
2. scaffold_kind({kind:"Table"})      → a minimal Table document to fill in
3. get_columns({name:"sales"})        → {columns:["region","ac1","pl1",...]}
4. draft the Table manifest using those columns
5. validate_draft({yaml:"..."})       → {valid:false, diagnostics:[{message:"...", ...}]}
6. fix and re-validate                → {valid:true}
7. create_manifest({kind:"Table", name:"q3", spec:{...}})
8. build({artefacts:["q3"]})          → q3.pdf

The server runs SQL, reads the filesystem, and (via build) launches headless Chrome. This is intended for local use over stdio and a loopback HTTP endpoint. Exposing the daemon on a non-loopback address (bino daemon --listen-addr) is out of scope for this surface and would require additional hardening.

registry_publish is off by default. It is only registered when a human starts the server with bino mcp --allow-publish, or bino daemon --mcp-allow-publish when bino mcp proxies to a running daemon. Publishing is irreversible — it mints an immutable version that cannot be deleted — and a first publish with visibility: public makes the package public, so an agent must not be able to trigger it by accident. The other registry tools only change the local project and never return a credential; when registry_auth_status reports none, the human runs bino registry login.