Skip to main content

Orbit-as-MCP: hosted server handshake

Devotel Orbit can be exposed as an MCP server at POST/GET /api/v1/mcp, so an external MCP client — Claude, ChatGPT, or an IDE agent — operates your tenant through a curated tool catalog. This page documents that inbound surface: the JSON-RPC handshake, the scoped catalog, and the dashboard page that exercises it without any client setup.

Inbound vs outbound MCP

MCP comes up in two directions on the platform, and they are separate features:
  • Inbound (this page): Orbit acts as the server. An external MCP client calls the hosted endpoint and drives your tenant through tool methods such as list_campaigns, send_sms, or list_numbers.
  • Outbound: your Orbit agents register third-party MCP servers and call their tools. Those registrations are managed under the Agents section; the Probe MCP Server endpoint dry-runs a registration before it is saved.
Nothing here depends on a local npx process — the inbound server is hosted behind the API gateway. The Claude / Cursor client setup guide covers connecting specific clients; this page is the protocol reference for the surface they (and the dashboard) talk to.

The JSON-RPC handshake

The endpoint is a single JSON-RPC 2.0 service (POST /api/v1/mcp) that always replies with a plain JSON body — it never upgrades to an SSE stream. A GET /api/v1/mcp probe returns the same capability descriptor without a body of methods. The first call is initialize:
Request
Response
Authentication is the platform’s normal API-key bearer — the same X-API-Key or Authorization: Bearer header every other route accepts. There is no OAuth handshake or MCP-specific credential.

Fetching the scoped tool catalog

Call tools/list to read the catalog your API key is scoped for:
Request
Response
Each tools[] row carries name, an optional description, and an optional inputSchema. The full catalog is listed under Available tools in the client setup guide.

How the dashboard page uses it

Open Dashboard → Developer → MCP Server. The page is the no-client path for validating all of this from the browser:
  1. Test connection fires the initialize request above and, on success, marks the session connected (it renders the server name, protocol version, transport, and server version as badges).
  2. Only once connected does the page issue tools/list — the catalog fetch is gated on the connected flag, so a failed probe never renders stale rows.
  3. The two raw request bodies the client island sends are exactly the curl payloads shown in the previous two sections — run them in a terminal to debug outside the page.
If tools/list returns an empty tools array, the page says so explicitly and points you at the scopes fix (below) rather than hanging on an empty list.

Scoping the catalog

The catalog is scoped per API key: each tool is gated by a matching OAuth-style scope on the key (for example messages:read, campaigns:read, voice:write). A key with narrower scopes sees fewer tools, and a tool your key lacks scope for is indistinguishable from a tool that doesn’t exist — the response gives no hint either way. Grant or revoke scopes under Dashboard → Settings → API Keys, then re-run Test connection to refresh the catalog.

Security notes

Because the inbound surface reuses the platform’s API-key bearer auth:
  • Revoking or rotating the key in Settings → API Keys governs access — an MCP client goes dark the same moment a REST integration would.
  • Every tools/call is audit-logged and rate-limited per tenant, on top of the underlying route’s own checks.

See also