Skip to Content
DocumentationTools and MCP Architecture

Tools and MCP Architecture

Everything a model can call in Eneo is a Model Context Protocol (MCP) tool. Eneo is the MCP host: it decides which tools a completion may see, connects to the servers that implement them, runs every call through one proxy, and checks whatever comes back before it reaches the model, the conversation or the user. The servers themselves run in three different places, chosen by what the tool needs rather than by who wrote it.

This page is the map. It names the three execution tiers, explains why the design is split along those lines, and points to the pages that own each part.

Related pages: Knowledge Retrieval and MCP Interoperability owns the proxy pipeline, the two kinds of approval, file references and failure behaviour. Built-in Tool Servers owns the loopback servers and the placement rule for new built-in tools. Tool Runtime Security owns the isolated runtime’s design assumptions and controls. Administrators work through MCP Servers and Functions.

One protocol, one proxy, three places to run

Loopback serversBundled tool runtimeIndependently operated servers
Runs inThe backend process, mounted at /internal-mcp/<name>/mcpA separate container in the release bundle (tool-runtime/, image eneo-tool-runtime)Any Streamable HTTP MCP server an administrator registers
Maintained byEneoEneoThe operator or a third party
ServesKnowledge search, attachment reading, image generationCompute, charts, tabular file analysis, document and spreadsheet creationDomain integrations, web search, and alternative providers for any Function
Tool definitionsTaken from the deployed code on every completion; nothing to reviewTaken from the running runtime’s catalog, stored and refreshed without review, with an audit entrySynced, stored and approved by an administrator before the model sees them
CredentialsA 15-minute token Eneo mints for itself per completionA shared bearer read from the deployment environment at connect time; nothing storedPublic, a stored encrypted bearer or API-key header sent only over https (plain http only to a loopback host); optional identity headers
Access to Eneo dataFull, through the acting user’s normal permission checksNone: no database, no signing key, only the signed links a call carriesNone beyond the signed links a call carries
Per-call user approvalSkipped: scope is fixed by Eneo’s code and the completion tokenFollows the conversation’s settingFollows the conversation’s setting
Isolation from other tenants’ dataThe backend’s own authorizationOne confined child process per job, locked engines, hardened containerWhatever the operator provides
FailureRequest-local; nothing accumulatesTool call fails; chat continuesCircuit breaker per server; chat continues

What every tier shares

The tiers differ in where code runs and who vouches for it. They do not differ in how a completion uses them:

  • One client and one proxy. The backend connects to all three with its ordinary Streamable HTTP MCP client, lazily, when the model first calls a tool on that server, and reuses the connection for the rest of the completion. Prefixing (server__tool), parallel calls, output limits, retries, reference capture and cleanup are implemented once.
  • One way to attach. A tool reaches a completion either because a Function the assistant enabled resolved to a provider for this user, or because a general MCP server is enabled for the space and assistant, or because the request itself needs a built-in helper (knowledge in tool mode, attached files). The same gates apply regardless of tier: the user’s role, the space, the assistant, the security classification, and a model that supports tool calling.
  • One file transport. The model holds credential-free handles (eneo-file:…). Eneo resolves them against the request’s authorised files into short-lived signed URLs just before dispatch, so every provider, internal or external, receives an ordinary URL and needs no knowledge of Eneo’s handles. Links to any other file stop the call.
  • One result pipeline. Text is budgeted, images and embedded files are admitted by count, size and the purpose the server serves, generated documents are checked byte by byte, tokens are redacted before anything is stored or replayed, and results that carry an interactive view are shown through the MCP Apps host.

Two ways a tool is configured

FunctionGeneral MCP server
What is savedA purpose (web_search, image_generation, file_analysis, file_creation, charts, compute) on the space and assistantThe server and its tools on the space and assistant
Who serves itResolved at ask time: a group provider or the tenant default, from any tierThe one server that was selected
Replacing the implementationActivate another provider; saved intent is untouchedEdit each space and assistant
Typical useCapabilities with interchangeable providers, including the ones Eneo shipsDomain tools that are what they are: a ticketing system, a records API

Functions exist so that “this assistant can analyse files” is not the same statement as “this assistant talks to server X”. An administrator can move a Function from the bundled runtime to an external provider, or the reverse, without touching a single assistant. See Functions.

Why the architecture is split this way

Why Eneo’s own tools speak MCP

