mcp: add resource subscriptions (#138)
This CL adds the ability for clients to subscribe and receive updates for resources as described in https://modelcontextprotocol.io/specification/2025-06-18/server/resources#subscriptions Fixes: #23
This commit is contained in:
parent
ea6162ca1c
commit
bcbb31f072
1 changed files with 214 additions and 6 deletions
|
|
@ -60,7 +60,7 @@ func TestEndToEnd(t *testing.T) {
|
|||
|
||||
// Channels to check if notification callbacks happened.
|
||||
notificationChans := map[string]chan int{}
|
||||
for _, name := range []string{"initialized", "roots", "tools", "prompts", "resources", "progress_server", "progress_client"} {
|
||||
for _, name := range []string{"initialized", "roots", "tools", "prompts", "resources", "progress_server", "progress_client", "resource_updated", "subscribe", "unsubscribe"} {
|
||||
notificationChans[name] = make(chan int, 1)
|
||||
}
|
||||
waitForNotification := func(t *testing.T, name string) {
|
||||
|
|
@ -78,6 +78,14 @@ func TestEndToEnd(t *testing.T) {
|
|||
ProgressNotificationHandler: func(context.Context, *ServerSession, *ProgressNotificationParams) {
|
||||
notificationChans["progress_server"] <- 0
|
||||
},
|
||||
SubscribeHandler: func(context.Context, *SubscribeParams) error {
|
||||
notificationChans["subscribe"] <- 0
|
||||
return nil
|
||||
},
|
||||
UnsubscribeHandler: func(context.Context, *UnsubscribeParams) error {
|
||||
notificationChans["unsubscribe"] <- 0
|
||||
return nil
|
||||
},
|
||||
}
|
||||
s := NewServer(testImpl, sopts)
|
||||
AddTool(s, &Tool{
|
||||
|
|
@ -128,6 +136,9 @@ func TestEndToEnd(t *testing.T) {
|
|||
ProgressNotificationHandler: func(context.Context, *ClientSession, *ProgressNotificationParams) {
|
||||
notificationChans["progress_client"] <- 0
|
||||
},
|
||||
ResourceUpdatedHandler: func(context.Context, *ClientSession, *ResourceUpdatedNotificationParams) {
|
||||
notificationChans["resource_updated"] <- 0
|
||||
},
|
||||
}
|
||||
c := NewClient(testImpl, opts)
|
||||
rootAbs, err := filepath.Abs(filepath.FromSlash("testdata/files"))
|
||||
|
|
@ -421,6 +432,37 @@ func TestEndToEnd(t *testing.T) {
|
|||
waitForNotification(t, "progress_server")
|
||||
})
|
||||
|
||||
t.Run("resource_subscriptions", func(t *testing.T) {
|
||||
err := cs.Subscribe(ctx, &SubscribeParams{
|
||||
URI: "test",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
waitForNotification(t, "subscribe")
|
||||
s.ResourceUpdated(ctx, &ResourceUpdatedNotificationParams{
|
||||
URI: "test",
|
||||
})
|
||||
waitForNotification(t, "resource_updated")
|
||||
err = cs.Unsubscribe(ctx, &UnsubscribeParams{
|
||||
URI: "test",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
waitForNotification(t, "unsubscribe")
|
||||
|
||||
// Verify the client does not receive the update after unsubscribing.
|
||||
s.ResourceUpdated(ctx, &ResourceUpdatedNotificationParams{
|
||||
URI: "test",
|
||||
})
|
||||
select {
|
||||
case <-notificationChans["resource_updated"]:
|
||||
t.Fatalf("resource updated after unsubscription")
|
||||
case <-time.After(time.Second):
|
||||
}
|
||||
})
|
||||
|
||||
// Disconnect.
|
||||
cs.Close()
|
||||
clientWG.Wait()
|
||||
|
|
|
|||
Loading…
Reference in a new issue