feat(mcp): improve OAuth auth UX - post-auth feedback, i18n, clear auth, and bug fixes

- Show tool count and completion message after successful authentication
- Auto-navigate back to server details after auth success (2s delay)
- Add structured i18n messages for OAuth display (core emits key/params, CLI translates)
- Add 'Clear Authentication' option for servers with stored OAuth tokens
- Fix: clearing auth now disconnects server (not just deleting tokens)
- Fix: auth popup infinite loop caused by onSuccess triggering reload/remount cycle
- Add ToolRegistry.disconnectServer() (disconnect without adding to exclusion list)
- Add i18n translations for all 6 languages (en/zh/de/ja/pt/ru)
This commit is contained in:
LaZzyMan 2026-03-12 20:46:59 +08:00
parent 17581c1e8a
commit dcf986838c
13 changed files with 213 additions and 21 deletions

View file

@ -25,6 +25,7 @@ import { useConfig } from '../../contexts/ConfigContext.js';
import {
getMCPServerStatus,
DiscoveredMCPTool,
MCPOAuthTokenStorage,
type MCPServerConfig,
type AnyDeclarativeTool,
type DiscoveredMCPPrompt,
@ -109,6 +110,16 @@ export const MCPManagementDialog: React.FC<MCPManagementDialogProps> = ({
(t) => !t.name || !t.description,
).length;
// Check if OAuth tokens exist for this server
let hasOAuthTokens = false;
try {
const tokenStorage = new MCPOAuthTokenStorage();
const credentials = await tokenStorage.getCredentials(name);
hasOAuthTokens = credentials !== null;
} catch {
// Ignore errors when checking token existence
}
serverInfos.push({
name,
status,
@ -118,6 +129,7 @@ export const MCPManagementDialog: React.FC<MCPManagementDialogProps> = ({
invalidToolCount,
promptCount: serverPrompts.length,
isDisabled,
hasOAuthTokens,
});
}
@ -249,6 +261,36 @@ export const MCPManagementDialog: React.FC<MCPManagementDialogProps> = ({
}
}, [fetchServerData]);
// Clear OAuth authentication tokens and disconnect the server
const handleClearAuth = useCallback(async () => {
if (!config || !selectedServer) return;
try {
setIsLoading(true);
const tokenStorage = new MCPOAuthTokenStorage();
await tokenStorage.deleteCredentials(selectedServer.name);
debugLogger.info(
`Cleared OAuth tokens for server '${selectedServer.name}'`,
);
// Disconnect the server so it no longer appears as connected
const toolRegistry = config.getToolRegistry();
if (toolRegistry) {
await toolRegistry.disconnectServer(selectedServer.name);
}
// Reload to update hasOAuthTokens flag and server status
await reloadServers();
} catch (error) {
debugLogger.error(
`Error clearing OAuth tokens for server '${selectedServer.name}':`,
error,
);
} finally {
setIsLoading(false);
}
}, [config, selectedServer, reloadServers]);
// Reconnect server
const handleReconnect = useCallback(async () => {
if (!config || !selectedServer) return;
@ -537,6 +579,7 @@ export const MCPManagementDialog: React.FC<MCPManagementDialogProps> = ({
onReconnect={handleReconnect}
onDisable={handleDisable}
onAuthenticate={handleAuthenticate}
onClearAuth={handleClearAuth}
onBack={handleNavigateBack}
/>
);
@ -569,10 +612,10 @@ export const MCPManagementDialog: React.FC<MCPManagementDialogProps> = ({
return (
<AuthenticateStep
server={selectedServer}
onSuccess={() => {
onBack={() => {
handleNavigateBack();
void reloadServers();
}}
onBack={handleNavigateBack}
/>
);
@ -594,6 +637,7 @@ export const MCPManagementDialog: React.FC<MCPManagementDialogProps> = ({
handleReconnect,
handleDisable,
handleAuthenticate,
handleClearAuth,
handleNavigateBack,
handleSelectTool,
handleSelectDisableScope,