DEV Community

Cover image for Setup MCP server in C#
Aditya
Aditya

Posted on

4 2 1 1 1

Setup MCP server in C#

Introduction

Integrating large language models (LLMs) into real‑world applications often means wiring up every model–backend pair by hand. As you add more models or more services (databases, APIs, function libraries), the work grows exponentially (the “N×M” problem). The Model Context Protocol (MCP) addresses this by defining a standard JSON‑RPC interface over pluggable transports (HTTP, stdio, WebSocket, etc.) so that:

  1. Back‑end teams write a single MCP server exposing resources and tools.

  2. LLM‑hosting teams embed an MCP client in their host (chatbot framework, IDE plugin, etc.).

  3. Any MCP‑capable model can call any MCP‑compliant service with zero bespoke integration.

Below, we’ll explore MCP’s core components and walk through a minimal C# server and client example using Anthropic’s MCP SDK.

MCP server

Setting Up Your C# Project

Host the server

  • Create a new .NET 8 Web API
dotnet new webapi -n MpcDemoServer
cd MpcDemoServer
Enter fullscreen mode Exit fullscreen mode
  • Add the MCP SDK
dotnet add package Anthropic.Mcp.Server
Enter fullscreen mode Exit fullscreen mode
  • Define Your Service Contracts

In Models/Customer.cs:

public record Customer(string Id, string Name, string Email);
Enter fullscreen mode Exit fullscreen mode

In Services/ICustomerService.cs:

public interface ICustomerService
{
  Task<Customer?> GetCustomerByIdAsync(string id);
  Task<IEnumerable<Customer>> ListCustomersAsync();
}
Enter fullscreen mode Exit fullscreen mode
  • Implement the Service

In Services/InMemoryCustomerService.cs:

public class InMemoryCustomerService : ICustomerService
{
  private static readonly List<Customer> _data = new()
  {
    new Customer("1", "Alice", "alice@example.com"),
    new Customer("2", "Bob",   "bob@example.com")
  };

  public Task<Customer?> GetCustomerByIdAsync(string id) =>
    Task.FromResult(_data.FirstOrDefault(c => c.Id == id));

  public Task<IEnumerable<Customer>> ListCustomersAsync() =>
    Task.FromResult<IEnumerable<Customer>>(_data);
}
Enter fullscreen mode Exit fullscreen mode

Building the MCP Server

  • Configure in Program.cs
using Anthropic.Mcp.Server;
using MpcDemoServer.Services;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSingleton<ICustomerService, InMemoryCustomerService>();
builder.Services.AddMcpServer(options =>
{
  options.AddResource<Customer>("customer");
  options.AddTool("getCustomer", typeof(ICustomerService)
    .GetMethod(nameof(ICustomerService.GetCustomerByIdAsync))!);
  options.AddTool("listCustomers", typeof(ICustomerService)
    .GetMethod(nameof(ICustomerService.ListCustomersAsync))!);
});

var app = builder.Build();
app.MapMcpServer("/mcp");
app.Run();
Enter fullscreen mode Exit fullscreen mode
  • Run the Server
dotnet run
Enter fullscreen mode Exit fullscreen mode

Your MCP server is now listening on http://localhost:5000/mcp. It exposes:

  • Resource: customer

  • Tools: getCustomer, listCustomers

Writing an MCP Client in C-Sharp

In your chatbot or host framework, add:

dotnet add package Anthropic.Mcp.Client
Enter fullscreen mode Exit fullscreen mode

Then, create a client wrapper:

using Anthropic.Mcp.Client;
using Anthropic.Mcp.Client.Transport;
using Anthropic.Mcp.Client.Rpc;

public class MpcDemoClient
{
  private readonly McpClient _client;

  public MpcDemoClient(string serverUrl, string apiKey)
  {
    // Use HTTP transport with Bearer token auth
    var transport = new HttpTransport(
      serverUrl,
      new BearerTokenAuthenticator(apiKey)
    );
    _client = new McpClient(transport);
  }

  public async Task<Customer?> GetCustomerAsync(string id)
  {
    return await _client.InvokeMethodAsync<Customer?>(
      "getCustomer",
      new { id }
    );
  }

  public async Task<IEnumerable<Customer>> ListCustomersAsync()
  {
    return await _client.InvokeMethodAsync<IEnumerable<Customer>>(
      "listCustomers",
      new { }
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

Putting It All Together in a Chatbot

We created a minimal console‑based host that interleaves LLM prompts and MCP calls:

using System;
using System.Threading.Tasks;
using Anthropic.Client;            // hypothetical LLM client SDK
using Anthropic.Mcp.Client;

class Program
{
  static async Task Main()
  {
    var mcpClient = new MpcDemoClient("http://localhost:5000/mcp", "<YOUR-MCP-KEY>");
    var llm = new ClaudeClient("<YOUR-LLM-KEY>");

    Console.WriteLine("Ask: ‘Who is customer 1?’");
    while (true)
    {
      Console.Write("> ");
      var userInput = Console.ReadLine();
      if (string.IsNullOrWhiteSpace(userInput)) break;

      // Example prompt instructing the model to call MCP
      var prompt = @$"
You are an assistant that can call MCP tools.
User says: {userInput}

If the user asks for customer data, respond with:
[MCP-ACTION]
tool: getCustomer
args: {{ ""id"": ""1"" }}
[/MCP-ACTION]

Otherwise, answer normally.
";

      var llmResponse = await llm.GenerateAsync(prompt);
      Console.WriteLine($"Model: {llmResponse.Text}");

      if (llmResponse.Text.Contains("[MCP-ACTION]"))
      {
        // Extract tool name and args (parsing omitted for brevity)...
        var customer = await mcpClient.GetCustomerAsync("1");
        Console.WriteLine($"→ Fetched via MCP: {customer?.Name} ({customer?.Email})");
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Conclusion
By adopting MCP in C#, you can:

  • Speed up integrations between any LLM and your C#‑based services.

  • Standardize how you expose tools and data as JSON‑RPC methods.

  • Future‑proof your architecture against new models or new back‑ends.


Let connect on LinkedIn and checkout my GitHub repos:

AWS Q Developer image

Build your favorite retro game with Amazon Q Developer CLI in the Challenge & win a T-shirt!

Feeling nostalgic? Build Games Challenge is your chance to recreate your favorite retro arcade style game using Amazon Q Developer’s agentic coding experience in the command line interface, Q Developer CLI.

Participate Now

Top comments (0)

DevCycle image

Ship Faster, Stay Flexible.

DevCycle is the first feature flag platform with OpenFeature built-in to every open source SDK, designed to help developers ship faster while avoiding vendor-lock in.

Start shipping

👋 Kindness is contagious

Explore this insightful write-up, celebrated by our thriving DEV Community. Developers everywhere are invited to contribute and elevate our shared expertise.

A simple "thank you" can brighten someone’s day—leave your appreciation in the comments!

On DEV, knowledge-sharing fuels our progress and strengthens our community ties. Found this useful? A quick thank you to the author makes all the difference.

Okay