{"record":{"id":"c880d5361ecc49d1","repo":"Hmbown/CodeWhale","slug":"mcp-oauth-setup-cancelled-after-plugin-authority-c","errorCode":null,"errorMessage":"MCP OAuth setup cancelled after plugin authority changed","messagePattern":"MCP OAuth setup cancelled after plugin authority changed","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"warning","filePath":"crates/tui/src/mcp.rs","lineNumber":1554,"sourceCode":"                        } else {\n                            attempt.stop()\n                        }\n                    }));\n            }\n            client_builder =\n                configure_mcp_proxy(client_builder, config.reviewed_plugin.is_some(), |name| {\n                    std::env::var(name)\n                });\n            let client = client_builder.build()?;\n            let oauth_runtime = if config.reviewed_plugin.is_some() {\n                None\n            } else {\n                match oauth::build_default_headers(&config.headers, &config.env_headers) {\n                    Ok(default_headers) => {\n                        let prepared = tokio::select! {\n                            biased;\n                            _ = cancel_token.cancelled() => {\n                                anyhow::bail!(\n                                    \"MCP OAuth setup cancelled after plugin authority changed\"\n                                )\n                            }\n                            prepared = oauth::McpOAuthRuntime::from_server_config(\n                                &name,\n                                &config,\n                                default_headers,\n                            ) => prepared,\n                        };\n                        match prepared {\n                            Ok(runtime) => runtime,\n                            Err(err) => {\n                                if config.reviewed_plugin.is_some() {\n                                    tracing::warn!(\n                                        target: \"mcp\",\n                                        server = %name,\n                                        \"failed to prepare reviewed plugin MCP OAuth runtime; provider details suppressed; continuing without stored OAuth token\"\n                                    );","sourceCodeStart":1536,"sourceCodeEnd":1572,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/8880682c63083a91624de936797efa3ce9e498fd/crates/tui/src/mcp.rs#L1536-L1572","documentation":"While preparing OAuth for an HTTP MCP server, connect_with_policy races McpOAuthRuntime::from_server_config against the connection's CancellationToken in a biased select (crates/tui/src/mcp.rs:1551-1563). If the token fires first - the cross-process authority watcher revoked a plugin receipt, or the setup was torn down - OAuth preparation aborts with this message instead of continuing half-configured. It is a transient cancellation, not a permanent failure.","triggerScenarios":"A plugin trust/revoke/reload in another process lands exactly while OAuth token storage or dynamic client registration is being read; connection teardown races a slow authorization-server metadata fetch.","commonSituations":"Two TUI instances sharing a plugin directory; /plugin reload executed during startup; slow or flaky OAuth metadata endpoints widening the race window.","solutions":["Retry the connect once plugin/config churn has settled - the race is transient by construction.","Avoid running /plugin trust, /plugin revoke or /plugin reload concurrently with live MCP connections.","If it recurs, fix reachability/latency of the authorization server's metadata endpoint so OAuth preparation completes quickly."],"exampleFix":"// before\nlet conn = McpConnection::connect_with_policy(name, cfg, &timeouts, policy).await?;\n// after: retry once on this transient cancellation\nlet conn = match McpConnection::connect_with_policy(name, cfg.clone(), &timeouts, policy).await {\n    Ok(conn) => conn,\n    Err(err) if err.to_string().contains(\"OAuth setup cancelled\") => {\n        McpConnection::connect_with_policy(name, cfg, &timeouts, policy).await?\n    }\n    Err(err) => return Err(err),\n};","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"let conn = match McpConnection::connect_with_policy(name, cfg.clone(), &timeouts, policy).await {\n    Ok(conn) => conn,\n    Err(err) if err.to_string().contains(\"OAuth setup cancelled\") => {\n        // Transient cancellation race; safe to retry after churn settles.\n        McpConnection::connect_with_policy(name, cfg, &timeouts, policy).await?\n    }\n    Err(err) => return Err(err),\n};","preventionTips":["Do not run /plugin trust / revoke / reload while MCP connections are being established.","Avoid two instances sharing a plugin directory while one reconnects.","Keep authorization-server metadata endpoints fast and reachable."],"tags":["oauth","mcp","cancellation","concurrency"],"backgroundTag":null,"analyzedSha":"8880682c63083a91624de936797efa3ce9e498fd","analyzedAt":"2026-08-16T11:31:27.956Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}