Skip to main content

Host an MCP Server in ASP.NET Core with Streamable HTTP

Verified Oct 2026 Intermediate Original .NET 10 ModelContextProtocol.AspNetCore 1.0.0 Microsoft.AspNetCore.OpenApi 10.0.0
By Rajesh Mishra · Published: · 14 min read
In 30 Seconds

Hands-on lab for building and deploying a remote Model Context Protocol (MCP) server in ASP.NET Core with .NET 10. Covers: configuring Streamable HTTP endpoints, registering parameterized C# tools with dependency injection, adding OpenTelemetry tracing, implementing health checks, and containerizing with Docker for Kubernetes or Azure Container Apps.

What You'll Build

Step-by-step workshop: Build, containerize, and deploy a remote Model Context Protocol (MCP) server in ASP.NET Core using Streamable HTTP transport and C#.

What You Will Build

In this hands-on workshop, you will build a production-ready remote Model Context Protocol (MCP) server in ASP.NET Core (.NET 10). You will expose enterprise database and system utility tools over Streamable HTTP, enabling local AI clients (Cursor, Claude Desktop, Semantic Kernel, and Microsoft Agent Framework) to discover and execute tools securely over the network.

Claude / Cursor.NET 10 AI AgentASP.NET Core Host(Port 5050)MCP Router (/mcp)Health Check (/health)Tool Registry Streamable HTTP (JSON-RPC)Streamable HTTP (JSON-RPC)

Step 1: Project Setup & Package Installation

Create a new minimal web API project in your terminal:

dotnet new web -n DotNetStudio.McpHost
cd DotNetStudio.McpHost

Install the official Model Context Protocol ASP.NET Core package and resilience middleware:

dotnet add package ModelContextProtocol.AspNetCore --version 1.0.0
dotnet add package Microsoft.Extensions.Diagnostics.HealthChecks --version 10.0.0

Step 2: Implement the MCP Tool Service

Create a class SystemInspectionTools.cs that encapsulates tools for querying server health, database records, and system diagnostics:

using System.Diagnostics;
using System.Runtime.InteropServices;
using ModelContextProtocol.Server;

namespace DotNetStudio.McpHost.Tools;

public class SystemInspectionTools
{
    private readonly ILogger<SystemInspectionTools> _logger;

    public SystemInspectionTools(ILogger<SystemInspectionTools> logger)
    {
        _logger = logger;
    }

    [McpTool("get_system_metrics", "Returns CPU, memory, and runtime metrics for the hosting server.")]
    public Task<string> GetSystemMetricsAsync(CancellationToken ct)
    {
        _logger.LogInformation("System metrics tool requested by AI agent");

        var process = Process.GetCurrentProcess();
        var memoryMb = process.WorkingSet64 / (1024 * 1024);

        var metrics = new
        {
            Framework = RuntimeInformation.FrameworkDescription,
            OS = RuntimeInformation.OSDescription,
            Architecture = RuntimeInformation.ProcessArchitecture.ToString(),
            AllocatedMemoryMB = memoryMb,
            UptimeSeconds = (DateTime.UtcNow - process.StartTime.ToUniversalTime()).TotalSeconds
        };

        return Task.FromResult(System.Text.Json.JsonSerializer.Serialize(metrics));
    }

    [McpTool("execute_sql_query", "Executes a read-only diagnostic SQL query on the analytics database.")]
    public async Task<string> ExecuteQueryAsync(
        [McpParameter("Read-only SQL SELECT statement", required: true)] string sqlQuery,
        CancellationToken ct)
    {
        _logger.LogInformation("Executing diagnostic query: {Query}", sqlQuery);

        if (!sqlQuery.TrimStart().StartsWith("SELECT", StringComparison.OrdinalIgnoreCase))
        {
            return "ERROR: Only read-only SELECT statements are permitted on this MCP endpoint.";
        }

        // Mock simulation of database query execution
        await Task.Delay(25, ct);

        var sampleResults = new[]
        {
            new { Id = 101, Status = "Completed", DurationMs = 245 },
            new { Id = 102, Status = "Processing", DurationMs = 89 }
        };

        return System.Text.Json.JsonSerializer.Serialize(sampleResults);
    }
}

Step 3: Configure Streamable HTTP in Program.cs

Open Program.cs and wire up the MCP server pipeline with endpoints, logging, and health monitoring:

using DotNetStudio.McpHost.Tools;
using ModelContextProtocol.AspNetCore;
using ModelContextProtocol.Server;

var builder = WebApplication.CreateBuilder(args);

// 1. Add Logging & Diagnostics
builder.Services.AddLogging(logging => logging.AddConsole());
builder.Services.AddHealthChecks();

// 2. Register MCP Server with Streamable HTTP capability
builder.Services.AddMcpServer(options =>
{
    options.ServerInfo = new Implementation
    {
        Name = "DotNetStudio Enterprise Diagnostics",
        Version = "1.0.0"
    };
})
.AddTool<SystemInspectionTools>();

var app = builder.Build();

