diff --git a/.github/workflows/ci-build-test.yml b/.github/workflows/ci-build-test.yml index a9bf1a658..b9d6c4339 100644 --- a/.github/workflows/ci-build-test.yml +++ b/.github/workflows/ci-build-test.yml @@ -63,6 +63,10 @@ jobs: - name: 🧪 Test run: make test CONFIGURATION=${{ matrix.configuration }} + - name: 🧪 AOT Compatibility + if: matrix.configuration == 'Release' + run: make test-aot CONFIGURATION=${{ matrix.configuration }} + - name: 📦 Pack if: matrix.configuration == 'Release' run: make pack CONFIGURATION=${{ matrix.configuration }} diff --git a/Makefile b/Makefile index ce3d7f986..993c3dd76 100644 --- a/Makefile +++ b/Makefile @@ -30,6 +30,10 @@ test: build -- \ RunConfiguration.CollectSourceInformation=true +test-aot: + dotnet publish tests/ModelContextProtocol.AotCompatibility.TestApp/ModelContextProtocol.AotCompatibility.TestApp.csproj --configuration $(CONFIGURATION) -o $(ARTIFACT_PATH)/aot-publish + $(ARTIFACT_PATH)/aot-publish/ModelContextProtocol.AotCompatibility.TestApp + pack: restore dotnet pack --no-restore --configuration $(CONFIGURATION) diff --git a/ModelContextProtocol.slnx b/ModelContextProtocol.slnx index 64e834b35..3036f301e 100644 --- a/ModelContextProtocol.slnx +++ b/ModelContextProtocol.slnx @@ -70,6 +70,7 @@ + diff --git a/tests/ModelContextProtocol.AotCompatibility.TestApp/ModelContextProtocol.AotCompatibility.TestApp.csproj b/tests/ModelContextProtocol.AotCompatibility.TestApp/ModelContextProtocol.AotCompatibility.TestApp.csproj new file mode 100644 index 000000000..2b505f9ed --- /dev/null +++ b/tests/ModelContextProtocol.AotCompatibility.TestApp/ModelContextProtocol.AotCompatibility.TestApp.csproj @@ -0,0 +1,24 @@ + + + + Exe + net10.0 + + + true + false + + $(NoWarn);MCPEXP001 + + + + + + + + + + + + + diff --git a/tests/ModelContextProtocol.AotCompatibility.TestApp/Program.cs b/tests/ModelContextProtocol.AotCompatibility.TestApp/Program.cs new file mode 100644 index 000000000..687d78e4e --- /dev/null +++ b/tests/ModelContextProtocol.AotCompatibility.TestApp/Program.cs @@ -0,0 +1,36 @@ +using ModelContextProtocol.Client; +using ModelContextProtocol.Protocol; +using ModelContextProtocol.Server; +using System.IO.Pipelines; + +Pipe clientToServerPipe = new(), serverToClientPipe = new(); + +// Create a server using a stream-based transport over an in-memory pipe. +await using McpServer server = McpServer.Create( + new StreamServerTransport(clientToServerPipe.Reader.AsStream(), serverToClientPipe.Writer.AsStream()), + new McpServerOptions() + { + ToolCollection = [McpServerTool.Create((string arg) => $"Echo: {arg}", new() { Name = "Echo" })] + }); +_ = server.RunAsync(); + +// Connect a client using a stream-based transport over the same in-memory pipe. +await using McpClient client = await McpClient.CreateAsync( + new StreamClientTransport(clientToServerPipe.Writer.AsStream(), serverToClientPipe.Reader.AsStream())); + +// List all tools. +var tools = await client.ListToolsAsync(); +if (tools.Count == 0) +{ + throw new Exception("Expected at least one tool."); +} + +// Invoke a tool. +var echo = tools.First(t => t.Name == "Echo"); +var result = await echo.InvokeAsync(new() { ["arg"] = "Hello World" }); +if (result is null || !result.ToString()!.Contains("Echo: Hello World")) +{ + throw new Exception($"Unexpected result: {result}"); +} + +Console.WriteLine("Success!");