MCP Servers
Model Context Protocol (MCP) servers give assistants access to external tools and live data. This guide covers setup, tool approval, user-specific catalogs, cross-turn state, and day-to-day operation.
This guide covers administrator setup for external MCP servers. For the map of where tools run and why, see Tools and MCP Architecture; for the deeper mechanics, including knowledge retrieval modes, Eneo’s built-in loopback MCP servers, and how internal and external tools interoperate, see Knowledge Retrieval and MCP Interoperability. Servers that provide a function (web search, image generation, ask a file, create a file or charts) are managed as functions instead; see Functions.
Overview
MCP is an open protocol that lets AI assistants call external tools — such as searching a database, creating tickets, or fetching live data. Eneo connects to MCP servers over Streamable HTTP transport and acts as a proxy between assistants and the remote server.
Key concepts:
| Concept | Description |
|---|---|
| MCP Server | A remote service that exposes tools via the MCP protocol |
| Tool | A single function the server provides (e.g. search_tickets, create_issue) |
| Tool Sync | Discovering tools from the remote server and detecting changes |
| Approved catalog | The tool names, descriptions, and schemas an admin has accepted in Eneo |
| Live catalog | The tools the remote server returns for the signed-in user during this request |
| Approval | Admin review before a new or changed definition becomes active |
| Space | Where you enable MCP servers so assistants can use their tools |
For a server that receives user identity, Eneo exposes only the intersection of the two catalogs:
approved and enabled in Eneo ∩ visible to this user now = tools sent to the modelThe remote server decides what the user can see. Eneo decides what the model is allowed to call. A tool must pass both checks.
Adding an MCP Server
MCP servers are managed on the MCP servers tab of Admin → Tools (/admin/tools; the former /admin/mcp-servers URL redirects there). Only admins can add, edit, or remove servers.
The server form has a Function selection. Leave it at General tools for a server whose tools attach directly to assistants. Choose a function (Web search, Image generation, Ask a file, Create a file or Charts) to register the server as a source for it; it is then managed on the Functions tab and covered by Functions.
Steps
- Click Add MCP Server
- Fill in the required fields:
- Name — A display name for the server
- Server URL — The Streamable HTTP endpoint (e.g.
https://example.com/mcp)
- Configure optional settings:
- Description — What the server does
- Authentication — Choose between
Public(no auth) orBearer Token - Forward user identity — Send the acting user’s Eneo identity to this server
- Tool catalog limits — Set the largest catalog and tool definition Eneo will accept
- Documentation URL — Link to the server’s documentation
- Security Classification — Restrict which spaces can use this server
- Click Add MCP Server
Eneo will test the connection before saving. If the URL is unreachable or returns an error, the server is not created and you get an error message.
On successful creation, Eneo connects to the server and stores the tools visible to the creating admin. These initial tools are enabled by default because the admin is explicitly adding the server. When identity forwarding is enabled, other users may have a different catalog; their additional tools enter the approval flow described below.
Authentication
If the MCP server requires authentication, select Bearer Token and enter the token. The token is encrypted at rest using Fernet encryption (AES-128-CBC + HMAC-SHA256) and is never shown in the UI after saving.
When editing a server, leave the token field empty to keep the existing token.
Credentials need https
Eneo sends a bearer token or API key only over https. A server whose
authentication sends one must have a Server URL that starts with
https://; plain http:// is accepted only for localhost, 127.0.0.1 and
[::1], which Eneo connects to directly, never through a proxy set in
HTTP_PROXY or ALL_PROXY. The form explains this before you save, and Eneo
refuses to add or save such a server. A user name and password in the
Server URL (https://user:password@...) are a credential as well, sent as
Basic authentication, so the same rule applies to them whatever the
authentication setting. Servers without authentication and without a user
name or password in the URL are not affected.
A server saved with a plain http:// address and a credential before this
rule existed is no longer contacted: saving it and syncing its tools fail with
a message asking you to change the address to https. In chat, a tool call to
such a server reports that an administrator must do so; a server with identity
forwarding instead has its tools left out of the request, as when its
identity-scoped discovery fails. Edit the server and change its Server URL
to the server’s https address.
MCP servers behind an internal certificate authority
Eneo verifies the server’s TLS certificate, and has no setting that turns the
verification off. It trusts the public certificate authorities bundled with
the backend. For a server whose certificate comes from your organisation’s own
CA, point SSL_CERT_FILE at a file that holds both the public roots and your
CA (SSL_CERT_DIR, a directory prepared with openssl rehash, is read only
when SSL_CERT_FILE is unset):
# In a container of the backend image: the bundled public roots plus your CA.
cat "$(python -m certifi)" internal-ca.pem > eneo-ca-bundle.pemMount the file and set SSL_CERT_FILE=/path/to/eneo-ca-bundle.pem on the
backend service, which makes the MCP calls for chats, connection tests and
syncs. The HTTP client Eneo uses for MCP (httpx) then loads that file instead
of its bundled roots, not in addition to them, so a file with only your CA
breaks connections to MCP servers with public certificates. Other HTTP clients
in the backend read the variable too, which is another reason to keep the
public roots in it. A self-signed certificate is trusted only when that
certificate itself is in the file.
Forwarding user identity
Identity forwarding is off by default. Enable it only when the MCP server is trusted to receive personal data and uses that identity to authorize each request.
Eneo sends the available values in these headers:
X-Eneo-User-Id,X-Eneo-User-Email, andX-Eneo-User-NameX-Eneo-Tenant-IdandX-Eneo-Tenant-NameX-Eneo-Role
Empty values are omitted. Text values are stripped of control characters and invisible formatting characters (such as zero-width spaces) and percent-encoded as UTF-8; the receiving server must decode them before display or matching. Headers are sent during connection checks, tool discovery, and tool calls.
Forwarded headers are identity claims from Eneo, not a replacement for a protected network path. The MCP server must accept them only from the trusted Eneo backend and must authorize every request.
Tool catalog limits
Open Tool catalog limits in the server form to set two safeguards for that server:
| Setting | Default | Allowed range |
|---|---|---|
| Maximum tools | 256 | 1–4,096 |
| Maximum catalog size | 16 MiB | 1–64 MiB |
| Maximum size per tool | 64 KiB | 1–1,024 KiB |
The sizes include tool names, descriptions, and input schemas as serialized JSON. The total-size limit prevents a large collection of individually valid tools from becoming one oversized database write. Choose values that cover the server’s expected catalog without accepting unbounded data. These limits protect chat latency and database growth; they do not decide how many approved tools an assistant should receive.
Eneo validates the complete live catalog before saving or exposing anything. If either limit is exceeded, that server contributes no tools to the current request and Eneo writes no partial catalog. Increase a limit only after checking that the larger catalog is intentional.
Tool attempts in chat
An assistant may adjust its input and try again after a tool call fails. If a later call to the same tool on the same server succeeds within the reply, the earlier failed call appears as a muted Previous attempt (Tidigare försök) in the activity list. It no longer adds a red failure icon to the grouped summary. Expand the attempt to inspect its original parameters and error.
This describes the sequence of calls, not a guarantee that every requested operation succeeded. Failures without a later success, interrupted calls and rejected approvals keep their failure or rejection indicators. The same presentation applies when reopening chat history.
Interactive tool views
When MCP Apps are enabled, a tool can show an interactive table, chart or form under its answer. An administrator approves the view’s HTML and requested network policy with the tool. Updated or removed view metadata takes effect when the pending change is approved.
Views run in an isolated browser frame and use the official MCP Apps SDK to communicate with Eneo. An external view asks for permission for each tool call, showing the tool name and arguments. The model’s automatic-tool setting does not grant external views ongoing permission. Every call also rechecks the originating tool’s current approval and the exact view version.
With the built-in Ask a file capability, users can ask “Show me the rows in this file” or “Show orders from last month”. The assistant’s tool descriptions make in-chat results the default for browsing; users do not need to name a tool or request an interactive table. Asking for a downloadable CSV or Excel file still uses file generation.
Users can expand a view beside the conversation and return it inline without losing filters or loaded rows. Views cannot navigate to another page or embed nested frames; opening a link requires the user’s confirmation. Self-contained views are preferred: scripts loaded from an approved external resource origin can change independently of the stored HTML.
Built-in app views ship as Eneo code. Their catalog and view definitions are kept current automatically, and their tool calls follow the user’s automatic-tool preference. External apps require administrator approval and individual consent for each app-initiated tool call.
Apps share the side panel with Eneo’s native document workspace and file previews. The native workspace handles drafts, assistant-driven edits, versions and exports independently of the app feature flag. See Tools, files and views for the complete spreadsheet-to-report workflow and current editing limitations.
Deployment requires MCP_APPS_ENABLED=true, a separate
MCP_APP_CONTENT_BASE_URL, and PUBLIC_ORIGIN. For configuration and supported
extension features, see the repository’s
interactive tool view deployment guide .
Tools and Tool Discovery
Each MCP server exposes a set of tools. When you first add a server, its tools are discovered automatically. After that, you can re-discover tools by clicking Sync Tools.
Viewing Tools
In the MCP servers table, click the expand arrow on a server row to see its tools. Each tool shows:
- Name — The tool’s function name (e.g.
search_documents) - Description — What the tool does
- Enabled/Disabled toggle — Whether the tool is available to assistants
Enabling and Disabling Tools
Use the toggle switch on each tool to enable or disable it. You can also use the All on / All off buttons for bulk changes.
The header shows the count of enabled tools, e.g. 2 / 5 enabled.
Disabling a tool in admin removes it globally for all spaces. To control tools per-space, manage them in the space settings instead.
Syncing Tools
Over time, an MCP server may add new tools, change existing tool descriptions, or remove tools. To detect these changes, click Sync Tools in the tools panel.
What Happens During Sync
Eneo connects to the remote server, fetches the current tool list, and compares it against what is stored locally:
| Scenario | What happens |
|---|---|
| New tool | Created with pending status — requires approval before it becomes active |
| Changed tool (description or schema updated) | Change is stored as pending — the tool continues using its previous version until the change is approved |
| Removed tool (global catalog) | Marked as removed from server — requires approval to delete |
| Unchanged tool | No action needed |
For an identity-forwarding server, an admin sync is only the acting admin’s view. Eneo therefore does not mark a tool as removed merely because that admin cannot see it.
Before every tool-capable model turn, Eneo lists tools on identity-forwarding servers as the signed-in user. A user-only tool that is not in the approved catalog is stored as a pending definition and omitted from that model request. After an admin approves it, a later request may expose it to users for whom the remote server still returns it. Other MCP servers connect when a tool is first called.
If a tool reports an explicit Unauthorized or 401 error, Eneo retains the
server’s original error and adds a short permissions and credentials message to
the failed tool result. This does not change the server’s configuration or
disable its other tools.
Why approval? The approval step is a security measure. It prevents a compromised or misbehaving MCP server from silently injecting or modifying tool definitions. An admin must review and explicitly approve every change before it takes effect.
Pending Changes Banner
When there are pending changes, a banner appears:
1 pending update — Tool uses previous version until update is approved
This means the tool is still active and usable — it simply runs on the previous approved version. Nothing is blocked; the update just waits for your review.
Reviewing Changes
For each pending tool, you can see:
- Description changes — Side-by-side comparison of the current and proposed description
- Removed from server — The tool no longer exists on the remote server
Use the approve (checkmark) or reject (X) buttons on individual tools, or use Approve all / Reject all for bulk actions.
What Approve and Reject Do
| Action | New tool | Changed tool | Removed tool |
|---|---|---|---|
| Approve | Tool becomes active with the proposed description and schema | Pending values replace current values | Tool is deleted from the database |
| Reject | Tool is deleted (never activated) | Pending values are discarded, current values remain | Removed flag is cleared, tool stays active |
Adding MCP Servers to Spaces
After configuring MCP servers in the admin panel, you make them available to assistants by enabling them in individual spaces.
Steps
- Go to Space → Settings
- In the MCP Servers section, toggle the servers you want to enable
- Optionally expand a server to enable/disable individual tools for that space
When a server is added to a space, all its tools are enabled by default. You can then disable specific tools you don’t need.
Security Classification
If your organisation uses security classifications, an MCP server must meet the space’s classification level to be selectable. Servers that don’t meet the requirement are greyed out with a tooltip explaining why.
For example, if a space is classified as “Confidential” (level 3), only MCP servers with a security classification at level 3 or higher can be enabled in that space.
How Eneo builds a tool-enabled request
The approved catalog remains the control point even when each user sees a different remote catalog.
- Eneo loads the approved and enabled definitions from PostgreSQL.
- For identity-forwarding servers, it lists tools as the signed-in user. Independent server probes run concurrently under one bounded preparation deadline.
- Unknown definitions are queued for admin review and remain hidden. Discovery failure or timeout hides that server’s tools for this request.
- The model receives only the approved/live intersection. Descriptions and schemas always come from the approved catalog, not the live response.
- If the model selects a tool, Eneo calls the same remote server and returns the result to the model.
Cross-turn state for stateful servers
Eneo opens a fresh MCP connection for every completion and does not persist or resume MCP protocol sessions. This follows the direction of the MCP specification (revision 2026-07-28 removes protocol-level sessions): a server that needs state to span several user turns should mint an explicit handle and exchange it through tool calls, not rely on transport-session affinity.
The pattern:
- The tool that creates the state (for example, ingesting an uploaded file)
returns a handle in its result text, such as
workspace_id: ws_8a3b. - Later tools accept that handle as an ordinary parameter. Eneo replays earlier tool calls and results to the model on every turn, so the model can read the handle from turn 1 and pass it on turn 5.
- The server binds each handle to the forwarded identity headers
(
X-Eneo-User-Id,X-Eneo-Tenant-Id) and rejects calls where they do not match. Possession of a handle alone must never grant access: handles appear in conversation history and logs by design. - The server expires held state with its own TTL. Eneo does not signal conversation deletion to remote servers.
Two reliability details for server authors: repeat the handle in every tool result (long conversations drop the oldest turns from model context first, so a handle mentioned only once can age out), and state in the tool descriptions that the model should reuse the handle from earlier results.
Security and failure boundaries
| Event | Eneo behavior |
|---|---|
| Live tool is not approved | Store as pending; do not expose it |
| Live schema differs from approved schema | Continue using the approved schema until review |
| User cannot see an approved tool | Omit it from this request |
| Identity-scoped discovery fails or times out | Omit that server’s tools from this request |
| Catalog exceeds an admin limit | Reject the entire catalog for this request; save nothing |
| Server with a credential has a plain-http address | Do not connect. Without identity forwarding, the tool call reports that an administrator must switch the address to https; with it, omit that server’s tools from this request |
| Admin cannot see a user-only tool during sync | Keep the existing tool; absence is not deletion evidence |
Checklist for MCP server operators
- Support Streamable HTTP and return a user-scoped
tools/listwhen identity forwarding is enabled. - Authorize every list and call request; do not rely on the model or Eneo’s catalog as your only access check.
- Keep tool names stable and treat description/schema changes as reviewed contract changes.
- If state continuity matters, mint explicit handles in tool results, bind them to the forwarded identity, and expire them with a TTL.
- Ensure Eneo can reach the endpoint within the configured connect and list-tools timeouts.
Troubleshooting
Connection Failed on Create
Symptoms: Error message when adding a server
Solutions:
- Verify the URL is correct and the server is running
- Check that the URL is reachable from the Eneo backend (firewall, DNS)
- If using authentication, verify the token is correct and that the URL starts with
https://(see Credentials need https) - The server must support Streamable HTTP transport
Sync Shows No Tools
Symptoms: After syncing, no tools appear
Solutions:
- Verify the MCP server actually exposes tools (check its documentation)
- Check backend logs for connection errors
- Try removing and re-adding the server
Tools Not Available in Space
Symptoms: Assistants can’t use tools even though the server is enabled
Solutions:
- Verify the server is enabled in the space settings (not just in admin)
- Check that individual tools are toggled on in the space
- If using security classifications, verify the server meets the space’s classification level
- Check that pending tool changes have been approved — new tools are inactive until approved
Different Users See Different Tools
This is expected when identity forwarding is enabled and the MCP server returns an identity-scoped catalog. Confirm that the remote authorization rules are correct. Eneo will not expose an approved tool to a user when it is absent from that user’s live catalog.
A User-Specific Tool Is Missing
Ask the user to retry once, then check the server’s pending tool changes in admin. The first observation stores an unknown tool for review but deliberately does not expose it. Approve the definition and retry as a user who is authorized by the remote server.
Identity Headers Are Missing or Encoded
- Confirm Forward user identity is enabled on this server.
- One-shot operations without an acting user cannot supply user identity.
- Decode percent-encoded UTF-8 header values on the server before using names or roles.
Stateful Tools Lose Their State
- Verify the server returns its state handle in tool results and accepts it as a parameter on later calls.
- Verify the server did not restart or expire the held state; configure a TTL long enough for normal conversation gaps.
- In very long conversations the oldest turns leave the model’s context; servers should repeat the handle in every result.
Pending Changes Won’t Clear
Symptoms: Tools stuck in pending state
Solutions:
- Approve or reject all pending changes
- If the issue persists, try syncing again to refresh the state