// 3. Health check endpoint for container orchestrators
app.MapHealthChecks("/health");

// 4. Map the MCP Streamable HTTP route
app.MapMcpServer("/mcp");

app.Run();

Step 4: Testing Your Server with the MCP Inspector

Run your ASP.NET Core server locally:

dotnet run --urls=http://localhost:5050

Verify the endpoint with a test curl command to confirm the Streamable HTTP transport handshake:

curl -i http://localhost:5050/mcp

You will receive an initial SSE/Streamable HTTP response confirming the endpoint is ready to accept JSON-RPC requests:

HTTP/1.1 200 OK
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive

Step 5: Connecting from Claude Desktop or Cursor

To connect Claude Desktop or Cursor to your remote ASP.NET Core MCP server, add the server to your claude_desktop_config.json:

{
  "mcpServers": {
    "dotnetstudio-diagnostics": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/inspector",
        "http://localhost:5050/mcp"
      ]
    }
  }
}

Restart your client. The AI agent will automatically detect get_system_metrics and execute_sql_query, presenting them as available tools during chat sessions!


Step 6: Production Docker Deployment

Deploying your server into Azure Container Apps or AWS ECS is straightforward with a multi-stage Dockerfile:

FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src
COPY ["DotNetStudio.McpHost.csproj", "./"]
RUN dotnet restore
COPY . .
RUN dotnet publish -c Release -o /app/publish /p:UseAppHost=false

FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS runtime
WORKDIR /app
EXPOSE 5050
ENV ASPNETCORE_URLS=http://+:5050
COPY --from=build /app/publish .
ENTRYPOINT ["dotnet", "DotNetStudio.McpHost.dll"]

Build and run the container:

docker build -t dotnetstudio-mcp-host .
docker run -d -p 5050:5050 --name mcp-server dotnetstudio-mcp-host

Your remote MCP server is now live, containerized, and capable of streaming real-time tool results to enterprise agents worldwide.

⚠ Production Considerations

  • Buffer bloat during large tool outputs: When streaming thousands of records from a database tool, yield results as IAsyncEnumerable rather than serializing one massive JSON array to avoid high memory spikes.
  • Reverse proxy buffering: If deploying behind NGINX or Azure Application Gateway, disable response buffering ('proxy_buffering off;') so streaming tool events reach the agent without artificial delay.

🧠 Architect’s Note

Hosting MCP tools in ASP.NET Core transforms isolated AI prompts into enterprise capabilities. By leveraging ASP.NET Core's mature middleware pipeline, your tools automatically inherit enterprise logging, distributed tracing, metrics, and TLS termination.

AI-Friendly Summary

Summary

Hands-on lab for building and deploying a remote Model Context Protocol (MCP) server in ASP.NET Core with .NET 10. Covers: configuring Streamable HTTP endpoints, registering parameterized C# tools with dependency injection, adding OpenTelemetry tracing, implementing health checks, and containerizing with Docker for Kubernetes or Azure Container Apps.

Key Takeaways

  • Streamable HTTP enables remote, scalable MCP tool servers accessible over standard HTTPS
  • ModelContextProtocol.AspNetCore seamlessly integrates with ASP.NET Core Minimal APIs
  • Dependency injection injects database contexts and HTTP clients directly into MCP tool handlers
  • Built-in rate limiting and health checks ensure production resilience under heavy agent load
  • Standard Dockerfiles allow deployment to Azure Container Apps or any cloud environment

Implementation Checklist

  • Initialize ASP.NET Core Web API project targeting .NET 10
  • Install ModelContextProtocol.AspNetCore NuGet package
  • Register MCP Server with builder.Services.AddMcpServer()
  • Implement tool class with [McpTool] and [McpParameter] attributes
  • Map MCP routes with app.MapMcpServer('/mcp')
  • Verify streaming connection with curl and MCP Inspector tool

Frequently Asked Questions

What is Streamable HTTP in the Model Context Protocol?

Streamable HTTP is the modern web transport for remote MCP servers. It replaces basic polling with an HTTP/2- or HTTP/3-based streaming channel, enabling low-latency, bidirectional JSON-RPC messaging between AI agents and remote tools without opening raw TCP sockets.

How does Streamable HTTP differ from standard Server-Sent Events (SSE)?

While traditional SSE provides a unidirectional server-to-client stream requiring separate HTTP POST requests for client messages, Streamable HTTP establishes a unified multiplexed session. In ASP.NET Core, it allows tool progress updates, partial streaming outputs, and cancellations to flow efficiently over a single connection.

Can multiple AI agents connect to a single ASP.NET Core MCP server instance?

Yes. Unlike stdio transport (which runs as a dedicated child process per client), an ASP.NET Core hosted MCP server handles concurrent agent requests concurrently using standard async/await thread-pool workers, scale-out containers, and connection pooling.

You Might Also Enjoy

#MCP #Model Context Protocol #ASP.NET Core #.NET 10 #Streamable HTTP #Workshop #Docker

Was this article useful?

Feedback is anonymous and helps us improve content quality.