Skip to content

mcp-proxy: cache OAuth tokens for remote MCP servers (blocked on #227) #263

@ojongerius

Description

@ojongerius

Background

Spun out of #262 (originally framed as an OAuth token caching problem; the actual issue there turned out to be an -http port collision in mcp-proxy's approval listener, unrelated to OAuth).

This issue tracks the separate, still-valid idea of OAuth token caching for remote MCP servers.

Why it's worth doing

When mcp-proxy wraps a remote OAuth-protected MCP server (e.g. Atlassian, Slack, Linear), the OAuth flow today is owned entirely by the spawned mcp-remote child process. That has two visible costs:

  1. Cold-start browser round-trip on every fresh session — slow and disruptive UX.
  2. Per-session OAuth statemcp-remote runs its own callback listener on a port; concurrent sessions can collide there too (separate from mcp-proxy: -http port collision crashes second concurrent session #262's issue, which is mcp-proxy's own approval port).

Caching the token on disk after first auth, keyed by -name, would let subsequent sessions skip the browser dance entirely:

  1. Valid cached token → inject directly, no callback listener, no browser
  2. Expired token + refresh token → silent refresh, update cache
  3. No token / refresh failed → full OAuth dance, write cache on success

The architectural question

Token caching only makes sense in mcp-proxy if mcp-proxy owns the OAuth flow. Today it doesn't — mcp-remote does. So this issue is blocked on / scoped against #227 (native HTTP/SSE transport for remote MCP servers).

Two paths forward:

Proposed scope

Token cache layout (when we own it):

  • ~/.agent-receipts/oauth/<name>.token.json — keyed by -name
  • Permissions 0600, sits alongside the existing PEM key
  • Contents: {access_token, refresh_token, expires_at, issuer, scopes}

Decision tree on startup:

  1. Read cache → if valid, inject token, skip OAuth listener
  2. If expired but refresh token present → silent refresh via stored token endpoint, update cache
  3. Else → full flow with HTTP callback (random port, not hardcoded), write cache on success

Acceptance (post #227)

  • Token cache file format + path documented
  • First auth populates the cache
  • Subsequent sessions reuse it without browser round-trip
  • Refresh path tested
  • Concurrent sessions all see the cached token
  • Cache file permissions verified at 0600

Related

Metadata

Metadata

Assignees

Labels

enhancementNew feature or requestgoGo SDK and Go modulessecuritySecurity-related issues and improvements

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions