gemini-cli icon indicating copy to clipboard operation
gemini-cli copied to clipboard

MCP OAuth redirectUri is using a random port even when a port is specified in the config

Open drstrangelooker opened this issue 2 months ago • 7 comments

What happened?

It is impossible to MCP Auth with a fixed redirect uri. Gemini should be listening on http://localhost:7777/oauth/callback for oauth redirects, but Gemini is listening using a random port even when that uri is specifically requested.

What did you expect to happen?

Gemini should listen on the correct uri

Client information

Client Information

Run gemini to enter the interactive CLI, then run the /about command.

│ About Gemini CLI                                                                                                                      │
│                                                                                                                                       │
│ CLI Version                                    0.19.0                                                                                 │
│ Git Commit                                     90a5dc3da                                                                              │
│ Model                                          auto                                                                                   │
│ Sandbox                                        no sandbox                                                                             │
│ OS                                             linux                                                                                  │
│ Auth Method                                    gemini-api-key                                                                         │
│ User Email                                     [email protected]                                                               │
│ GCP Project                                    google.com:looker-sandbox 

Login information

API key

Anything else we need to know?

This used to work

drstrangelooker avatar Dec 03 '25 01:12 drstrangelooker

Found possible duplicate issues:

  • #12551

If you believe this is not a duplicate, please remove the status/possible-duplicate label.

gemini-cli[bot] avatar Dec 03 '25 01:12 gemini-cli[bot]

Found possible duplicate issues:

If you believe this is not a duplicate, please remove the status/possible-duplicate label.

Not the same issue. I cannot remove the possible duplicate label, however.

drstrangelooker avatar Dec 03 '25 01:12 drstrangelooker

@drstrangelooker redirect URI works fine for me building off main...

jackwotherspoon avatar Dec 04 '25 13:12 jackwotherspoon

I'll test again on the next release.

drstrangelooker avatar Dec 04 '25 15:12 drstrangelooker

https://github.com/google-gemini/gemini-cli/pull/12520 does not take into consideration ~/.gemini/setting.json:.mcpServers.<SERVER_NAME>.oauth.redirectUri's port number when creating the oauth callback server

doc sample https://github.com/google-gemini/gemini-cli/blob/v0.19.1/docs/tools/mcp-server.md#oauth-configuration-properties:

{
  "mcpServers": {
    "<SERVER_NAME>": {
      "oauth": {
        "enabled": "true",
        "redirectUri": "http://localhost:7777/oauth/callback",
      }
    }
  }
}

Workaround for Linux/MacOS:

OAUTH_CALLBACK_PORT=7777 gemini

Workaround for Windows:

$env:OAUTH_CALLBACK_PORT = 7777
gemini

agabani avatar Dec 04 '25 21:12 agabani

#12520 does not take into consideration ~/.gemini/setting.json:.mcpServers.<SERVER_NAME>.oauth.redirectUri's port number when creating the oauth callback

interesting so maybe it respects project/workspace level redirectUri but not user level?

Let me test that.

jackwotherspoon avatar Dec 04 '25 22:12 jackwotherspoon

Here's a sample fix that resolves the issue.

diff --git a/packages/core/src/mcp/oauth-provider.ts b/packages/core/src/mcp/oauth-provider.ts
index 06f5a95cf..069eac546 100644
--- a/packages/core/src/mcp/oauth-provider.ts
+++ b/packages/core/src/mcp/oauth-provider.ts
@@ -264,9 +264,13 @@ export class MCPOAuthProvider {
    * The server will listen on the specified port (or port 0 for OS assignment).
    *
    * @param expectedState The state parameter to validate
+   * @param redirectPort The port of the redirect URI
    * @returns Object containing the port (available immediately) and a promise for the auth response
    */
-  private startCallbackServer(expectedState: string): {
+  private startCallbackServer(
+    expectedState: string,
+    redirectPort: string | undefined,
+  ): {
     port: Promise<number>;
     response: Promise<OAuthAuthorizationResponse>;
   } {
@@ -354,7 +358,7 @@ export class MCPOAuthProvider {
         });
 
         // Determine which port to use (env var or OS-assigned)
-        const portStr = process.env['OAUTH_CALLBACK_PORT'];
+        const portStr = redirectPort ?? process.env['OAUTH_CALLBACK_PORT'];
         let listenPort = 0; // Default to OS-assigned port
         if (portStr) {
           const envPort = parseInt(portStr, 10);
@@ -794,7 +798,14 @@ export class MCPOAuthProvider {
 
     // Start callback server first to allocate port
     // This ensures we only create one server and eliminates race conditions
-    const callbackServer = this.startCallbackServer(pkceParams.state);
+    const redirectUriPort = config.redirectUri
+      ? getPort(config.redirectUri)
+      : undefined;
+
+    const callbackServer = this.startCallbackServer(
+      pkceParams.state,
+      redirectUriPort,
+    );
 
     // Wait for server to start and get the allocated port
     // We need this port for client registration and auth URL building
@@ -1023,3 +1034,29 @@ ${authUrl}
     return null;
   }
 }
+
+/**
+ * Get the port of the URL. If none is explicity defined, the protocol's default is returned.
+ *
+ * @param url URL
+ * @returns Returns a port or undefined if one can not be determined
+ */
+function getPort(url: string): string | undefined {
+  const u = new URL(url);
+
+  if (u.port) {
+    return u.port;
+  }
+
+  switch (u.protocol) {
+    case 'http:': {
+      return '80';
+    }
+    case 'https:': {
+      return '443';
+    }
+    default: {
+      return undefined;
+    }
+  }
+}
diff --git a/docs/tools/mcp-server.md b/docs/tools/mcp-server.md
index 5d24407f5..9fae194fb 100644
--- a/docs/tools/mcp-server.md
+++ b/docs/tools/mcp-server.md
@@ -235,7 +235,7 @@ Use the `/mcp auth` command to manage OAuth authentication:
 - **`tokenUrl`** (string): OAuth token endpoint (auto-discovered if omitted)
 - **`scopes`** (string[]): Required OAuth scopes
 - **`redirectUri`** (string): Custom redirect URI (defaults to
-  `http://localhost:7777/oauth/callback`)
+  `http://localhost:<RANDOM_PORT>/oauth/callback`)
 - **`tokenParamName`** (string): Query parameter name for tokens in SSE URLs
 - **`audiences`** (string[]): Audiences the token is valid for

agabani avatar Dec 04 '25 23:12 agabani