can1357/oh-my-pi · error · Error

this server proxies OAuth through mcp-remote, which caches t

Error message

this server proxies OAuth through mcp-remote, which caches tokens machine-wide in ~/.mcp-auth (shared across every OMP profile). Clear ~/.mcp-auth to force a fresh login, or replace the proxy with ${httpHint} so OMP manages OAuth per profile.

What it means

Thrown by #resolveOAuthEndpointsFromServer when /mcp reauth is requested for a server whose transport is not http/sse (i.e. stdio). OMP's OAuth flow only works over HTTP transports; for stdio servers the child process manages its own credentials, so there is no OMP-side OAuth to refresh. When the command line contains mcp-remote, the message additionally warns that mcp-remote caches tokens machine-wide in ~/.mcp-auth, shared across all OMP profiles, and suggests switching to a direct http config.

Source

Thrown at packages/coding-agent/src/modes/controllers/mcp-command-controller.ts:1210

		const next = { ...config } as MCPServerConfig & { auth?: MCPAuthConfig };
		delete next.auth;
		return next;
	}

	async #resolveOAuthEndpointsFromServer(
		config: MCPServerConfig,
		authChallenge?: MCPAuthChallenge,
	): Promise<OAuthEndpoints> {
		// Stdio servers manage credentials inside the child process; OMP's OAuth
		// flow only applies to http/sse transports. Without this guard the
		// unauthenticated preflight below spawns the child, which happily reuses
		// its own cached tokens (e.g. mcp-remote's machine-wide ~/.mcp-auth) and
		// produces the misleading "reauthorization is not required".
		if (config.type !== "http" && config.type !== "sse") {
			const remoteUrl = config.args?.find(arg => /^https?:\/\//.test(arg));
			const httpHint = `{ "type": "http", "url": ${JSON.stringify(remoteUrl ?? "<remote url>")} }`;
			const usesMcpRemote = [config.command, ...(config.args ?? [])].some(part => part?.includes("mcp-remote"));
			throw new Error(
				usesMcpRemote
					? `this server proxies OAuth through mcp-remote, which caches tokens machine-wide in ~/.mcp-auth (shared across every OMP profile). Clear ~/.mcp-auth to force a fresh login, or replace the proxy with ${httpHint} so OMP manages OAuth per profile.`
					: `stdio servers manage their own credentials, so OMP has no OAuth to reauthorize. If the service supports OAuth over HTTP, configure it as ${httpHint} instead.`,
			);
		}
		// First test if server actually needs auth by connecting without OAuth
		let connectionSucceeded = false;
		let connectionError: Error | undefined;
		try {
			await this.#handleTestConnection(this.#stripOAuthAuth(config), { oauth: false });
			connectionSucceeded = true;
		} catch (error) {
			connectionError = error as Error;
		}

		// Server connected fine without auth. A tool-level challenge overrides
		// this: servers may allow the anonymous handshake yet protect individual
		// tool calls with `_meta["mcp/www_authenticate"]`. Even without such a

View on GitHub (pinned to 9690622007)

Solutions

  1. If it uses mcp-remote: delete ~/.mcp-auth to clear the shared token cache, then log in again.
  2. Better: replace the mcp-remote proxy with a native http config — `{ "type": "http", "url": "<the remote url>" }` — so OMP manages OAuth per profile (run /mcp reauth again afterwards).
  3. For plain stdio servers: re-authorize through the service's own CLI/tooling; OMP has no OAuth to manage. If the service supports OAuth over HTTP, reconfigure it as an http server.

Example fix

// before (stdio via mcp-remote, shared token cache)
{ "type": "stdio", "command": "npx", "args": ["-y", "mcp-remote", "https://mcp.example.com/mcp"] }
// after (native http transport, OMP-managed OAuth per profile)
{ "type": "http", "url": "https://mcp.example.com/mcp" }
Defensive patterns

Strategy: validation

Validate before calling

const cfg = getServerConfig(name);
if (cfg.type !== "http" && cfg.type !== "sse") {
  throw new Error(`/mcp reauth only applies to http/sse servers; '${name}' is ${cfg.type}`);
}

Type guard

function isRemoteMcpConfig(c: MCPServerConfig): c is MCPServerConfig & { type: "http" | "sse"; url: string } {
  return (c.type === "http" || c.type === "sse") && "url" in c && typeof c.url === "string";
}

Try / catch

try {
  await reauthServer(name);
} catch (err) {
  if (err instanceof Error && err.message.includes("mcp-remote")) {
    // stdio/mcp-remote target: switch config to native http and clear ~/.mcp-auth
  } else throw err;
}

Prevention

When it happens

Trigger: Running /mcp reauth <name> where the server config has type stdio (or any type other than http/sse) — either a plain stdio server, or one launched via `npx mcp-remote https://...`.

Common situations: Users copy a Claude Code / Cursor config that wraps a remote MCP server in mcp-remote for OAuth support, then try to re-authorize inside OMP; tokens appear 'stuck' because ~/.mcp-auth is machine-global and profile-independent.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/0dc608c8cfc4f0a8. Report an issue: GitHub.