xprem: observability, device identity and an MCP server
- Server
- Dashboard
- eoas CLI
- Observe
- MCP
- Enterprise
- Helm & Docker
Expo Open OTA is now xprem. Same project, same maintainers, same licenses, renamed to respect Expo's trademark. xprem is not affiliated with, sponsored or endorsed by Expo.
The rename
Everything is republished under the new name and every old name keeps working:
| New | Old, still published | |
|---|---|---|
| Repository | mercuretechnologies/xprem | redirects |
| Docker image | ghcr.io/mercuretechnologies/xprem | ghcr.io/mercuretechnologies/expo-open-ota, ghcr.io/axelmarciano/expo-open-ota |
| Helm chart | oci://ghcr.io/mercuretechnologies/charts/xprem | oci://ghcr.io/mercuretechnologies/charts/expo-open-ota |
| Docs | mercure-technologies.gitbook.io/xprem | |
| CLI | npx eoas, unchanged |
No environment variable, API route or bucket layout changes. Bump the tag, switch image and chart names when you want.
Observability with expo-observe
The server is a backend for Expo's expo-observe SDK: point extra.eas.observe.endpointUrl at it and keep the stock SDK. Native and JS crashes, cold launch, bundle load, time to first render, time to interactive, sessions, and your own events and logs are stored with the update, branch and channel that produced them.
The data lands in your ClickHouse. The dashboard gets an Observe section: an overview with a live device map, per-metric percentiles with breakdowns by device model, OS, region, app version and screen (read from expo-router or react-navigation), an event explorer and a log stream. Grafana, PostHog or Datadog can read the same tables.
Device identity
Every device that checks in is registered per app: first and last seen, model, OS, current update, branch, runtime version and location. The Devices view lists and searches them, with a live online count.
Custom device attributes (Enterprise): declare an allowlist of typed keys, then send $set, $set_once and $unset operations from the app through the expo-observe pipeline. Each key becomes a filter and a breakdown dimension across metrics, events, logs and update health.
MCP server
The server exposes /mcp. Agents sign in with OAuth 2.1 as dashboard users: dynamic client registration, PKCE, refresh tokens with revocation, no API keys. Every call runs with that user's per-app permissions.
16 tools ship under MIT and cover the dashboard operations: list apps, branches, channels and updates, inspect rollouts, create and delete branches and channels, roll back, republish. 10 more come with the Enterprise edition and read the observability dataset: update health, metric breakdowns, events, logs, audit logs and device search.
Publish groups
One eoas publish produces an iOS update and an Android update. They are now linked by a publish group. The dashboard shows them as one row with health aggregated over both platforms, and republish and rollback act on the whole group. Older CLIs keep publishing ungrouped rows.
Republish and roll back from the dashboard
Revert a branch to its previous update, or put any past update or publish group back live, from the Updates feed.
GeoIP
Two options: trust the location headers your CDN already sets (Cloudflare, CloudFront, Vercel, or custom X-Geo-* headers), or give the server MaxMind GeoLite2 credentials and it downloads and refreshes the database itself. Location feeds the device map and adds region as a breakdown dimension. Configure neither and the rest works as before.
Server configuration wizard
npx eoas server:init walks through storage, delivery, database, cache, key store, GeoIP and replicas, then writes a .env for Docker or a values.yaml plus a gitignored secrets file for Helm. It reuses an existing master key on re-run. npx eoas server:validate checks a config before deploy.
Hot path
Manifest signatures are cached, keyed by content hash. App config and channel mappings get short-TTL caches. A new S3 presigned URL delivery mode serves assets from a private bucket with no CDN and no traffic through the server.
A reproducible k6 load test ships with the repo. One 1-vCPU instance served real expo-updates polls from 100,000 devices with code signing and telemetry on, at 938 req/s at the peak of a full-fleet rollout, with zero errors. Method and raw data in test/load/results.
Security
- Sign-in, token issuance and uploads are rate limited.
- Dashboard sessions can be revoked server-side. Refresh tokens rotate with session-version invalidation.
- API tokens carry specific roles instead of blanket access.
- Upload requests are validated before touching storage.
- GitHub workflows run read-only by default.
Also
DISABLE_DEVICE_TELEMETRY=trueswitches off the device registry and telemetry ingest.eoasasks before overwriting an existing config.- Dashboard: debounced filters, loading skeletons, richer update details.
- pgx 5.9.2.