justinyoo details how to build a .NET MCP server capable of handling both STDIO and HTTP transports using the builder pattern and a runtime switch, streamlining server management and flexibility.

One MCP Server, Two Transports: STDIO and HTTP

In this tutorial, justinyoo demonstrates how to build a single MCP (Model Context Protocol) server in .NET that supports both STDIO and HTTP transports, allowing the hosting mode to be switched at runtime with a simple --http flag. This reduces the management overhead of maintaining separate codebases or hosts for each transport.

When to Use MCP Servers

  • Most MCP servers run locally (directly or in containers).
  • Integration scenarios like Copilot Studio, or secure environments, often require remote HTTP-based servers.

Design Goal

Support both STDIO and HTTP with a single server instance, switching modes with a --http command-line argument rather than duplicating code.

Using the .NET Builder Pattern

  • Start with either a console app builder or a web app builder, depending on the hosting mode.
  • Interface in common: IHostApplicationBuilder.

Console Application:

var builder = Host.CreateApplicationBuilder(args);

Web Application:

var builder = WebApplication.CreateBuilder(args);

Determining Hosting Mode

A command-line switch, --http, determines which builder to use:

Example:

dotnet run --project MyMcpServer -- --http

Function to select transport:

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

Using the selector:

var useStreamableHttp = UseStreamableHttp(Environment.GetEnvironmentVariables(), args);
IHostApplicationBuilder builder = useStreamableHttp ? WebApplication.CreateBuilder(args) : Host.CreateApplicationBuilder(args);

Configuring the MCP Server

Add dependencies to the builder, import prompts, resources, and tools:

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

Select the transport based on the switch:

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

Running the Server

Cast to the appropriate host type and run the server:

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 Apps and Resources

By following this approach, developers can manage a single, versatile MCP server project in .NET, simplifying deployment and integration with various platforms.

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