From 747c0154c51dfc42f001c3f14cdd9484dcdd8d29 Mon Sep 17 00:00:00 2001 From: cliffhall Date: Sat, 8 Mar 2025 11:05:13 -0500 Subject: [PATCH] WIP: Subscribe to resources * In App.tsx - added subscribeToResource() - takes a uri - sends a `resources/subscribe` message with the uri - added unsubscribeFromResource() - takes a uri - sends a `resources/unsubscribe` message with the uri - in ResourcesTab element, - pass subscribeToResource and subscribeToResource invokers to component * In notificationTypes.ts - add ServerNotificationSchema to NotificationSchema to permit server update messages. * In ResourcesTab.tsx - deconstruct subscribeToResource and unsubscribeFromResource and add prop types - Add Subscribe and Unsubscribe buttons to selected resource panel, left of the refresh button. They call the sub and unsub functions that came in on props, passing the selected resource URI. - [WIP]: Will show the appropriate button in a follow up commit. * In useConnection.ts - import ResourceUpdatedNotificationSchema - in the connect function, - set onNotification as the handler for ResourceUpdatedNotificationSchema --- client/src/App.tsx | 33 +++++++++++++++++++++++ client/src/components/ResourcesTab.tsx | 36 ++++++++++++++++++++------ client/src/lib/hooks/useConnection.ts | 6 +++++ client/src/lib/notificationTypes.ts | 7 ++--- 4 files changed, 71 insertions(+), 11 deletions(-) diff --git a/client/src/App.tsx b/client/src/App.tsx index a9adea5..f5b1f79 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -308,6 +308,31 @@ const App = () => { setResourceContent(JSON.stringify(response, null, 2)); }; + const subscribeToResource = async (uri: string) => { + + await makeRequest( + { + method: "resources/subscribe" as const, + params: { uri }, + }, + z.object({}), + "resources", + ); + }; + + const unsubscribeFromResource = async (uri: string) => { + + await makeRequest( + { + method: "resources/unsubscribe" as const, + params: { uri }, + }, + z.object({}), + "resources", + ); + }; + + const listPrompts = async () => { const response = await makeRequest( { @@ -485,6 +510,14 @@ const App = () => { clearError("resources"); setSelectedResource(resource); }} + subscribeToResource={(uri) => { + clearError("resources"); + subscribeToResource(uri); + }} + unsubscribeFromResource={(uri) => { + clearError("resources"); + unsubscribeFromResource(uri); + }} handleCompletion={handleCompletion} completionsSupported={completionsSupported} resourceContent={resourceContent} diff --git a/client/src/components/ResourcesTab.tsx b/client/src/components/ResourcesTab.tsx index 93127a9..9d94296 100644 --- a/client/src/components/ResourcesTab.tsx +++ b/client/src/components/ResourcesTab.tsx @@ -26,6 +26,8 @@ const ResourcesTab = ({ readResource, selectedResource, setSelectedResource, + subscribeToResource, + unsubscribeFromResource, handleCompletion, completionsSupported, resourceContent, @@ -52,6 +54,8 @@ const ResourcesTab = ({ nextCursor: ListResourcesResult["nextCursor"]; nextTemplateCursor: ListResourceTemplatesResult["nextCursor"]; error: string | null; + subscribeToResource: (uri: string) => void; + unsubscribeFromResource: (uri: string) => void; }) => { const [selectedTemplate, setSelectedTemplate] = useState(null); @@ -164,14 +168,30 @@ const ResourcesTab = ({ : "Select a resource or template"} {selectedResource && ( - + <> + + + + )}
diff --git a/client/src/lib/hooks/useConnection.ts b/client/src/lib/hooks/useConnection.ts index 75b5467..9e7bb11 100644 --- a/client/src/lib/hooks/useConnection.ts +++ b/client/src/lib/hooks/useConnection.ts @@ -9,6 +9,7 @@ import { CreateMessageRequestSchema, ListRootsRequestSchema, ProgressNotificationSchema, + ResourceUpdatedNotificationSchema, Request, Result, ServerCapabilities, @@ -247,6 +248,11 @@ export function useConnection({ ProgressNotificationSchema, onNotification, ); + + client.setNotificationHandler( + ResourceUpdatedNotificationSchema, + onNotification, + ); } if (onStdErrNotification) { diff --git a/client/src/lib/notificationTypes.ts b/client/src/lib/notificationTypes.ts index 7aa6518..abd714b 100644 --- a/client/src/lib/notificationTypes.ts +++ b/client/src/lib/notificationTypes.ts @@ -1,6 +1,7 @@ import { NotificationSchema as BaseNotificationSchema, ClientNotificationSchema, + ServerNotificationSchema, } from "@modelcontextprotocol/sdk/types.js"; import { z } from "zod"; @@ -11,9 +12,9 @@ export const StdErrNotificationSchema = BaseNotificationSchema.extend({ }), }); -export const NotificationSchema = ClientNotificationSchema.or( - StdErrNotificationSchema, -); +export const NotificationSchema = ClientNotificationSchema + .or(StdErrNotificationSchema) + .or(ServerNotificationSchema); export type StdErrNotification = z.infer; export type Notification = z.infer;