MCP OAuth redirectUri is using a random port even when a port is specified in the config
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
Found possible duplicate issues:
- #12551
If you believe this is not a duplicate, please remove the status/possible-duplicate label.
Found possible duplicate issues:
If you believe this is not a duplicate, please remove the
status/possible-duplicatelabel.
Not the same issue. I cannot remove the possible duplicate label, however.
@drstrangelooker redirect URI works fine for me building off main...
I'll test again on the next release.
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
#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.
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