Named Services: Ontologic Tools
Named services give an agent one small grammar — list, search, get, act — and let every domain teach its own vocabulary at runtime. A domain models itself once, as a realm: typed objects, self-contained refs, its own questions and selectors, and policy-guarded use cases. Agents use every realm through the same bounded tool grammar; UIs, jobs, and other apps consume the same provider-owned object contract through their own adapters.
Every tool an agent carries costs something before it is ever called.
It occupies context. It competes for the agent's attention at every decision. It ships its own parameter shapes, its own error dialect, its own half-documented conventions. Connect an agent to mail, chat, conversation history, boards, and memory the direct way — one tool per operation — and the tool list grows with every domain. Twenty domains later the agent spends its judgement choosing between eighty near-synonyms, and every new domain makes every old one slightly harder to use.
Named services take the other road. The agent carries a bounded grammar of generic operations, and each domain plugs in as a realm — a namespace that describes itself: what its objects are, how to find them, what can be done to them, and who may do it. The grammar is learned once. The domains are open-ended.
Implementation highlights
The shipped system is not only a naming convention. These contracts make the small grammar work across apps, processes, agents, and UI surfaces:
| Concept | Implemented contract |
|---|---|
| Bounded agent grammar | The model-callable SDK surface has at most nine generic tools: provider_about, object_schema, list_objects, search_objects, get_object, object_action, upsert_object, host_file, and delete_object. A tool appears only when at least one configured namespace allows its provider operation. |
| Provider-owned ontology and affordances | The provider owns object kinds, canonical refs, relations, constraints, selectors, bounded actions, and human presentation. Semantic object search appears only when the provider supplies it; KDCube does not index the provider's object space. Its adapter translates domain requests into provider IDs and API calls. |
| Recursive capability discovery | object_schema returns a root catalog, one nested schema_path, ranked capability matches for query, one kind, or one exact operation contract. The shared capability index contains provider declarations only and reports whether lexical, semantic, or hybrid matching actually ran. |
| Cross-process discovery | Providers register per tenant/project in Named Service Discovery. Consumers resolve a provider by namespace, operation, ref pattern, and object kind instead of linking to its app code. |
| Opaque, round-trippable refs | Generic clients preserve object_ref and ask the owner to resolve it. A ref carries owner/object identity without ambient object-selection state; caller identity and delegated authority travel separately in the authorization context. |
| One contract, several adapters | Agent tools, the external MCP gateway, canvas/chat resolvers, react.pull, jobs, and peer apps adapt to the same provider operations. They share semantics without pretending every surface is a model tool. |
| Actor and grantor stay distinct | An agent, external connector, or automation is a delegated actor, not the user. The approving user remains the grantor; the actor identity, delegated resources/operations, expiry, and revocation state remain independently auditable. |
| Layered authorization | Consumer allow-lists, per-user capability choices, and the caller's delegated grants guard the outer boundary; provider ACLs or connected-account claims guard the realm itself. |
| Actionable consent | Connected-account requirements can be presented proactively. If an attempted operation still lacks access, one structured error names the reason, claims, account candidates, openable Connection Hub route, and retry behavior. |
| Complete data without context flooding | Search emits lean object refs. Long collections expose cursors; large objects and files expose signed out-of-band delivery or a harness stream. The client decides how much retrieved data enters model context. |
The practical lesson is that genericity comes from a strict ownership boundary: the platform owns the grammar and routing; each realm owns meaning, identity, authorization, and effects.
The whole idea in one line
The platform fixes the verbs; each domain declares its nouns and use cases; policy and grants decide who may conjugate what.
the tools provider_about · object_schema · list_objects · search_objects
get_object · object_action · upsert_object
host_file · delete_object (bounded at nine)
the nouns object kinds + refs, declared per realm (open-ended)
the guard consumer policy and grants at the boundary,
the realm's own authorization inside (layered)
This is why ontology-guided fits. A realm publishes a lightweight operational ontology — the domain's entities, identities, relations, and constraints. The selectors, bounded operations, claims, errors, and delivery choices are its affordance layer: the executable language over that model. This is not a claim of formal OWL/RDF ontology or automated logical inference.
The schema is the realm's language for an agent, not a catalog of the provider's endpoints. It can say that documents contain tabs, comment threads, replies, and exports; it can offer selectors such as a tab title or a comment topic. The provider adapter turns a supported domain request into opaque provider IDs and one or more API calls. The schema advertises only what that adapter can execute: ambiguity returns choices, and unavailable or preview-only behavior is reported precisely.
Those are the generic agent-facing tool names. The provider protocol also contains operations
used by adapters — for example provider.capabilities,
object.resolve, and block production/rendering. An MCP gateway may expose
discovery wrappers around them, while a UI may call a resolver. They do not inflate the
agent's tool catalog into domain-specific tools.
A hundred APIs become a navigable realm, not a hundred tools
There are two reductions, and they happen in different places.
First, the provider adapter maps implementation endpoints into user-meaningful objects and effects. Several API calls may implement one action. Distinct effects that need separate authorization remain distinct actions.
Second, the provider arranges those declared operations in a recursive capability catalog. A catalog can be as deep as the domain needs:
docs /
documents
work /
read
edit
transfer
discussion
The agent can browse one node with
object_schema(schema_path="/work/edit") or ask the schema itself:
object_schema(query="reply to a comment", search_mode="hybrid")
-> catalog_path: /discussion
-> object_kind: docs.comment_thread
-> schema_operation: object.action:reply_comment
It then expands that exact kind/operation pair and receives one executable payload contract. If a provider really has 100 distinct agent effects, it still declares 100 stable operation ids. They no longer arrive as 100 top-level tools or 100 full schemas in every round.
The query above searches capability declarations: labels, descriptions, keywords, kinds,
and operation ids. It does not search the user's documents, mail, or messages.
search_objects(query=...) remains the separate provider-backed object search.
What a realm declares
Modeling a domain as a realm means answering six questions. The mail: realm
answers them like this:
- Object kinds are the domain's nouns — typed, with the fields an operator can actually act on. Internal ranking scores and storage details stay out of the model.
- Refs are the identities. A ref emitted by search or list is a promise:
hand it back to
getoractionlater — from another process, another session, another client — and it resolves. Refs embed what they need (mail:gmail:<account>:message:<id>carries its account), so no ambient object-selection state is required. Authorization context still travels separately. - Search and selectors speak the domain's own question language and natural ways to identify an intended object. Mail can select by account and query; memory by origin, kind, and labels; a document realm by title, author, or status. The provider resolves those terms to opaque IDs and returns choices when a request is ambiguous.
- Actions are the domain's use cases, named and bounded:
send,forward,post_message,request_upload. Each action is a deliberate decision about what this domain offers to outside operators. Dispatch usesobject.action, while policy may grant an exact key such asobject.action.sendindependently. - Complete data stays reachable through pagination cursors, signed out-of-band delivery, and harness streams even when the ordinary result stays compact.
- About and schema make the realm self-teaching. They describe its recursive capability catalog, objects, selectors, actions, claims, account selection, file delivery, and consent errors. Provider endpoint names and call sequences stay behind the adapter.
Same verb, every domain's vocabulary
Once the grammar is fixed, domains stop being integrations and start being vocabularies.
The operator's skill transfers completely: learn to work one realm, and the next realm costs
only a schema read.
A real trace, end to end, from an external agent connected over MCP — finding the pictures a teammate posted with a phrase:
search namespace=slack query="ПР 176 in:#kdcube-users"
-> one hit: slack:…:message:C…:1782589383.978809 (labeled account, channel, ts)
get the channel ref, window = that one timestamp
-> the message object: text + THREE file refs (slack:…:file:F…)
get each file ref
-> download: {encoding: "url", url, expires_at} (signed, short-lived)
HTTP GET each url
-> three PNGs, bytes never inside a tool result
There is no Slack-specific tool schema on the agent's side: one generic search, one generic channel read, then one generic file read per returned ref. The same operations, with different provider-declared vocabulary, walk mail, memory, boards, and conversation history.
The signed URL is a KDCube delivery boundary, not a provider token. For a KDCube-hosted artifact it streams stored bytes. For a connected Mail, Slack, or Google Sheets object it can verify the signed ref, resolve the user's current credential and consent server-side, and stream current provider data. A resident harness agent instead materializes a stable turn snapshot. The caller grant is checked when the URL is minted; the URL itself is the short-lived download capability, while provider consent is checked again on each use. In every case complete data remains reachable while the model-facing result stays compact.
Two authorization gates
Exposing a domain to outside operators is an act of trust. The runtime applies two gates that answer two different questions.
Identity rule: agent is not user. A hosted agent, an external MCP client such as Claude Code, and an automation using a manually issued token are separate delegated actors. The user who approved access remains the grantor. That is one delegated-representative identity model: hosted-agent linkage is automatic, while a connector or manually issued token is linked through Connection Hub. The distinction enables per-agent consent, revocation, audit, and accounting without handing an agent the user's full session.
Gate one belongs to the consumer/platform boundary. App configuration
exposes only allowed namespace operations; per-user capabilities and, for external MCP or
automation clients, consented delegated grants narrow that surface further, down to exact
variants such as object.action.send when declared. The question is: may this
caller, under this delegation, invoke this operation on this resource?
Gate two belongs to the domain. The realm receives the delegate actor
plus the authority projected from the grantor and authorizes with its own rules —
connected-account claims for provider-backed realms (gmail:send,
slack:files:write), the realm's ownership/ACL model everywhere else. The
agent is never silently rewritten into the user.
Connected-account requirements can be declared in provider metadata and shown proactively in the capability picker. The attempted operation remains the authoritative, demand-driven check: if a required claim or account is still missing, that exact attempt raises a scoped ask. A denial is an answer, never a dead end:
needs_connected_account_consent
reason: connect_required | claim_upgrade_required |
reconnect_required | account_required
candidates: [{account_id, label, email, workspace, status, claims}]
connection_hub_url: openable deep link (absolute for external clients)
retry_hint: whether retrying after the stated fix should succeed
instructions: the agent's next step, in words it can relay
An operator that hits a wall learns which wall, who can open it, and whether to retry. The agent relays a fix; the user performs one consent; the call succeeds.
Model your own domain
The recipe generalizes to any subsystem you want operators to work with. Take a logistics desk as an example — shipments, carriers, exceptions:
- Name the nouns.
freight.shipment,freight.carrier,freight.exception— the entities an operator reasons about, with the fields they can act on. - Give them identities.
freight:shipment:<id>,freight:exception:<shipment>:<seq>— refs that round-trip with no ambient object-selection state; authorization travels separately. - Write the questions and selectors. Search filters the desk already
thinks in —
status,carrier,route,overdue_days— plus how an operator names one intended shipment or exception. - Name the use cases.
reschedule,assign_carrier,escalate_exception,attach_pod— the operations the domain chooses to offer, each a bounded verb with a declared payload. - Guard them.
freight:readfor search/get;freight:dispatchfor the actions that move real trucks. The door checks grants; the domain applies its own approval rules inside. - Arrange the capability catalog. Group operations by domain and subdomain; add labels, descriptions, and keywords that make paths and capability queries useful.
- Teach it. Put selection and ambiguity rules, the file story, capability
limits, and denial shapes into
about/schema; keep provider API details behind the adapter. - Keep data reachable. Declare cursors, complete signed delivery, and harness stream behavior.
- Teach it to humans too. Declare the presentation layer beside the schema: a purpose sentence, an honest works-with line, human labels per operation and action ("Reschedule a shipment"), object-kind one-liners. The capability picker renders exactly this as the realm's service card — the user reads it, understands it, and narrows it per operation.
The test of a good realm now has two readers: an operator who has never seen your domain opens the schema root, browses or searches capabilities, expands one exact operation, finds an object, and performs one guarded action correctly without learning provider IDs; and a user who has never seen your domain reads its card and knows what it does, what it touches, and how to turn any part of it off.
One realm contract, every operator
The same declaration serves every kind of operator the platform hosts:
- Any agent can receive the generic named-service tools in its catalog and reach configured realms inside its run — searching conversations, reading memory, sending mail, or patching a board.
- External agents over MCP connect to one gateway surface, consent to grants, and work the same realms with the same verbs — including moving real files through signed upload slots and download URLs.
- UIs keep refs opaque and call resolver adapters for capabilities, preview, open, download, or owner-defined actions. Named-service search results remain object artifacts, not files.
- Automations and peer apps address the same objects through an explicit authorization context and the provider/client contract, without requiring a browser session.
That is the payoff of modeling the domain once through an ontology-guided contract: the vocabulary is written one time, by the people who own the domain — and every operator, human-driven or agentic, inherits it.
Read more
- How a named service introduces itself: intro, about, schema
- Ontologic tools
- Named-service model tools and catalog
- Named Service Discovery
- Make a named service agent-friendly over MCP
- Build a named-service app
- Namespace service providers
- Per-user agent capabilities
- Mail named service over MCP
- Slack integration
- Google Sheets integration
- Ported LangGraph app
- Move files in and out over MCP
- File hosting for turn-less transports
- Delegate a KDCube service to an external client