Carrier
Blog
6 min read

How Carrier's MCP architecture works — HTTP transport + Durable Objects

Most MCP servers run as a local stdio process — a child spawned by the AI client, living and dying with the conversation. That works fine for file-system tools or shell commands. It breaks down the moment you need persistent session state, cross-region consistency, or a server that can outlive the client process. Carrier has different requirements, and the architecture reflects that.


Why stdio isn't enough for fleet ops

An eSIM fleet operation isn't stateless. When you ask Claude to activate a batch of ICCIDs, Carrier needs to track which ones succeeded, which ones hit OCS rate limits, and which ones are pending a carrier-side confirmation. That state has to live somewhere reliable — not in the AI context window, and not in a process that vanishes when the conversation ends.

There's also a latency problem. stdio MCP requires the server binary to be on the same machine as the client. For a globally distributed fleet, that means your AI in London is making OCS calls through a local proxy to a server in the US — adding two hops when you need one.

StreamableHTTP: MCP over the network

The MCP 2025-03-26 specification introduced the StreamableHTTP transport. Instead of piping JSON-RPC over stdin/stdout, the client opens an HTTP connection to a remote endpoint. Tool calls are HTTP POST requests; streaming results come back as Server-Sent Events on the same connection.

This matters for Carrier because it means:

Install is a single command:

claude mcp add --transport http carrier https://mcp.carrier.llc/mcp

Durable Objects: one session, one actor

The harder problem is session state. HTTP is stateless by default — each request hits a different Worker instance. For Carrier, that's a problem: OCS operations can span multiple tool calls (list → inspect → modify → confirm), and the intermediate state needs to be consistent.

Cloudflare Durable Objects solve this with a single-instance actor model. When you authenticate with Carrier MCP, a CarrierMcpAgent Durable Object is created for your session. Every subsequent tool call routes to the same instance — guaranteed by the Cloudflare runtime, regardless of which edge node handles the HTTP request.

The Durable Object holds:

When the session ends, the Durable Object hibernates. If you reconnect with the same OAuth token, it wakes up and restores context. P50 latency from a cold wake is under 50 ms; from a warm instance it's under 10 ms.

The auth flow end-to-end

The first time a client connects, it initiates an OAuth 2.1 + PKCE flow against mcp.carrier.llc/oauth/authorize. The browser opens, you sign in to your Carrier account (passkeys supported — no password needed), and you paste your eSIMVault API token. Carrier encrypts it with AES-GCM 256-bit and stores it in Cloudflare KV, bound to your user ID.

From that point, the client holds an opaque bearer token. The eSIMVault credential never leaves Carrier's infrastructure — every tool call is executed server-side, authenticated with your stored token, and the result returned to the client.

Scope gates in practice

Not every tool call should be available to every session. Carrier enforces three scope tiers at the Durable Object level, before any OCS call is made:

If a client attempts a write tool on a read-only session, the Durable Object rejects it before the OCS ever sees the request — no credits burned, no partial state written.

What this means for builders

The practical upshot: you point your AI client at a URL, authenticate once, and get a stateful, low-latency, scope-enforced connection to your entire OCS. No local server to maintain, no process to restart, no credential files in your home directory.

For teams running multi-agent workflows — where one agent queries fleet state while another processes billing — each agent gets its own Durable Object session. They can't interfere with each other's state, and audit logs capture every tool call independently.

The full tool reference is at mcp.carrier.llc. Questions: support@carrier.llc.