Skip to content

Commit 07a3c17

Browse files
committed
fix(oauth): de-duplicate deep-link handling; quiet status-poll log
On a warm launch the OAuth approval deep link (mcpmux://authorize?request_id=…) is delivered twice — once by the deep-link plugin's on_open_url and again by the single-instance callback — so the whole consent flow ran twice per approval (duplicate consent emit + two get_pending_consent calls, visible in logs as back-to-back "[OAuth] Fetching pending consent"). - Drop a repeat of the same deep-link URL within a 3s window (`deep_link_is_duplicate`, gated by the pure, unit-tested `is_recent_duplicate_link`). Distinct authorizations carry a fresh request_id, so legitimate back-to-back flows are never collapsed. - Lower the per-call `get_gateway_status` log from INFO to DEBUG: the UI polls it on a timer and on every domain event, flooding the log (several lines/sec) and burying the events that matter. Note: this does not change the post-approval latency. Server-side, approval → code → token are all sub-millisecond; the redirect to a `cursor://` URL is handed to the OS via ShellExecuteW (returns in ~0.5s) and the remaining delay is the Windows shell routing the custom scheme + the client's own callback handling — outside the gateway. Claude-Session: https://claude.ai/code/session_01Baan9JmzR43uxxRUh7CAMF Signed-off-by: Mohammod Al Amin Ashik <maa.ashik00@gmail.com>
1 parent 5598451 commit 07a3c17

2 files changed

Lines changed: 104 additions & 3 deletions

File tree

apps/desktop/src-tauri/src/commands/gateway.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use serde::Serialize;
1414
use std::sync::Arc;
1515
use tauri::{AppHandle, Emitter, State};
1616
use tokio::sync::RwLock;
17-
use tracing::{error, info, trace, warn};
17+
use tracing::{debug, error, info, trace, warn};
1818
use uuid::Uuid;
1919

2020
/// Gateway status response
@@ -810,7 +810,10 @@ pub async fn get_gateway_status(
810810
}
811811
};
812812

813-
info!(
813+
// DEBUG, not INFO: the UI polls this on a timer and on every domain event,
814+
// so at INFO it floods the log (several lines/sec) and drowns the events
815+
// that matter. The data is still available with `RUST_LOG=debug`.
816+
debug!(
814817
"[Gateway] get_gateway_status: running={}, url={:?}, sessions={}, backends={}, space={:?}",
815818
state.running, state.url, active_sessions, connected_backends, space_id
816819
);

apps/desktop/src-tauri/src/commands/oauth.rs

Lines changed: 99 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@
2626
2727
use std::collections::HashMap;
2828
use std::sync::atomic::{AtomicBool, Ordering};
29-
use std::sync::{Arc, Mutex};
29+
use std::sync::{Arc, Mutex, OnceLock};
30+
use std::time::{Duration, Instant};
3031

3132
use mcpmux_core::branding;
3233
use serde::{Deserialize, Serialize};
@@ -120,6 +121,47 @@ pub struct ConsentRequestDetails {
120121
pub consent_token: String,
121122
}
122123

124+
/// Window within which an identical deep-link URL is treated as a duplicate
125+
/// and dropped. On a warm launch BOTH the deep-link plugin's `on_open_url` and
126+
/// the single-instance callback fire for the same `mcpmux://` URL, so without
127+
/// this guard the whole consent flow (deep-link emit → `get_pending_consent` →
128+
/// consent modal) runs twice per approval.
129+
const DEEP_LINK_DEDUP_WINDOW: Duration = Duration::from_secs(3);
130+
131+
/// Pure predicate: is `url` a repeat of `last_url` seen `elapsed` ago, within
132+
/// `window`? Extracted so the dedup rule is unit-testable without the clock.
133+
fn is_recent_duplicate_link(
134+
last_url: Option<&str>,
135+
elapsed: Duration,
136+
url: &str,
137+
window: Duration,
138+
) -> bool {
139+
last_url == Some(url) && elapsed < window
140+
}
141+
142+
/// True if this exact URL was just handled within [`DEEP_LINK_DEDUP_WINDOW`].
143+
/// Records `url` as the most-recent on a miss. Distinct authorizations carry a
144+
/// fresh `request_id` (different URL), so legitimate back-to-back flows are
145+
/// never collapsed.
146+
fn deep_link_is_duplicate(url: &str) -> bool {
147+
static LAST: OnceLock<Mutex<Option<(String, Instant)>>> = OnceLock::new();
148+
let cell = LAST.get_or_init(|| Mutex::new(None));
149+
let mut guard = cell.lock().unwrap_or_else(|p| p.into_inner());
150+
let now = Instant::now();
151+
let dup = guard.as_ref().is_some_and(|(last_url, seen_at)| {
152+
is_recent_duplicate_link(
153+
Some(last_url.as_str()),
154+
now.duration_since(*seen_at),
155+
url,
156+
DEEP_LINK_DEDUP_WINDOW,
157+
)
158+
});
159+
if !dup {
160+
*guard = Some((url.to_string(), now));
161+
}
162+
dup
163+
}
164+
123165
/// Handle an incoming deep link URL
124166
///
125167
/// Routes based on the URL path:
@@ -137,6 +179,14 @@ pub fn handle_deep_link<R: tauri::Runtime>(app: &tauri::AppHandle<R>, url: &str)
137179
return;
138180
}
139181

