Building a Remote MCP Server with .NET 10 and Prompts
Building a Remote MCP Server with .NET 10 and Prompts
Model Context Protocol (MCP) gives AI clients a standard way to discover and call server capabilities. Most examples focus on tools first, but this project demonstrates an equally important direction: prompt-first server design.
In this post, we walk through a practical ASP.NET Core implementation that exposes:
- tool operations (for executable tasks)
- reusable prompts (for instruction templates and interaction quality)
- HTTP MCP transport for remote clients
- lightweight operational endpoints for health and diagnostics
By the end, you will understand how this server is structured, how prompts are registered and invoked, and how to expand the design for production scenarios.
Why Prompt-First MCP Servers Matter
Tools answer what the server can do. Prompts shape how those capabilities are used.
In assistant systems, quality often depends on strong instruction templates:
- consistent phrasing
- clear required input
- predictable output structure
- fallback behavior when user requests are ambiguous
When prompts are exposed through MCP, clients can discover them dynamically and compose better experiences without hardcoding all instructions in the client itself.
This creates a cleaner split of responsibilities:
- server owns domain guidance and prompt governance
- client owns orchestration and user interface
Get Started
The complete, production-ready source code is available on GitHub:
remote-MCP-servers-using-dotnet-sdk-prompts
Clone it locally:
git clone https://github.com/azurecorner/remote-MCP-servers-using-dotnet-sdk-prompts.git
In the repository you’ll find:
- Full source code for tool, prompt, and resource implementations
- PowerShell scripts for testing MCP capabilities
- Configuration files for local VS Code MCP client integration
- Examples ready to extend and adapt for your own domain
Project Overview
This repository contains a remote MCP server built on:
- ASP.NET Core
- ModelContextProtocol.AspNetCore
- .NET 10
Main capabilities:
- MCP endpoint at /mcp
- health check endpoint at /api/healthz
- weather tool integration through Open-Meteo
- prompt discovery and retrieval through prompts/list and prompts/get
Core source layout:
- src/McpServer/McpServer: MCP host app, tools, prompts, resources, startup
- src/McpServer/WeatherService: external weather API integration
- scripts: PowerShell automation for MCP protocol calls
Runtime and Transport Design
The server is configured with both HTTP transport and stdio transport. HTTP is the primary remote integration path, while stdio can be useful for local tool-chain and debugging workflows.
At startup, the app:
- reads FUNCTIONS_CUSTOMHANDLER_PORT (default 8081)
- binds Kestrel to 0.0.0.0:port
- registers tools, resources, and prompts in the MCP pipeline
- maps /mcp for protocol traffic
- maps /api/healthz for liveness checks
This split is operationally useful:
- /mcp handles AI protocol traffic
- /api/healthz supports probes and platform health monitors
Prompt Architecture Deep Dive
Prompt definitions live in a dedicated prompt container class decorated with an MCP prompt type attribute.
Prompt Container Responsibilities
The prompt class has three key responsibilities:
- define discoverable prompt methods
- document methods and arguments with metadata
- optionally log invocation context for observability
The implementation includes dependency-injected logging, making it straightforward to trace usage patterns in real deployments.
Prompt 1: default_prompt
Purpose:
- provide a baseline system instruction for concise, reliable responses
Behavior:
- returns a compact instruction block emphasizing brevity and non-hallucination
- includes explicit uncertainty handling by asking for clarification when needed
Why this is valuable:
- offers a reusable default instruction that clients can apply consistently
- avoids duplicating base instruction text across multiple clients
Prompt 2: weather_query_guide
Purpose:
- teach users or orchestrators how to ask weather questions effectively
Behavior:
- returns structured guidance with examples and best practices
- accepts optional userContext and appends it when provided
Why argumentized prompts are powerful:
- one prompt template can adapt to locale, user preferences, or interaction history
- client-side logic remains simple while server controls guidance quality
Prompt 3: weather_data_interpretation
Purpose:
- standardize how weather tool output should be interpreted and presented
Behavior:
- explains expected weather fields and presentation strategy
- includes recommendation patterns, for example suggesting umbrella advice when appropriate
Why this helps:
- decouples raw tool output from user-facing narrative quality
- improves consistency across multi-client environments
Prompt Discovery and Invocation Flow
MCP interaction is straightforward:
- Client calls prompts/list
- Server returns prompt metadata including names, descriptions, and argument schema
- Client calls prompts/get with a selected prompt name (and optional arguments)
- Server returns prompt content ready for orchestration
This means client authors can build dynamic UIs or agent planners that adapt to server capabilities at runtime, without shipping fixed prompt catalogs.
Local Run and Verification
From repo root:
dotnet restore .\src\McpServer\McpServer.slnx
dotnet run --project .\src\McpServer\McpServer\McpServer.csproj
Default MCP endpoint:
- http://0.0.0.0:8081/mcp
Health check:
- http://localhost:8081/api/healthz
Then, in a second terminal, verify protocol behavior with scripts.
Script-Driven MCP Validation
The scripts folder includes ready-to-use protocol calls for tools, prompts, and optional resources.
List prompts:
.\scripts\list-mcp-server-prompts.ps1
Get a specific prompt:
.\scripts\call-mcp-prompt.ps1 -PromptName "default_prompt"
Get weather query guide:
.\scripts\call-mcp-prompt.ps1 -PromptName "weather_query_guide"
Get weather interpretation guide:
.\scripts\call-mcp-prompt.ps1 -PromptName "weather_data_interpretation"
Validate tools too:
.\scripts\list-mcp-server-tools.ps1
.\scripts\call-mcp-tool.ps1 -toolName "ping" -toolParams @{ message = "hello from test" }
.\scripts\call-mcp-tool.ps1 -toolName "get_weather" -toolParams @{ city = "Paris" }
How to Add a New Prompt Correctly
Recommended process:
- Add a method to the prompt container class.
- Decorate it as an MCP prompt.
- Add clear descriptions on method and arguments.
- Return string or Task<string>.
- Keep output deterministic and easy for clients to reuse.
- Verify with prompts/list and prompts/get.
[McpServerPrompt]
[Description("Provides concise guidance for travel weather planning")]
public Task<string> TravelWeatherGuide(
[Description("Destination city")] string city,
[Description("Optional number of travel days")] int? days = null)
{
var output = $"""
# Travel Weather Guide
Destination: {city}
Duration: {(days.HasValue ? $"{days} day(s)" : "unspecified")}
Ask for:
- daily highs/lows
- rain probability
- wind conditions
""";
return Task.FromResult(output);
}
Defined in src/McpServer/McpServer/McpServerPrompts.cs and registered in src/McpServer/McpServer/Program.cs with:
.WithPrompts<McpServerPrompts>();

