Add WithXx overloads that take target instance (#706)
* Add WithXx overloads that take target instance * Special-case enumerables
This commit is contained in:
parent
aef509fd92
commit
2fa658e439
1 changed files with 290 additions and 4 deletions
|
|
@ -4,8 +4,12 @@ using Microsoft.Extensions.Options;
|
|||
using ModelContextProtocol.Client;
|
||||
using ModelContextProtocol.Protocol;
|
||||
using ModelContextProtocol.Server;
|
||||
using Moq;
|
||||
using System.Collections;
|
||||
using System.ComponentModel;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Channels;
|
||||
using static ModelContextProtocol.Tests.Configuration.McpServerBuilderExtensionsPromptsTests;
|
||||
|
||||
namespace ModelContextProtocol.Tests.Configuration;
|
||||
|
||||
|
|
@ -243,13 +247,59 @@ public partial class McpServerBuilderExtensionsResourcesTests : ClientServerTest
|
|||
|
||||
Assert.Throws<ArgumentNullException>("resourceTemplates", () => builder.WithResources((IEnumerable<McpServerResource>)null!));
|
||||
Assert.Throws<ArgumentNullException>("resourceTemplateTypes", () => builder.WithResources((IEnumerable<Type>)null!));
|
||||
Assert.Throws<ArgumentNullException>("target", () => builder.WithResources<object>(target: null!));
|
||||
|
||||
IMcpServerBuilder nullBuilder = null!;
|
||||
Assert.Throws<ArgumentNullException>("builder", () => nullBuilder.WithResources<object>());
|
||||
Assert.Throws<ArgumentNullException>("builder", () => nullBuilder.WithResources(new object()));
|
||||
Assert.Throws<ArgumentNullException>("builder", () => nullBuilder.WithResources(Array.Empty<Type>()));
|
||||
Assert.Throws<ArgumentNullException>("builder", () => nullBuilder.WithResourcesFromAssembly());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task WithResources_TargetInstance_UsesTarget()
|
||||
{
|
||||
ServiceCollection sc = new();
|
||||
|
||||
var target = new ResourceWithId(new ObjectWithId() { Id = "42" });
|
||||
sc.AddMcpServer().WithResources(target);
|
||||
|
||||
McpServerResource resource = sc.BuildServiceProvider().GetServices<McpServerResource>().First(t => t.ProtocolResource?.Name == "returns_string");
|
||||
var result = await resource.ReadAsync(new RequestContext<ReadResourceRequestParams>(new Mock<IMcpServer>().Object)
|
||||
{
|
||||
Params = new()
|
||||
{
|
||||
Uri = "returns://string"
|
||||
}
|
||||
}, TestContext.Current.CancellationToken);
|
||||
|
||||
Assert.Equal(target.ReturnsString(), (result?.Contents[0] as TextResourceContents)?.Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task WithResources_TargetInstance_UsesEnumerableImplementation()
|
||||
{
|
||||
ServiceCollection sc = new();
|
||||
|
||||
sc.AddMcpServer().WithResources(new MyResourceProvider());
|
||||
|
||||
var resources = sc.BuildServiceProvider().GetServices<McpServerResource>().ToArray();
|
||||
Assert.Equal(2, resources.Length);
|
||||
Assert.Contains(resources, t => t.ProtocolResource?.Name == "Returns42");
|
||||
Assert.Contains(resources, t => t.ProtocolResource?.Name == "Returns43");
|
||||
}
|
||||
|
||||
private sealed class MyResourceProvider : IEnumerable<McpServerResource>
|
||||
{
|
||||
public IEnumerator<McpServerResource> GetEnumerator()
|
||||
{
|
||||
yield return McpServerResource.Create(() => "42", new() { Name = "Returns42" });
|
||||
yield return McpServerResource.Create(() => "43", new() { Name = "Returns43" });
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Empty_Enumerables_Is_Allowed()
|
||||
{
|
||||
|
|
@ -307,4 +357,11 @@ public partial class McpServerBuilderExtensionsResourcesTests : ClientServerTest
|
|||
[McpServerResource, Description("Another neat direct resource")]
|
||||
public static string AnotherNeatDirectResource() => "This is a neat resource";
|
||||
}
|
||||
|
||||
[McpServerResourceType]
|
||||
public sealed class ResourceWithId(ObjectWithId id)
|
||||
{
|
||||
[McpServerResource(UriTemplate = "returns://string")]
|
||||
public string ReturnsString() => $"Id: {id.Id}";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue