Model Context Protocol (MCP) lets AI models work with your data and services, and .NET already has an SDK for it. Here's what the protocol is, which problem it solves, and how to build your own MCP server in C#.
What is Model Context Protocol?
MCP is a standardized protocol for structured exchange of context and data between AI models and client applications. As AI becomes an ordinary part of software, there's a practical question of how the different components of AI systems exchange data with each other. MCP answers exactly that.
The conceptual scheme of MCP operation can be depicted as follows:
flowchart LR
subgraph "Client side"
A[IDE from GitHub Copilot] --> B[MCP Client SDK]
F[Client application] --> B
end
subgraph "Server side"
C[MCP Server SDK] --> D[Tools/APIs]
D --> E1[Databases]
D --> E2[REST API]
D --> E3[File system]
end
B <--> |MCP Protocol| C
Key benefits and use cases of MCP
MCP gives you a single interface for working with different AI models, so you don't have to build a separate integration for each one. Through structured tools you give the model access to external data and APIs, and your existing services, databases and infrastructure plug into AI directly. MCP is most useful when you work with AI assistants such as Copilot, claude and others in agent mode.
Typical usage scenarios
The most obvious scenario is enterprise integration: the model gets secure access to internal data and APIs, while authentication and authorization stay under your control. The second is developer tooling: you can work with Git, GitHub, test systems and the file system right from the IDE. And for specific tasks such as data processing, code generation or calling external services, you can write your own tools.
Creating an MCP server with the C# SDK
The C# SDK for MCP makes it simple to build both servers and clients. Here's how to build a simple MCP server step by step.
Project settings
Start by creating a console application and adding the packages you need:
1
2
3
dotnet new console -n MyFirstMCP
dotnet add package ModelContextProtocol --prerelease
dotnet add package Microsoft.Extensions.Hosting
MCP server settings
Next, the basic server structure in Program.cs:
1
2
3
4
5
6
7
8
9
10
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
var builder = Host.CreateEmptyApplicationBuilder(settings: null);
builder.Services
.AddMcpServer()
.WithStdioServerTransport()
.WithToolsFromAssembly();
await builder.Build().RunAsync();
This code:
- Creates an application host instance
- Adds MCP server services
- Configures the standard transport (stdio)
- Configures discovery of tools in the current assembly
Creation of tools (Tools)
Tools are the core of an MCP server. They're methods that clients can call:
1
2
3
4
5
6
7
8
[McpServerTool, Description("Get a list of all projects")]
public static string GetAllProjects()
{
return JsonSerializer.Serialize(_projects, new JsonSerializerOptions
{
WriteIndented = true
});
}
Each method with the [McpServerTool] attribute becomes available for calling via the MCP protocol. This example tool returns a list of projects in JSON format.
Real example: MCP server for working with data
Now a more complex example: an MCP server that acts as an intermediary for reading and modifying data.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
[McpServerToolType]
public static class ProjectTools
{
private static readonly List<ProjectDto> _projects =
[
new()
{
StartDate = DateTime.Today,
Description = "Project 1 description",
Status = ProjectStatus.Planning,
Name = "Project 1"
},
new()
{
StartDate = DateTime.UtcNow.AddDays(-25),
Description = "Project 2 description",
Status = ProjectStatus.InProgress,
Name = "Project 2"
},
new()
{
StartDate = DateTime.UtcNow.AddYears(-1),
Description = "Project 3 description",
Status = ProjectStatus.Completed,
Name = "Project 3"
},
new()
{
StartDate = DateTime.UtcNow.AddMonths(-2),
Description = "Project 4 description",
Status = ProjectStatus.Cancelled,
Name = "Project 4"
},
];
[McpServerTool, Description("Get a list of all projects")]
public static string GetAllProjects()
{
return JsonSerializer.Serialize(_projects, new JsonSerializerOptions
{
WriteIndented = true
});
}
[McpServerTool, Description("Get projects by status")]
public static string GetProjectsByStatus(
[Description("Project status (Planning, InProgress, OnHold, Completed, Cancelled)")] string status)
{
if (Enum.TryParse<ProjectStatus>(status, out var projectStatus))
{
var projects = _projects.Where(p => p.Status == projectStatus);
return JsonSerializer.Serialize(projects, new JsonSerializerOptions
{
WriteIndented = true
});
}
return "Incorrect project status. Available options: Planning, InProgress, OnHold, Completed, Cancelled";
}
[McpServerTool, Description("Change project status")]
public static string UpdateProjectStatus(
[Description("Project ID")] string projectId,
[Description("New status (Planning, InProgress, OnHold, Completed, Cancelled)")] string newStatus)
{
if (!Guid.TryParse(projectId, out var id))
{
return "Incorrect project ID";
}
var project = _projects.FirstOrDefault(p => p.Id == id);
if (project == null)
{
return "Project not found";
}
if (!Enum.TryParse<ProjectStatus>(newStatus, out var status))
{
return "Incorrect project status. Available options: Planning, InProgress, OnHold, Completed, Cancelled";
}
var oldStatus = project.Status;
// Update project status
return $"Project status '{project.Name}' changed from {oldStatus} to {status}";
}
}
public enum ProjectStatus
{
Planning,
InProgress,
OnHold,
Completed,
Cancelled
}
public class ProjectDto
{
public Guid Id { get; set; } = Guid.NewGuid();
public string Name { get; set; }
public string Description { get; set; }
public ProjectStatus Status { get; set; }
public DateTime StartDate { get; set; }
}
To keep the example simple, I'm not using a database, but I think the idea is clear. The server can return a list of projects, find projects by status and change a project's status.
You can call its methods from any client that supports the MCP protocol, for example an AI agent. Or use MCP Inspector by running this command:
1
npx @modelcontextprotocol/inspector dotnet run
MCP Inspector lets you call server methods and view their documentation.

Configuration and use of MCP in Claude Desktop
You can connect the MCP server to Claude Desktop. To do that:
- Open
%APPDATA%/Claude/claude_desktop_config.json - Add the following code:
1
2
3
4
5
6
7
8
9
{
"mcpServers": {
"MyFirstMCP": {
"type": "stdio",
"command": "file path\\MyFirstMCP.exe",
"args": []
}
}
}
After that, Claude Desktop sees the MCP server and can call its methods.


Conclusion
MCP with the .NET SDK gives AI assistants access to corporate data, APIs and tools through a secure, controlled interface. There are plenty of uses, from business data analysis to development automation and user support, and servers and clients are simple to write, so MCP is quickly becoming a standard developer tool.
It's most valuable in development tools like Copilot/Claude: they make it easier to work with the code base, automate routine tasks and pull in enterprise knowledge right from the IDE. If you want to try it, start with a single tool for one of your internal APIs.