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 a9adea53..f5b1f79d 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 93127a93..9d942961 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 75b54679..9e7bb11f 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 7aa65182..abd714b4 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;