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.
Why HTTP MCP matters
Section titled “Why HTTP MCP matters”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.
Supported transports
Section titled “Supported transports”| Transport | Use case |
|---|---|
stdio | Local servers — spawn a child process, communicate over stdin/stdout |
sse | Remote servers via Server-Sent Events |
http | Remote servers via plain HTTP |
Configuring an HTTP MCP server
Section titled “Configuring an HTTP MCP server”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/defaultThe 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.
Authenticating with talonctl auth-mcp
Section titled “Authenticating with talonctl auth-mcp”Run the one-time OAuth dance for a skill’s MCP server:
# Interactive mode — opens your browsernpx talonctl auth-mcp glean:default
# Headless mode — prints URL and callback instructionsnpx talonctl auth-mcp glean:default --headlessThe CLI performs the full OAuth 2.0 flow:
- RFC 9728 discovery — fetches the server’s
.well-known/oauth-authorization-server - RFC 7591 dynamic client registration — registers Talon as an OAuth client
- PKCE authorization code flow — opens a local browser or prints a URL
- 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.
Automatic token refresh
Section titled “Automatic token refresh”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.
Migration from stdio bridges
Section titled “Migration from stdio bridges”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.
Security notes
Section titled “Security notes”- Token files are written with mode
0600(owner read/write only) - The
authfield is never exposed to provider CLIs — it’s resolved and stripped inside the daemon - Unsupported
auth.kindvalues are rejected at startup with a clear error
For the full configuration reference, see the MCP Integration guide.