Eneo could have called its knowledge search, file reader or image model as plain Python functions inside the completion loop. It routes them through MCP instead, as loopback servers the backend hosts and then connects to, because that gives internal and external tools one integration boundary. The completion adapter has no separate code path for “RAG tools” and “MCP tools”; anything that works for one works for the other. It also keeps Eneo honest about replaceability: a bundled provider and an external one receive the same signed URL and return the same MCP content, so an operator can swap either for the other.

The route is a network path, not a trust shortcut. Every loopback call carries a per-completion token that fixes the assistant (and, for a built-in provider, the provider row) in a claim the model cannot change, and each tool reconstructs the acting user’s normal service container before it reads anything.

Why some tools stay inside the backend

A loopback tool is a pure function of the request, the tenant database and at most one outbound provider call, finishing inside a tool-call timeout. It needs no process of its own, no storage and no heavyweight dependency. For that shape the backend is the cheapest and safest place to be: the data is already authorised, the code ships with the release, and there is nothing to review or operate. Knowledge search, attachment reading and image generation fit; the placement rule and its two attachment patterns are spelled out in Built-in Tool Servers.

Why heavy and untrusted work runs in a separate runtime

Compute, tabular analysis, charts and file creation have four properties that knowledge search does not:

  1. The input is not Eneo’s own. The model writes the JavaScript and the SQL. Users supply the CSV, XLSX and DOCX files. None of it can be reviewed before it runs, so it has to be contained instead.
  2. They need engines. DuckDB, QuickJS, an OOXML renderer, HTML-to-PDF layout and SVG rasterising are large native or WebAssembly dependencies with their own vulnerability history.
  3. Their memory is proportional to the file, not to the request.
  4. They need a sandbox. Code the model wrote must not be able to read another conversation’s files, reach Eneo’s credentials or the network, or run forever.

The backend process is the chat API for every tenant. Running such work there would mean one query competing with every other request for memory, one engine failure affecting chat, and the engines sharing a process with the database connection and the signing keys. So the work moved to a runtime that:

  • runs each job in a fresh child process with a stripped environment, a private directory and Linux Landlock confinement, so an engine sees only the files that one job was given;
  • holds no credentials and no data, has no database, no signing key and, in the reference deployment, no route to PostgreSQL, Redis or the internet, so there is nothing to take;
  • keeps its dependency set out of the backend image, so the backend’s vulnerability surface and release cadence stay its own;
  • has its own CPU, memory and process limits and a fair scheduler, so one tenant’s load degrades its own tools and not the chat API.

Tool Runtime Security describes each of these layers and what they do and do not cover.

Why “bundled” rather than “just another external server”

The runtime is an MCP server like any other at the protocol level, and that is deliberate. What makes it bundled is operational:

  • It is built and published with the backend and frontend from the same source revision, as one verified release bundle, so there is no version skew to manage and Admin > Tools can warn when one appears.
  • Its address and bearer come from the deployment environment (TOOL_RUNTIME_URL, TOOL_RUNTIME_TOKEN), read at connect time. Nothing is stored in the database, and the connection form is read-only.
  • Its tool definitions and views are Eneo’s own code, so the backend takes the running runtime’s catalog without an administrator’s review, keeps the administrator’s per-tool enablement and display names, and records each change in the audit log. A new image is in force as soon as it runs.
  • It is registered through the ordinary Admin > Tools page as a Built into Eneo provider for each Function, and an external provider can replace it at any time.

The runtime is not a plugin host. New endpoints belong there only when they need platform-owned isolation and Eneo maintains them. Domain integrations (statistics APIs, open-data portals, case systems) stay independently operated servers.

Why files, not shared storage, connect tools

A query export feeds a chart, a chart image goes into a report, a spreadsheet is built from a query result. These chains never pass large data through the model and never require two providers to share storage:

  1. A tool returns its output inside the MCP result (an embedded resource or an image block). The runtime keeps no copy and serves no download links.
  2. Eneo admits the file only if the producing server serves a Function that delivers that type, checks the bytes, and saves it in the conversation with its exact original and extracted text.
  3. The model receives a stable handle for the new file in the same answer (in a streaming chat) and passes it to the next tool, where Eneo resolves it to a fresh signed URL.

Eneo owns every file; providers hold only short-lived links. The runtime’s cache of original bytes and parsed sheets is a performance detail keyed by tenant, user and content hash, and it can never stand in for the access check, because every call redeems its own link first.

Why presentation is split between native views and MCP Apps

