MCP server

Auth

The Extentos auth model. All 18 MCP tools, code generation, validation, on-device simulation, and real-hardware testing work with no account. The one thing that requires sign-in is the browser simulator at extentos.com/s — once linked, sessions are unlimited. Sign-in flows through the OAuth 2.0 device-code pattern (RFC 8628) so it works in any environment, including headless CI and remote shells. The completeAuthLink MCP tool polls the backend after createSimulatorSession returns auth_required, persists the token to ~/.extentos/auth.json, and the original tool call retries automatically. No manual token paste, no payment.

The Extentos auth model is account-required for the browser simulator, free for everything else. All 18 MCP tools, code generation, validation, on-device LocalSimTransport simulation, and real-hardware testing through RealMetaTransport work with no account, no email, no payment — forever. The one thing that requires sign-in is the browser simulator at extentos.com/s. The first time your agent calls createSimulatorSession, the backend returns auth_required and the device-code flow fires to link a free email-only account. The agent handles the handoff programmatically via the completeAuthLink MCP tool — you sign in once in your browser (Google one-click or email + password), the bearer token persists to ~/.extentos/auth.json, and the original tool call retries automatically. From then on, sessions are unlimited. No manual token paste, no payment at any tier. This page covers the identity states, the device-code mechanics, the CLI subcommands, the state files, and the env-var dials.

Identity states

Extentos has two operational identity states (plus a placeholder for future paid features):

StateIdentifierWhat you can doCost
No accountinstallId (per-machine, at ~/.extentos/install_id)All 18 MCP tools. LocalSimTransport. Code generation. Validation. Real-hardware testing through RealMetaTransport (your own Meta credentials).Free forever
Free accountaccountId (linked via device-code flow)Everything above, plus minting browser-simulator sessions. Email + ToS acceptance only.Free, no payment
(Future) Paidn/aReserved for post-launch evolution if Extentos ever introduces paid features. No paid tier exists.n/a

The installId is anonymous and never tied to your identity. The accountId is created when you sign up at the verification URL during the device-code flow. The simulator is gated because it's the one thing that runs on Extentos's backend infrastructure — every other surface either runs locally or talks directly to Meta.

See pricing for the full breakdown.

The device-code flow

Extentos uses the OAuth 2.0 Device Authorization Grant (RFC 8628) — the standard pattern for headless / CLI scenarios where the application can't perform a browser redirect. AI coding agents are exactly that case: the agent runs in a terminal, the developer's browser is somewhere else.

Sequence diagram

Developer        Agent              MCP server         Backend          Verification URL (browser)
    │              │                    │                  │                    │
    │ "build app"  │                    │                  │                    │
    │─────────────▶│                    │                  │                    │
    │              │                    │                  │                    │
    │              │ createSimulator-   │                  │                    │
    │              │ Session(...)       │                  │                    │
    │              │───────────────────▶│                  │                    │
    │              │                    │ POST /api/.../   │                    │
    │              │                    │ session          │                    │
    │              │                    │─────────────────▶│                    │
    │              │                    │                  │                    │
    │              │                    │   auth_required, │                    │
    │              │                    │   deviceCode,    │                    │
    │              │                    │   userCode,      │                    │
    │              │                    │   verificationUrl│                    │
    │              │                    │◀─────────────────│                    │
    │              │ { status:          │                  │                    │
    │              │   "auth_required"  │                  │                    │
    │              │   verificationUrl, │                  │                    │
    │              │   userCode,        │                  │                    │
    │              │   deviceCode }     │                  │                    │
    │              │◀───────────────────│                  │                    │
    │              │                    │                  │                    │
    │              │ open browser       │                  │                    │
    │              │ at verificationUrl │                  │                    │
    │              │─────────────────────────────────────────────────────────▶  │
    │              │                                                            │
    │              │ completeAuthLink({ deviceCode })                           │
    │              │───────────────────▶│                  │                    │
    │              │                    │ poll /api/.../   │                    │
    │              │                    │ token            │                    │
    │              │                    │◀────────────────▶│  pending, pending  │
    │              │                                                            │
    │  signs up at verificationUrl ────────────────────────────────────────────▶│
    │                                                      │ confirms signup    │
    │                                                      │◀───────────────────│
    │              │                    │                  │                    │
    │              │                    │ poll →           │                    │
    │              │                    │   authToken,     │                    │
    │              │                    │   accountId,     │                    │
    │              │                    │   tier           │                    │
    │              │                    │◀─────────────────│                    │
    │              │ persist to         │                  │                    │
    │              │ ~/.extentos/       │                  │                    │
    │              │ auth.json          │                  │                    │
    │              │                    │                  │                    │
    │              │ retry              │                  │                    │
    │              │ createSimulator-   │                  │                    │
    │              │ Session            │                  │                    │
    │              │───────────────────▶│                  │                    │
    │              │                    │ uses bearer token │                   │
    │              │  session ready    │                  │                    │
    │              │◀───────────────────│                  │                    │

