Remote MCP Servers using .NET

Remote MCP Servers using .NET: Getting Started

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.

Features

  • HTTP Transport: Stateless HTTP-based MCP server for remote access and horizontal scalability
  • Server-Sent Events (SSE): Supports streaming responses using SSE with JSON-RPC 2.0 protocol
  • Diagnostic Tools: Built-in health check and ping functionality for server monitoring
  • Structured Logging: Console logging with configurable trace levels for debugging
  • Modern .NET: Built on .NET 10 with C# 14.0 and minimal APIs
  • JSON-RPC 2.0: Standard protocol implementation for tool invocation

Prerequisites

  • .NET 10 SDK or later
  • Visual Studio 2026, VS Code, or any .NET-compatible IDE
  • PowerShell 5.1+ or PowerShell Core 7+ (for testing scripts)

Project Structure

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

Core Files

Program.cs – Application Bootstrap and Configuration

The main entry point that configures and runs the MCP server using ASP.NET Core minimal APIs.

Key Responsibilities:

  • Web Host Configuration: Configures the server to listen on all network interfaces (0.0.0.0) on port 8081 (default) or the port specified by MCP_PORT environment variable for Azure Functions compatibility
  • MCP Server Registration: Registers the MCP server with HTTP transport in stateless mode for horizontal scalability
  • Tool Registration: Registers McpServerTools class containing tool implementations using WithTools<McpServerTools>()
  • Logging Configuration: Sets up console logging with trace-level output to stderr for container/cloud compatibility
  • Endpoint Mapping:
    • /api/healthz (GET) – Simple health check endpoint returning “Healthy” for liveness probes
    • /mcp (POST) – Main MCP protocol endpoint for JSON-RPC 2.0 requests

Configuration 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");

McpServerTools.cs – MCP Tool Implementations

Contains the tool implementations exposed via the MCP protocol. Tools are automatically discovered and registered through attributes.

Architecture:

  • Class-level Attribute: [McpServerToolType] marks the class as a tool container
  • Method-level Attributes: [McpServerTool] marks methods as invocable tools
  • Parameter Attributes: [Description] provides metadata for parameters
Current Tool: Ping

A diagnostic tool that serves dual purposes:

  1. Health Check: Returns server status when called with an empty message
  2. Echo Service: Returns the message back with confirmation when provided

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:

  • Name: Ping (derived from method name)
  • Input Parameter: message (string) – Message to echo or empty for health check
  • Return Type: string – Status message with emoji for visual confirmation
  • Async Support: Uses async/await pattern for consistency with I/O-bound operations
  • Null Safety: Handles empty, null, and whitespace-only messages

Usage Scenarios:

  1. Liveness Probe: Call with empty message to verify server is responding
  2. Connectivity Test: Send a test message to verify request/response cycle
  3. Latency Measurement: Measure round-trip time for diagnostic purposes

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:

  • Discovered at startup via reflection
  • Exposed through the /mcp endpoint
  • Documented in tools/list JSON-RPC responses
  • Invoked via tools/call JSON-RPC requests

Configuration

Environment Variables

Variable Description Default
ASPNETCORE_ENVIRONMENT Environment (Development/Production) Production
ASPNETCORE_URLS Server binding URLs http://0.0.0.0:{PORT}

Application Settings

Configure in appsettings.json:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*"
}

MCP Server Configuration

The server is configured in Program.cs with:

  • HTTP transport: RESTful API with JSON-RPC 2.0 and SSE support
  • Console logging: Standard error output with trace-level diagnostics
  • Health endpoint: /api/healthz for monitoring and liveness checks
  • MCP endpoint: /mcp for protocol communication

Architecture

Technology Stack

  • ASP.NET Core Minimal APIs: Lightweight web framework for high performance
  • Model Context Protocol SDK: Official MCP .NET SDK for protocol implementation
  • JSON-RPC 2.0: Standard protocol for remote procedure calls
  • Server-Sent Events (SSE): Streaming response format for real-time updates

Key Components

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

Request Flow

Client Request → HTTP Transport → JSON-RPC 2.0 → MCP Server → Tool Execution → SSE Response
  1. Client sends POST request to /mcp with JSON-RPC payload
  2. HTTP Transport validates headers (Accept: application/json, text/event-stream)
  3. MCP Server parses JSON-RPC request and routes to appropriate tool
  4. Tool executes business logic (e.g., Ping tool)
  5. Server formats response as Server-Sent Events (SSE)
  6. Client receives streaming response with result

Installation

  1. Clone the repository:

    git clone https://github.com/azurecorner/remote-MCP-servers-using-dotnet.git
    cd remote-MCP-servers-using-dotnet
    
  2. Restore dependencies:

    cd src/McpServer/McpServer
    dotnet restore
    
  3. Build the project:

    dotnet build
    

Running Locally

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

Usage

Health Check Endpoint

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

MCP Tools Endpoint

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.

Test MCP Tools Endpoint

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

List Available Tools

Invoke the Ping Tool

# 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

Testing Scripts

The repository includes PowerShell scripts for testing:

  • test-mcp-server.ps1: Quick test to verify server connectivity and tool listing
  • list-mcp-server-tools.ps1: Formatted display of all available MCP tools

Run a test:

.\test-mcp-server.ps1

./test-mcp-server.ps1

Additional Resources

Source code

https://github.com/azurecorner/remote-MCP-servers-using-dotnet.git


Gora LEYE

I'm a microsoft most valuable professional (MVP) .NET Architect and Technical Expert skills located in Paris (FRANCE). The purpose of this blog is mainly to post general .NET tips and tricks, www.masterconduite.com Gora LEYE

Support us

BMC logoBuy me a coffee