Skip to content
Thomas Mangin edited this page Aug 16, 2026 · 4 revisions

Pre-Alpha. This page describes behavior that may change.

The MCP server is the surface you use when an AI assistant should drive Ze. It speaks the Model Context Protocol, exposes typed tools with structured parameters, and gives any MCP-compatible client (Claude, GPT, custom agents) the same control surface a human gets at the CLI. The point of MCP, as opposed to "scrape the CLI output", is that the assistant gets typed inputs and structured outputs, so it does not have to parse text it might misread.

Starting the server

ze start --mcp 8080            # start from stored (blob) config; run `ze init` first
ze --mcp 8080 config.conf      # start from a config file
environment {
    mcp {
        enabled true;
        server main {
            ip   127.0.0.1;
            port 8080;
        }
    }
}

The default listener is 127.0.0.1:8080. That is deliberate: MCP is local-only unless you explicitly override it with ze.mcp.listen=ip:port. Bearer-token auth is available through --mcp-token, the ze.mcp.token environment variable, or the token leaf in the config. The auth mode and token in the environment mcp block now apply whichever way you start the server: they used to be discarded unless the block was enabled with a ported server, so ze --mcp <port> served accept-all.

The tools

Two tools are hand-written: ze_execute and ze_reference. Every other tool is auto-generated from the command registry at runtime, so any new YANG command or plugin command appears as a typed MCP tool with no code changes. A command prefix becomes the tool name, with - and space mapped to _: show bgp rib becomes ze_show_bgp_rib.

Tool Description
ze_execute Run any CLI command. The escape hatch. Hand-written.
ze_reference The full machine-readable reference for this daemon: commands, RPC endpoints, dispatch keys, plugins, families, services. Same JSON as ze help ai --json. Call it first. Hand-written.
ze_announce Announce routes with typed parameters: origin, next-hop, communities, prefixes. Auto-generated.
ze_withdraw Withdraw routes. Auto-generated.
ze_show_bgp Peer state, ASN, uptime, and summary views. Auto-generated from show bgp ....
ze_request_peer Teardown, pause, resume, flush a peer. Auto-generated from request peer ....

A plugin command registered with Hidden true reaches no tool list. The flag already removed the command from completion and from help, and one function builds the metadata both the MCP tool list and the REST command list read, so the flag now means one thing on every surface.

ze_execute is the part that turns "structured tools for the common cases" into "full daemon control": anything you can do at ze cli or ze cli -c, the assistant can do here. Route management, RIB queries, peer lifecycle, configuration commits, cache operations, event subscription, schema discovery: all of it.

A typical flow

An assistant connected through MCP can do something like this without ever touching plain text.

  1. Call ze_reference once to learn what this daemon exposes.
  2. Call ze_show_bgp to get every peer's state as structured JSON.
  3. Call ze_announce with origin=igp, next-hop=10.0.0.1, prefixes=[10.0.0.0/24].
  4. Call ze_execute with show bgp rib sent peer peer1 family ipv4/unicast to verify propagation.
  5. Call ze_withdraw if it needs to roll back.

Each call returns structured data, not text the assistant has to scan.

Generating an AI command reference

The tool registry is auto-generated, but the command catalogue is too. ze help ai produces a machine-readable command reference from the code, suitable for feeding to an assistant as context. It lists every command, parameter, description, and example.

ze help ai --json > ze-commands.json
ze help ai api                      # daemon API endpoints (ze-show:*, ze-set:*, ...)

The legacy ze help --ai flag form is still accepted. Drop the file into the assistant's context and the assistant can pick the right command without trial and error.

Testing and CI

ze-test mcp provides a functional test client with a wait-established synchroniser that is what you want in a CI pipeline if you want to test that MCP-driven changes apply correctly without racing the BGP FSM.

It also provides a probe-* directive family, which drives deliberately malformed requests at the conformance surface: header mismatch, unsupported version, malformed _meta, GET and DELETE. Task behavior is driven by task-call, its twin call-sync (which requires a synchronous answer and no taskId), then task-get, task-update, task-cancel and task-wait. The --tasks flag declares the Tasks extension on every request; a run without the flag is itself a test, because the server must still serve an undeclaring client synchronously.

Protocol revision 2026-07-28

Ze speaks MCP protocol revision 2026-07-28 and no other. Revisions 2024-11-05 through 2025-11-25 were dropped rather than maintained alongside it.

The profile is stateless. Every message is its own HTTP POST to /mcp, carrying its own protocol version, client capabilities and credential in three standard headers and a _meta block inside params. Four things the old transport was built on are gone, because the revision removes them: the initialize handshake, protocol-level sessions and Mcp-Session-Id, the GET stream, and server-initiated JSON-RPC requests.

Two consequences are worth stating plainly.

Authentication runs on every request. A revoked token stops working on the very next call rather than at session expiry, and there is no long-lived identifier acting as a bearer credential in its own right. A stolen session id used to be exactly that.

Elicitation is inverted, not gone. A server can no longer push a prompt, because the revision forbids it to send an independent request on any stream. The server returns the prompt instead: ze_execute called with no command answers resultType: "input_required" with an inputRequests map carrying an elicitation/create request. The client retries the original call with inputResponses. Ze holds nothing between the two requests and authenticates each one on its own. A client that did not declare form-mode elicitation is never prompted; it gets the missing-argument error instead.

Discovery, caching and extensions

Capability discovery is a single optional call. server/discover returns the supported versions, the server's capabilities, and natural-language instructions. Its capabilities.extensions names two: io.modelcontextprotocol/ui (MCP Apps) and io.modelcontextprotocol/tasks (Tasks). The second is what makes the task result type interpretable, because a client may reject a resultType that no advertised extension defines.

server/discover, tools/list, resources/list and resources/read return ttlMs and cacheScope, so a client can hold a result rather than re-fetch it every turn. The tool inventory and the discovery result are fresh for 60 seconds; the embedded UI assets for one hour. Every one is scoped private, so a shared gateway may not serve one caller's response to another. tools/call and the tasks/* methods return no hints and are not cacheable.

Ze has no push invalidation, so that 60-second TTL is also the window in which a client can still offer a command a config reload has removed. Calling it returns an error, which the protocol names as grounds for an early re-fetch.

Long-running work

Background execution goes through the Tasks extension: a tools/call the server answers with a task handle, then polling with tasks/get, client-to-server input with tasks/update, and tasks/cancel. The redesigned extension replaced the blocking tasks/result with polling and removed tasks/list, so Ze implements neither and answers both -32601. A client that declares no extension is still served, synchronously, which is itself a tested case.

Resources and MCP Apps

resources/list and resources/read serve every conformant caller, with no client-capability gate. resources is a member of ServerCapabilities, not of ClientCapabilities, so a conformant client never declares it and a gate on it refused everybody. A ui:// URI is validated before any read: the scheme must match, the cleaned path must equal the given path, and the depth is capped at eight segments.

Tool descriptors for command groups carrying a ze:ui-resource YANG annotation include _meta.ui, pointing at a ui:// asset the host renders in a sandboxed panel. That metadata is emitted only when the request declared the UI extension. A host without MCP Apps support gets the same tool list, the same tools and the same behavior, minus the panel metadata. Ze rejects nothing.

See also

  • Introspection for ze help ai and the schema discovery surfaces.
  • REST API if you would rather drive Ze with plain HTTP.
  • CLI for the human-facing equivalent.

Adapted from main/docs/features/mcp-integration.md.

Home

About

First Steps

Configuration

Operation

Interfaces

Plugins

Plugin Development

Chaos Testing

Blueprints

Development

Reference

Clone this wiki locally