MCP with .NET
Summaryโ
MCP Tools, Resources, and Prompts explained the primitives. This page shows how to implement an MCP server in .NET and how to connect it to a .NET AI application.
.NET is a strong fit for MCP servers because many enterprise capabilities already live in C#, ASP.NET Core, worker services, and internal APIs. MCP lets you expose those existing capabilities to AI hosts without rebuilding business logic in another stack.
| Concern | .NET approach | Example |
|---|---|---|
| Tool implementation | Wrap existing domain/application services in typed methods instead of duplicating business rules in the MCP layer. | CreateIncidentTool calls existing IncidentService.CreateAsync(...) with policy checks already enforced in the service layer. |
| Validation | Use request/response DTOs, data annotations, and explicit guard clauses before executing downstream operations. | Reject a request when priority is missing or outside allowed values (low, medium, high) before calling any repository/API. |
| Transport hosting | Start with a console-hosted stdio server for local integration; move to ASP.NET Core hosted remote transport when multiple hosts need shared access. | Local desktop copilot uses stdio; later, a centralized internal assistant calls the same server over secured HTTP streaming. |
| Observability | Emit structured logs and traces for every tool invocation, including correlation IDs, latency, and outcome status. | Log: tool=GetDeviceStatus correlationId=... durationMs=84 status=success and export spans via OpenTelemetry to Application Insights. |
Your MCP layer should usually be thin. It should adapt existing application services, policy checks, and repositories rather than duplicating domain logic inside a new server project.
C# request and response types make it easier to validate inputs, produce predictable outputs, and keep tool schemas aligned with the actual runtime behaviour.
Once a server is shared across AI hosts, debugging without traces becomes expensive. Emit tool name, latency, correlation ID, and outcome for every invocation from day one.
Why This Mattersโ
Order lookup, policy evaluation, CRM search, document generation, and back-office workflows often already exist in .NET services. MCP gives those systems an AI-facing contract without changing their core responsibility.
Typed request models, enums, validation attributes, and dependency injection all help build safer tool surfaces than loosely typed dictionaries passed through dynamic handlers.
A local MCP server can be a small console app over stdio. A shared enterprise server can run as ASP.NET Core behind your normal auth and monitoring stack. The platform options are already familiar to most .NET teams.
Core Conceptsโ
Minimal server shapeโ
public sealed class TicketSearchRequest
{
public required string Query { get; init; }
public string Status { get; init; } = "open";
}
public sealed class TicketSearchResult
{
public required string TicketId { get; init; }
public required string Title { get; init; }
public required string Status { get; init; }
}
public interface ITicketService
{
Task<IReadOnlyList<TicketSearchResult>> SearchAsync(TicketSearchRequest request, CancellationToken cancellationToken);
}
Thin MCP adapter patternโ
public sealed class TicketTools(ITicketService ticketService, ILogger<TicketTools> logger)
{
public async Task<IReadOnlyList<TicketSearchResult>> SearchTicketsAsync(
TicketSearchRequest request,
CancellationToken cancellationToken)
{
if (string.IsNullOrWhiteSpace(request.Query))
{
throw new ArgumentException("Query is required.", nameof(request));
}
using var scope = logger.BeginScope("mcp_tool:{ToolName}", "search_tickets");
logger.LogInformation("Searching tickets with status {Status}", request.Status);
return await ticketService.SearchAsync(request, cancellationToken);
}
}
Host-side usage with a .NET AI appโ
using Microsoft.Extensions.AI;
IChatClient chatClient = new OpenAIChatClient(
modelId: "gpt-4.1",
apiKey: builder.Configuration["OpenAI:ApiKey"]!);
// Pseudocode: connect an MCP client and surface approved tools to the agent loop.
var approvedTools = await mcpClient.ListToolsAsync(cancellationToken);
var safeTools = approvedTools.Where(tool => tool.Name is "search_tickets" or "get_ticket_details");
var response = await chatClient.GetResponseAsync(
messages,
new ChatOptions
{
Tools = safeTools.Select(ConvertToAIFunction).ToList()
},
cancellationToken);
Recommended production layoutโ
Realistic Exampleโ
Scenarioโ
An internal IT support copilot runs in ASP.NET Core. The business already has a C# service DeviceInventoryService used by the admin portal. The team adds an MCP server exposing:
find_devices_by_userget_device_compliancelist_recent_repairs
The MCP layer stays thin: each tool validates input, calls the existing service, and returns a predictable DTO. Authorization still happens in the domain service using the authenticated user context supplied by the host.
Senior Tech vs Dev Conversationโ
Senior Tech: Should the MCP server contain all the business logic?
Dev: No. The MCP server should adapt business logic, not become the business logic. If you move rules, authorization, and data access into the MCP layer, you create a second application surface that diverges from the original system. Keep the domain in domain services.
Senior Tech: How do we avoid exposing dangerous tools to every AI host?
Dev: Two layers. First, the server enforces authorization and can reject calls even if a host attempts them. Second, each host curates the visible tools for its scenario. A read-only assistant should not even see reset_device or delete_ticket.
Common Pitfallsโ
| Pitfall | What goes wrong | Prevention |
|---|---|---|
| Rewriting domain logic in the MCP layer | Duplicate rules and inconsistent behaviour | Keep MCP adapter thin over existing services |
| Using anonymous request dictionaries | Weak validation and poor schema quality | Use typed request/response models |
| No correlation IDs in logs | Hard to trace multi-host issues | Emit trace or correlation IDs on every invocation |
| Exposing admin-only tools broadly | Unsafe execution surface | Curate visible tools per host and enforce auth server-side |
References and Next Stepsโ
- Next: MCP with Python โ
- Previous: MCP Tools, Resources, and Prompts โ
- .NET AI abstractions: learn.microsoft.com/dotnet/ai
- MCP: modelcontextprotocol.io