182+
// Drop the duplicate that the on_open_url + single-instance paths both
183+
// deliver for the same warm-launch URL — otherwise the consent modal and
184+
// `get_pending_consent` fire twice per approval.
185+
if deep_link_is_duplicate(url) {
186+
info!("[DeepLink] Ignoring duplicate within {DEEP_LINK_DEDUP_WINDOW:?}: {url}");
187+
return;
188+
}
189+
140190
// Check for OAuth callback first (mcpmux://callback/oauth?...)
141191
if branding::is_oauth_callback(url) {
142192
let parsed = match Url::parse(url) {
@@ -1095,3 +1145,51 @@ pub async fn revoke_oauth_client_feature_set(
10951145

10961146
Ok(())
10971147
}
1148+
1149+
#[cfg(test)]
1150+
mod tests {
1151+
use super::*;
1152+
1153+
const W: Duration = Duration::from_secs(3);
1154+
const URL: &str = "mcpmux://authorize?request_id=abc-123";
1155+
1156+
#[test]
1157+
fn first_sighting_is_not_a_duplicate() {
1158+
// No prior URL → never a duplicate.
1159+
assert!(!is_recent_duplicate_link(None, Duration::ZERO, URL, W));
1160+
}
1161+
1162+
#[test]
1163+
fn same_url_within_window_is_a_duplicate() {
1164+
// The on_open_url + single-instance double-fire: same URL, ~ms apart.
1165+
assert!(is_recent_duplicate_link(
1166+
Some(URL),
1167+
Duration::from_millis(40),
1168+
URL,
1169+
W
1170+
));
1171+
}
1172+
1173+
#[test]
1174+
fn same_url_after_window_is_not_a_duplicate() {
1175+
// A genuine re-auth of the same URL long after is allowed through.
1176+
assert!(!is_recent_duplicate_link(
1177+
Some(URL),
1178+
Duration::from_secs(5),
1179+
URL,
1180+
W
1181+
));
1182+
}
1183+
1184+
#[test]
1185+
fn different_request_id_is_never_a_duplicate() {
1186+
// Distinct authorizations carry a fresh request_id even back-to-back.
1187+
let other = "mcpmux://authorize?request_id=def-456";
1188+
assert!(!is_recent_duplicate_link(
1189+
Some(URL),
1190+
Duration::from_millis(10),
1191+
other,
1192+
W
1193+
));
1194+
}
1195+
}

0 commit comments

Comments
 (0)