mirror of
https://github.com/ModernRelay/omnigraph.git
synced 2026-06-21 02:28:07 +02:00
5.4 KiB
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/jsonJSON-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 a409under cluster-backed serving — evolve viacluster applyand restart), and agraph_healthliveness 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 astored_query_list+stored_query_rundiscovery/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/listis 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 "protectmain, write feature branches" policy,graph_mutateis listed for an actor who can write unprotected branches.- Stored queries sit behind the coarse
invoke_querygate (a stored mutation is additionallychange-gated); for a caller withoutinvoke_query, a stored tool masks as an unknown tool so the catalog can't be probed. Anexpose: falsequery 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@instructionannotation is folded into the MCP tool description (after@description), so the how/when-to-use guidance shows up intools/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-Schemadescriptionin both the MCP tool input schema and theGET /queriescatalog. @mcp(tool_name: "…", expose: <bool>). A dedicated MCP-presentation annotation:tool_nameoverrides the tool id (unique-checked at boot, can't shadow a built-in);expose: falsehides the query from the agent tool surface (tools/list/stored_query_list/stored_query_run) while keeping it HTTP/service-callable by name.exposeis presentation only — Cedarinvoke_queryremains 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
Hostset (127.0.0.1,::1,localhost) regardless of which IP stack it bound; a non-loopback bind rejects an unexpected browserOriginand restrictsHostto the configured public hosts. - The
MCP-Protocol-Versionheader is validated on follow-up requests (an unsupported version is a400);initializenegotiates the version in its body and is exempt by design.
Upgrade notes
GET /graphs/{id}/queriesis nowinvoke_query-gated (wasread). The stored-query catalog uses the same authority as invocation and the MCPtools/listsurface, so discovery and invocation agree ("see the menu iff you can order from it"). A caller with onlyread(and noinvoke_query) now gets403instead of a listing; in default-deny mode the endpoint returns403until aninvoke_queryrule 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>/mcpand 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.