|
10 | 10 | using ModelContextProtocol.Server;
|
11 | 11 | using ModelContextProtocol.Tests.Utils;
|
12 | 12 | using ModelContextProtocol.Utils.Json;
|
| 13 | +using TestServerWithHosting.Tools; |
13 | 14 |
|
14 | 15 | namespace ModelContextProtocol.Tests;
|
15 | 16 |
|
@@ -95,6 +96,56 @@ public async Task ConnectAndReceiveNotification_InMemoryServer()
|
95 | 96 | Assert.Equal("Hello from server!", message);
|
96 | 97 | }
|
97 | 98 |
|
| 99 | + [Fact] |
| 100 | + public async Task AddMcpServer_CanBeCalled_MultipleTimes() |
| 101 | + { |
| 102 | + var firstOptionsCallbackCallCount = 0; |
| 103 | + var secondOptionsCallbackCallCount = 0; |
| 104 | + |
| 105 | + Builder.Services.AddMcpServer(options => |
| 106 | + { |
| 107 | + Interlocked.Increment(ref firstOptionsCallbackCallCount); |
| 108 | + }) |
| 109 | + .WithTools<EchoTool>(); |
| 110 | + |
| 111 | + Builder.Services.AddMcpServer(options => |
| 112 | + { |
| 113 | + Interlocked.Increment(ref secondOptionsCallbackCallCount); |
| 114 | + }) |
| 115 | + .WithTools<SampleLlmTool>(); |
| 116 | + |
| 117 | + |
| 118 | + await using var app = Builder.Build(); |
| 119 | + app.MapMcp(); |
| 120 | + await app.StartAsync(TestContext.Current.CancellationToken); |
| 121 | + |
| 122 | + using var httpClient = CreateHttpClient(); |
| 123 | + await using var mcpClient = await ConnectMcpClient(httpClient); |
| 124 | + |
| 125 | + // Options can be lazily initialized, but they must be instantiated by the time an MCP client can finish connecting. |
| 126 | + // Callbacks can be called multiple times if configureOptionsAsync is configured, because that uses the IOptionsFactory, |
| 127 | + // but that's not the case in this test. |
| 128 | + Assert.Equal(1, firstOptionsCallbackCallCount); |
| 129 | + Assert.Equal(1, secondOptionsCallbackCallCount); |
| 130 | + |
| 131 | + var tools = await mcpClient.ListToolsAsync(cancellationToken: TestContext.Current.CancellationToken); |
| 132 | + |
| 133 | + Assert.Equal(2, tools.Count); |
| 134 | + Assert.Contains(tools, tools => tools.Name == "Echo"); |
| 135 | + Assert.Contains(tools, tools => tools.Name == "sampleLLM"); |
| 136 | + |
| 137 | + var echoResponse = await mcpClient.CallToolAsync( |
| 138 | + "Echo", |
| 139 | + new Dictionary<string, object?> |
| 140 | + { |
| 141 | + ["message"] = "from client!" |
| 142 | + }, |
| 143 | + cancellationToken: TestContext.Current.CancellationToken); |
| 144 | + var textContent = Assert.Single(echoResponse.Content, c => c.Type == "text"); |
| 145 | + |
| 146 | + Assert.Equal("hello from client!", textContent.Text); |
| 147 | + } |
| 148 | + |
98 | 149 | private static void MapAbsoluteEndpointUriMcp(IEndpointRouteBuilder endpoints)
|
99 | 150 | {
|
100 | 151 | var loggerFactory = endpoints.ServiceProvider.GetRequiredService<ILoggerFactory>();
|
|
0 commit comments