{"record":{"id":"12d75660b10d13fc","repo":"Hmbown/CodeWhale","slug":"oauth-logout-is-only-supported-for-url-based-mcp-s","errorCode":null,"errorMessage":"OAuth logout is only supported for URL-based MCP servers","messagePattern":"OAuth logout is only supported for URL-based MCP servers","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/mcp/oauth.rs","lineNumber":561,"sourceCode":"        http_headers,\n        env_headers,\n        scopes,\n        oauth_client_id,\n        oauth_resource,\n        callback_port,\n        callback_url,\n    )\n    .await?\n    .finish()\n    .await\n}\n\npub fn delete_oauth_tokens_for_server(name: &str, server: &McpServerConfig) -> Result<bool> {\n    if server.reviewed_plugin.is_some() {\n        bail!(\"OAuth storage is disabled for plugin-contributed MCP servers\");\n    }\n    let Some(url) = server.url.as_deref() else {\n        bail!(\"OAuth logout is only supported for URL-based MCP servers\");\n    };\n    delete_oauth_tokens(name, url)\n}\n\nfn server_has_manual_authorization(server: &McpServerConfig) -> bool {\n    server.bearer_token_env_var.is_some()\n        || contains_authorization_header(&server.headers)\n        || contains_authorization_header(&server.env_headers)\n}\n\npub fn build_default_headers(\n    http_headers: &HashMap<String, String>,\n    env_headers: &HashMap<String, String>,\n) -> Result<HeaderMap> {\n    let mut headers = HeaderMap::new();\n    for (name, value) in http_headers {\n        insert_header(&mut headers, name, value)?;\n    }","sourceCodeStart":543,"sourceCodeEnd":579,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/tui/src/mcp/oauth.rs#L543-L579","documentation":"The logout path mirrors the login path: OAuth tokens are keyed by server URL (delete_oauth_tokens(name, url)), and a stdio/command server has no URL and never obtained OAuth tokens (oauth.rs:561). The bail happens before any storage lookup.","triggerScenarios":"Calling delete_oauth_tokens_for_server on an McpServerConfig whose url field is None (command-based stdio server).","commonSituations":"Scripts or UI flows that call logout for every configured server without filtering by transport; a server entry that was switched from url to command while stale OAuth tokens were expected; trying to 'clear credentials' on a local process server.","solutions":["Skip logout for stdio servers — remove static credentials (bearer_token_env_var, env vars) instead","If the server should be URL-based, fix the config by adding its url, then retry logout","Filter server lists by server.url.is_some() before offering the logout action"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"if server.url.is_none() {\n    // stdio server: clear static credentials instead of OAuth tokens\n    return Ok(false);\n}","typeGuard":"fn supports_oauth_logout(server: &McpServerConfig) -> bool {\n    server.url.is_some() && server.reviewed_plugin.is_none()\n}","tryCatchPattern":null,"preventionTips":["Gate every logout call site on server.url.is_some()","Combine the guard with the reviewed_plugin check from login/storage rules","Automate config audits: stdio entries should never reference OAuth lifecycle commands"],"tags":["oauth","mcp","configuration","stdio"],"backgroundTag":"oauth-configuration-error","analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}