Blog · Orma · How we built it · · 6 min read

How we built Orma's public API and MCP server

One prompt turned Orma from a private dashboard into an open-source platform with OAuth, eleven scopes, and a remote MCP server AI tools can use.

Orma's App Usage dashboard showing total time, categories and top apps

Orma (formerly xeve) started as a private dashboard. A macOS tracker, a web app, and a backend that only its own clients could talk to. The only way to get your data out was to look at a chart or export a CSV. That changed in August 2026, when a single prompt shifted the direction of the whole product.

The decision

The context was a sign-in bug. While looking at what the web app was doing on first load, the conversation shifted to what the product should become:

yes i want to open source and self hostable with plugin support

That sentence became a plan, then a branch, then the largest single piece of work in the repository. The result: the backend code published as open source, a plugin host where each integration connector — Spotify, GitHub, Whoop — became a loadable module the server schedules, and a public ingest API with per-device tokens so the native apps could communicate with it.

The plugin system mattered because it changed the shape of adding an integration. Previously, connecting a new service meant a function in a fixed platform nobody could inspect or run locally. With the plugin host, a new connector is a module with a declared schema and a cron schedule. The team can add one, and so can anyone running the server from the repository.

Giving machines a way in

Orma already tracked app usage, coding time, GitHub activity, heart rate, and Spotify history. The dashboard made that visible to you. The question was whether an AI assistant could use the same data — to answer "what did I actually work on last Tuesday?" or "has my deep work time dropped?" — and do it with your permission, not by scraping a page.

The answer required a public front door.

PR #133, merged on 21 August 2026, added three things at once:

OAuth 2.0. Access tokens issued through the flow are the same objects as device tokens in the settings page — same revocation list, same audit trail. Eleven scopes, enforced on every route. A replayed authorization code or a reused refresh token triggers full revocation of the entire grant, not just the duplicate.

A remote MCP server at api.xeve.io/mcp: Streamable HTTP, stateless, 16 read-only tools. Each tool is a name, a scope, and an API path. The actual read runs through the same route as the web dashboard, so the access control and data logic happen once, in code that already had tests. A tool cannot read what its token was not granted.

Markdown from every page. Every public page on orma.xeve.io now answers Accept: text/markdown and has a .md sibling URL. The developer docs, the OpenAPI spec, /.well-known/mcp and llms.txt all landed at the same time, so a machine landing on any page has somewhere to go next.

By the end of that PR there were 641 server tests and 27 browser specs — 58 server tests and 19 browser specs new to this PR — all green.

Orma's Coding dashboard showing coding time broken out by project, language and editor The Coding dashboard. A connected AI tool with the right scope can read the same data.

The bugs that appeared while the system was live

The week after the main work merged, two prompts came in within a day of each other.

no data has been updated so far in my dashboard for today can u check what broke

The cause: a hung upload in the macOS tracker. One failed sync attempt had stalled the retry queue, and no new data was reaching the dashboard. The fix changed how the tracker handles a stuck upload: each attempt gets a time budget, and when it runs out, the next session goes through instead. A single stalled upload can no longer block everything behind it.

when i click disconnect in settings for spotify its not disconnecting , why

The Spotify connector was accepting the disconnect request but not acting on it. Both the connect and disconnect paths needed fixing, and neither had been tested end to end.

Neither bug was introduced by the recent work. Both were pre-existing. They surfaced because more code paths were being exercised with real data and real sessions. That is the argument for running software under live conditions before assuming it works: a passing unit test proves a function works in isolation. It says nothing about whether that function gets called, or whether the paths between functions are wired correctly.

What Orma is now

Orma is open source at github.com/xeveio/xeve and free during early access at orma.xeve.io. The web dashboard has 24+ pages, a correlation engine that computes 19 metric pairs automatically, an AI weekly digest, and team dashboards with role-based views. The macOS and Windows trackers run without timers. The VS Code extension and Claude Code hook track coding time. The iPhone companion adds HealthKit, location, and widgets.

The public API and MCP server mean that an AI tool can now read your Orma data with your explicit permission. Eleven scopes let you grant access to what you want read, nothing else. A question like "how much time did I actually spend on writing this month?" has an answer that comes from real tracking data rather than a guess.

The whole arc started with one sentence. The weeks that followed were mostly working out what it meant in code — and finding the things that had been quietly broken for a while.