> For the complete documentation index, see [llms.txt](https://mercure-technologies.gitbook.io/xprem/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://mercure-technologies.gitbook.io/xprem/ai/mcp-server.md).

# MCP Server

xprem ships with a built-in MCP (Model Context Protocol) server, so AI agents such as Claude Code, Cursor or Codex can connect to your deployment and work with it directly: listing apps, branches, channels and updates, following a progressive rollout, publishing a rollback, or digging into device telemetry. An agent always acts as the dashboard account of the person who connected it, and it can never do more than that account could do in the dashboard.

The endpoint lives at `https://<your-server>/mcp` and uses the streamable HTTP transport. There is nothing to enable: the endpoint is present on every deployment that runs the control plane.

{% hint style="info" %}
The MCP server authenticates dashboard accounts, so it requires the control plane. A stateless deployment (no [database](/xprem/installation-guide/database-configuration.md)) does not expose the `/mcp` endpoint.
{% endhint %}

## How authentication works

The server implements the OAuth 2.1 flow. From your side the whole thing is a browser round-trip: the first time an agent connects, it opens your server's consent page, you log in with your dashboard account (single sign-on included, when configured), you approve the client, and the agent is connected.

## What a connected agent may do

Agents inherit the same authorization rules as the dashboard, applied at two levels. When an agent connects, its tool list is filtered: a tool the account cannot use on any visible app is simply absent from the session. Each tool call is then checked again against the specific app it targets, so seeing a tool never grants it on every app. The `whoami` tool returns the exact picture: the account's role and, for every app it can see, each permission granted or denied.

Who can use what depends on whether Enterprise RBAC feature is enabled:

* Without RBAC (the community default), every member can use the read tools on the apps they see, while the certificate download and every write tool (creating or deleting branches and channels, rolling back, republishing) are reserved to admins.
* With Enterprise roles, the per-app permissions listed in the tables below decide, and members can be granted write access app by app. The audit log tool remains admin only in both cases.

The destructive tools (`delete_branch`, `delete_channel`, `rollback_branch`) declare the MCP destructive annotation, so well-behaved clients ask you for an explicit confirmation before calling them. Write tools go through the same services as the dashboard, which means that on Enterprise deployments every action lands in the audit log with the account as actor.

### Core tools

These tools are part of the MIT core and are present on every deployment.

| Tool                   | What it does                                                                                                                               | Permission            |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | --------------------- |
| `whoami`               | Returns the account you are connected as, its role, and for every app it can see the permissions granted and denied.                       | Any signed-in account |
| `get_apps`             | Lists the id and name of every app the account is allowed to see.                                                                          | Any signed-in account |
| `get_branches`         | Lists an app's branches with their release channel, protection flag and current update.                                                    | Visibility on the app |
| `get_runtime_versions` | Lists the runtime versions published on one branch, with update counts, last publication date and active rollout state.                    | Visibility on the app |
| `get_channels`         | Lists an app's release channels with the branch each one points at, its current updates and any rollout in progress.                       | Visibility on the app |
| `get_channel_rollouts` | Lists only the channels currently running a progressive rollout from one branch to another.                                                | Visibility on the app |
| `get_updates`          | Lists published updates newest first, paged, with filters on branch, runtime version, platform, publish group, commit hash and date range. | Visibility on the app |
| `get_update_rollout`   | Reports whether the latest update of a branch and runtime version is being rolled out, and to what percentage on each platform.            | Visibility on the app |
| `get_server_config`    | Returns the deployment's settings as the dashboard settings page shows them, with key-like values masked.                                  | Any signed-in account |
| `get_certificate`      | Returns the app's public code-signing certificate.                                                                                         | `certificate:read`    |
| `create_branch`        | Creates a branch on an app.                                                                                                                | `branch:create`       |
| `delete_branch`        | Deletes a branch and the update files it holds, refusing when it is protected, mapped to a channel, or serving an active rollout.          | `branch:delete`       |
| `create_channel`       | Creates a release channel, optionally mapped to a branch straight away.                                                                    | `channel:create`      |
| `delete_channel`       | Deletes a release channel, after which devices still pointing at it stop receiving updates.                                                | `channel:delete`      |
| `rollback_branch`      | Publishes a rollback to the embedded bundle for one branch and runtime version, recording the reason you pass with it.                     | `update:publish`      |
| `republish_update`     | Republishes a past update, or every platform of a publish group, as the newest update of its branch and runtime version.                   | `update:publish`      |

When roles are not enforced, every permission in that table falls back to admin only, `get_certificate` included.

### Enterprise tools

These tools come from the Enterprise Edition part of the binary, and appear when the feature behind them is configured on your deployment. Your license is checked when a tool runs rather than when the session opens, so activating a key, or letting one lapse, takes effect from the next call on.

| Tool                    | What it does                                                                                                                             | Permission            |
| ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | --------------------- |
| `query_audit_logs`      | Returns the deployment's audit events newest first, filterable by actor, action, target, app and outcome.                                | Admin only            |
| `get_update_health`     | Returns the adoption, success and failure counts of one or more updates, or of a whole publish group, with their history over time.      | Visibility on the app |
| `search_devices`        | Returns a page of the app's registered installs, most recently seen first, filtered on platform, release, location or custom attributes. | `identity:read`       |
| `get_device`            | Returns one install by its EAS client id, with its platform, release, hardware, location and attributes.                                 | `identity:read`       |
| `count_online_devices`  | Counts the devices that contacted the server within a recent window, using the same filters as `search_devices`.                         | `identity:read`       |
| `get_device_attributes` | Lists the attribute keys declared on the app with their type, or the values seen for one key with a device count each.                   | `identity:read`       |
| `query_logs`            | Returns the app's log and crash lines newest first, paged, with filters on severity, free text, event name, device and release.          | `observe:read`        |
| `get_observe_overview`  | Summarises a time window: users, sessions, events and releases, the busiest metrics with their percentiles, and the top cities.          | `observe:read`        |
| `get_metric_breakdown`  | Splits one timing metric by a dimension and returns devices, samples, p50 and p90 per segment, against the overall baseline.             | `observe:read`        |
| `get_observe_events`    | Lists the event names emitted over a window, busiest first, with line, install and session counts.                                       | `observe:read`        |

`identity:read` and `observe:read` are the two permissions every member holds by default, so the device and telemetry tools stay available to members on the apps they can see even when roles are not enforced.

## Connect a client

The MCP endpoint of your deployment is `https://<your-server>/mcp`. With Claude Code, for instance:

```bash
claude mcp add --transport http xprem https://updates.example.com/mcp
```

Clients configured through JSON (Cursor, VS Code and most desktop agents) follow the same shape:

```json
{
  "mcpServers": {
    "xprem": {
      "type": "http",
      "url": "https://updates.example.com/mcp"
    }
  }
}
```

The first request opens the login and consent page in your browser; after that, the client stores and refreshes its tokens on its own. Sessions idle for more than 30 minutes are dropped server side, which is harmless: the client simply re-initializes on its next call.

## Server configuration

There is no dedicated switch for the MCP server; it relies on settings you have already configured:

* A [database](/xprem/installation-guide/database-configuration.md), because accounts, OAuth clients and refresh tokens live in Postgres.
* `BASE_URL` must be the exact public URL your clients reach the server on: it is the OAuth issuer and the audience of every access token, so a mismatch (an internal hostname, a missing path) breaks client discovery. See [server configuration](/xprem/installation-guide/server-configuration.md).
* `JWT_SECRET` signs the MCP access tokens, the same way it signs dashboard sessions. Rotating it invalidates every issued token.

If the server sits behind a reverse proxy, make sure `/mcp`, `/oauth/` and `/.well-known/` are all forwarded on that same public host, since clients resolve every endpoint from `BASE_URL`. If you run several replicas, route `/mcp` with session affinity: an MCP session lives in the memory of the replica that created it.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://mercure-technologies.gitbook.io/xprem/ai/mcp-server.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