A saved file is shown by Eneo’s own previews and document workspace: drafts, revisions, version navigation and export are Eneo features, not tool features, and they work without any app feature flag. Tool-specific interaction (sorting a query result, zooming a chart, re-running a calculation with edited inputs) is an MCP App: one self-contained HTML page the server attaches to its tool, shown in a sandboxed frame on a separate origin through the official MCP Apps SDK.

The trust split follows the tiers. An external server’s view is part of its tool definition and is approved, pinned by content hash and served only while the approval holds. The bundled runtime’s views are Eneo’s code and follow the release like its tools. In both cases the view cannot read or change anything in Eneo, and a tool call made from a view is rate-limited, rechecked against the current approval on every request, limited to the files its originating call used, and audited. Such calls are not added to the conversation and the model does not see them; a message a view offers goes into the composer for the user to send. See Interactive tool views and the MCP Apps deployment guide .

Trust decisions, boundary by boundary

BoundaryDecisionLoopbackBundledExternal
CatalogWhat the model may be told a tool doesDeployed codeRunning runtime, auditedAdministrator approval; changed definitions wait at the previous version
AttachmentWhether this completion gets the toolRequest needs it (knowledge mode, files present) or a Function resolved to itFunction resolved to itFunction or space and assistant selection
DispatchWhether this call may go outRole, space, classification; token fixes scopeSame, plus foreign-link refusal and handle resolutionSame, plus the conversation’s per-call approval
TransportWhat the server learns about the userFull identity in the scoped tokenOpaque user and tenant IDsIdentity headers only when the administrator opted in
ResultWhat comes back into EneoText budget, reference captureText budget, file admission by purpose, byte checksThe same guards; files only for servers serving a file-delivering Function
StorageWhat is keptTool trace with tokens redactedSaved generated files, redacted traceThe same

The central invariant: the three tiers converge at the proxy only after each has applied its own availability, authorization and trust decisions. Sharing the execution plumbing does not merge their security boundaries.

Skills, Functions, tools and views

These features separate instructions, access, execution and presentation. A Function can use the bundled runtime, but the two are not interchangeable.

PartOwnsDoes not supply
SkillReusable Markdown instructions pinned to an exact revisionExecutable scripts, tool installation or permission grants
FunctionSaved purpose such as file_analysis or charts; provider selection under organisation and user controlsA particular implementation or a guarantee of every native UI operation
General MCP integrationApproved domain tools attached through Space and Assistant configurationA new Function merely because it uses MCP
Loopback serverBackend-owned knowledge, attachment reading or image-model callsA host for heavy file processing or arbitrary compute
Bundled tool runtimeEneo-maintained isolated calculations, tabular analysis, charts and file creationA plugin host or durable document store
MCP AppA tool’s interactive result view, such as a query table or chartAn editable saved document or unrestricted access to Eneo
Native document workspace and previewsFile display, streaming drafts, assistant-driven revisions, version navigation and export controlsDirect rich-text or spreadsheet cell editing

Eneo Apps that builders configure in Spaces are separate from MCP Apps. The former are application resources that can bind Skills; the latter are interactive HTML views attached to MCP tools.

  • Instruction reuse is independent of authority. Loading a Skill changes the model’s context. Existing role, Space, Assistant, classification and tool-approval checks still decide what it may call. A Skill can describe how to use an available compute tool without carrying executable code itself.
  • Saved intent survives provider changes. Assistants store Function purposes, and Eneo resolves an eligible group provider or tenant default at request time. Native operations may require a narrower tool contract: exporting a Markdown document uses create_document, so generic file-creation capability alone is insufficient.

Saved state and failure boundaries

State or operationBehaviour
Skill revision and Function selectionSaved configuration; provider changes do not update a Skill pin or erase Function intent
Generated document revisionA new saved file; conversation tool calls link revisions through revises and generated file IDs
Streaming document draftA preview of in-progress tool arguments; successful file delivery establishes the saved result
App filters, loaded rows and chart zoomPreserved when moving the same frame between inline and expanded display; not guaranteed across reloads
Markdown export to Word/PDFRenders the selected saved text through a compatible current provider without another model response; download bytes are not saved as a version
Runtime unavailableIts tool calls can fail; ordinary chat and already-saved native previews do not depend on runtime readiness
MCP Apps disabledNative previews still work; bundled table tools return data and charts fall back to PNG
View approval revoked or originating tool disabledAn already-open app loses tool access when the host rechecks its next request