In early April Microsoft published C# SDK for MCP Server. If you aren’t familiar with MCP you can check great definition from Philipp Schmid blog. If you are too lazy to read it I can give you a short intro: MCP is a standardized way to give capabilities for LLM apps. That is like most simplified way to intro it. You can implement your own tools (servers in MCP world) and give them to LLM solutions like chatbots and AI agents. These tools can then be used to invoke actions, search data, browse internet or do what ever you want. LLM will know how to interact with these tools and use them without much of a guidance.
The most important word in the intro is standardized. Standardization means that we can get these tools out from the box. We don’t need to build these tools by ourself anymore and we can utilize the servers, that are build in different programming languages.
MCP C# SDK
MCP C# SDK is a NuGet package, that gives us tools to build these MCP Servers and to build clients that are using these standardized servers. SDK supports both STDIO and SSE transports. Well what the heck are those I hear you asking. You can think STDIO as “executable” and SSE as HTTP. If you want to run server locally in the same computer (or as container) you use STDIO transport and if you want to use server from the interweb, then you use SSE.
Own MCP Server
Let’s cut the bullshit and move to code. I recommend you to build the first MCP server as console application. Console application is simple and does not have other distractions like Blazor pages or Web API hosts. The console application means that you can run this server in STDIO transport method as local app. The sample project contains MCP server and GitHub tool, which can read issues and pull requests from GitHub. GitHub has it’s own MCP server also available, but I think this is cooler.
Create new .NET console application and add following NuGet packages into project.

After that paste following code into Program.cs
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; var builder = Host.CreateApplicationBuilder(args); builder.Logging.AddConsole(consoleLogOptions => { // Configure all logs to go to stderr consoleLogOptions.LogToStandardErrorThreshold = LogLevel.Trace; }); builder.Services .AddMcpServer(cfg => { cfg.ServerInfo = new() { Name = "GitHub", Version = "0.1" }; }) .WithStdioServerTransport() .WithToolsFromAssembly(); await builder.Build().RunAsync();
All the MCP magic happens in three lines:
- AddMcpServer creates our MCP server called “GitHub” and sets the server version to 0.1
- WithStdioServerTransport defines that MCP supports STDIO clients, SSE is the other option if you want to access the server through HTTP.
- WithToolsFromAssembly adds all the classes that are marked with McpServerToolType attribute as tools into our server.
Ok now we have simple server, but no tools for fools. Let’s implement our GitHub tool, which can read stuff from GitHub.
using ModelContextProtocol.Server; using Octokit; using System.ComponentModel; using System.Text; namespace GitHubServer { [McpServerToolType()] public class GitHubTool { private readonly GitHubClient gitHubClient; public GitHubTool() { gitHubClient = new GitHubClient(new ProductHeaderValue("MCPChat")) { Credentials = new Credentials("(your very secret PAT)") }; } [McpServerTool, Description("Get Pull Requests from given owners repository")] public string PullRequests(string owner, string repository) { var pullRequests = gitHubClient.PullRequest.GetAllForRepository(owner, repository).Result; var result = new StringBuilder(); foreach (var pullRequest in pullRequests) { result.AppendLine($"Title: {pullRequest.Title}, URL: {pullRequest.HtmlUrl}"); } return result.ToString(); } [McpServerTool, Description("Get issues from given owners repository")] public string Issues(string owner, string repository) { var issues = gitHubClient.Issue.GetAllForRepository(owner, repository).Result; var result = new StringBuilder(); foreach (var issue in issues) { result.AppendLine($"Title: {issue.Title}, URL: {issue.HtmlUrl}"); } return result.ToString(); } } }
The tool implementation is quite straight forward. We just need to create class with McpServerToolType attribute and then add methods that are marked with McpServerTool, Description(“…”) attribute. In this sample we are invoking the GitHub client with our PAT token and returning some well formatted string as answer.
If you want to see that server is really working, open new terminal into C# project folder and type:
npx @modelcontextprotocol/inspector dotnet run
This runs a MCP Inspector program which shows details about our MCP Server implementation. It lists all the tools and you can even invoke them directly from the Web UI.

Summary
MCP is more than just tools, but to keep it simple I wanted to start with tools, which I think are the most important part of the standard. In next post we will implement MCP client and use Ollama to run some local models. We will build Blazor app that has chat interface and it can interact with our MCP server.