Skip to content

Connect a client

askrelay is a remote MCP server with an embedded OAuth 2.1 authorization server, so browser and terminal AI clients connect with no install beyond the relay URL. Authentication is your device credential (from enrollment); there are no passwords and no signup.

Every client does the same dance:

  1. You add the relay’s base URL as a custom MCP server / connector.

  2. The client fetches the relay’s OAuth metadata from /.well-known/oauth-authorization-server — issuer, authorization endpoint, token endpoint, JWKS, registration endpoint. The issuer is the relay’s base URL.

  3. The client registers itself: Dynamic Client Registration at POST /oauth/register (RFC 7591), or a Client ID Metadata Document.

  4. The client opens the relay’s login page in a browser.

  5. You paste your device credential. The relay verifies it and then — before minting anything — re-checks that the device is still active.

  6. The client exchanges its PKCE-bound code for an access token and the askrelay tools appear.

The metadata document is deliberately narrow:

  • response_types — code.
  • grant_types — authorization_code and refresh_token.
  • code_challenge_methods — S256 only. plain is never offered; the downgrade is refused rather than advertised and ignored.
  • token_endpoint_auth_methods — none. Clients are public, and PKCE is the client authentication.
  • client_id_metadata_document_supported — true.

Protected-resource metadata (RFC 9728) is served separately at /.well-known/oauth-protected-resource. It is what a client reads to find the authorization server, and it is where a failed request points: a bad or missing bearer token gets a 401 plus a WWW-Authenticate challenge naming the PRM URL, so a client that guessed wrong can discover its way back.

Three lifetimes, and they are not the same number:

  • The device credential comes out of enrollment and is long-lived — 365 days. It is not the kill switch.
  • The access token lives exactly 1h. It is an EdDSA-signed JWT bound to a single audience, the relay’s base URL.
  • Revocation is immediate, because the login step re-reads the device from the store on every authorization. Revoke the device and the next code mint fails, whatever the credential’s expiry says.

A revoked device and a wrong credential are refused with the same opaque message — “that device credential is not valid” — so the login page is not an oracle for which devices exist.

The MCP endpoint is POST /mcp: stateless Streamable HTTP with JSON responses, protocol 2025-11-25, request bodies capped at 128 KiB. There is no session to resume and no server-initiated stream — every call is client-initiated.

Nine tools appear: check_inbox, get_thread, wait_for_activity, approve_message, decline_message, set_thread_grant, send_message, approve_reply, and discard_reply. They are the same nine for every client.

wait_for_activity blocks until something needs you, or until its timeout expires — and that timeout is clamped to a ceiling chosen from the client type the authorization server stamped on your token. Ask for longer and you get the cap.

Client type on the token Ceiling
claude.ai, claude-desktop 240s
claude-code-remote 25 min
anything else — including ChatGPT 45s

The last row is the default branch, not an oversight: an unrecognized client gets the safe 45s. It is the difference you will feel most between clients.

Unverified

The 240s and 45s figures are the shipped values. The 25-minute one is a placeholder the source itself flags — treat it as subject to change.

Could not verify: the 25-minute `claude-code-remote` ceiling is marked provisional in the source, pending spike S-02.

Unverified

The OAuth server is implemented and unit-tested — the mechanism above is real. What is not confirmable from askrelay is the click path through each vendor’s product. The steps below are the current shape and a starting point; expect wording differences per vendor, and trust the flow, not the labels.

Could not verify: the CLI invocation and the per-vendor menu paths are vendor UI, not askrelay source; end-to-end validation against each live vendor connector is scheduled as spike S-04, which has not run.

Claude Code connects to remote HTTP MCP servers and handles OAuth for you:

Terminal window
claude mcp add --transport http askrelay https://relay.example.com/mcp

On first use it opens the authorization page; paste your device credential. From then on the ten tools are available in the session.

Settings → Connectors → Add custom connector → enter the relay URL (https://relay.example.com/mcp). Claude walks the OAuth flow (Dynamic Client Registration), shows the relay login page, and you paste your device credential. Tools appear as a connected connector.

Add the relay as a connector / MCP server in ChatGPT’s connector settings (Streamable HTTP). ChatGPT authenticates via a Client ID Metadata Document. Complete the OAuth login by pasting your device credential. Note the 45s wait_for_activity ceiling above — it applies here.

What each client can do converges on client-initiated tool calls. No client gets server push right now — not even Claude Code. Every side polls check_inbox, or parks on wait_for_activity until its cap expires.

Built, not yet wired · WP-10

Push is live as a desktop notification: run askrelay daemon and it holds a socket to the relay, raising a notification the moment mail arrives. What is not built is push into the session — channels and an in-terminal approval prompt are WP-10, deferred until real use says they are needed. So today you are notified outside your AI client, then approve inside it.

See Concepts for the delivery model and what the approval gate changes.

Verified against askrelay 2e019ea on . Anything newer than that commit is not reflected here.