Overhaul of Resources (#125)
* Supporting resource templates with read resource callback Fixes #123 * Aligning the resource data structures with the 2024-11-05 schema - Introducing separate classes for Text and Blob ResourceContents - Custom JSON converter to allow those types to be returned, making it easier to follow the type system against the spec - Updated tests * Apply suggestions from code review Co-authored-by: Stephen Toub <stoub@microsoft.com> Co-authored-by: Peder Holdgaard Pedersen <127606677+PederHP@users.noreply.github.com> * Putting files back where they belong * Adding an internal constructor to prevent overloads * Addressing feedback * Apply suggestions from code review Co-authored-by: Stephen Toub <stoub@microsoft.com> * Update src/ModelContextProtocol/Protocol/Types/ResourceContents.cs * Addressing feedback --------- Co-authored-by: Stephen Toub <stoub@microsoft.com> Co-authored-by: Peder Holdgaard Pedersen <127606677+PederHP@users.noreply.github.com>
This commit is contained in:
parent
2ab9db0878
commit
3c0679e92b
4 changed files with 290 additions and 49 deletions
|
|
@ -224,7 +224,9 @@ public class ClientIntegrationTests : LoggedTest, IClassFixture<ClientIntegratio
|
|||
|
||||
Assert.NotNull(result);
|
||||
Assert.Single(result.Contents);
|
||||
Assert.NotNull(result.Contents[0].Text);
|
||||
|
||||
TextResourceContents textResource = Assert.IsType<TextResourceContents>(result.Contents[0]);
|
||||
Assert.NotNull(textResource.Text);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
|
@ -241,7 +243,9 @@ public class ClientIntegrationTests : LoggedTest, IClassFixture<ClientIntegratio
|
|||
|
||||
Assert.NotNull(result);
|
||||
Assert.Single(result.Contents);
|
||||
Assert.NotNull(result.Contents[0].Blob);
|
||||
|
||||
BlobResourceContents blobResource = Assert.IsType<BlobResourceContents>(result.Contents[0]);
|
||||
Assert.NotNull(blobResource.Blob);
|
||||
}
|
||||
|
||||
// Not supported by "everything" server version on npx
|
||||
|
|
|
|||
|
|
@ -0,0 +1,100 @@
|
|||
using Microsoft.Extensions.DependencyInjection;
|
||||
using ModelContextProtocol.Protocol.Types;
|
||||
using ModelContextProtocol.Server;
|
||||
|
||||
namespace ModelContextProtocol.Tests.Server;
|
||||
|
||||
public class McpServerResourceTests
|
||||
{
|
||||
[Fact]
|
||||
public void CanCreateServerWithResourceTemplates()
|
||||
{
|
||||
var services = new ServiceCollection();
|
||||
|
||||
services.AddMcpServer()
|
||||
.WithStdioServerTransport()
|
||||
.WithListResourceTemplatesHandler((ctx, ct) =>
|
||||
{
|
||||
return Task.FromResult(new ListResourceTemplatesResult
|
||||
{
|
||||
ResourceTemplates =
|
||||
[
|
||||
new ResourceTemplate { Name = "Static Resource", Description = "A static resource with a numeric ID", UriTemplate = "test://static/resource/{id}" }
|
||||
]
|
||||
});
|
||||
})
|
||||
.WithReadResourceHandler((ctx, ct) =>
|
||||
{
|
||||
return Task.FromResult(new ReadResourceResult
|
||||
{
|
||||
Contents = [new TextResourceContents
|
||||
{
|
||||
Uri = ctx.Params!.Uri!,
|
||||
Text = "Static Resource",
|
||||
MimeType = "text/plain",
|
||||
}]
|
||||
});
|
||||
});
|
||||
|
||||
var provider = services.BuildServiceProvider();
|
||||
|
||||
provider.GetRequiredService<IMcpServer>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanCreateServerWithResources()
|
||||
{
|
||||
var services = new ServiceCollection();
|
||||
|
||||
services.AddMcpServer()
|
||||
.WithStdioServerTransport()
|
||||
.WithListResourcesHandler((ctx, ct) =>
|
||||
{
|
||||
return Task.FromResult(new ListResourcesResult
|
||||
{
|
||||
Resources =
|
||||
[
|
||||
new Resource { Name = "Static Resource", Description = "A static resource with a numeric ID", Uri = "test://static/resource/foo.txt" }
|
||||
]
|
||||
});
|
||||
})
|
||||
.WithReadResourceHandler((ctx, ct) =>
|
||||
{
|
||||
return Task.FromResult(new ReadResourceResult
|
||||
{
|
||||
Contents = [new TextResourceContents
|
||||
{
|
||||
Uri = ctx.Params!.Uri!,
|
||||
Text = "Static Resource",
|
||||
MimeType = "text/plain",
|
||||
}]
|
||||
});
|
||||
});
|
||||
|
||||
var provider = services.BuildServiceProvider();
|
||||
|
||||
provider.GetRequiredService<IMcpServer>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreatingReadHandlerWithNoListHandlerFails()
|
||||
{
|
||||
var services = new ServiceCollection();
|
||||
services.AddMcpServer()
|
||||
.WithStdioServerTransport()
|
||||
.WithReadResourceHandler((ctx, ct) =>
|
||||
{
|
||||
return Task.FromResult(new ReadResourceResult
|
||||
{
|
||||
Contents = [new TextResourceContents
|
||||
{
|
||||
Uri = ctx.Params!.Uri!,
|
||||
Text = "Static Resource",
|
||||
MimeType = "text/plain",
|
||||
}]
|
||||
});
|
||||
});
|
||||
var sp = services.BuildServiceProvider();
|
||||
Assert.Throws<McpServerException>(() => sp.GetRequiredService<IMcpServer>());
|
||||
}
|
||||
}
|
||||
|
|
@ -349,7 +349,7 @@ public class McpServerTests : LoggedTest
|
|||
{
|
||||
return Task.FromResult(new ReadResourceResult
|
||||
{
|
||||
Contents = [new() { Text = "test" }]
|
||||
Contents = [new TextResourceContents() { Text = "test" }]
|
||||
});
|
||||
},
|
||||
ListResourcesHandler = (request, ct) => throw new NotImplementedException(),
|
||||
|
|
@ -364,7 +364,9 @@ public class McpServerTests : LoggedTest
|
|||
var result = (ReadResourceResult)response;
|
||||
Assert.NotNull(result.Contents);
|
||||
Assert.NotEmpty(result.Contents);
|
||||
Assert.Equal("test", result.Contents[0].Text);
|
||||
|
||||
TextResourceContents textResource = Assert.IsType<TextResourceContents>(result.Contents[0]);
|
||||
Assert.Equal("test", textResource.Text);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -120,7 +120,9 @@ public class SseServerIntegrationTests : LoggedTest, IClassFixture<SseServerInte
|
|||
|
||||
Assert.NotNull(result);
|
||||
Assert.Single(result.Contents);
|
||||
Assert.NotNull(result.Contents[0].Text);
|
||||
|
||||
TextResourceContents textContent = Assert.IsType<TextResourceContents>(result.Contents[0]);
|
||||
Assert.NotNull(textContent.Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -137,7 +139,9 @@ public class SseServerIntegrationTests : LoggedTest, IClassFixture<SseServerInte
|
|||
|
||||
Assert.NotNull(result);
|
||||
Assert.Single(result.Contents);
|
||||
Assert.NotNull(result.Contents[0].Blob);
|
||||
|
||||
BlobResourceContents blobContent = Assert.IsType<BlobResourceContents>(result.Contents[0]);
|
||||
Assert.NotNull(blobContent.Blob);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
|||
Loading…
Reference in a new issue