Transports handle the communication layer between MCP clients and servers. The C# SDK supports three transport mechanisms: stdio for local processes, Streamable HTTP for modern remote servers, and SSE (Server-Sent Events) for legacy compatibility.
Use StdioServerTransport for servers that communicate over stdin/stdout:
using Microsoft.Extensions.Hosting;using ModelContextProtocol.Server;var builder = Host.CreateApplicationBuilder(args);// CRITICAL: Log to stderr, not stdoutbuilder.Logging.AddConsole(options =>{ options.LogToStandardErrorThreshold = LogLevel.Trace;});builder.Services .AddMcpServer() .WithStdioServerTransport() .WithToolsFromAssembly();await builder.Build().RunAsync();
Important: For stdio servers, all logging MUST go to stderr. Stdout is reserved exclusively for MCP protocol messages. Writing anything else to stdout will corrupt the protocol stream.
var serverOptions = new McpServerOptions{ ServerInfo = new Implementation { Name = "MyServer", Version = "1.0.0" }};var transport = new StdioServerTransport(serverOptions, loggerFactory);// Or with just a name:var transport = new StdioServerTransport("MyServer", loggerFactory);
The client can automatically detect the best transport mode:
var transport = new HttpClientTransport(new HttpClientTransportOptions{ Endpoint = new Uri("https://mcp-server.example.com/mcp"), TransportMode = HttpTransportMode.AutoDetect // Default});
Detection logic:
Tries Streamable HTTP first
Falls back to SSE if server doesn’t support Streamable HTTP
var transport = new HttpClientTransport(new HttpClientTransportOptions{ Endpoint = new Uri("https://mcp-server.example.com/sse"), TransportMode = HttpTransportMode.Sse, MaxReconnectionAttempts = 5, DefaultReconnectionInterval = TimeSpan.FromSeconds(1)});await using var client = await McpClient.CreateAsync(transport);
Local: Use stdio for CLIs, desktop apps, and local integrations.Remote: Use HTTP-based transports for web services, cloud deployments, and multi-client scenarios.
2
Session Requirements
Need resumption? Use Streamable HTTP (protocol version 2025-11-25+).Short-lived sessions: Any transport works.
3
Authentication Needs
Process-level: stdio is sufficient.OAuth/JWT/API keys: Use HTTP transports with AdditionalHeaders.
4
Deployment Environment
Desktop/CLI: stdioDocker/Kubernetes: Streamable HTTPServerless: Streamable HTTP (stateless with session IDs)Legacy systems: SSE for compatibility
var client = await McpClient.CreateAsync(transport);_ = Task.Run(async () =>{ var completion = await client.Completion; if (completion.Exception is not null) { logger.LogError(completion.Exception, "Transport disconnected unexpectedly"); // Attempt reconnection or cleanup }});
Use AutoDetect for flexible HTTP clients
// Works with both Streamable HTTP and SSE serversvar transport = new HttpClientTransport(new HttpClientTransportOptions{ Endpoint = serverUrl, TransportMode = HttpTransportMode.AutoDetect});
Implement proper logging for stdio servers
builder.Logging.AddConsole(options =>{ // Route ALL logs to stderr for stdio options.LogToStandardErrorThreshold = LogLevel.Trace;});// Also configure other loggersbuilder.Logging.AddFile("server.log"); // OK - writes to file