@@ -6,7 +6,7 @@ use tool::{IntoToolRoute, ToolRoute};
66use super :: ServerHandler ;
77use crate :: {
88 RoleServer , Service ,
9- model:: { ClientRequest , ListPromptsResult , ListToolsResult , ServerResult } ,
9+ model:: { ClientNotification , ClientRequest , ListPromptsResult , ListToolsResult , ServerResult } ,
1010 service:: NotificationContext ,
1111} ;
1212
@@ -18,17 +18,22 @@ pub struct Router<S> {
1818 pub tool_router : tool:: ToolRouter < S > ,
1919 pub prompt_router : prompt:: PromptRouter < S > ,
2020 pub service : Arc < S > ,
21+ peer_slot : Arc < std:: sync:: OnceLock < crate :: service:: Peer < RoleServer > > > ,
2122}
2223
2324impl < S > Router < S >
2425where
2526 S : ServerHandler ,
2627{
2728 pub fn new ( service : S ) -> Self {
29+ let ( notifier, peer_slot) = tool:: ToolRouter :: < S > :: deferred_peer_notifier ( ) ;
30+ let mut tool_router = tool:: ToolRouter :: new ( ) ;
31+ tool_router. set_notifier ( notifier) ;
2832 Self {
29- tool_router : tool :: ToolRouter :: new ( ) ,
33+ tool_router,
3034 prompt_router : prompt:: PromptRouter :: new ( ) ,
3135 service : Arc :: new ( service) ,
36+ peer_slot,
3237 }
3338 }
3439
7277 notification : <RoleServer as crate :: service:: ServiceRole >:: PeerNot ,
7378 context : NotificationContext < RoleServer > ,
7479 ) -> Result < ( ) , crate :: ErrorData > {
80+ if matches ! (
81+ & notification,
82+ ClientNotification :: InitializedNotification ( _)
83+ ) {
84+ let _ = self . peer_slot . set ( context. peer . clone ( ) ) ;
85+ }
7586 self . service
7687 . handle_notification ( notification, context)
7788 . await
8394 ) -> Result < <RoleServer as crate :: service:: ServiceRole >:: Resp , crate :: ErrorData > {
8495 match request {
8596 ClientRequest :: CallToolRequest ( request) => {
86- if self . tool_router . has_route ( request. params . name . as_ref ( ) )
97+ if self
98+ . tool_router
99+ . map
100+ . contains_key ( request. params . name . as_ref ( ) )
87101 || !self . tool_router . transparent_when_not_found
88102 {
89103 let tool_call_context = crate :: handler:: server:: tool:: ToolCallContext :: new (
@@ -134,6 +148,81 @@ where
134148 }
135149
136150 fn get_info ( & self ) -> <RoleServer as crate :: service:: ServiceRole >:: Info {
137- ServerHandler :: get_info ( & self . service )
151+ let mut info = ServerHandler :: get_info ( & self . service ) ;
152+ info. capabilities
153+ . tools
154+ . get_or_insert_with ( Default :: default)
155+ . list_changed = Some ( true ) ;
156+ info
157+ }
158+ }
159+
160+ #[ cfg( test) ]
161+ mod tests {
162+ use std:: sync:: Arc ;
163+
164+ use super :: * ;
165+ use crate :: {
166+ model:: { CallToolResult , ClientNotification , ServerNotification , Tool } ,
167+ service:: { AtomicU32RequestIdProvider , Peer , PeerSinkMessage , RequestIdProvider } ,
168+ } ;
169+
170+ struct DummyHandler ;
171+ impl ServerHandler for DummyHandler { }
172+
173+ async fn recv_notification (
174+ rx : & mut tokio:: sync:: mpsc:: Receiver < PeerSinkMessage < RoleServer > > ,
175+ ) -> ServerNotification {
176+ let msg = tokio:: time:: timeout ( std:: time:: Duration :: from_secs ( 1 ) , rx. recv ( ) )
177+ . await
178+ . expect ( "timed out" )
179+ . expect ( "channel closed" ) ;
180+ match msg {
181+ PeerSinkMessage :: Notification {
182+ notification,
183+ responder,
184+ } => {
185+ let _ = responder. send ( Ok ( ( ) ) ) ;
186+ notification
187+ }
188+ other => panic ! ( "expected notification, got {other:?}" ) ,
189+ }
190+ }
191+
192+ #[ tokio:: test]
193+ async fn test_router_deferred_notifier_e2e ( ) {
194+ let mut router = Router :: new ( DummyHandler ) . with_tool ( tool:: ToolRoute :: new_dyn (
195+ Tool :: new ( "my_tool" , "test" , Arc :: new ( Default :: default ( ) ) ) ,
196+ |_ctx| Box :: pin ( async { Ok ( CallToolResult :: default ( ) ) } ) ,
197+ ) ) ;
198+
199+ let id_provider: Arc < dyn RequestIdProvider > =
200+ Arc :: new ( AtomicU32RequestIdProvider :: default ( ) ) ;
201+ let ( peer, mut rx) = Peer :: < RoleServer > :: new ( id_provider, None ) ;
202+
203+ let context = crate :: service:: NotificationContext {
204+ peer : peer. clone ( ) ,
205+ meta : Default :: default ( ) ,
206+ extensions : Default :: default ( ) ,
207+ } ;
208+ router
209+ . handle_notification (
210+ ClientNotification :: InitializedNotification ( Default :: default ( ) ) ,
211+ context,
212+ )
213+ . await
214+ . unwrap ( ) ;
215+
216+ router. tool_router . disable_route ( "my_tool" ) ;
217+ assert ! ( matches!(
218+ recv_notification( & mut rx) . await ,
219+ ServerNotification :: ToolListChangedNotification ( _)
220+ ) ) ;
221+
222+ router. tool_router . enable_route ( "my_tool" ) ;
223+ assert ! ( matches!(
224+ recv_notification( & mut rx) . await ,
225+ ServerNotification :: ToolListChangedNotification ( _)
226+ ) ) ;
138227 }
139228}
0 commit comments