diff --git a/ModelContextProtocol.slnx b/ModelContextProtocol.slnx
index 5ed8ba0d6..d4fed7ea9 100644
--- a/ModelContextProtocol.slnx
+++ b/ModelContextProtocol.slnx
@@ -12,6 +12,7 @@
+
diff --git a/samples/InMemoryTransport/InMemoryTransport.csproj b/samples/InMemoryTransport/InMemoryTransport.csproj
new file mode 100644
index 000000000..7c1161ce9
--- /dev/null
+++ b/samples/InMemoryTransport/InMemoryTransport.csproj
@@ -0,0 +1,15 @@
+
+
+
+ Exe
+ net8.0
+ enable
+ enable
+ true
+
+
+
+
+
+
+
diff --git a/samples/InMemoryTransport/Program.cs b/samples/InMemoryTransport/Program.cs
new file mode 100644
index 000000000..67e2d320c
--- /dev/null
+++ b/samples/InMemoryTransport/Program.cs
@@ -0,0 +1,40 @@
+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 IMcpServer server = McpServerFactory.Create(
+ new StreamServerTransport(clientToServerPipe.Reader.AsStream(), serverToClientPipe.Writer.AsStream()),
+ new McpServerOptions()
+ {
+ Capabilities = new()
+ {
+ Tools = new()
+ {
+ 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 IMcpClient client = await McpClientFactory.CreateAsync(
+ new StreamClientTransport(clientToServerPipe.Writer.AsStream(), serverToClientPipe.Reader.AsStream()));
+
+// List all tools.
+var tools = await client.ListToolsAsync();
+foreach (var tool in tools)
+{
+ Console.WriteLine($"Tool Name: {tool.Name}");
+}
+Console.WriteLine();
+
+// Invoke a tool.
+var echo = tools.First(t => t.Name == "Echo");
+Console.WriteLine(await echo.InvokeAsync(new()
+{
+ ["arg"] = "Hello World"
+}));
\ No newline at end of file