Built using .NET 10 and the Model Context Protocol
A .NET 10 implementation of a Model Context Protocol (MCP) server that demonstrates how to build scalable, stateless, remote MCP servers using ASP.NET Core with support for Azure Functions deployment.
remote-MCP-servers-using-dotnet/
βββ .github/
β βββ workflows/ # CI/CD workflows
βββ .vscode/
β βββ mcp.json # VS Code MCP configuration
βββ src/
β βββ McpServer/
β βββ McpServer/
β β βββ Program.cs # Application entry point and configuration
β β βββ McpServerTools.cs # MCP tool definitions (Ping, etc.)
β β βββ McpServer.csproj # Project file with dependencies
β β βββ appsettings.json # Application configuration
β β βββ Properties/
β β βββ launchSettings.json # Development launch profiles
β βββ McpServer.slnx # Solution file
β βββ README.md # This documentation
βββ test-mcp-server.ps1 # Quick test script
βββ list-mcp-server-tools.ps1 # Tool listing script
βββ README.md # Project overview
βββ LICENSE # MIT License
The main entry point that configures and runs the MCP server using ASP.NET Core minimal APIs.
Key Responsibilities:
0.0.0.0) on port 8081 (default) or the port specified by MCP_PORT environment variable for Azure Functions compatibilityMcpServerTools class containing tool implementations using WithTools<McpServerTools>()/api/healthz (GET) – Simple health check endpoint returning βHealthyβ for liveness probes/mcp (POST) – Main MCP protocol endpoint for JSON-RPC 2.0 requestsConfiguration Highlights:
// Port binding with Azure Functions support
var port = Environment.GetEnvironmentVariable("MCP_PORT") ?? "8081";
builder.WebHost.UseUrls($"http://0.0.0.0:{port}");
// MCP server with stateless HTTP transport
builder.Services.AddMcpServer()
.WithHttpTransport((options) => { options.Stateless = true; })
.WithTools<McpServerTools>();
// Health check and MCP endpoints
app.MapGet("/api/healthz", () => "Healthy");
app.MapMcp(pattern: "/mcp");
Contains the tool implementations exposed via the MCP protocol. Tools are automatically discovered and registered through attributes.
Architecture:
[McpServerToolType] marks the class as a tool container[McpServerTool] marks methods as invocable tools[Description] provides metadata for parametersA diagnostic tool that serves dual purposes:
Implementation Details:
[McpServerTool, Description(
"Health check tool. Behaves as follows:\n" +
"- If message is empty, respond with server health\n" +
"- Otherwise echo the message"
)]
public async Task<string> Ping([Description("Ping message")] string message)
{
await Task.CompletedTask;
return string.IsNullOrWhiteSpace(message)
? "✅ MCP server is alive."
: $"✅ MCP server received: {message}";
}
Tool Characteristics:
Ping (derived from method name)message (string) – Message to echo or empty for health checkstring – Status message with emoji for visual confirmationUsage Scenarios:
Extensibility:
To add more tools, simply add new methods with the [McpServerTool] attribute:
[McpServerTool, Description("Description of your tool")]
public async Task<string> YourToolName(
[Description("Parameter description")] string param1)
{
// Tool implementation
return "result";
}
Tools are automatically:
/mcp endpointtools/list JSON-RPC responsestools/call JSON-RPC requests| Variable | Description | Default |
|---|---|---|
ASPNETCORE_ENVIRONMENT |
Environment (Development/Production) | Production |
ASPNETCORE_URLS |
Server binding URLs | http://0.0.0.0:{PORT} |
Configure in appsettings.json:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
The server is configured in Program.cs with:
/api/healthz for monitoring and liveness checks/mcp for protocol communication| Component | Purpose | Location |
|---|---|---|
Program.cs |
Application bootstrap, DI configuration, middleware pipeline | src/McpServer/McpServer/Program.cs |
McpServerTools.cs |
Tool implementations decorated with [McpServerTool] |
src/McpServer/McpServer/McpServerTools.cs |
Client Request β HTTP Transport β JSON-RPC 2.0 β MCP Server β Tool Execution β SSE Response
/mcp with JSON-RPC payloadAccept: application/json, text/event-stream)Clone the repository:
git clone https://github.com/azurecorner/remote-MCP-servers-using-dotnet.git
cd remote-MCP-servers-using-dotnet
Restore dependencies:
cd src/McpServer/McpServer
dotnet restore
Build the project:
dotnet build
Start the MCP server:
dotnet run --project McpServer.csproj
Expected Output:
Using launch settings from Properties\launchSettings.json...
Building...
info: Microsoft.Hosting.Lifetime[14]
Now listening on: http://0.0.0.0:8081
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
Hosting environment: Development
The server will be available at http://localhost:8081
Verify the server is running:
curl http://localhost:8081/api/healthz
PowerShell:
Invoke-WebRequest -Uri "http://localhost:8081/api/healthz" -UseBasicParsing
# Output:
# StatusCode: 200
# Content: Healthy
The MCP server exposes tools via the /mcp endpoint using JSON-RPC 2.0 protocol.
** Important**: The server requires both application/json and text/event-stream in the Accept header.
PowerShell:
$mcpEndpoint = "http://localhost:8081/mcp"
$body = @{
jsonrpc = "2.0"
id = 1
method = "tools/list"
params = @{}
} | ConvertTo-Json
$headers = @{
"Content-Type" = "application/json"
"Accept" = "application/json, text/event-stream"
}
$response = Invoke-WebRequest -Uri $mcpEndpoint `
-Method Post `
-Headers $headers `
-Body $body `
-UseBasicParsing
Write-Host $response.Content
Response (SSE Format):
event: message
data: {"result":{"tools":[{"name":"ping","description":"Health check tool...","inputSchema":{...}}]},"id":1,"jsonrpc":"2.0"}
# MCP endpoint
$mcpEndpoint = "http://localhost:8081/mcp"
# JSON-RPC request body
$body = @{
jsonrpc = "2.0"
id = 1
method = "tools/list"
params = @{}
} | ConvertTo-Json -Depth 5
# HTTP headers
$headers = @{
"Content-Type" = "application/json"
"Accept" = "application/json, text/event-stream"
}
# Send request
$response = Invoke-WebRequest `
-Uri $mcpEndpoint `
-Method Post `
-Headers $headers `
-Body $body `
-UseBasicParsing
# Read response content
$content = $response.Content
# Parse Server-Sent Events (SSE) JSON payload
if ($content -match 'data:\s*(.+)') {
$jsonData = $matches[1] | ConvertFrom-Json
$jsonData.result.tools | ForEach-Object {
Write-Host "`nTool: $($_.name)" -ForegroundColor Cyan
Write-Host "Description: $($_.description)" -ForegroundColor Gray
Write-Host "Input Schema:" -ForegroundColor Yellow
$_.inputSchema | ConvertTo-Json -Depth 10 | Write-Host -ForegroundColor White
}
}
Write-Host "Success!" -ForegroundColor Green
The repository includes PowerShell scripts for testing:
test-mcp-server.ps1: Quick test to verify server connectivity and tool listinglist-mcp-server-tools.ps1: Formatted display of all available MCP toolsRun a test:
.\test-mcp-server.ps1
./test-mcp-server.ps1
https://github.com/azurecorner/remote-MCP-servers-using-dotnet.git
Don't fall into the anti-AI hype
I'm glad someone was brave enough to say this. There is a lot of anti-AI sentiment in the software development community these days. Much of it is justified, but if you let people convince you that AI isn't genuinely useful for software developers or that this whole thing will blow over soon it's becoming clear that you're taking on a very real risk to your future career.As Salvatore Sanfilippo puts it:
It does not matter if AI companies will not be able to get their money back and the stock market will crash. All that is irrelevant, in the long run. It does not matter if this or the other CEO of some unicorn is telling you something that is off putting, or absurd. Programming changed forever, anyway.
I do like this hopeful positive outlook on what this could all mean, emphasis mine:
How do I feel, about all the code I wrote that was ingested by LLMs? I feel great to be part of that, because I see this as a continuation of what I tried to do all my life: democratizing code, systems, knowledge. LLMs are going to help us to write better software, faster, and will allow small teams to have a chance to compete with bigger companies. The same thing open source software did in the 90s.
This post has been the subject of heated discussions all day today on both Hacker News and Lobste.rs.
Tags: salvatore-sanfilippo, ai, generative-ai, llms, ai-assisted-programming, ai-ethics