Remove warnings from build (#29)
* Remove warnings from build * More fixes. * Using const for transport types
This commit is contained in:
parent
80daa5b73d
commit
7d69499ad5
12 changed files with 277 additions and 263 deletions
|
|
@ -17,7 +17,7 @@ public class IntegrationTests
|
|||
{
|
||||
Id = "everything",
|
||||
Name = "Everything",
|
||||
TransportType = "stdio",
|
||||
TransportType = McpDotNet.Protocol.Transport.TransportTypes.StdIo,
|
||||
TransportOptions = new Dictionary<string, string>
|
||||
{
|
||||
["command"] = "npx",
|
||||
|
|
@ -59,9 +59,11 @@ public class IntegrationTests
|
|||
.Build();
|
||||
|
||||
// Create message list
|
||||
IList<ChatMessage> messages = new List<ChatMessage>();
|
||||
// Add a system message
|
||||
messages.Add(new(ChatRole.System, "You are a helpful assistant, helping us test MCP server functionality."));
|
||||
IList<ChatMessage> messages =
|
||||
[
|
||||
// Add a system message
|
||||
new(ChatRole.System, "You are a helpful assistant, helping us test MCP server functionality."),
|
||||
];
|
||||
// If MCP server provides instructions, add them as an additional system message (you could also add it as a content part)
|
||||
if (!string.IsNullOrEmpty(client.ServerInstructions))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\McpDotNet.Extensions.AI\McpDotNet.Extensions.AI.csproj" />
|
||||
<ProjectReference Include="..\..\src\mcpdotnet\mcpdotnet.csproj" />
|
||||
<PackageReference Include="Microsoft.Extensions.AI.OpenAI" Version="9.3.0-preview.1.25114.11" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ internal class Program
|
|||
|
||||
server.CallToolHandler = async (request, cancellationToken) =>
|
||||
{
|
||||
if (request.Name == "echo")
|
||||
if (request?.Name == "echo")
|
||||
{
|
||||
if (request.Arguments is null || !request.Arguments.TryGetValue("message", out var message))
|
||||
{
|
||||
|
|
@ -119,7 +119,7 @@ internal class Program
|
|||
Content = [new Content() { Text = "Echo: " + message.ToString(), Type = "text" }]
|
||||
};
|
||||
}
|
||||
else if (request.Name == "sampleLLM")
|
||||
else if (request?.Name == "sampleLLM")
|
||||
{
|
||||
if (request.Arguments is null ||
|
||||
!request.Arguments.TryGetValue("prompt", out var prompt) ||
|
||||
|
|
@ -137,14 +137,14 @@ internal class Program
|
|||
}
|
||||
else
|
||||
{
|
||||
throw new McpServerException($"Unknown tool: {request.Name}");
|
||||
throw new McpServerException($"Unknown tool: {request?.Name}");
|
||||
}
|
||||
};
|
||||
#endregion
|
||||
|
||||
#region Resources
|
||||
List<Resource> resources = new();
|
||||
List<ResourceContents> resourceContents = new();
|
||||
List<Resource> resources = [];
|
||||
List<ResourceContents> resourceContents = [];
|
||||
for (int i = 0; i < 100; ++i)
|
||||
{
|
||||
string uri = $"test://static/resource/{i + 1}";
|
||||
|
|
@ -216,15 +216,14 @@ internal class Program
|
|||
|
||||
server.ReadResourceHandler = (request, cancellationToken) =>
|
||||
{
|
||||
if (request.Uri is null)
|
||||
if (request?.Uri is null)
|
||||
{
|
||||
throw new McpServerException("Missing required argument 'uri'");
|
||||
}
|
||||
ResourceContents? contents = resourceContents.FirstOrDefault(r => r.Uri == request.Uri);
|
||||
if (contents is null)
|
||||
{
|
||||
throw new McpServerException("Resource not found");
|
||||
}
|
||||
|
||||
ResourceContents contents = resourceContents.FirstOrDefault(r => r.Uri == request.Uri)
|
||||
?? throw new McpServerException("Resource not found");
|
||||
|
||||
return Task.FromResult(new ReadResourceResult()
|
||||
{
|
||||
Contents = [contents]
|
||||
|
|
@ -247,8 +246,8 @@ internal class Program
|
|||
{
|
||||
Name = "complex_prompt",
|
||||
Description = "A prompt with arguments",
|
||||
Arguments = new()
|
||||
{
|
||||
Arguments =
|
||||
[
|
||||
new PromptArgument()
|
||||
{
|
||||
Name = "temperature",
|
||||
|
|
@ -261,7 +260,7 @@ internal class Program
|
|||
Description = "Output style",
|
||||
Required = false
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
|
|
@ -269,8 +268,8 @@ internal class Program
|
|||
|
||||
server.GetPromptHandler = (request, cancellationToken) =>
|
||||
{
|
||||
List<PromptMessage> messages = new();
|
||||
if (request.Name == "simple_prompt")
|
||||
List<PromptMessage> messages = [];
|
||||
if (request?.Name == "simple_prompt")
|
||||
{
|
||||
messages.Add(new PromptMessage()
|
||||
{
|
||||
|
|
@ -282,7 +281,7 @@ internal class Program
|
|||
}
|
||||
});
|
||||
}
|
||||
else if (request.Name == "complex_prompt")
|
||||
else if (request?.Name == "complex_prompt")
|
||||
{
|
||||
string temperature = request.Arguments?["temperature"]?.ToString() ?? "unknown";
|
||||
string style = request.Arguments?["style"]?.ToString() ?? "unknown";
|
||||
|
|
@ -317,7 +316,7 @@ internal class Program
|
|||
}
|
||||
else
|
||||
{
|
||||
throw new McpServerException($"Unknown prompt: {request.Name}");
|
||||
throw new McpServerException($"Unknown prompt: {request?.Name}");
|
||||
}
|
||||
|
||||
return Task.FromResult(new GetPromptResult()
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using McpDotNet.Client;
|
||||
using McpDotNet.Configuration;
|
||||
using McpDotNet.Protocol.Transport;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace McpDotNet.Tests;
|
||||
|
|
@ -26,7 +27,7 @@ public class ClientIntegrationTestFixture : IDisposable
|
|||
{
|
||||
Id = "everything",
|
||||
Name = "Everything",
|
||||
TransportType = "stdio",
|
||||
TransportType = TransportTypes.StdIo,
|
||||
TransportOptions = new Dictionary<string, string>
|
||||
{
|
||||
["command"] = "npx",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using McpDotNet.Client;
|
||||
using McpDotNet.Configuration;
|
||||
using McpDotNet.Protocol.Messages;
|
||||
using McpDotNet.Protocol.Transport;
|
||||
using McpDotNet.Protocol.Types;
|
||||
|
||||
namespace McpDotNet.Tests;
|
||||
|
|
@ -151,7 +152,7 @@ public class ClientIntegrationTests : IClassFixture<ClientIntegrationTestFixture
|
|||
// act
|
||||
var client = await _fixture.Factory.GetClientAsync("everything");
|
||||
|
||||
List<Resource> allResources = new();
|
||||
List<Resource> allResources = [];
|
||||
string? cursor = null;
|
||||
do
|
||||
{
|
||||
|
|
@ -267,7 +268,7 @@ public class ClientIntegrationTests : IClassFixture<ClientIntegrationTestFixture
|
|||
{
|
||||
Id = "everything",
|
||||
Name = "Everything",
|
||||
TransportType = "stdio",
|
||||
TransportType = TransportTypes.StdIo,
|
||||
TransportOptions = new Dictionary<string, string>
|
||||
{
|
||||
["command"] = "npx",
|
||||
|
|
@ -335,7 +336,7 @@ public class ClientIntegrationTests : IClassFixture<ClientIntegrationTestFixture
|
|||
{
|
||||
Id = "everything",
|
||||
Name = "everything",
|
||||
TransportType = "stdio",
|
||||
TransportType = TransportTypes.StdIo,
|
||||
TransportOptions = new Dictionary<string, string>
|
||||
{
|
||||
["command"] = "npx",
|
||||
|
|
@ -394,7 +395,7 @@ public class ClientIntegrationTests : IClassFixture<ClientIntegrationTestFixture
|
|||
{
|
||||
Id = "everything",
|
||||
Name = "everything",
|
||||
TransportType = "stdio",
|
||||
TransportType = TransportTypes.StdIo,
|
||||
TransportOptions = new Dictionary<string, string>
|
||||
{
|
||||
["command"] = "npx",
|
||||
|
|
@ -429,7 +430,7 @@ public class ClientIntegrationTests : IClassFixture<ClientIntegrationTestFixture
|
|||
{
|
||||
Id = "memory",
|
||||
Name = "memory",
|
||||
TransportType = "stdio",
|
||||
TransportType = TransportTypes.StdIo,
|
||||
TransportOptions = new Dictionary<string, string>
|
||||
{
|
||||
["command"] = "npx",
|
||||
|
|
@ -450,7 +451,7 @@ public class ClientIntegrationTests : IClassFixture<ClientIntegrationTestFixture
|
|||
// act
|
||||
var result = await client.CallToolAsync(
|
||||
"read_graph",
|
||||
new Dictionary<string, object>(),
|
||||
[],
|
||||
CancellationToken.None
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ namespace McpDotNet.Tests;
|
|||
|
||||
public class EverythingSseServerFixture : IAsyncDisposable
|
||||
{
|
||||
private Process _process;
|
||||
private Process? _process;
|
||||
|
||||
public async Task StartAsync()
|
||||
{
|
||||
|
|
@ -18,7 +18,8 @@ public class EverythingSseServerFixture : IAsyncDisposable
|
|||
UseShellExecute = false,
|
||||
};
|
||||
|
||||
_process = Process.Start(processStartInfo);
|
||||
_process = Process.Start(processStartInfo)
|
||||
?? throw new InvalidOperationException($"Could not start process for {processStartInfo.FileName} with '{processStartInfo.Arguments}'.");
|
||||
|
||||
// Wait for the server to start
|
||||
await Task.Delay(10000);
|
||||
|
|
@ -36,7 +37,8 @@ public class EverythingSseServerFixture : IAsyncDisposable
|
|||
UseShellExecute = false
|
||||
};
|
||||
|
||||
using var psProcess = Process.Start(psInfo);
|
||||
using var psProcess = Process.Start(psInfo)
|
||||
?? throw new InvalidOperationException($"Could not start process for {psInfo.FileName} with '{psInfo.Arguments}'.");
|
||||
string containerId = await psProcess.StandardOutput.ReadToEndAsync();
|
||||
containerId = containerId.Trim();
|
||||
|
||||
|
|
@ -50,7 +52,8 @@ public class EverythingSseServerFixture : IAsyncDisposable
|
|||
UseShellExecute = false
|
||||
};
|
||||
|
||||
using var stopProcess = Process.Start(stopInfo);
|
||||
using var stopProcess = Process.Start(stopInfo)
|
||||
?? throw new InvalidOperationException($"Could not start process for {stopInfo.FileName} with '{stopInfo.Arguments}'.");
|
||||
await stopProcess.WaitForExitAsync();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
using System.Threading.Channels;
|
||||
using McpDotNet.Client;
|
||||
using McpDotNet.Configuration;
|
||||
using McpDotNet.Protocol.Messages;
|
||||
using McpDotNet.Protocol.Transport;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Moq;
|
||||
using System.Threading.Channels;
|
||||
|
||||
namespace McpDotNet.Tests.Client;
|
||||
|
||||
|
|
@ -23,7 +23,7 @@ public class McpClientFactoryTests
|
|||
{
|
||||
Id = "test-server",
|
||||
Name = "Test Server",
|
||||
TransportType = "stdio",
|
||||
TransportType = TransportTypes.StdIo,
|
||||
Location = "/path/to/server",
|
||||
TransportOptions = new Dictionary<string, string>
|
||||
{
|
||||
|
|
@ -70,7 +70,7 @@ public class McpClientFactoryTests
|
|||
{
|
||||
Id = "test-server",
|
||||
Name = "Test Server",
|
||||
TransportType = "stdio",
|
||||
TransportType = TransportTypes.StdIo,
|
||||
Location = "/path/to/server"
|
||||
};
|
||||
|
||||
|
|
@ -87,11 +87,11 @@ public class McpClientFactoryTests
|
|||
.Returns(Task.CompletedTask);
|
||||
mockClient.Setup(c => c.IsInitialized).Returns(true);
|
||||
|
||||
var factory = new McpClientFactory([config],
|
||||
var factory = new McpClientFactory([config],
|
||||
_defaultOptions,
|
||||
NullLoggerFactory.Instance,
|
||||
transportFactoryMethod: _ => mockTransport.Object,
|
||||
clientFactoryMethod: (_,_,_) => mockClient.Object);
|
||||
transportFactoryMethod: _ => mockTransport.Object,
|
||||
clientFactoryMethod: (_, _, _) => mockClient.Object);
|
||||
|
||||
// Act
|
||||
var client1 = await factory.GetClientAsync("test-server");
|
||||
|
|
@ -105,7 +105,7 @@ public class McpClientFactoryTests
|
|||
public async Task GetClientAsync_WithInvalidServerId_ThrowsArgumentException()
|
||||
{
|
||||
// Arrange
|
||||
var factory = new McpClientFactory(Array.Empty<McpServerConfig>(),
|
||||
var factory = new McpClientFactory(Array.Empty<McpServerConfig>(),
|
||||
_defaultOptions,
|
||||
NullLoggerFactory.Instance);
|
||||
|
||||
|
|
@ -144,7 +144,7 @@ public class McpClientFactoryTests
|
|||
{
|
||||
Id = "test-server",
|
||||
Name = "Test Server",
|
||||
TransportType = "stdio",
|
||||
TransportType = TransportTypes.StdIo,
|
||||
Location = "/path/to/server"
|
||||
};
|
||||
|
||||
|
|
@ -164,7 +164,7 @@ public class McpClientFactoryTests
|
|||
var factory = new McpClientFactory([config],
|
||||
_defaultOptions,
|
||||
NullLoggerFactory.Instance,
|
||||
transportFactoryMethod: _ => mockTransport.Object,
|
||||
transportFactoryMethod: _ => mockTransport.Object,
|
||||
clientFactoryMethod: (_, _, _) => mockClient.Object);
|
||||
|
||||
// Act
|
||||
|
|
@ -180,8 +180,8 @@ public class McpClientFactoryTests
|
|||
// Arrange
|
||||
McpServerConfig[] configs =
|
||||
[
|
||||
new McpServerConfig { Id = "duplicate", Name = "duplicate", TransportType = "stdio", Location = "/path1" },
|
||||
new McpServerConfig { Id = "duplicate", Name = "duplicate", TransportType = "stdio", Location = "/path2" }
|
||||
new McpServerConfig { Id = "duplicate", Name = "duplicate", TransportType = TransportTypes.StdIo, Location = "/path1" },
|
||||
new McpServerConfig { Id = "duplicate", Name = "duplicate", TransportType = TransportTypes.StdIo, Location = "/path2" }
|
||||
];
|
||||
|
||||
// Act & Assert
|
||||
|
|
@ -197,10 +197,10 @@ public class McpClientFactoryTests
|
|||
{
|
||||
Id = "test-server",
|
||||
Name = "Test Server",
|
||||
TransportType = "sse",
|
||||
TransportType = TransportTypes.Sse,
|
||||
Location = "http://localhost:8080"
|
||||
};
|
||||
|
||||
|
||||
// Create a mock transport
|
||||
var mockTransport = new Mock<IClientTransport>();
|
||||
mockTransport.Setup(t => t.ConnectAsync(It.IsAny<CancellationToken>()))
|
||||
|
|
@ -238,7 +238,7 @@ public class McpClientFactoryTests
|
|||
{
|
||||
Id = "test-server",
|
||||
Name = "Test Server",
|
||||
TransportType = "sse",
|
||||
TransportType = TransportTypes.Sse,
|
||||
Location = "http://localhost:8080",
|
||||
TransportOptions = new Dictionary<string, string>
|
||||
{
|
||||
|
|
@ -260,10 +260,11 @@ public class McpClientFactoryTests
|
|||
|
||||
// Assert
|
||||
Assert.NotNull(transport);
|
||||
Assert.True(transport.Options.ConnectionTimeout == TimeSpan.FromSeconds(10));
|
||||
Assert.True(transport.Options.MaxReconnectAttempts == 2);
|
||||
Assert.True(transport.Options.ReconnectDelay == TimeSpan.FromSeconds(5));
|
||||
Assert.True(transport.Options.AdditionalHeaders["test"] == "the_header_value");
|
||||
Assert.Equal(TimeSpan.FromSeconds(10), transport.Options.ConnectionTimeout);
|
||||
Assert.Equal(2, transport.Options.MaxReconnectAttempts);
|
||||
Assert.Equal(TimeSpan.FromSeconds(5), transport.Options.ReconnectDelay);
|
||||
Assert.NotNull(transport.Options.AdditionalHeaders);
|
||||
Assert.Equal("the_header_value", transport.Options.AdditionalHeaders["test"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -274,7 +275,7 @@ public class McpClientFactoryTests
|
|||
{
|
||||
Id = "test-server",
|
||||
Name = "Test Server",
|
||||
TransportType = "sse",
|
||||
TransportType = TransportTypes.Sse,
|
||||
Location = "http://localhost:8080"
|
||||
};
|
||||
|
||||
|
|
@ -305,7 +306,7 @@ public class McpClientFactoryTests
|
|||
{
|
||||
Id = "test-server",
|
||||
Name = "Test Server",
|
||||
TransportType = "sse",
|
||||
TransportType = TransportTypes.Sse,
|
||||
Location = "http://localhost:8080",
|
||||
TransportOptions = new Dictionary<string, string>
|
||||
{
|
||||
|
|
@ -327,10 +328,11 @@ public class McpClientFactoryTests
|
|||
|
||||
// Assert
|
||||
Assert.NotNull(transport);
|
||||
Assert.True(transport.Options.ConnectionTimeout == TimeSpan.FromSeconds(10));
|
||||
Assert.True(transport.Options.MaxReconnectAttempts == defaultOptions.MaxReconnectAttempts);
|
||||
Assert.True(transport.Options.ReconnectDelay == defaultOptions.ReconnectDelay);
|
||||
Assert.True(transport.Options.AdditionalHeaders["test"] == "the_header_value");
|
||||
Assert.Equal(TimeSpan.FromSeconds(10), transport.Options.ConnectionTimeout);
|
||||
Assert.Equal(defaultOptions.MaxReconnectAttempts, transport.Options.MaxReconnectAttempts);
|
||||
Assert.Equal(defaultOptions.ReconnectDelay, transport.Options.ReconnectDelay);
|
||||
Assert.NotNull(transport.Options.AdditionalHeaders);
|
||||
Assert.Equal("the_header_value", transport.Options.AdditionalHeaders["test"]);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
|
@ -344,7 +346,7 @@ public class McpClientFactoryTests
|
|||
{
|
||||
Id = "test-server",
|
||||
Name = "Test Server",
|
||||
TransportType = "sse",
|
||||
TransportType = TransportTypes.Sse,
|
||||
Location = "http://localhost:8080",
|
||||
TransportOptions = new Dictionary<string, string>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
using McpDotNet.Client;
|
||||
using McpDotNet.Configuration;
|
||||
using McpDotNet.Protocol.Transport;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace McpDotNet.Tests;
|
||||
|
||||
|
|
@ -28,7 +28,7 @@ public class ServerIntegrationTestFixture : IDisposable
|
|||
{
|
||||
Id = "test_server",
|
||||
Name = "TestServer",
|
||||
TransportType = "stdio",
|
||||
TransportType = TransportTypes.StdIo,
|
||||
TransportOptions = new Dictionary<string, string>
|
||||
{
|
||||
["command"] = "TestServer.exe",
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ public class ServerIntegrationTests : IClassFixture<ServerIntegrationTestFixture
|
|||
// act
|
||||
var client = await _fixture.Factory.GetClientAsync("test_server");
|
||||
|
||||
List<Resource> allResources = new();
|
||||
List<Resource> allResources = [];
|
||||
string? cursor = null;
|
||||
do
|
||||
{
|
||||
|
|
|
|||
|
|
@ -32,8 +32,8 @@ public class SseIntegrationTests
|
|||
{
|
||||
Id = "test_server",
|
||||
Name = "In-memory Test Server",
|
||||
TransportType = "sse",
|
||||
TransportOptions = new Dictionary<string, string>(),
|
||||
TransportType = TransportTypes.Sse,
|
||||
TransportOptions = [],
|
||||
Location = "http://localhost:5000/sse"
|
||||
};
|
||||
|
||||
|
|
@ -75,8 +75,8 @@ public class SseIntegrationTests
|
|||
{
|
||||
Id = "everything",
|
||||
Name = "Everything",
|
||||
TransportType = "sse",
|
||||
TransportOptions = new Dictionary<string, string>(),
|
||||
TransportType = TransportTypes.Sse,
|
||||
TransportOptions = [],
|
||||
Location = "http://localhost:3001/sse"
|
||||
};
|
||||
|
||||
|
|
@ -123,8 +123,8 @@ public class SseIntegrationTests
|
|||
{
|
||||
Id = "everything",
|
||||
Name = "Everything",
|
||||
TransportType = "sse",
|
||||
TransportOptions = new Dictionary<string, string>(),
|
||||
TransportType = TransportTypes.Sse,
|
||||
TransportOptions = [],
|
||||
Location = "http://localhost:3001/sse"
|
||||
};
|
||||
|
||||
|
|
@ -193,8 +193,8 @@ public class SseIntegrationTests
|
|||
{
|
||||
Id = "test_server",
|
||||
Name = "In-memory Test Server",
|
||||
TransportType = "sse",
|
||||
TransportOptions = new Dictionary<string, string>(),
|
||||
TransportType = TransportTypes.Sse,
|
||||
TransportOptions = [],
|
||||
Location = "http://localhost:5000/sse"
|
||||
};
|
||||
|
||||
|
|
@ -238,8 +238,8 @@ public class SseIntegrationTests
|
|||
{
|
||||
Id = "test_server",
|
||||
Name = "In-memory Test Server",
|
||||
TransportType = "sse",
|
||||
TransportOptions = new Dictionary<string, string>(),
|
||||
TransportType = TransportTypes.Sse,
|
||||
TransportOptions = [],
|
||||
Location = "http://localhost:5000/sse"
|
||||
};
|
||||
|
||||
|
|
@ -255,11 +255,13 @@ public class SseIntegrationTests
|
|||
// Wait for SSE connection to be established
|
||||
await server.WaitForConnectionAsync(TimeSpan.FromSeconds(10));
|
||||
|
||||
var receivedNotification = new TaskCompletionSource<string>();
|
||||
client.OnNotification("test/notification", async (args) =>
|
||||
var receivedNotification = new TaskCompletionSource<string?>();
|
||||
client.OnNotification("test/notification", (args) =>
|
||||
{
|
||||
var msg = ((JsonElement)args.Params).GetProperty("message").GetString();
|
||||
var msg = ((JsonElement?)args.Params)?.GetProperty("message").GetString();
|
||||
receivedNotification.SetResult(msg);
|
||||
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
|
||||
// Act
|
||||
|
|
@ -291,8 +293,8 @@ public class SseIntegrationTests
|
|||
{
|
||||
Id = "test_server",
|
||||
Name = "In-memory Test Server",
|
||||
TransportType = "sse",
|
||||
TransportOptions = new Dictionary<string, string>(),
|
||||
TransportType = TransportTypes.Sse,
|
||||
TransportOptions = [],
|
||||
Location = "http://localhost:5000/sse"
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ public class SseTransportTests
|
|||
{
|
||||
Id = "test-server",
|
||||
Name = "Test Server",
|
||||
TransportType = "sse",
|
||||
TransportType = TransportTypes.Sse,
|
||||
Location = "http://localhost:8080"
|
||||
};
|
||||
|
||||
|
|
@ -35,21 +35,22 @@ public class SseTransportTests
|
|||
|
||||
// Assert
|
||||
Assert.NotNull(transport);
|
||||
Assert.True(transport.Options.ConnectionTimeout == TimeSpan.FromSeconds(10));
|
||||
Assert.True(transport.Options.MaxReconnectAttempts == 2);
|
||||
Assert.True(transport.Options.ReconnectDelay == TimeSpan.FromSeconds(5));
|
||||
Assert.True(transport.Options.AdditionalHeaders["test"] == "header");
|
||||
Assert.Equal(TimeSpan.FromSeconds(10), transport.Options.ConnectionTimeout);
|
||||
Assert.Equal(2, transport.Options.MaxReconnectAttempts);
|
||||
Assert.Equal(TimeSpan.FromSeconds(5), transport.Options.ReconnectDelay);
|
||||
Assert.NotNull(transport.Options.AdditionalHeaders);
|
||||
Assert.Equal("header", transport.Options.AdditionalHeaders["test"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void SseTransportSendMessageAsync_WithMessageEndpointNotSet_ThrowsException()
|
||||
public async Task SseTransportSendMessageAsync_WithMessageEndpointNotSet_ThrowsException()
|
||||
{
|
||||
// Arrange
|
||||
var config = new McpServerConfig
|
||||
{
|
||||
Id = "test-server",
|
||||
Name = "Test Server",
|
||||
TransportType = "sse",
|
||||
TransportType = TransportTypes.Sse,
|
||||
Location = "http://localhost:8080"
|
||||
};
|
||||
|
||||
|
|
@ -69,6 +70,6 @@ public class SseTransportTests
|
|||
|
||||
// Assert
|
||||
Assert.True(string.IsNullOrEmpty(transport.MessageEndpoint?.ToString()));
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(() => transport.SendMessageAsync(new JsonRpcRequest() { Method = "test"}, CancellationToken.None));
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(() => transport.SendMessageAsync(new JsonRpcRequest() { Method = "test" }, CancellationToken.None));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Net;
|
||||
using System.Text.Json;
|
||||
using McpDotNet.Protocol.Messages;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
|
||||
namespace McpDotNet.Tests.Utils;
|
||||
|
||||
|
|
@ -21,7 +21,7 @@ public sealed class TestSseServer : IAsyncDisposable
|
|||
private readonly string _messagePath;
|
||||
|
||||
// Keep track of all open SSE connections (StreamWriters).
|
||||
private readonly ConcurrentBag<StreamWriter> _sseClients = new();
|
||||
private readonly ConcurrentBag<StreamWriter> _sseClients = [];
|
||||
|
||||
public TestSseServer(int port = 5000, ILogger<TestSseServer>? logger = null)
|
||||
{
|
||||
|
|
@ -90,13 +90,13 @@ public sealed class TestSseServer : IAsyncDisposable
|
|||
|
||||
// Handle SSE endpoint
|
||||
if (request.HttpMethod.Equals("GET", StringComparison.OrdinalIgnoreCase)
|
||||
&& request.Url.AbsolutePath.Equals(_endpointPath, StringComparison.OrdinalIgnoreCase))
|
||||
&& request.Url?.AbsolutePath.Equals(_endpointPath, StringComparison.OrdinalIgnoreCase) == true)
|
||||
{
|
||||
await HandleSseConnectionAsync(context, ct);
|
||||
}
|
||||
// Handle POST /message
|
||||
else if (request.HttpMethod.Equals("POST", StringComparison.OrdinalIgnoreCase)
|
||||
&& request.Url.AbsolutePath.Equals(_messagePath, StringComparison.OrdinalIgnoreCase))
|
||||
&& request.Url?.AbsolutePath.Equals(_messagePath, StringComparison.OrdinalIgnoreCase) == true)
|
||||
{
|
||||
await HandlePostMessageAsync(context, ct);
|
||||
}
|
||||
|
|
@ -135,7 +135,7 @@ public sealed class TestSseServer : IAsyncDisposable
|
|||
await writer.WriteLineAsync($"data: {_messagePath}");
|
||||
}
|
||||
await writer.WriteLineAsync(); // blank line to end an SSE message
|
||||
await writer.FlushAsync();
|
||||
await writer.FlushAsync(ct);
|
||||
|
||||
_logger.LogInformation("New SSE client connected.");
|
||||
_connectionEstablished.TrySetResult(); // Signal connection is ready
|
||||
|
|
@ -149,7 +149,7 @@ public sealed class TestSseServer : IAsyncDisposable
|
|||
_logger.LogDebug("SSE connection alive check");
|
||||
// Optionally do a periodic no-op to keep connection alive:
|
||||
await writer.WriteLineAsync(": keep-alive");
|
||||
await writer.FlushAsync();
|
||||
await writer.FlushAsync(ct);
|
||||
await Task.Delay(TimeSpan.FromSeconds(5), ct);
|
||||
}
|
||||
}
|
||||
|
|
@ -187,7 +187,7 @@ public sealed class TestSseServer : IAsyncDisposable
|
|||
try
|
||||
{
|
||||
using var reader = new StreamReader(request.InputStream);
|
||||
string content = await reader.ReadToEndAsync();
|
||||
string content = await reader.ReadToEndAsync(ct);
|
||||
|
||||
var jsonRpcNotification = JsonSerializer.Deserialize<JsonRpcNotification>(content);
|
||||
if (jsonRpcNotification != null && jsonRpcNotification.Method != "initialize")
|
||||
|
|
@ -220,7 +220,7 @@ public sealed class TestSseServer : IAsyncDisposable
|
|||
// Write "accepted" as the response body
|
||||
using var writer = new StreamWriter(response.OutputStream);
|
||||
await writer.WriteAsync("accepted");
|
||||
await writer.FlushAsync();
|
||||
await writer.FlushAsync(ct);
|
||||
|
||||
// Then process the message and send the response via SSE
|
||||
if (jsonRpcRequest != null)
|
||||
|
|
@ -245,14 +245,14 @@ public sealed class TestSseServer : IAsyncDisposable
|
|||
}
|
||||
}
|
||||
|
||||
private async Task<JsonRpcResponse> ProcessRequestAsync(JsonRpcRequest jsonRpcRequest)
|
||||
private static Task<JsonRpcResponse> ProcessRequestAsync(JsonRpcRequest jsonRpcRequest)
|
||||
{
|
||||
// This is a test server so we just echo back the request
|
||||
return new JsonRpcResponse
|
||||
return Task.FromResult(new JsonRpcResponse
|
||||
{
|
||||
Id = jsonRpcRequest.Id,
|
||||
Result = jsonRpcRequest.Params
|
||||
};
|
||||
Result = jsonRpcRequest.Params!
|
||||
});
|
||||
}
|
||||
|
||||
private async Task SendSseMessageAsync(JsonRpcResponse jsonRpcResponse)
|
||||
|
|
@ -261,7 +261,7 @@ public sealed class TestSseServer : IAsyncDisposable
|
|||
await BroadcastMessageAsync(JsonSerializer.Serialize(jsonRpcResponse));
|
||||
}
|
||||
|
||||
private async Task SendJsonRpcErrorAsync(HttpListenerResponse response, RequestId? id, int code, string message, string? data = null)
|
||||
private static async Task SendJsonRpcErrorAsync(HttpListenerResponse response, RequestId? id, int code, string message, string? data = null)
|
||||
{
|
||||
var errorResponse = new JsonRpcError
|
||||
{
|
||||
|
|
@ -281,21 +281,10 @@ public sealed class TestSseServer : IAsyncDisposable
|
|||
await writer.WriteAsync(JsonSerializer.Serialize(errorResponse));
|
||||
}
|
||||
|
||||
private async Task HandleInitializationRequest(HttpListenerResponse response, JsonRpcRequest jsonRpcRequest)
|
||||
private static async Task HandleInitializationRequest(HttpListenerResponse response, JsonRpcRequest jsonRpcRequest)
|
||||
{
|
||||
// We don't need to validate the client's initialization request for the test
|
||||
// Just send back a valid server initialization response
|
||||
var jsonResponse = new
|
||||
{
|
||||
protocolVersion = "2024-11-05",
|
||||
capabilities = new
|
||||
{
|
||||
experimental = (object?)null,
|
||||
roots = (object?)null,
|
||||
sampling = (object?)null
|
||||
}
|
||||
};
|
||||
|
||||
var jsonRpcResponse = new JsonRpcResponse()
|
||||
{
|
||||
Id = jsonRpcRequest.Id,
|
||||
|
|
@ -353,7 +342,7 @@ public sealed class TestSseServer : IAsyncDisposable
|
|||
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
_cts.Cancel();
|
||||
await _cts.CancelAsync();
|
||||
|
||||
if (_serverTask != null)
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in a new issue