Skip to content

GraphOS Embedded Fleet Gateway

GraphOS owns progressive discovery and invocation of the configured MCP connector fleet. The internal multiplexer implementation is a library component of the GraphOS process, not a separately launched console command, container, or network service.

Runtime shape

flowchart LR
    Client[MCP client] --> GraphOS[GraphOS]
    GraphOS --> Catalog[find_tools / list_catalog]
    GraphOS --> Loader[load_tools / unload_tools]
    GraphOS --> Refresh[catalog_refresh / catalog_dispatch]
    Loader --> Probe[Canonical child client boundary]
    Refresh --> Probe
    Toolkit[KG toolkit ingestion] --> Probe
    Probe --> Fleet[*-mcp connector fleet]
    Refresh --> Writer[Canonical fleet source-sync writer]
    Writer --> KG[Knowledge Graph]

At startup GraphOS exposes its focused graph tools and a bounded fleet catalog. A caller discovers a capability, loads only its selected child tools, invokes them through GraphOS, and may unload them to reclaim context. The catalog uses deterministic collision-free prefixes and never recursively registers GraphOS as its own child.

Isolation and resilience

Each child runtime enforces its configured concurrency bound, queue timeout, connection pool, call timeout, restart budget, and circuit breaker. A child failure is isolated and returned as a typed error; it cannot block GraphOS startup or remove unrelated capabilities. Child transports may be stdio, streamable HTTP, or SSE as declared by AgentConfig.

When a recovered child reconnects, its required handshake tools/list is also used to compare the newly advertised forwarding catalog with the bounded digest already exposed by GraphOS. A changed schema replaces only the affected FastMCP forwarders before the recovered generation accepts calls, invalidates that child's derived discovery/embedding caches, and queues notifications/tools/list_changed for each session that had the old forwarder loaded. Recovery is a detached supervisor task, so the notification is sent only on each affected session's next real request rather than reusing a stale response stream. FastMCP 4 registers duplicate replacements one at a time, so the multiplexer stages the complete executable component registry and restores the exact prior SDK components with one registry swap if any native registration fails. A persistent failure therefore retains the prior live tool and routing state while failing only that child closed with a stable health category. An equivalent reconnect does not probe the provider again or churn host registrations. A hot catalog reload removes mux-owned forwarders and per-session eager-load results before mounting the revised catalog, so same-named tools cannot retain obsolete schemas.

An administrator refreshes the complete authorization-scoped catalog through catalog_refresh or its exact REST twin, POST /api/mcp/catalog/refresh. The request carries the expected configuration revision, catalog generation, and snapshot digest. GraphOS obtains tools, prompts, resources, and resource templates from each child under one deadline, validates the complete candidate, synchronously acknowledges the existing source-sync projection, checks the replica cohort, and only then publishes one immutable generation. Any missing family, failed projection, deadline, stale expectation, or divergent replica rejects the candidate without partial publication.

catalog_dispatch resolves a tool against that exact generation and digest. If a read-only tool that was present in the snapshot reaches GraphOS but its child answers Unknown tool, GraphOS may relist the same child generation once, check the descriptor still exists, and retry once. This does not repair a client-side advertised-name miss that never reaches GraphOS; the client/service bridge remains responsible for refreshing its own advertised catalog.

The anti-sprawl boundary is explicit: McpCatalogReconciler is the sole transport-neutral snapshot/generation/high-watermark authority; MCPMultiplexer is the sole child-session and FastMCP I/O adapter; source-sync is a downstream projection; and REST/WebUI bind to the actually served multiplexer. They never construct a detached catalog or child pool.

KG live metadata discovery does not construct a second MCP client. It calls the same bounded one-shot probe used by the fleet gateway. Consequently every transport resolves named TLS references through AgentConfig, denies redirects, pins DNS and peer identity, applies the exact private-host policy, and fails closed when configured authentication cannot be materialized. Stdio children receive only the minimal runtime allowlist plus their explicitly delegated configuration; unrelated parent credentials never cross the process boundary. Runtime-materialized credentials are authenticated with a process-ephemeral attestation over the complete child declaration: executable and arguments, transport destination, TLS and private-host policy, time bounds, headers and environment, and parent-only controls. Mutation after materialization therefore invalidates both child secret use and Langfuse parent-mediated graph ingestion.

Provider tools use one explicit client-execution boundary. Asynchronous SDK methods are awaited directly; synchronous SDK methods are moved to an AnyIO worker thread. The strict synchronous helper rejects async callables instead of returning an unexecuted coroutine. This keeps the GraphOS event loop responsive and prevents action handlers from silently dropping asynchronous provider work.

The probe bounds initialization and total discovery time, tool count, aggregate catalog bytes, nesting depth, and collection size. Errors expose only stable categories. A failed connection is distinct from an authoritative empty tool catalog, so ingestion never fabricates tools from configuration flags after an authentication, trust, or transport failure.

The same bounded probe also enumerates a child's Skills-over-MCP skill:// Resources alongside its Tools (best-effort — a server without resource-listing support degrades to no skills, never a failed tool probe), so find_tools ranks skills and tools in one result set. See Skills-over-MCP for the full unified-capability design.

Interactive discovery uses one shared wall-clock budget for catalog probes and semantic reranking. When the request names a configured domain such as GitHub or Mattermost, GraphOS probes that matching server first through the same canonical boundary, then spends the remaining budget on broad fleet fan-out. A large set of slow unrelated children therefore cannot hide the named server behind a catalog budget timeout.

Configuration

GraphOS reads one AgentConfig-backed mcp_config.json. Child entries may declare enable/disable filters and bounded resilience overrides. Secrets, endpoints, and authentication material remain external configuration and are never copied into documentation, traces, or graph records.

Persistent catalogs express child credential slots as neutral uppercase aliases such as env://CHILD_ACCESS_TOKEN. A live environment or runtime-secrets projection for that alias has precedence. When the direct alias is absent, AgentConfig.MCP_FLEET_SECRET_REFS may map it to one validated env://, vault://, or secret:// reference. The mapping contains references only, is resolved at the exact child boundary, and fails closed for malformed or unavailable values. An env://ALIAS self-map selects that key from the runtime-secrets source before execution. Resolved material is never written back to the catalog or AgentConfig.

Freshness records contain a keyed opaque identity plus neutral metadata only. The identity binds endpoint, command, arguments, TLS selection, and non-secret configuration without retaining any of those values; resolved credential values do not participate. Production uses the configured persistence identity key. The zero-infrastructure development profile uses a process-ephemeral key and therefore conservatively refreshes after restart.

The process-level deployment contract is therefore simple:

graph-os --transport stdio
graph-os --transport streamable-http --host 0.0.0.0 --port 8004

Clients connect only to GraphOS. The internal implementation lives in agent_utilities.mcp.multiplexer and agent_utilities.mcp.child_resilience, but neither module defines an independently deployed service contract.