Blog Post

Microsoft Developer Community Blog
3 MIN READ

One MCP Server, Two Transports: STDIO and HTTP

justinyoo's avatar
justinyoo
Icon for Microsoft rankMicrosoft
Aug 15, 2025

This post shows how to build a single MCP server that supports both transports, selected at runtime with a "--http" switch, using the .NET builder pattern.

Let's think about a situation for using MCP servers. Most MCP servers run on a local machine – either directly or in a container. But with other integration scenarios like using Copilot Studio, enterprise-wide MCP servers or need more secure environments, those MCP server should run remotely through HTTP.

As long as the core logic lives in a shared layer, wrapping it in a console (STDIO) or web (HTTP) host is straightforward. However, maintaining two hosts can duplicate code. What if a single MCP server supports both STDIO and HTTP, controlled by a simple switch? It will be reducing significant amount of management overhead.

This post shows how to build a single MCP server that supports both transports, selected at runtime with a --http switch, using the .NET builder pattern.

.NET Builder Pattern

A .NET console app starts the builder pattern using Host.CreateApplicationBuilder(args).

 

var builder = Host.CreateApplicationBuilder(args);

 

The builder instance is the type of HostApplicationBuilder implementing the IHostApplicationBuilder interface. On the other hand, an ASP.NET web app starts the builder pattern using WebApplication.CreateBuilder(args).

 

var builder = WebApplication.CreateBuilder(args);

 

This builder instance is the type of WebApplicationBuilder also implementing the IHostApplicationBuilder interface. Now, both builder instances have IHostApplicationBuilder in common, and this is the key of this post today.

If we decide the hosting mode before creating the builder instance, the server can run as either STDIO or HTTP.

The --http Switch as an Argument

As you can see, both Host.CreateApplicationBuilder(args) and WebApplication.CreateBuilder(args) take the list of arguments that are passed from the command-line. Therefore, before initializing the builder instance, we can identify the server type. Let's use a --http switch as the selector. Then pass --http when running the server.

 

dotnet run --project MyMcpServer -- --http

 

Then, before creating the builder instance, check whether the switch is present. It looks for the environment variables first, then checks the arguments passed.

 

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;
}

 

Here's the usage:

 

var useStreamableHttp = UseStreamableHttp(Environment.GetEnvironmentVariables(), args);

 

We've identified whether to use HTTP or not. Therefore, the builder instance is built in this way:

 

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

 

With this builder instance, we can add more dependencies specific to web app or console app depending on the scenario.

The Transport Type

Let's add the MCP server to the builder instance.

 

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

 

We haven’t told mcpServerBuilder which transport to use yet. Use useStreamableHttp to select the transport.

 

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

 

Type Casting to Run Server

While configuring an ASP.NET web app, middlewares are added. The HTTP host also needs middleware, and the builder must be cast. After the builder instance is built, the webApp instance adds middleware including the endpoint mapping.

 

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;
}

 

Note that WebApplication implements IHost, so you can assign it to an IHost variable. The console host built from HostApplicationBuilder is already an IHost.

Use this app instance to run the MCP server.

 

await app.RunAsync();

 

That's it! Now you can run the MCP server with the STDIO transport or the HTTP transport by providing a single switch, --http.

Sample apps

Sample apps are available for you to check out. Visit the MCP Samples in .NET repository, and you'll find MCP server apps. All server apps in the repo support both STDIO and HTTP via the switch.

More resources

If you'd like to learn more about MCP in .NET, here are some additional resources worth exploring:

Updated Aug 15, 2025
Version 1.0
No CommentsBe the first to comment