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.
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.