Skip to content

Commit 34a6f1c

Browse files
authored
Fix resource subscription handling (#89)
* Fix resource subscription handling Add resource subscription tests * Fix typo * Typo * small fixes * Fix concurrency issue with test * Align with specification schemas
1 parent 08b0a04 commit 34a6f1c

15 files changed

+210
-36
lines changed

src/mcpdotnet/Client/McpClientExtensions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ public static Task SubscribeToResourceAsync(this IMcpClient client, string uri,
227227
{
228228
Throw.IfNull(client);
229229

230-
return client.SendRequestAsync<dynamic>(
230+
return client.SendRequestAsync<EmptyResult>(
231231
CreateRequest("resources/subscribe", new() { ["uri"] = uri }),
232232
cancellationToken);
233233
}
@@ -242,7 +242,7 @@ public static Task UnsubscribeFromResourceAsync(this IMcpClient client, string u
242242
{
243243
Throw.IfNull(client);
244244

245-
return client.SendRequestAsync<dynamic>(
245+
return client.SendRequestAsync<EmptyResult>(
246246
CreateRequest("resources/unsubscribe", new() { ["uri"] = uri }),
247247
cancellationToken);
248248
}

src/mcpdotnet/Configuration/McpServerBuilderExtensions.Handler.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ public static IMcpServerBuilder WithGetCompletionHandler(this IMcpServerBuilder
107107
/// </summary>
108108
/// <param name="builder">The builder instance.</param>
109109
/// <param name="handler">The handler.</param>
110-
public static IMcpServerBuilder WithSubscribeToResourcesHandler(this IMcpServerBuilder builder, Func<RequestContext<string>, CancellationToken, Task> handler)
110+
public static IMcpServerBuilder WithSubscribeToResourcesHandler(this IMcpServerBuilder builder, Func<RequestContext<SubscribeRequestParams>, CancellationToken, Task<EmptyResult>> handler)
111111
{
112112
Throw.IfNull(builder);
113113

@@ -120,7 +120,7 @@ public static IMcpServerBuilder WithSubscribeToResourcesHandler(this IMcpServerB
120120
/// </summary>
121121
/// <param name="builder">The builder instance.</param>
122122
/// <param name="handler">The handler.</param>
123-
public static IMcpServerBuilder WithUnsubscribeFromResourcesHandler(this IMcpServerBuilder builder, Func<RequestContext<string>, CancellationToken, Task> handler)
123+
public static IMcpServerBuilder WithUnsubscribeFromResourcesHandler(this IMcpServerBuilder builder, Func<RequestContext<UnsubscribeRequestParams>, CancellationToken, Task<EmptyResult>> handler)
124124
{
125125
Throw.IfNull(builder);
126126

src/mcpdotnet/Protocol/Types/Capabilities.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,13 +126,13 @@ public record ResourcesCapability
126126
/// Gets or sets the handler for subscribe to resources messages.
127127
/// </summary>
128128
[JsonIgnore]
129-
public Func<RequestContext<string>, CancellationToken, Task>? SubscribeToResourcesHandler { get; init; }
129+
public Func<RequestContext<SubscribeRequestParams>, CancellationToken, Task<EmptyResult>>? SubscribeToResourcesHandler { get; init; }
130130

131131
/// <summary>
132132
/// Gets or sets the handler for unsubscribe from resources messages.
133133
/// </summary>
134134
[JsonIgnore]
135-
public Func<RequestContext<string>, CancellationToken, Task>? UnsubscribeFromResourcesHandler { get; init; }
135+
public Func<RequestContext<UnsubscribeRequestParams>, CancellationToken, Task<EmptyResult>>? UnsubscribeFromResourcesHandler { get; init; }
136136
}
137137

138138
/// <summary>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using System.Text.Json.Serialization;
2+
3+
namespace McpDotNet.Protocol.Types;
4+
5+
/// <summary>
6+
/// The server's response to a completion/complete request
7+
/// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.json">See the schema for details</see>
8+
/// </summary>
9+
public class CompleteResult
10+
{
11+
/// <summary>
12+
/// The completion object containing the completion values.
13+
/// </summary>
14+
[JsonPropertyName("completion")]
15+
public Completion Completion { get; set; } = new Completion();
16+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
namespace McpDotNet.Protocol.Types;
2+
3+
/// <summary>
4+
/// An empty result object.
5+
/// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.json">See the schema for details</see>
6+
/// </summary>
7+
public class EmptyResult
8+
{
9+
10+
}

src/mcpdotnet/Protocol/Types/Reference.cs

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -66,15 +66,3 @@ public bool Validate([NotNullWhen(false)] out string? validationMessage)
6666
return true;
6767
}
6868
}
69-
70-
/// <summary>
71-
/// The server's response to a completion/complete request
72-
/// </summary>
73-
public class CompleteResult
74-
{
75-
/// <summary>
76-
/// The completion object containing the completion values.
77-
/// </summary>
78-
[JsonPropertyName("completion")]
79-
public Completion Completion { get; set; } = new Completion();
80-
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
namespace McpDotNet.Protocol.Types;
2+
3+
/// <summary>
4+
/// Sent from the server as the payload of "notifications/resources/updated" notifications whenever a subscribed resource changes.
5+
/// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.json">See the schema for details</see>
6+
/// </summary>
7+
public class ResourceUpdatedNotificationParams
8+
{
9+
/// <summary>
10+
/// The URI of the resource to subscribe to. The URI can use any protocol; it is up to the server how to interpret it.
11+
/// </summary>
12+
[System.Text.Json.Serialization.JsonPropertyName("uri")]
13+
public string? Uri { get; init; }
14+
}

src/mcpdotnet/Protocol/Types/SubscribeToResourceRequestParams.cs renamed to src/mcpdotnet/Protocol/Types/SubscribeRequestParams.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
namespace McpDotNet.Protocol.Types;
22

33
/// <summary>
4-
/// Sent from the client to request resources/updated notifications from the server whenever a particular resource changes.
4+
/// Sent from the client to request updated notifications from the server whenever a particular primitive changes.
55
/// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.json">See the schema for details</see>
66
/// </summary>
7-
public class SubscribeToResourceRequestParams
7+
public class SubscribeRequestParams
88
{
99
/// <summary>
1010
/// The URI of the resource to subscribe to. The URI can use any protocol; it is up to the server how to interpret it.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
namespace McpDotNet.Protocol.Types;
2+
3+
/// <summary>
4+
/// Sent from the client to request not receiving updated notifications from the server whenever a primitive resource changes.
5+
/// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.json">See the schema for details</see>
6+
/// </summary>
7+
public class UnsubscribeRequestParams
8+
{
9+
/// <summary>
10+
/// The URI of the resource to unsubscribe fro. The URI can use any protocol; it is up to the server how to interpret it.
11+
/// </summary>
12+
[System.Text.Json.Serialization.JsonPropertyName("uri")]
13+
public string? Uri { get; init; }
14+
}

src/mcpdotnet/Server/McpServer.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,8 @@ private void SetResourcesHandler(McpServerOptions options)
163163
throw new McpServerException("Resources capability was enabled with subscribe support, but SubscribeToResources and/or UnsubscribeFromResources handlers were not specified.");
164164
}
165165

166-
// TODO: Implement Subscribe support
166+
SetRequestHandler<SubscribeRequestParams, EmptyResult>("resources/subscribe", request => subscribeHandler(new(this, request), cancellationToken));
167+
SetRequestHandler<UnsubscribeRequestParams, EmptyResult>("resources/unsubscribe", request => unsubscribeHandler(new(this, request), cancellationToken));
167168
}
168169

169170
private void SetPromptsHandler(McpServerOptions options)

0 commit comments

Comments
 (0)