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: Back‑end teams write a single MCP server exposing resources and tools. LLM‑hosting teams embed an MCP client in their host (chatbot framework, IDE plugin, etc.). 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. Setting Up Your C# Project Create a new .NET 8 Web API dotnet new webapi -n MpcDemoServer cd MpcDemoServer Add the MCP SDK dotnet add package Anthropic.Mcp.Server Define Your Service Contracts In Models/Customer.cs: public record Customer(string Id, string Name, string Email); In Services/ICustomerService.cs: public interface ICustomerService { Task GetCustomerByIdAsync(string id); Task ListCustomersAsync(); } Implement the Service In Services/InMemoryCustomerService.cs: public class InMemoryCustomerService : ICustomerService { private static readonly List _data = new() { new Customer("1", "Alice", "alice@example.com"), new Customer("2", "Bob", "bob@example.com") }; public Task GetCustomerByIdAsync(string id) => Task.FromResult(_data.FirstOrDefault(c => c.Id == id)); public Task ListCustomersAsync() => Task.FromResult(_data); } Building the MCP Server Configure in Program.cs using Anthropic.Mcp.Server; using MpcDemoServer.Services; var builder = WebApplication.CreateBuilder(args); builder.Services.AddSingleton(); builder.Services.AddMcpServer(options => { options.AddResource("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(); Run the Server dotnet run 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 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 GetCustomerAsync(string id) { return await _client.InvokeMethodAsync( "getCustomer", new { id } ); } public async Task ListCustomersAsync() { return await _client.InvokeMethodAsync( "listCustomers", new { } ); } } 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", ""); var llm = new ClaudeClient(""); 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})"); } } } } 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

Apr 22, 2025 - 16:45
 0
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
  • Add the MCP SDK
dotnet add package Anthropic.Mcp.Server
  • Define Your Service Contracts

In Models/Customer.cs:

public record Customer(string Id, string Name, string Email);

In Services/ICustomerService.cs:

public interface ICustomerService
{
  Task<Customer?> GetCustomerByIdAsync(string id);
  Task<IEnumerable<Customer>> ListCustomersAsync();
}
  • 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);
}

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();
  • Run the Server
dotnet run

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

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 { }
    );
  }
}

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", "");
    var llm = new ClaudeClient("");

    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})");
      }
    }
  }
}

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: