justinyoo explains how to implement a .NET MCP server with runtime-selectable STDIO and HTTP transports, reducing management overhead and supporting integration with Copilot Studio and other platforms.

Building a Dual-Transport MCP Server with .NET: STDIO and HTTP Support

Author: justinyoo

This guide will show you how to build a single Model Context Protocol (MCP) server that can operate using either STDIO (console) or HTTP transports, selectable with a simple --http command-line switch. The approach leverages the .NET builder pattern to avoid code duplication and simplify deployment, supporting integration scenarios such as with Copilot Studio or enterprise solutions where HTTP may be required.

Why Dual-Transport MCP Servers?

  • Flexibility: Run MCP servers locally (STDIO) or across networks (HTTP) without modifying core logic.
  • Maintainability: Minimize code duplication by sharing core logic and abstracting transport selection.
  • Integration: Easily integrate with tooling like Copilot Studio or enable secure, remote access via HTTP.

Using the .NET Builder Pattern

There are two primary .NET builder interfaces:

  • Console apps use:

    var builder = Host.CreateApplicationBuilder(args);
    
  • ASP.NET web apps use:

    var builder = WebApplication.CreateBuilder(args);
    

Both result in a builder implementing IHostApplicationBuilder, giving a common ground for adding services and logic prior to selecting the hosting mode.

Mode Selection at Runtime

Determine the transport mode via argument or environment variable:

dotnet run --project MyMcpServer -- --http

Check for --http in the arguments or UseHttp in environment variables:

public static bool UseStreamableHttp(IDictionary env, string[] args) {
    var useHttp = env.Contains("UseHttp") && bool.TryParse(env["UseHttp"]?.ToString()?.ToLowerInvariant(), out var result) && result;
    if (args.Length == 0) return useHttp;
    useHttp = args.Contains("--http", StringComparer.InvariantCultureIgnoreCase);
    return useHttp;
}

Use this selector to choose the builder:

IHostApplicationBuilder builder = useStreamableHttp
    ? WebApplication.CreateBuilder(args)
    : Host.CreateApplicationBuilder(args);

Registering the MCP Server

Add your MCP server and related services to the DI container:

var mcpServerBuilder = builder.Services.AddMcpServer()
    .WithPromptsFromAssembly()
    .WithResourcesFromAssembly()
    .WithToolsFromAssembly();

Select the correct transport based on the runtime check:

if (useStreamableHttp) {
    mcpServerBuilder.WithHttpTransport(o => o.Stateless = true);
} else {
    mcpServerBuilder.WithStdioServerTransport();
}

Bootstrapping and Running the Server

Depending on the hosting mode, cast and build appropriately:

IHost app;
if (useStreamableHttp) {
    var webApp = (builder as WebApplicationBuilder)!.Build();
    webApp.UseHttpsRedirection();
    webApp.MapMcp("/mcp");
    app = webApp;
} else {
    var consoleApp = (builder as HostApplicationBuilder)!.Build();
    app = consoleApp;
}
await app.RunAsync();

Sample Code and Additional Resources

This technique enables efficient and maintainable MCP server deployments in .NET for both local development and broader enterprise integration scenarios.

This post appeared first on “Microsoft Tech Community”. Read the entire article here