What the agent should show the user

When createSimulatorSession returns auth_required, the agent receives both userCode (a 6-character ABCD-1234 string) and verificationUrl (https://extentos.com/activate?code=ABCD-1234 — the URL pre-fills the code). The agent must surface both to the user, with explicit guidance to cross-check the code on the verification page matches:

Sign in to link this terminal:
  1. Open https://extentos.com/activate?code=ABCD-1234 (browser auto-opening)
  2. Confirm the code on the page reads ABCD-1234 (matches what's above)
  3. Sign in (Google or email) and click Approve

I'll detect the link and continue automatically.

This is an RFC 8628 §3.3 anti-phishing cross-check. The verification page renders the user code as a small inline cross-check line ("Verify this matches your terminal: ABCD-1234") above the signup form — it is not an entry field, since the URL already carries the code as a query parameter. The user's job is just to confirm what they see on the page matches what their agent printed before clicking Approve. Without this cross-check, a phishing URL with a different valid code would let an attacker have the user approve linking the attacker's device.

The agent's fixHint in the tool response carries this guidance verbatim — agents that surface fixHint directly to the user (Claude Code, Cursor, Cline default behavior) get this for free.

Backend endpoints

Verified from mcp-server/src/cli/login.ts and mcp-server/src/tools/handlers/completeAuthLink.ts:

EndpointMethodPurpose
/api/auth/device/codePOSTIssue a device code. Body: { scope: "account_full" }. Returns { deviceCode, userCode, verificationUrl, expiresInSeconds, pollIntervalSeconds }
/api/auth/device/tokenPOSTPoll for completion. Body: { deviceCode }. Returns { pending: true, pollIntervalSeconds } while waiting; { authToken, accountId, tier, linkedAt, expiresAt } on approval

Defaults and limits

FieldDefaultNotes
Device-code window600 seconds (10 min)Backend returns the actual expiresInSeconds; completeAuthLink enforces a max of 600
Poll interval5 secondsBackend may bump this via pollIntervalSeconds in poll responses; agent honors
completeAuthLink.maxWaitSeconds600Caller can lower; capped at 600 by the handler
completeAuthLink.pollIntervalSeconds5Range 1-30 (clamped)

HTTP status codes

StatusWhat it meansRetryable
200 (pending: true)User hasn't finished signup yet — keep pollingyes (continue)
200 (with authToken)Approved — token issueddone
403User declined the signup prompt at the verification pageyes (after asking the user to retry)
404Unknown deviceCode (never existed or already consumed)no (need a fresh code)
410Device-code window elapsed (10-min default)yes (need a fresh code)
Other / network failureBackend unreachableyes (after the network issue resolves)

The agent-facing primitive for the device-code flow. After createSimulatorSession returns status: "auth_required", the agent calls completeAuthLink with the returned deviceCode.

Parameters

ParameterTypeRequiredDefaultNotes
deviceCodestringyesn/aFrom the auth_required response
maxWaitSecondsintegerno6001-600
pollIntervalSecondsintegerno51-30

Response on success

{
  "linked": true,
  "tier": "free_account",
  "accountId": "acc_...",
  "linkedAt": "2026-05-01T12:34:56Z",
  "expiresAt": "2027-05-01T12:34:56Z",
  "authTokenFile": {
    "path": "/home/dev/.extentos/auth.json",
    "written": true,
    "error": null
  },
  "pollCount": 3,
  "summary": "Account linked (tier: free_account). Re-invoke createSimulatorSession to use the new bearer token."
}

The pollCount lets the agent know how long it took. The summary is the agent-facing reminder.

Error codes

CodeCauseRetryable
unknown_device_codeBackend doesn't recognize the deviceCodeno — call createSimulatorSession again for a fresh code
device_code_expired10-min window elapsedyes — call createSimulatorSession again
device_code_deniedUser declined at the verification pageyes — ask the developer to retry and accept
backend_unreachableNetwork failure or backend downyes
backend_invalid_responseMalformed poll bodyno — version mismatch
auth_timeoutPolled past maxWaitSeconds without approvalyes — the developer hasn't finished signup yet

Telemetry events fire on every flow outcome: account.login_initiated, account.login_completed (with outcome success | code_expired | user_denied | network_error | polling_aborted), and account.linked (only on success). Tagged with installId, no PII.

CLI subcommands

extentos-mcp is a developer CLI in addition to the MCP server. The auth-related subcommands:

SubcommandWhat it doesWhen to use
loginManually trigger the device-code flow. Initiates the flow against /api/auth/device/code, prints the userCode + verificationUrl, auto-opens the browser, polls until completion.When the developer wants to link before the agent's first createSimulatorSession call (rare — the agent does this automatically when needed)
logoutDelete ~/.extentos/auth.json. Install returns to the anonymous tier (the installId survives).When switching machines, debugging auth state, or revoking the link
whoamiPrint install state — installId, accountId (if linked), tier, auth expiryDiagnosing auth issues, before filing bug reports

Run any of them with:

npx @extentos/mcp-server@latest login
npx @extentos/mcp-server@latest logout
npx @extentos/mcp-server@latest whoami

The login command output looks like:

Extentos account linking

  User code:          ABCD-1234
  Verification URL:   https://extentos.com/activate?code=ABCD-1234

On the page, confirm the 6-character code matches "ABCD-1234" before approving.
Opening browser… (if it doesn't open, paste the URL above)
Polling for up to 600s. Ctrl-C to cancel.

State files

Auth state lives in ~/.extentos/ by default (overridable with EXTENTOS_CONFIG_DIR):

FileContentsCreated by
install_idA per-machine UUID, never expiresFirst MCP server start
auth.json{ authToken, accountId, linkedAt, expiresAt, scope } after linkingSuccessful completeAuthLink (or extentos-mcp login)
consentTelemetry consent state (accepted / declined / unset)First privacy notice acceptance or extentos-mcp accept-privacy / decline-privacy

logout deletes auth.json only. install_id persists — wiping the entire ~/.extentos/ directory creates a fresh anonymous identity with a fresh meter, which is one of the abuse vectors flagged in docs/mcp/ACCOUNTS_AND_PRICING.md (acceptable at MVP scale because it requires the developer to wipe the agent's MCP context each time).

Environment variables

VariableDefaultPurpose
EXTENTOS_BACKEND_URLProduction backendOverride the backend URL the auth endpoints hit. Used for local backend development.
EXTENTOS_CONFIG_DIR~/.extentosOverride the config / auth / consent directory
EXTENTOS_NO_AUTO_OPENunsetSet to 1 to disable browser auto-open. The verification URL is still printed; the developer pastes it manually. Useful for headless / SSH / cloud-hosted-agent environments.

Browser auto-open

When the device-code flow fires, the MCP server attempts to open the verification URL in the developer's default browser via:

PlatformCommand
macOSopen <url>
Windowscmd.exe /c start "" <url>
Linuxxdg-open <url>

If auto-open fails (no GUI, no default handler, sandboxed environment), the URL is still printed to the agent's tool response and the CLI's stdout. The developer copies it into their browser. Set EXTENTOS_NO_AUTO_OPEN=1 to skip the auto-open attempt entirely.

Telemetry consent is a separate mechanism from authentication. The MCP server emits anonymous usage telemetry (tool calls, install events, no source code or PII) tagged with the per-machine installId. Consent is consent-default with first-run notice — the same pattern used by Vercel CLI, Astro, and Vite.

The consent state lives at ~/.extentos/consent. It's set by:

ActionEffect
First MCP tool call after installPrivacy notice injected once into the response (PRIVACY_NOTICE constant in mcp-server/src/index.ts); telemetry stays enabled by default
extentos-mcp accept-privacyRecords explicit consent
extentos-mcp decline-privacyDisables telemetry upload — events still emit locally for debugging but never leave the machine
Setting EXTENTOS_TELEMETRY=0Same as decline-privacy for the current shell, but doesn't persist to the consent file

Telemetry consent has nothing to do with whether you're authenticated. A no-account install can opt out of telemetry; a linked account can opt out too. The two systems are independent.

Frequently asked questions

Why is the simulator account-required when everything else is anonymous?

The browser simulator runs on Extentos's own backend infrastructure — a WebSocket hub keeps the live session alive, the voice proxy handles STT/TTS, and the event log persists. That's the one Extentos surface that costs per-session compute, so it's the one thing we gate behind a free account. Every other Extentos surface (MCP tools, code generation, validation, on-device LocalSimTransport, real-hardware testing through your own Meta credentials) either runs on your machine or talks directly to Meta — no Extentos compute, no account needed. Sign-in is a free email-only account (Google one-click or email + password); once linked, sessions are unlimited.

Why device-code instead of OAuth redirect?

OAuth redirect requires the application to be a web app that can register a callback URL and receive a redirect. An AI coding agent isn't a web app — it's a process running in the developer's terminal. Device-code (RFC 8628) is the OAuth flow designed for exactly this case: the device shows the user a code and a URL, the user authorizes on a separate browser, the device polls to learn the result. No redirect, no callback URL, no web server.

Can I use Extentos without ever signing up?

Yes — every part of Extentos except the browser simulator works with no account, no email, no payment, forever. MCP tools, code generation, validation, on-device LocalSimTransport simulation, and real-hardware testing through your own Meta credentials all stay free without an account. The signup ask only fires the first time your agent tries to mint a browser-simulator session.

Does signing up cost anything?

No. The free account is the only tier that exists. No payment, no card, no upfront commitment. Email + ToS acceptance only (or Google one-click).

What if the device-code expires before I finish signup?

Call createSimulatorSession again to get a fresh deviceCode. The backend issues a new code with a fresh 10-minute window. Your prior install state is preserved.

What if I'm on a headless machine (cloud agent, SSH session)?

Set EXTENTOS_NO_AUTO_OPEN=1. The verification URL prints to the agent's response; the developer copies it to their local browser. The polling continues in the headless environment regardless of where the URL was opened.

How do I rotate or revoke my auth token?

extentos-mcp logout deletes ~/.extentos/auth.json locally. To revoke server-side, log in to your Extentos account at extentos.com and revoke the device. The next API call from the revoked install will get a 401 and prompt re-linking.

Is the auth token a secret?

Yes — treat it like any other API token. It's stored at ~/.extentos/auth.json with file-mode 0600 (owner read/write only). Don't commit it to version control. Don't share it across machines.

Is the installId a secret?

No — it's a per-machine anonymous identifier. Other apps on the same machine can read ~/.extentos/install_id; the same value is sent to api.extentos.com on every tool call as the telemetry key. It's not a credential.

What happens if ~/.extentos/auth.json is corrupted?

The MCP server treats it as not-linked. The next createSimulatorSession call returns auth_required and the device-code flow re-links the install. Or run extentos-mcp login proactively to re-link.