From 5b19b89db3fe738f3cf6e604f1f63e85eca77623 Mon Sep 17 00:00:00 2001 From: Mohammod Al Amin Ashik Date: Tue, 3 Mar 2026 15:42:31 +0800 Subject: [PATCH] refactor: remove client active/inactive status tracking The has_active_tokens field and clients_with_tokens in-memory set tracked whether clients had been issued tokens to show Active/Inactive status badges in the UI. This status was unreliable (in-memory only, lost on restart) and not needed. Removes the status badges from the clients page, the tracking state from the gateway, and the field from both gateway and Tauri response structs. Signed-off-by: Mohammod Al Amin Ashik --- apps/desktop/src-tauri/src/commands/oauth.rs | 43 +++++++------- .../src/features/clients/ClientsPage.tsx | 39 ++----------- apps/desktop/src/lib/api/gateway.ts | 1 - crates/mcpmux-gateway/src/server/handlers.rs | 56 +++++++------------ crates/mcpmux-gateway/src/server/state.rs | 3 - scripts/take-screenshots.cjs | 4 +- tests/e2e/specs/clients.spec.ts | 12 ++-- 7 files changed, 52 insertions(+), 106 deletions(-) diff --git a/apps/desktop/src-tauri/src/commands/oauth.rs b/apps/desktop/src-tauri/src/commands/oauth.rs index 48bcb6e5..2eba910a 100644 --- a/apps/desktop/src-tauri/src/commands/oauth.rs +++ b/apps/desktop/src-tauri/src/commands/oauth.rs @@ -668,28 +668,25 @@ pub async fn get_oauth_clients( // Map to response format let client_infos: Vec = clients .into_iter() - .map(|client| { - OAuthClientInfo { - client_id: client.client_id, - registration_type: client.registration_type.as_str().to_string(), - client_name: client.client_name, - client_alias: client.client_alias, - redirect_uris: client.redirect_uris, - scope: client.scope, - approved: client.approved, - logo_uri: client.logo_uri, - client_uri: client.client_uri, - software_id: client.software_id, - software_version: client.software_version, - metadata_url: client.metadata_url, - metadata_cached_at: client.metadata_cached_at, - metadata_cache_ttl: client.metadata_cache_ttl, - connection_mode: client.connection_mode, - locked_space_id: client.locked_space_id, - last_seen: client.last_seen, - created_at: client.created_at, - has_active_tokens: false, // TODO: Check if client has active tokens - } + .map(|client| OAuthClientInfo { + client_id: client.client_id, + registration_type: client.registration_type.as_str().to_string(), + client_name: client.client_name, + client_alias: client.client_alias, + redirect_uris: client.redirect_uris, + scope: client.scope, + approved: client.approved, + logo_uri: client.logo_uri, + client_uri: client.client_uri, + software_id: client.software_id, + software_version: client.software_version, + metadata_url: client.metadata_url, + metadata_cached_at: client.metadata_cached_at, + metadata_cache_ttl: client.metadata_cache_ttl, + connection_mode: client.connection_mode, + locked_space_id: client.locked_space_id, + last_seen: client.last_seen, + created_at: client.created_at, }) .collect(); @@ -763,7 +760,6 @@ pub struct OAuthClientInfo { pub locked_space_id: Option, pub last_seen: Option, pub created_at: String, - pub has_active_tokens: bool, } /// Request to update client settings @@ -837,7 +833,6 @@ pub async fn update_oauth_client( locked_space_id: updated_client.locked_space_id, last_seen: updated_client.last_seen, created_at: updated_client.created_at, - has_active_tokens: false, }) } diff --git a/apps/desktop/src/features/clients/ClientsPage.tsx b/apps/desktop/src/features/clients/ClientsPage.tsx index 475d5770..3d158488 100644 --- a/apps/desktop/src/features/clients/ClientsPage.tsx +++ b/apps/desktop/src/features/clients/ClientsPage.tsx @@ -11,8 +11,6 @@ import { Lock, Unlock, HelpCircle, - Wifi, - WifiOff, RefreshCw, Settings, Trash2, @@ -649,21 +647,6 @@ export default function ClientsPage() { - {/* Status Badge */} -
- - {client.has_active_tokens ? ( - <> Active - ) : ( - <> Inactive - )} - -
- {/* Connection Mode */}
@@ -722,25 +705,11 @@ export default function ClientsPage() {
- {/* Quick Status */} -
- - {selectedClient.has_active_tokens ? ( - <> Connected - ) : ( - <> Inactive - )} + {selectedClient.software_version && ( + + v{selectedClient.software_version} - {selectedClient.software_version && ( - - v{selectedClient.software_version} - - )} -
+ )} {/* Scrollable Content */} diff --git a/apps/desktop/src/lib/api/gateway.ts b/apps/desktop/src/lib/api/gateway.ts index 03023ffe..fd3f0604 100644 --- a/apps/desktop/src/lib/api/gateway.ts +++ b/apps/desktop/src/lib/api/gateway.ts @@ -131,7 +131,6 @@ export interface OAuthClient { locked_space_id: string | null; last_seen: string | null; created_at: string; - has_active_tokens: boolean; } /** diff --git a/crates/mcpmux-gateway/src/server/handlers.rs b/crates/mcpmux-gateway/src/server/handlers.rs index 3e4129a4..22376b2c 100644 --- a/crates/mcpmux-gateway/src/server/handlers.rs +++ b/crates/mcpmux-gateway/src/server/handlers.rs @@ -602,12 +602,9 @@ pub async fn oauth_token( let client_id_for_tracking = pending.client_id.clone(); drop(gateway_state); - // Track that this client has active tokens and emit event + // Update last_seen and emit event { - let mut gateway_state = state.write().await; - gateway_state - .clients_with_tokens - .insert(client_id_for_tracking.clone()); + let gateway_state = state.read().await; // Update last_seen in database if let Some(repo) = gateway_state.inbound_client_repository() { @@ -949,7 +946,6 @@ pub struct OAuthClientInfoResponse { pub locked_space_id: Option, pub last_seen: Option, pub created_at: String, - pub has_active_tokens: bool, } /// List all registered OAuth clients @@ -969,28 +965,24 @@ pub async fn oauth_list_clients( Ok(db_clients) => { let clients: Vec = db_clients .into_iter() - .map(|c| { - let has_active = gateway_state.clients_with_tokens.contains(&c.client_id); - OAuthClientInfoResponse { - client_id: c.client_id, - registration_type: c.registration_type.as_str().to_string(), - client_name: c.client_name, - client_alias: c.client_alias, - redirect_uris: c.redirect_uris, - scope: c.scope, - logo_uri: c.logo_uri, - client_uri: c.client_uri, - software_id: c.software_id, - software_version: c.software_version, - metadata_url: c.metadata_url, - metadata_cached_at: c.metadata_cached_at, - metadata_cache_ttl: c.metadata_cache_ttl, - connection_mode: c.connection_mode, - locked_space_id: c.locked_space_id, - last_seen: c.last_seen, - created_at: c.created_at, - has_active_tokens: has_active, - } + .map(|c| OAuthClientInfoResponse { + client_id: c.client_id, + registration_type: c.registration_type.as_str().to_string(), + client_name: c.client_name, + client_alias: c.client_alias, + redirect_uris: c.redirect_uris, + scope: c.scope, + logo_uri: c.logo_uri, + client_uri: c.client_uri, + software_id: c.software_id, + software_version: c.software_version, + metadata_url: c.metadata_url, + metadata_cached_at: c.metadata_cached_at, + metadata_cache_ttl: c.metadata_cache_ttl, + connection_mode: c.connection_mode, + locked_space_id: c.locked_space_id, + last_seen: c.last_seen, + created_at: c.created_at, }) .collect(); info!("[OAuth] Listed {} clients from database", clients.len()); @@ -1213,9 +1205,6 @@ pub async fn oauth_update_client( .await { Ok(Some(client)) => { - let has_active = gateway_state - .clients_with_tokens - .contains(&client.client_id); let response = OAuthClientInfoResponse { client_id: client.client_id, registration_type: client.registration_type.as_str().to_string(), @@ -1234,7 +1223,6 @@ pub async fn oauth_update_client( locked_space_id: client.locked_space_id, last_seen: client.last_seen, created_at: client.created_at, - has_active_tokens: has_active, }; info!("[OAuth] Client updated: {}", response.client_id); Json(response).into_response() @@ -1264,7 +1252,7 @@ pub async fn oauth_delete_client( ) -> Response { info!("[OAuth] Deleting client: {}", client_id); - let mut gateway_state = state.write().await; + let gateway_state = state.read().await; let Some(repo) = gateway_state.inbound_client_repository() else { warn!("[OAuth] Database not available for client deletion"); @@ -1273,8 +1261,6 @@ pub async fn oauth_delete_client( match repo.delete_client(&client_id).await { Ok(true) => { - // Remove from active tokens set - gateway_state.clients_with_tokens.remove(&client_id); info!("[OAuth] Client deleted: {}", client_id); StatusCode::NO_CONTENT.into_response() } diff --git a/crates/mcpmux-gateway/src/server/state.rs b/crates/mcpmux-gateway/src/server/state.rs index 582f21af..d4a7baf1 100644 --- a/crates/mcpmux-gateway/src/server/state.rs +++ b/crates/mcpmux-gateway/src/server/state.rs @@ -51,8 +51,6 @@ pub struct GatewayState { pub oauth_tokens: HashMap, /// Pending authorization codes (code -> PendingAuthorization) pub pending_authorizations: HashMap, - /// Set of client_ids that have been issued tokens (for "active" status) - pub clients_with_tokens: std::collections::HashSet, /// JWT signing secret (for issuing access tokens) pub jwt_signing_secret: Option>, /// Database connection (for persistent OAuth storage) @@ -74,7 +72,6 @@ impl GatewayState { access_keys: HashMap::new(), oauth_tokens: HashMap::new(), pending_authorizations: HashMap::new(), - clients_with_tokens: std::collections::HashSet::new(), jwt_signing_secret: None, db: None, inbound_client_repository: None, diff --git a/scripts/take-screenshots.cjs b/scripts/take-screenshots.cjs index 25daf3bc..7a0fdb3f 100644 --- a/scripts/take-screenshots.cjs +++ b/scripts/take-screenshots.cjs @@ -138,8 +138,8 @@ const FEATURE_SETS = [ ]; const OAUTH_CLIENTS = [ - { client_id: 'cursor-001', registration_type: 'dcr', client_name: 'Cursor', client_alias: null, redirect_uris: ['http://localhost:9315/callback'], scope: null, approved: true, logo_uri: null, client_uri: null, software_id: 'cursor', software_version: '0.45.0', metadata_url: null, metadata_cached_at: null, metadata_cache_ttl: null, connection_mode: 'follow_active', locked_space_id: null, last_seen: '2026-02-07T09:30:00Z', created_at: '2026-01-20T10:00:00Z', has_active_tokens: true }, - { client_id: 'vscode-001', registration_type: 'dcr', client_name: 'VS Code', client_alias: null, redirect_uris: ['http://localhost:9315/callback'], scope: null, approved: true, logo_uri: null, client_uri: null, software_id: 'vscode', software_version: '1.96.0', metadata_url: null, metadata_cached_at: null, metadata_cache_ttl: null, connection_mode: 'follow_active', locked_space_id: null, last_seen: '2026-02-07T08:45:00Z', created_at: '2026-01-22T10:00:00Z', has_active_tokens: true }, + { client_id: 'cursor-001', registration_type: 'dcr', client_name: 'Cursor', client_alias: null, redirect_uris: ['http://localhost:9315/callback'], scope: null, approved: true, logo_uri: null, client_uri: null, software_id: 'cursor', software_version: '0.45.0', metadata_url: null, metadata_cached_at: null, metadata_cache_ttl: null, connection_mode: 'follow_active', locked_space_id: null, last_seen: '2026-02-07T09:30:00Z', created_at: '2026-01-20T10:00:00Z' }, + { client_id: 'vscode-001', registration_type: 'dcr', client_name: 'VS Code', client_alias: null, redirect_uris: ['http://localhost:9315/callback'], scope: null, approved: true, logo_uri: null, client_uri: null, software_id: 'vscode', software_version: '1.96.0', metadata_url: null, metadata_cached_at: null, metadata_cache_ttl: null, connection_mode: 'follow_active', locked_space_id: null, last_seen: '2026-02-07T08:45:00Z', created_at: '2026-01-22T10:00:00Z' }, ]; function mkRegistry(id, name, desc, alias, icon, categories, auth, transportType, publisher, caps, hostingType, badges) { diff --git a/tests/e2e/specs/clients.spec.ts b/tests/e2e/specs/clients.spec.ts index a1c5fa4e..d489b8f3 100644 --- a/tests/e2e/specs/clients.spec.ts +++ b/tests/e2e/specs/clients.spec.ts @@ -55,18 +55,18 @@ test.describe('Clients Page', () => { }); test.describe('Client Details', () => { - test('should show client connection status', async ({ page }) => { + test('should show client details', async ({ page }) => { const dashboard = new DashboardPage(page); await dashboard.navigate(); await page.locator('nav button:has-text("Clients")').click(); - + const clientCards = page.locator('[class*="rounded"][class*="border"]'); const count = await clientCards.count(); - + if (count > 0) { - // Clients should have status indicators - const statusIndicator = page.locator('[class*="bg-green"], [class*="bg-red"], text=/connected|active/i'); - // May or may not be visible + // Clients should have connection mode indicators + const firstCard = clientCards.first(); + await expect(firstCard).toBeVisible(); } });