Skip to content
4 changes: 3 additions & 1 deletion samples/AspNetCoreSseServer/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@
using OpenTelemetry.Metrics;
using OpenTelemetry.Trace;
using TestServerWithHosting.Tools;
using TestServerWithHosting.Resources;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddMcpServer()
.WithHttpTransport()
.WithTools<EchoTool>()
.WithTools<SampleLlmTool>();
.WithTools<SampleLlmTool>()
.WithResources<SimpleResourceType>();

builder.Services.AddOpenTelemetry()
.WithTracing(b => b.AddSource("*")
Expand Down
12 changes: 12 additions & 0 deletions samples/AspNetCoreSseServer/Resources/SimpleResourceType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using ModelContextProtocol.Protocol;
using ModelContextProtocol.Server;
using System.ComponentModel;

namespace TestServerWithHosting.Resources;

[McpServerResourceType]
public class SimpleResourceType
{
[McpServerResource, Description("A direct text resource")]
public static string DirectTextResource() => "This is a direct resource";
}
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ private static AIFunctionFactoryOptions CreateAIFunctionFactoryOptions(
Name = name,
Title = options?.Title,
Description = options?.Description,
MimeType = options?.MimeType,
MimeType = options?.MimeType ?? "application/octet-stream",
};

return new AIFunctionMcpServerResource(function, resource);
Expand Down Expand Up @@ -295,7 +295,7 @@ private static string DeriveUriTemplate(string name, AIFunction function)
{
StringBuilder template = new();

template.Append("resource://").Append(Uri.EscapeDataString(name));
template.Append("resource:///").Append(Uri.EscapeDataString(name));

if (function.JsonSchema.TryGetProperty("properties", out JsonElement properties))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ public async Task Throws_When_Resource_Fails()
await using IMcpClient client = await CreateMcpClientForServer();

await Assert.ThrowsAsync<McpException>(async () => await client.ReadResourceAsync(
$"resource://{nameof(SimpleResources.ThrowsException)}",
$"resource:///{nameof(SimpleResources.ThrowsException)}",
cancellationToken: TestContext.Current.CancellationToken));
}

Expand All @@ -230,7 +230,7 @@ public async Task Throws_Exception_On_Unknown_Resource()
await using IMcpClient client = await CreateMcpClientForServer();

var e = await Assert.ThrowsAsync<McpException>(async () => await client.ReadResourceAsync(
"test://NotRegisteredResource",
"test:///NotRegisteredResource",
cancellationToken: TestContext.Current.CancellationToken));

Assert.Contains("Resource not found", e.Message);
Expand Down Expand Up @@ -268,8 +268,8 @@ public void Register_Resources_From_Current_Assembly()
sc.AddMcpServer().WithResourcesFromAssembly();
IServiceProvider services = sc.BuildServiceProvider();

Assert.Contains(services.GetServices<McpServerResource>(), t => t.ProtocolResource?.Uri == $"resource://{nameof(SimpleResources.SomeNeatDirectResource)}");
Assert.Contains(services.GetServices<McpServerResource>(), t => t.ProtocolResourceTemplate?.UriTemplate == $"resource://{nameof(SimpleResources.SomeNeatTemplatedResource)}{{?name}}");
Assert.Contains(services.GetServices<McpServerResource>(), t => t.ProtocolResource?.Uri == $"resource:///{nameof(SimpleResources.SomeNeatDirectResource)}");
Assert.Contains(services.GetServices<McpServerResource>(), t => t.ProtocolResourceTemplate?.UriTemplate == $"resource:///{nameof(SimpleResources.SomeNeatTemplatedResource)}{{?name}}");
}

[Fact]
Expand All @@ -279,13 +279,13 @@ public void Register_Resources_From_Multiple_Sources()
sc.AddMcpServer()
.WithResources<SimpleResources>()
.WithResources<MoreResources>()
.WithResources([McpServerResource.Create(() => "42", new() { UriTemplate = "myResources://Returns42/{something}" })]);
.WithResources([McpServerResource.Create(() => "42", new() { UriTemplate = "myResources:///returns42/{something}" })]);
IServiceProvider services = sc.BuildServiceProvider();

Assert.Contains(services.GetServices<McpServerResource>(), t => t.ProtocolResource?.Uri == $"resource://{nameof(SimpleResources.SomeNeatDirectResource)}");
Assert.Contains(services.GetServices<McpServerResource>(), t => t.ProtocolResourceTemplate?.UriTemplate == $"resource://{nameof(SimpleResources.SomeNeatTemplatedResource)}{{?name}}");
Assert.Contains(services.GetServices<McpServerResource>(), t => t.ProtocolResourceTemplate?.UriTemplate == $"resource://{nameof(MoreResources.AnotherNeatDirectResource)}");
Assert.Contains(services.GetServices<McpServerResource>(), t => t.ProtocolResourceTemplate.UriTemplate == "myResources://Returns42/{something}");
Assert.Contains(services.GetServices<McpServerResource>(), t => t.ProtocolResource?.Uri == $"resource:///{nameof(SimpleResources.SomeNeatDirectResource)}");
Assert.Contains(services.GetServices<McpServerResource>(), t => t.ProtocolResourceTemplate?.UriTemplate == $"resource:///{nameof(SimpleResources.SomeNeatTemplatedResource)}{{?name}}");
Assert.Contains(services.GetServices<McpServerResource>(), t => t.ProtocolResourceTemplate?.UriTemplate == $"resource:///{nameof(MoreResources.AnotherNeatDirectResource)}");
Assert.Contains(services.GetServices<McpServerResource>(), t => t.ProtocolResourceTemplate.UriTemplate == "myResources:///returns42/{something}");
}

[McpServerResourceType]
Expand Down
Loading