11//! Feature Service Facade - Unified API delegating to specialized services
22
33use anyhow:: Result ;
4+ use std:: collections:: HashSet ;
45use std:: sync:: Arc ;
56
67use crate :: pool:: instance:: McpClient ;
7- use crate :: services:: PrefixCacheService ;
8+ use crate :: services:: { PrefixCacheService , SessionOverrideRegistry } ;
89use mcpmux_core:: { FeatureSetRepository , FeatureType , ServerFeature , ServerFeatureRepository } ;
910
1011use super :: {
@@ -16,13 +17,15 @@ pub struct FeatureService {
1617 discovery : Arc < FeatureDiscoveryService > ,
1718 resolution : Arc < FeatureResolutionService > ,
1819 routing : Arc < FeatureRoutingService > ,
20+ session_overrides : Arc < SessionOverrideRegistry > ,
1921}
2022
2123impl FeatureService {
2224 pub fn new (
2325 feature_repo : Arc < dyn ServerFeatureRepository > ,
2426 feature_set_repo : Arc < dyn FeatureSetRepository > ,
2527 prefix_cache : Arc < PrefixCacheService > ,
28+ session_overrides : Arc < SessionOverrideRegistry > ,
2629 ) -> Self {
2730 let discovery = Arc :: new ( FeatureDiscoveryService :: new ( feature_repo. clone ( ) ) ) ;
2831
@@ -41,6 +44,7 @@ impl FeatureService {
4144 discovery,
4245 resolution,
4346 routing,
47+ session_overrides,
4448 }
4549 }
4650
@@ -86,35 +90,98 @@ impl FeatureService {
8690 . await
8791 }
8892
89- // Type-specific helpers
93+ /// Resolve granted feature sets to tools, applying session server overrides.
9094 pub async fn get_tools_for_grants (
9195 & self ,
9296 space_id : & str ,
9397 feature_set_ids : & [ String ] ,
98+ session_id : Option < & str > ,
9499 ) -> Result < Vec < ServerFeature > > {
95- self . resolution
96- . resolve_feature_sets ( space_id, feature_set_ids, Some ( FeatureType :: Tool ) )
97- . await
100+ self . get_features_for_grants (
101+ space_id,
102+ feature_set_ids,
103+ session_id,
104+ Some ( FeatureType :: Tool ) ,
105+ )
106+ . await
98107 }
99108
109+ /// Resolve granted feature sets to prompts, applying session server overrides.
100110 pub async fn get_prompts_for_grants (
101111 & self ,
102112 space_id : & str ,
103113 feature_set_ids : & [ String ] ,
114+ session_id : Option < & str > ,
104115 ) -> Result < Vec < ServerFeature > > {
105- self . resolution
106- . resolve_feature_sets ( space_id, feature_set_ids, Some ( FeatureType :: Prompt ) )
107- . await
116+ self . get_features_for_grants (
117+ space_id,
118+ feature_set_ids,
119+ session_id,
120+ Some ( FeatureType :: Prompt ) ,
121+ )
122+ . await
108123 }
109124
125+ /// Resolve granted feature sets to resources, applying session server overrides.
110126 pub async fn get_resources_for_grants (
111127 & self ,
112128 space_id : & str ,
113129 feature_set_ids : & [ String ] ,
130+ session_id : Option < & str > ,
114131 ) -> Result < Vec < ServerFeature > > {
115- self . resolution
116- . resolve_feature_sets ( space_id, feature_set_ids, Some ( FeatureType :: Resource ) )
117- . await
132+ self . get_features_for_grants (
133+ space_id,
134+ feature_set_ids,
135+ session_id,
136+ Some ( FeatureType :: Resource ) ,
137+ )
138+ . await
139+ }
140+
141+ /// Shared list materialization: binding FS resolution + session overrides.
142+ async fn get_features_for_grants (
143+ & self ,
144+ space_id : & str ,
145+ feature_set_ids : & [ String ] ,
146+ session_id : Option < & str > ,
147+ filter_type : Option < FeatureType > ,
148+ ) -> Result < Vec < ServerFeature > > {
149+ let binding_features = self
150+ . resolution
151+ . resolve_feature_sets ( space_id, feature_set_ids, filter_type. clone ( ) )
152+ . await ?;
153+
154+ let Some ( session_id) = session_id else {
155+ return Ok ( binding_features) ;
156+ } ;
157+
158+ let enabled = self . session_overrides . enabled_set ( session_id) ;
159+ let disabled = self . session_overrides . disabled_set ( session_id) ;
160+
161+ if enabled. is_empty ( ) && disabled. is_empty ( ) {
162+ return Ok ( binding_features) ;
163+ }
164+
165+ let mut binding_servers: HashSet < String > = binding_features
166+ . iter ( )
167+ . map ( |f| f. server_id . clone ( ) )
168+ . collect ( ) ;
169+ binding_servers. extend ( enabled. iter ( ) . cloned ( ) ) ;
170+ binding_servers. retain ( |server_id| !disabled. contains ( server_id) ) ;
171+
172+ if binding_servers. is_empty ( ) {
173+ return Ok ( Vec :: new ( ) ) ;
174+ }
175+
176+ let all_features = self
177+ . resolution
178+ . get_all_features_for_space ( space_id, filter_type)
179+ . await ?;
180+
181+ Ok ( all_features
182+ . into_iter ( )
183+ . filter ( |f| f. is_available && binding_servers. contains ( & f. server_id ) )
184+ . collect ( ) )
118185 }
119186
120187 // Delegate to FeatureRoutingService (with type-specific helpers)
0 commit comments