@@ -37,6 +37,7 @@ use tracing::{debug, error, info, warn};
3737use url:: Url ;
3838
3939use super :: gateway:: GatewayAppState ;
40+ use crate :: state:: AppState ;
4041
4142// ============================================================================
4243// Deep Link Handling
@@ -979,6 +980,7 @@ fn generate_api_key() -> (String, String, String) {
979980#[ tauri:: command]
980981pub async fn register_api_key_client (
981982 gateway_state : State < ' _ , Arc < RwLock < GatewayAppState > > > ,
983+ app : State < ' _ , AppState > ,
982984 name : String ,
983985 locked_space_id : Option < String > ,
984986) -> Result < RegisteredApiKeyClient , String > {
@@ -1042,6 +1044,18 @@ pub async fn register_api_key_client(
10421044 trimmed, client_id
10431045 ) ;
10441046
1047+ // Best-effort: auto-create a clientId-keyed mapping → the (locked or
1048+ // default) Space's Starter, so the client routes sensibly out of the box
1049+ // and the mapping is visible + editable in the Mapping tab. A failure here
1050+ // must not undo the registration — without an explicit mapping the resolver
1051+ // still falls back to the default Starter.
1052+ if let Err ( e) = auto_map_api_key_client ( & app, & client_id, locked_space_id. as_deref ( ) ) . await {
1053+ warn ! (
1054+ "[OAuth] auto-map for {} failed (non-fatal): {}" ,
1055+ client_id, e
1056+ ) ;
1057+ }
1058+
10451059 Ok ( RegisteredApiKeyClient {
10461060 client_id,
10471061 client_name : trimmed. to_string ( ) ,
@@ -1051,6 +1065,40 @@ pub async fn register_api_key_client(
10511065 } )
10521066}
10531067
1068+ /// Auto-create a clientId-keyed `id` mapping pointing at the (locked or
1069+ /// default) Space's Starter FeatureSet, so a freshly-registered API-key client
1070+ /// routes somewhere sensible by default and the operator can retarget it from
1071+ /// the Mapping tab.
1072+ async fn auto_map_api_key_client (
1073+ app : & AppState ,
1074+ client_id : & str ,
1075+ locked_space_id : Option < & str > ,
1076+ ) -> Result < ( ) , String > {
1077+ let space_id = match locked_space_id {
1078+ Some ( s) => uuid:: Uuid :: parse_str ( s) . map_err ( |e| e. to_string ( ) ) ?,
1079+ None => {
1080+ app. space_service
1081+ . get_default ( )
1082+ . await
1083+ . map_err ( |e| e. to_string ( ) ) ?
1084+ . ok_or ( "no default Space configured" ) ?
1085+ . id
1086+ }
1087+ } ;
1088+ let starter = app
1089+ . feature_set_repository
1090+ . get_starter_for_space ( & space_id. to_string ( ) )
1091+ . await
1092+ . map_err ( |e| e. to_string ( ) ) ?
1093+ . ok_or ( "Space has no Starter FeatureSet" ) ?;
1094+ let binding =
1095+ mcpmux_core:: WorkspaceBinding :: new_id ( client_id. to_string ( ) , space_id, vec ! [ starter. id] ) ;
1096+ app. workspace_binding_repository
1097+ . create ( & binding)
1098+ . await
1099+ . map_err ( |e| e. to_string ( ) )
1100+ }
1101+
10541102/// Issue an additional API key for an existing client (rotation). Returns the
10551103/// new key plaintext once.
10561104#[ tauri:: command]
0 commit comments