Restructure IMcpEndpoint, IMcpClient, and IMcpServer (#723)

* Remove `McpEndpoint` & `IMcpClient`

* Revise naming, add abstract classes

* Fix missing renames

* Move extension methods to instance methods

* Add back old API, but obsoleted

* Add back obsoleted factory classes

* Move deprecation attributes

* `SseClientTransport` -> `HttpClientTransport`

* Update src/ModelContextProtocol.Core/Server/AugmentedServiceProvider.cs

Co-authored-by: Stephen Halter <halter73@gmail.com>

* PR feedback

* PR feedback

* Add back dispose lock

* Fix docs projects

* PR feedback

* Undo `docs/*.md` changes

---------

Co-authored-by: Stephen Halter <halter73@gmail.com>
This commit is contained in:
Mackinnon Buck 2025-09-16 13:22:10 -04:00 • committed by GitHub
commit 38b4a26998
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -60,7 +60,7 @@ public partial class McpServerResourceTests
var provider = services.BuildServiceProvider();
provider.GetRequiredService<IMcpServer>();
provider.GetRequiredService<McpServer>();
}
@ -96,7 +96,7 @@ public partial class McpServerResourceTests
var provider = services.BuildServiceProvider();
provider.GetRequiredService<IMcpServer>();
provider.GetRequiredService<McpServer>();
}
[Fact]
@ -119,7 +119,7 @@ public partial class McpServerResourceTests
});
var sp = services.BuildServiceProvider();
sp.GetRequiredService<IMcpServer>();
sp.GetRequiredService<McpServer>();
}
[Fact]
@ -143,7 +143,7 @@ public partial class McpServerResourceTests
McpServerResource t;
ReadResourceResult? result;
IMcpServer server = new Mock<IMcpServer>().Object;
McpServer server = new Mock<McpServer>().Object;
t = McpServerResource.Create(() => "42", new() { Name = Name });
Assert.Equal("resource://mcp/Hello", t.ProtocolResourceTemplate.UriTemplate);
@ -153,7 +153,7 @@ public partial class McpServerResourceTests
Assert.NotNull(result);
Assert.Equal("42", ((TextResourceContents)result.Contents[0]).Text);
t = McpServerResource.Create((IMcpServer server) => "42", new() { Name = Name });
t = McpServerResource.Create((McpServer server) => "42", new() { Name = Name });
Assert.Equal("resource://mcp/Hello", t.ProtocolResourceTemplate.UriTemplate);
result = await t.ReadAsync(
new RequestContext<ReadResourceRequestParams>(server, CreateTestJsonRpcRequest()) { Params = new() { Uri = "resource://mcp/Hello" } },
@ -287,7 +287,7 @@ public partial class McpServerResourceTests
McpServerResource t = McpServerResource.Create((string arg1) => arg1, new() { Name = "Hello" });
Assert.Equal("resource://mcp/Hello{?arg1}", t.ProtocolResourceTemplate.UriTemplate);
Assert.Null(await t.ReadAsync(
new RequestContext<ReadResourceRequestParams>(new Mock<IMcpServer>().Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = uri } },
new RequestContext<ReadResourceRequestParams>(new Mock<McpServer>().Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = uri } },
TestContext.Current.CancellationToken));
}
@ -298,7 +298,7 @@ public partial class McpServerResourceTests
{
McpServerResource t = McpServerResource.Create(() => "resource", new() { UriTemplate = actualUri });
Assert.NotNull(await t.ReadAsync(
new RequestContext<ReadResourceRequestParams>(new Mock<IMcpServer>().Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = queriedUri } },
new RequestContext<ReadResourceRequestParams>(new Mock<McpServer>().Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = queriedUri } },
TestContext.Current.CancellationToken));
}
@ -327,7 +327,7 @@ public partial class McpServerResourceTests
McpServerResource t = McpServerResource.Create((string arg1, int arg2) => arg1, new() { Name = "Hello" });
Assert.Equal("resource://mcp/Hello{?arg1,arg2}", t.ProtocolResourceTemplate.UriTemplate);
await Assert.ThrowsAsync<ArgumentException>(async () => await t.ReadAsync(
new RequestContext<ReadResourceRequestParams>(new Mock<IMcpServer>().Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = uri } },
new RequestContext<ReadResourceRequestParams>(new Mock<McpServer>().Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = uri } },
TestContext.Current.CancellationToken));
}
@ -340,36 +340,36 @@ public partial class McpServerResourceTests
ReadResourceResult? result;
result = await t.ReadAsync(
new RequestContext<ReadResourceRequestParams>(new Mock<IMcpServer>().Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = "resource://mcp/Hello" } },
new RequestContext<ReadResourceRequestParams>(new Mock<McpServer>().Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = "resource://mcp/Hello" } },
TestContext.Current.CancellationToken);
Assert.NotNull(result);
Assert.Equal("", ((TextResourceContents)result.Contents[0]).Text);
result = await t.ReadAsync(
new RequestContext<ReadResourceRequestParams>(new Mock<IMcpServer>().Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = "resource://mcp/Hello?arg1=first" } },
new RequestContext<ReadResourceRequestParams>(new Mock<McpServer>().Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = "resource://mcp/Hello?arg1=first" } },
TestContext.Current.CancellationToken);
Assert.NotNull(result);
Assert.Equal("first", ((TextResourceContents)result.Contents[0]).Text);
result = await t.ReadAsync(
new RequestContext<ReadResourceRequestParams>(new Mock<IMcpServer>().Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = "resource://mcp/Hello?arg2=42" } },
new RequestContext<ReadResourceRequestParams>(new Mock<McpServer>().Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = "resource://mcp/Hello?arg2=42" } },
TestContext.Current.CancellationToken);
Assert.NotNull(result);
Assert.Equal("42", ((TextResourceContents)result.Contents[0]).Text);
result = await t.ReadAsync(
new RequestContext<ReadResourceRequestParams>(new Mock<IMcpServer>().Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = "resource://mcp/Hello?arg1=first&arg2=42" } },
new RequestContext<ReadResourceRequestParams>(new Mock<McpServer>().Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = "resource://mcp/Hello?arg1=first&arg2=42" } },
TestContext.Current.CancellationToken);
Assert.NotNull(result);
Assert.Equal("first42", ((TextResourceContents)result.Contents[0]).Text);
}
[Fact]
public async Task SupportsIMcpServer()
public async Task SupportsMcpServer()
{
Mock<IMcpServer> mockServer = new();
Mock<McpServer> mockServer = new();
McpServerResource resource = McpServerResource.Create((IMcpServer server) =>
McpServerResource resource = McpServerResource.Create((McpServer server) =>
{
Assert.Same(mockServer.Object, server);
return "42";
@ -391,7 +391,7 @@ public partial class McpServerResourceTests
sc.AddSingleton(expectedMyService);
IServiceProvider services = sc.BuildServiceProvider();
Mock<IMcpServer> mockServer = new();
Mock<McpServer> mockServer = new();
mockServer.SetupGet(s => s.Services).Returns(services);
MethodInfo? testMethod = typeof(HasCtorWithSpecialParameters).GetMethod(nameof(HasCtorWithSpecialParameters.TestResource));
@ -414,11 +414,11 @@ public partial class McpServerResourceTests
private sealed class HasCtorWithSpecialParameters
{
private readonly MyService _ms;
private readonly IMcpServer _server;
private readonly McpServer _server;
private readonly RequestContext<ReadResourceRequestParams> _request;
private readonly IProgress<ProgressNotificationValue> _progress;
public HasCtorWithSpecialParameters(MyService ms, IMcpServer server, RequestContext<ReadResourceRequestParams> request, IProgress<ProgressNotificationValue> progress)
public HasCtorWithSpecialParameters(MyService ms, McpServer server, RequestContext<ReadResourceRequestParams> request, IProgress<ProgressNotificationValue> progress)
{
Assert.NotNull(ms);
Assert.NotNull(server);
@ -477,7 +477,7 @@ public partial class McpServerResourceTests
McpServerResource resource = services.GetRequiredService<McpServerResource>();
Mock<IMcpServer> mockServer = new();
Mock<McpServer> mockServer = new();
await Assert.ThrowsAnyAsync<ArgumentException>(async () => await resource.ReadAsync(
new RequestContext<ReadResourceRequestParams>(mockServer.Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = "resource://mcp/Test" } },
@ -506,7 +506,7 @@ public partial class McpServerResourceTests
}, new() { Services = services, Name = "Test" });
var result = await resource.ReadAsync(
new RequestContext<ReadResourceRequestParams>(new Mock<IMcpServer>().Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = "resource://mcp/Test" } },
new RequestContext<ReadResourceRequestParams>(new Mock<McpServer>().Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = "resource://mcp/Test" } },
TestContext.Current.CancellationToken);
Assert.NotNull(result);
Assert.Equal("42", ((TextResourceContents)result.Contents[0]).Text);
@ -522,7 +522,7 @@ public partial class McpServerResourceTests
_ => new DisposableResourceType());
var result = await resource1.ReadAsync(
new RequestContext<ReadResourceRequestParams>(new Mock<IMcpServer>().Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = "test://static/resource/instanceMethod" } },
new RequestContext<ReadResourceRequestParams>(new Mock<McpServer>().Object, CreateTestJsonRpcRequest()) { Params = new() { Uri = "test://static/resource/instanceMethod" } },
TestContext.Current.CancellationToken);
Assert.NotNull(result);
Assert.Equal("0", ((TextResourceContents)result.Contents[0]).Text);
@ -533,8 +533,8 @@ public partial class McpServerResourceTests
[Fact]
public async Task CanReturnReadResult()
{
Mock<IMcpServer> mockServer = new();
McpServerResource resource = McpServerResource.Create((IMcpServer server) =>
Mock<McpServer> mockServer = new();
McpServerResource resource = McpServerResource.Create((McpServer server) =>
{
Assert.Same(mockServer.Object, server);
return new ReadResourceResult { Contents = new List<ResourceContents> { new TextResourceContents { Text = "hello" } } };
@ -550,8 +550,8 @@ public partial class McpServerResourceTests
[Fact]
public async Task CanReturnResourceContents()
{
Mock<IMcpServer> mockServer = new();
McpServerResource resource = McpServerResource.Create((IMcpServer server) =>
Mock<McpServer> mockServer = new();
McpServerResource resource = McpServerResource.Create((McpServer server) =>
{
Assert.Same(mockServer.Object, server);
return new TextResourceContents { Text = "hello" };
@ -567,8 +567,8 @@ public partial class McpServerResourceTests
[Fact]
public async Task CanReturnCollectionOfResourceContents()
{
Mock<IMcpServer> mockServer = new();
McpServerResource resource = McpServerResource.Create((IMcpServer server) =>
Mock<McpServer> mockServer = new();
McpServerResource resource = McpServerResource.Create((McpServer server) =>
{
Assert.Same(mockServer.Object, server);
return (IList<ResourceContents>)
@ -589,8 +589,8 @@ public partial class McpServerResourceTests
[Fact]
public async Task CanReturnString()
{
Mock<IMcpServer> mockServer = new();
McpServerResource resource = McpServerResource.Create((IMcpServer server) =>
Mock<McpServer> mockServer = new();
McpServerResource resource = McpServerResource.Create((McpServer server) =>
{
Assert.Same(mockServer.Object, server);
return "42";
@ -606,8 +606,8 @@ public partial class McpServerResourceTests
[Fact]
public async Task CanReturnCollectionOfStrings()
{
Mock<IMcpServer> mockServer = new();
McpServerResource resource = McpServerResource.Create((IMcpServer server) =>
Mock<McpServer> mockServer = new();
McpServerResource resource = McpServerResource.Create((McpServer server) =>
{
Assert.Same(mockServer.Object, server);
return new List<string> { "42", "43" };
@ -624,8 +624,8 @@ public partial class McpServerResourceTests
[Fact]
public async Task CanReturnDataContent()
{
Mock<IMcpServer> mockServer = new();
McpServerResource resource = McpServerResource.Create((IMcpServer server) =>
Mock<McpServer> mockServer = new();
McpServerResource resource = McpServerResource.Create((McpServer server) =>
{
Assert.Same(mockServer.Object, server);
return new DataContent(new byte[] { 0, 1, 2 }, "application/octet-stream");
@ -642,8 +642,8 @@ public partial class McpServerResourceTests
[Fact]
public async Task CanReturnCollectionOfAIContent()
{
Mock<IMcpServer> mockServer = new();
McpServerResource resource = McpServerResource.Create((IMcpServer server) =>
Mock<McpServer> mockServer = new();
McpServerResource resource = McpServerResource.Create((McpServer server) =>
{
Assert.Same(mockServer.Object, server);
return new List<AIContent>