Sr. Content Developer at Microsoft, working remotely in PA, TechBash conference organizer, former Microsoft MVP, Husband, Dad and Geek.
152562 stories
·
33 followers

The Big Debate: Azure Files vs. SharePoint

1 Share
a.k.a. How to migrate file data without breaking apps, users, or your weekends! All code for this blog can be found here ! In my time of supporting customers embracing a "digital transformation", every file migration starts the same way: “We just need to move our file shares to the cloud.” That sentence hides an enormous amount of complexity. Files are not just bytes on disk (I wish they were...life would be easier!). They encode how people collaborate, how applications behave, how...

Read the whole story
alvinashcraft
2 hours ago
reply
Pennsylvania, USA
Share this story
Delete

Remote MCP Servers using .NET

1 Share

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


Read the whole story
alvinashcraft
3 hours ago
reply
Pennsylvania, USA
Share this story
Delete

.NET 10: Streaming over WebSockets with the New WebSocket Stream API

1 Share
Introduction .NET 10 introduces a new WebSocket stream API that makes working with WebSockets feel...
Read the whole story
alvinashcraft
3 hours ago
reply
Pennsylvania, USA
Share this story
Delete

Hands On with New Experimental GitHub Copilot 'Agent Skills' in VS Code

1 Share
Visual Studio Code 1.108 introduces Agent Skills for GitHub Copilot, enabling developers to define reusable, domain-specific automation that can handle everything from code refactoring to custom text and formatting cleanup.
Read the whole story
alvinashcraft
3 hours ago
reply
Pennsylvania, USA
Share this story
Delete

.NET 10: Automatic support of TLS 1.3 on MacOS

1 Share
Introduction With .NET 10, macOS developers get a nice upgrade for free: TLS 1.3 is...
Read the whole story
alvinashcraft
3 hours ago
reply
Pennsylvania, USA
Share this story
Delete

Don't fall into the anti-AI hype

1 Share

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

Read the whole story
alvinashcraft
3 hours ago
reply
Pennsylvania, USA
Share this story
Delete
Next Page of Stories