docs(mcp): document the MCP surface, authoring controls, and skill (v0.8.0)

Document the per-graph MCP surface (POST /graphs/{id}/mcp, shipped in the
preceding commits and landing under v0.8.0) and the `.gq` authoring controls
that shape stored-query tools.

- New docs/user/operations/mcp.md: the client-facing guide — transport, tool
  catalog (built-ins + stored queries), projection modes, structured output,
  authorization (call-authoritative + list-relaxation), Host/Origin policy, the
  protocol-version contract.
- docs/user/operations/server.md: the /mcp endpoint + an "MCP surface" section;
  docs/user/index.md: a "Connect an MCP agent" pointer.
- docs/user/queries/index.md: an Annotations section — query @description /
  @instruction / @mcp(expose, tool_name) and per-parameter @description.
- AGENTS.md: topic-table row + MCP note on the HTTP-server capability row.
- docs/dev/testing.md: the omnigraph-mcp crate + server tests/mcp.rs.
- docs/dev/rfc-005 §D5: retire the "cluster = everything exposed" bridge —
  cluster mode honors source `@mcp(expose: …)`; presentation vs authorization
  split made explicit.
- skills/omnigraph: server-policy.md MCP section; stored-queries.md corrected
  (per-query controls now ship via @mcp, not "planned"); SKILL.md MCP triggers,
  Deep Dives row, version → 0.8.0.
- docs/releases/v0.8.0.md: the MCP surface + authoring-controls release notes.

Crate version manifests are deliberately NOT bumped — that is the v0.8.0
release-cut step; this lands on the feature branch.
This commit is contained in:
Ragnor Comerford 2026-06-17 16:04:29 +02:00
parent c8e91c11f0
commit c06343362a
No known key found for this signature in database
11 changed files with 349 additions and 13 deletions

89
docs/releases/v0.8.0.md Normal file
View file

@ -0,0 +1,89 @@
# Omnigraph v0.8.0
v0.8.0 makes every served graph an **MCP (Model Context Protocol) server**. An
MCP-capable agent — Claude Code/Desktop, Cursor, the OpenAI Responses `mcp` tool,
and others — can connect to a graph and operate it directly: run reads and
mutations, load data, manage branches, browse commits, read the schema, and
invoke the graph's curated stored queries. The surface adds no new capability and
no new business logic; every tool delegates to the same engine/handler path the
REST routes use and is gated by the same Cedar policy.
## Highlights
### MCP surface (`POST /graphs/{id}/mcp`)
- **One MCP endpoint per served graph**, mounted automatically by the cluster
server — no separate flag. It is a stateless Streamable-HTTP transport: a
single `application/json` JSON-RPC response per call, no SSE, no session id.
- **Built-in tools** cover the operational surface: `graph_query`,
`graph_mutate`, `graph_load`, `graph_snapshot`, `schema_get`, `branch_list`,
`branch_create` / `branch_delete` / `branch_merge`, `commit_list` /
`commit_get`, `schema_apply` (disabled with a `409` under cluster-backed
serving — evolve via `cluster apply` and restart), and a `graph_health`
liveness probe.
- **Stored queries as tools.** A graph's stored-query registry is projected as
tools, in one of two modes chosen automatically from the exposed-query count:
`per_query` (each exposed query is its own typed tool) below a threshold, or a
`stored_query_list` + `stored_query_run` discovery/execute pair at or above it,
so a client's tool count stays bounded.
- **Resources.** The graph schema (`omnigraph://schema`) and branch list
(`omnigraph://branches`) are exposed as MCP resources.
- **Structured output.** Tool results carry `structuredContent` (the same typed
result envelopes as the REST routes) plus a text mirror.
### Authorization parity with REST
- Every tool and resource resolves the actor from the bearer token and passes the
same Cedar gate as the equivalent REST route; the call-time gate is
authoritative.
- **`tools/list` is a relaxation of the per-call gate**: a tool the actor could
invoke on *some* branch is listed, so listing never hides a tool you can call,
while an actor with no grant for an action still does not see its tools. Under
the common "protect `main`, write feature branches" policy, `graph_mutate` is
listed for an actor who can write unprotected branches.
- Stored queries sit behind the coarse `invoke_query` gate (a stored mutation is
additionally `change`-gated); for a caller without `invoke_query`, a stored
tool masks as an unknown tool so the catalog can't be probed. An
`expose: false` query is unreachable on the MCP surface entirely (not listed,
not runnable by name) while remaining HTTP/service callable.
### Authoring stored queries as MCP tools
`.gq` gains the controls to shape how a stored query appears as an MCP tool, all
carried in the query source:
- **`@instruction("…")` reaches agents.** The query's `@instruction` annotation
is folded into the MCP tool description (after `@description`), so the
how/when-to-use guidance shows up in `tools/list` — previously it surfaced only
in the REST catalog.
- **Per-parameter docs.** A leading `@description("…")` on a parameter
(`@description("the user's slug") $slug: String`) is surfaced into the
parameter's JSON-Schema `description` in both the MCP tool input schema and the
`GET /queries` catalog.
- **`@mcp(tool_name: "…", expose: <bool>)`.** A dedicated MCP-presentation
annotation: `tool_name` overrides the tool id (unique-checked at boot, can't
shadow a built-in); `expose: false` hides the query from the agent tool surface
(`tools/list` / `stored_query_list` / `stored_query_run`) while keeping it
HTTP/service-callable by name. `expose` is presentation only — Cedar
`invoke_query` remains the authority for who may call a query.
### Transport hardening
- **Fail-closed Host / Origin posture**, derived from the bind address at
startup. A loopback bind accepts the full loopback `Host` set
(`127.0.0.1`, `::1`, `localhost`) regardless of which IP stack it bound; a
non-loopback bind rejects an unexpected browser `Origin` and restricts `Host`
to the configured public hosts.
- The `MCP-Protocol-Version` header is validated on follow-up requests (an
unsupported version is a `400`); `initialize` negotiates the version in its
body and is exempt by design.
## Upgrade notes
- **No breaking changes.** The REST surface, CLI, cluster config, and on-disk
format are unchanged. The MCP endpoint is additive.
- **Pointing an agent at a graph:** configure your MCP client with the URL
`https://<host>/graphs/<id>/mcp` and the same bearer token you use for REST.
See [docs/user/operations/mcp.md](../user/operations/mcp.md) for the connect
recipe, the tool catalog, projection modes, and the Host/Origin and
protocol-version contracts. Design and rationale: RFC-003.