The MCP surface

The engine inside Ouroboros is named Sophia; every tool your agent sees is sophia.*, grouped into 19 capability families, with a sandboxed execute_code isolate for composing several reads into one round trip.

Verified 2026-07-09 @ 80a91241

What this is

The engine inside Ouroboros is named Sophia — State Operating Platform for Human Intelligence Agents. The name is the architecture: humans use AI agents to get things done; agents use Sophia. It sits between your agent and the database as the MCP server they talk to, and everything an agent can do here happens through it. Every tool your agent sees over that connection is namespaced sophia.* — one flat list of typed calls, discoverable at runtime, with no separate manifest to keep in sync. From here on, sophia.* is just what the API is called.

Why it exists

An agent that has to guess a tool’s shape burns a round trip finding out it guessed wrong. Sophia’s answer is to make the surface self-describing: sophia.capability_catalog returns every tool grouped by capability with a version hash, and sophia.get_sdk_types returns generated TypeScript declarations for the same surface, so an agent can discover what it can call instead of being handed a static list that drifts out of date. The catalog returned by this daemon just now, captured live for this page, counts 166 tools across 19 capability groups, tagged with server_git_sha: "80a91241" — the exact build that produced the number. That count is a live property of the running server, not a fixed spec: it has moved before as tools shipped and merged, and it will move again. Treat any number on this page as a snapshot, not a promise.

How it works

The 166 tools sort into 19 groups: orient (session bootloaders like sophia.orient and sophia.panorama), coordination (inter-agent messaging), system (schema/permission/execute_code plumbing), seven read_* families (entities, finance, calendar, documents, knowledge, wiki, code), read_meta (briefings, search, mutation history, skills), preflight (evidence checks before a write), and seven mutate_* families gated behind approval. Most day-to-day work lives in the read families — writes are the minority of the surface by design.

Composing several reads into one call goes through sophia.execute_code: a TypeScript snippet run inside a real V8 isolate (isolated-vm), hosted in a spawned Node child process rather than in the Bun daemon’s own process — an 8MB heap limit, a 10-second default timeout (30s max), and a cap of 50 Sophia calls per run. Inside the isolate, sophia.* is a Proxy that forwards each camelCase method name to its dotted MCP tool (queryKnowledgesophia.query_knowledge) through a mapping built by reflection over the tool registry, not a hand-maintained list. The tool’s own description states the intended default directly: “Use this by default when you need 3+ Sophia reads or a read-modify-write sequence: it composes calls with Promise.all and keeps intermediate data inside the isolate instead of expanding every MCP result into the chat.”

Two smaller mechanisms cut round trips further. Every tool response — not just execute_code’s — carries an _inbox_unread field, spliced in by a shared response wrapper after the tool’s own result is built; a nonzero count means another agent left you something before your next call finishes. And several high-traffic read tools (query_knowledge, search, search_documents among them) accept compact: true for a curated ~5-key projection of each row, or fields: [...] for an exact key list — an unknown key in fields returns a structured error listing the tool’s valid keys instead of a generic failure, so a wrong guess costs nothing.

Both are context-economics tools: a response that carries five keys instead of forty — or an isolate that keeps intermediate results out of the conversation entirely — defends the agent’s reasoning quality, not just its token bill.

one round trip: execute_code batches reads inside the isolate
sequenceDiagram
  participant A as Your agent
  participant D as Daemon (MCP)
  participant I as V8 isolate (child process)
  A->>D: sophia.execute_code({ code })
  D->>I: spawn/reuse isolate, inject sophia.* proxy
  par Promise.all
    I->>D: queryKnowledge(...)
    I->>D: capabilityCatalog(...)
    I->>D: searchDocuments(...)
  and
    D-->>I: three results, scoped by connection
  end
  I-->>D: return value
  D-->>A: result + _inbox_unread

What your agent does with it

// Real response from this daemon, captured 2026-07-09:
const [briefing, catalog, docs] = await Promise.all([
sophia.orient({ goal: 'draft mcp-surface page' }),
sophia.capabilityCatalog({ brief: true }),
sophia.searchDocuments({ query: 'mcp', limit: 3, compact: true }),
]);
// → {
//   sync: { entity_count: 31, document_count: 6576,
//           knowledge_fact_count: 6519, unindexed_doc_count: 4526 },
//   total_tools: 166,
//   server_git_sha: '80a91241',
//   doc_hits: { items: [ /* 3 hits, compact-projected */ ], total: 3,
//     fusion: { method: 'rrf', k: 60, signals: ['bm25', 'dense'] } },
// }
// sophia_calls: 3, execution_time_ms: 3510

One execute_code call, three composed reads, one round trip — a session bootstrap, a live catalog check, and a scoped document search, none of which touched each other’s intermediate results outside the isolate. The same pattern is how an agent stays current on the tool count itself: sophia.capability_catalog is cheap enough to call at the start of a session rather than trusting a number written down last month.

Boundaries

Read tools run under whatever entity_scope the connection carries; write tools additionally depend on the connection’s profile. observer connections can’t call write tools at all. assistant connections get a per-call approval prompt on every write. full connections are pre-approved for ordinary writes — no per-call prompt — with one fixed exception: a small set of elevated tools (sophia.remember_fact, sophia.create_entity, sophia.begin_import_session, sophia.revert_mutation) always requires an explicit owner-approval gesture, regardless of profile, because each one can poison memory, plant false ground truth, bulk-write, or rewrite history. Portal connections — the owner’s own browser session, authenticated by cookie rather than a minted bearer — are exempt from that gate by design, not by oversight.

There is no OAuth-style interactive flow anywhere in this surface: no redirect, no consent screen, no refresh-token dance. Auth is a static bearer token checked against a connection row in the daemon’s ops database on every call. That simplicity has one sharp edge — a stale or revoked bearer doesn’t degrade gracefully, it fails outright with 401 Authentication required. Provide a valid Bearer token. (or, on the REST-style path, invalid_or_revoked_bearer). If every call in a session starts failing at once, check the bearer before you debug anything else.

How a connection actually gets minted, scoped, and approved is Security Model; the wiring steps to get a bearer into your agent’s config live at /connect/, not here. What sophia.search and its ranking signals (BM25, dense, fusion, rerank) actually do is Search & Retrieval. The daemon these tools sit in front of, and the graph/vault/gate split underneath them, is The State Layer; how a mutation gets journaled and reverted is Time Machine; how a claim gets grounded before it’s ever writable is Truth; and the inter-agent messaging that _inbox_unread is a side-channel for is Coordination.