omnigraph/docs/releases/v0.8.0.md
2026-06-17 20:16:56 +02:00

5.4 KiB

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

  • GET /graphs/{id}/queries is now invoke_query-gated (was read). The stored-query catalog uses the same authority as invocation and the MCP tools/list surface, so discovery and invocation agree ("see the menu iff you can order from it"). A caller with only read (and no invoke_query) now gets 403 instead of a listing; in default-deny mode the endpoint returns 403 until an invoke_query rule is configured. This is the one observable REST behavior change in this release.
  • Otherwise no breaking changes: the rest of 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 for the connect recipe, the tool catalog, projection modes, and the Host/Origin and protocol-version contracts. Design and rationale: RFC-003.