Add initial support for Resource Templates (#18)
* Add initial support for Resource Templates * Make ListResourceTemplatesHandler not required The server was throwing if this handler wasn't specified, and it should probably be optional anyway. * Remove extra line Co-authored-by: Stephen Toub <stoub@microsoft.com> * Fix spaces Co-authored-by: Stephen Toub <stoub@microsoft.com> * Fix spaces Co-authored-by: Stephen Toub <stoub@microsoft.com> * Add and use a default ListResourceTemplatesHandler If no ListResourceTemplatesHandler is specified, use a default one that returns an empty result. * Fix spaces * Spaces * Add Client extensions for ListResourceTemplates * Integration Test for Client ListResourceTemplates * Fix comment Co-authored-by: Stephen Toub <stoub@microsoft.com> * Make Defaults internal Co-authored-by: Stephen Toub <stoub@microsoft.com> * Simplify test call Co-authored-by: Stephen Toub <stoub@microsoft.com> * Make delegate static Co-authored-by: Stephen Toub <stoub@microsoft.com> * Fix test comment * Spaces * Fix xml doc Co-authored-by: Stephen Toub <stoub@microsoft.com> * Make default handler inline * Spaces Co-authored-by: Stephen Halter <halter73@gmail.com> --------- Co-authored-by: Stephen Toub <stoub@microsoft.com> Co-authored-by: Stephen Halter <halter73@gmail.com>
This commit is contained in:
parent
50cc48830e
commit
fe6b401014
8 changed files with 287 additions and 3 deletions
|
|
@ -139,6 +139,44 @@ public static class McpClientExtensions
|
|||
cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a sequence of available resource templates from the server.
|
||||
/// </summary>
|
||||
/// <param name="client">The client.</param>
|
||||
/// <param name="cancellationToken">A token to cancel the operation.</param>
|
||||
/// <returns>An asynchronous sequence of resource template information.</returns>
|
||||
public static async IAsyncEnumerable<ResourceTemplate> ListResourceTemplatesAsync(
|
||||
this IMcpClient client, [EnumeratorCancellation] CancellationToken cancellationToken = default)
|
||||
{
|
||||
string? cursor = null;
|
||||
do
|
||||
{
|
||||
var resources = await ListResourceTemplatesAsync(client, cursor, cancellationToken).ConfigureAwait(false);
|
||||
foreach (var resource in resources.ResourceTemplates)
|
||||
{
|
||||
yield return resource;
|
||||
}
|
||||
|
||||
cursor = resources.NextCursor;
|
||||
}
|
||||
while (cursor is not null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a list of available resources from the server.
|
||||
/// </summary>
|
||||
/// <param name="client">The client.</param>
|
||||
/// <param name="cursor">A cursor to paginate the results.</param>
|
||||
/// <param name="cancellationToken">A token to cancel the operation.</param>
|
||||
public static Task<ListResourceTemplatesResult> ListResourceTemplatesAsync(this IMcpClient client, string? cursor, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Throw.IfNull(client);
|
||||
|
||||
return client.SendRequestAsync<ListResourceTemplatesResult>(
|
||||
CreateRequest("resources/templates/list", CreateCursorDictionary(cursor)),
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a sequence of available resources from the server.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -11,6 +11,19 @@ namespace ModelContextProtocol;
|
|||
/// </summary>
|
||||
public static partial class McpServerBuilderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets the handler for list resource templates requests.
|
||||
/// </summary>
|
||||
/// <param name="builder">The builder instance.</param>
|
||||
/// <param name="handler">The handler.</param>
|
||||
public static IMcpServerBuilder WithListResourceTemplatesHandler(this IMcpServerBuilder builder, Func<RequestContext<ListResourceTemplatesRequestParams>, CancellationToken, Task<ListResourceTemplatesResult>> handler)
|
||||
{
|
||||
Throw.IfNull(builder);
|
||||
|
||||
builder.Services.Configure<McpServerHandlers>(s => s.ListResourceTemplatesHandler = handler);
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the handler for list tools requests.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -110,6 +110,12 @@ public record ResourcesCapability
|
|||
[JsonPropertyName("listChanged")]
|
||||
public bool? ListChanged { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the handler for list resource templates requests.
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public Func<RequestContext<ListResourceTemplatesRequestParams>, CancellationToken, Task<ListResourceTemplatesResult>>? ListResourceTemplatesHandler { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the handler for list resources requests.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
namespace ModelContextProtocol.Protocol.Types;
|
||||
|
||||
/// <summary>
|
||||
/// Sent from the client to request a list of resource templates the server has.
|
||||
/// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.json">See the schema for details</see>
|
||||
/// </summary>
|
||||
public class ListResourceTemplatesRequestParams
|
||||
{
|
||||
/// <summary>
|
||||
/// An opaque token representing the current pagination position.
|
||||
/// If provided, the server should return results starting after this cursor.
|
||||
/// </summary>
|
||||
[System.Text.Json.Serialization.JsonPropertyName("cursor")]
|
||||
public string? Cursor { get; init; }
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
using ModelContextProtocol.Protocol.Messages;
|
||||
|
||||
namespace ModelContextProtocol.Protocol.Types;
|
||||
|
||||
/// <summary>
|
||||
/// The server's response to a resources/templates/list request from the client.
|
||||
/// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.json">See the schema for details</see>
|
||||
/// </summary>
|
||||
public class ListResourceTemplatesResult : PaginatedResult
|
||||
{
|
||||
/// <summary>
|
||||
/// A list of resource templates that the server offers.
|
||||
/// </summary>
|
||||
[System.Text.Json.Serialization.JsonPropertyName("resourceTemplates")]
|
||||
public List<ResourceTemplate> ResourceTemplates { get; set; } = [];
|
||||
}
|
||||
42
src/ModelContextProtocol/Protocol/Types/ResourceTemplate.cs
Normal file
42
src/ModelContextProtocol/Protocol/Types/ResourceTemplate.cs
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
using ModelContextProtocol.Protocol.Types;
|
||||
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace ModelContextProtocol.Protocol.Types;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a known resource template that the server is capable of reading.
|
||||
/// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.json">See the schema for details</see>
|
||||
/// </summary>
|
||||
public record ResourceTemplate
|
||||
{
|
||||
/// <summary>
|
||||
/// The URI template (according to RFC 6570) that can be used to construct resource URIs.
|
||||
/// </summary>
|
||||
[JsonPropertyName("uriTemplate")]
|
||||
public required string UriTemplate { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// A human-readable name for this resource template.
|
||||
/// </summary>
|
||||
[JsonPropertyName("name")]
|
||||
public required string Name { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// A description of what this resource template represents.
|
||||
/// </summary>
|
||||
[JsonPropertyName("description")]
|
||||
public string? Description { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The MIME type of this resource template, if known.
|
||||
/// </summary>
|
||||
[JsonPropertyName("mimeType")]
|
||||
public string? MimeType { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Optional annotations for the resource template.
|
||||
/// </summary>
|
||||
[JsonPropertyName("annotations")]
|
||||
public Annotations? Annotations { get; init; }
|
||||
}
|
||||
|
|
@ -155,6 +155,12 @@ internal sealed class McpServer : McpJsonRpcEndpoint, IMcpServer
|
|||
SetRequestHandler<ListResourcesRequestParams, ListResourcesResult>("resources/list", (request, ct) => listResourcesHandler(new(this, request), ct));
|
||||
SetRequestHandler<ReadResourceRequestParams, ReadResourceResult>("resources/read", (request, ct) => readResourceHandler(new(this, request), ct));
|
||||
|
||||
// Set the list resource templates handler, or use the default if not specified
|
||||
var listResourceTemplatesHandler = resourcesCapability.ListResourceTemplatesHandler
|
||||
?? (static (_, _) => Task.FromResult(new ListResourceTemplatesResult()));
|
||||
|
||||
SetRequestHandler<ListResourceTemplatesRequestParams, ListResourceTemplatesResult>("resources/templates/list", (request, ct) => listResourceTemplatesHandler(new(this, request), ct));
|
||||
|
||||
if (resourcesCapability.Subscribe is not true)
|
||||
{
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -27,6 +27,11 @@ public sealed class McpServerHandlers
|
|||
/// </summary>
|
||||
public Func<RequestContext<GetPromptRequestParams>, CancellationToken, Task<GetPromptResult>>? GetPromptHandler { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the handler for list resource templates requests.
|
||||
/// </summary>
|
||||
public Func<RequestContext<ListResourceTemplatesRequestParams>, CancellationToken, Task<ListResourceTemplatesResult>>? ListResourceTemplatesHandler { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the handler for list resources requests.
|
||||
/// </summary>
|
||||
|
|
@ -82,11 +87,13 @@ public sealed class McpServerHandlers
|
|||
resourcesCapability = resourcesCapability is null ?
|
||||
new()
|
||||
{
|
||||
ListResourceTemplatesHandler = ListResourceTemplatesHandler,
|
||||
ListResourcesHandler = ListResourcesHandler,
|
||||
ReadResourceHandler = ReadResourceHandler
|
||||
} :
|
||||
resourcesCapability with
|
||||
{
|
||||
ListResourceTemplatesHandler = ListResourceTemplatesHandler ?? resourcesCapability.ListResourceTemplatesHandler,
|
||||
ListResourcesHandler = ListResourcesHandler ?? resourcesCapability.ListResourcesHandler,
|
||||
ReadResourceHandler = ReadResourceHandler ?? resourcesCapability.ReadResourceHandler
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue