Skip to content

Connect remote MCP servers over HTTP with OAuth

PR #212 makes HTTP MCP a first-class transport in Talon. Remote MCP servers no longer need a local stdio bridge or mcp-remote shim. Instead, Talon connects directly over HTTP or SSE and manages OAuth tokens internally.

The previous stdio approach had a fundamental problem: every provider CLI (Claude Code, Gemini CLI, Codex CLI) spawned its own copy of mcp-remote per agent run. The npx → sh → node chain leaked descendant processes that held ports across runs. Talon tried to work around this with /proc walking, env-marker stamping, settle delays, and orphan reaping — all symptoms of the wrong transport choice.

HTTP MCP removes the subprocess entirely. The daemon hits the remote server directly. No process leaks. No port conflicts. No reaping.

TransportUse case
stdioLocal servers — spawn a child process, communicate over stdin/stdout
sseRemote servers via Server-Sent Events
httpRemote servers via plain HTTP

Use url instead of command, and set transport to http or sse:

personas:
- name: assistant
mcp:
- name: glean
transport: http
url: https://contentful-be.glean.com/mcp/default
auth:
kind: oauth2
tokenStore: glean/default

The auth block is stripped before the config reaches the provider. Talon’s resolveMcpServers() materializes the credential into an Authorization: Bearer <token> header automatically. Providers stay completely unaware of OAuth — no per-provider plumbing needed.

Run the one-time OAuth dance for a skill’s MCP server:

Terminal window
# Interactive mode — opens your browser
npx talonctl auth-mcp glean:default
# Headless mode — prints URL and callback instructions
npx talonctl auth-mcp glean:default --headless

The CLI performs the full OAuth 2.0 flow:

  1. RFC 9728 discovery — fetches the server’s .well-known/oauth-authorization-server
  2. RFC 7591 dynamic client registration — registers Talon as an OAuth client
  3. PKCE authorization code flow — opens a local browser or prints a URL
  4. Token exchange — exchanges the code for access + refresh tokens

Tokens persist at <dataDir>/mcp-auth/<skill>/<server>.json with mode 0600 and atomic temp+rename writes. No scattered ~/.mcp-auth files.

The daemon’s OAuthTokenStore lazily refreshes access tokens within 60 seconds of expiry using the cached refresh_token. Concurrent refresh attempts for the same token store are coalesced via in-flight Promise dedup — the refresh token is never burned by parallel exchanges.

If you were using mcp-remote or a local stdio shim for a remote server, remove the command and replace it with transport: http, url, and an auth block. The Glean skill in Talon’s repo was migrated this way — it went from a stdio shim to direct HTTP with OAuth, eliminating subprocess spawn entirely.

  • Token files are written with mode 0600 (owner read/write only)
  • The auth field is never exposed to provider CLIs — it’s resolved and stripped inside the daemon
  • Unsupported auth.kind values are rejected at startup with a clear error

For the full configuration reference, see the MCP Integration guide.