主题
C# SDK 
Model Context Protocol (MCP) 的 C# SDK 提供了构建 MCP 服务器和客户端的完整 .NET 解决方案,支持 .NET 6+ 和现代 C# 特性。
安装 
NuGet 包管理器 
bash
dotnet add package ModelContextProtocol.SdkPackage Manager Console 
powershell
Install-Package ModelContextProtocol.SdkPackageReference 
xml
<PackageReference Include="ModelContextProtocol.Sdk" Version="1.0.0" />快速开始 
创建 MCP 服务器 
csharp
using ModelContextProtocol.Sdk.Server;
using ModelContextProtocol.Sdk.Tools;
using ModelContextProtocol.Sdk.Schema;
using System.Text.Json;
namespace MyMcpServer;
public class Program
{
    public static async Task Main(string[] args)
    {
        // 创建服务器
        var server = new McpServerBuilder()
            .WithName("my-csharp-server")
            .WithVersion("1.0.0")
            .WithDescription("C# MCP 服务器示例")
            .Build();
        
        // 注册工具
        server.RegisterTool<EchoTool>();
        
        // 启动服务器
        await server.StartAsync();
    }
}
public class EchoTool : ITool
{
    public string Name => "echo";
    public string Description => "回显输入的消息";
    
    public JsonSchema InputSchema => JsonSchema.CreateObject()
        .WithProperty("message", JsonSchema.CreateString()
            .WithDescription("要回显的消息"))
        .WithRequired("message");
    
    public async Task<ToolResult> CallAsync(ToolCall call, CancellationToken cancellationToken = default)
    {
        if (!call.Arguments.TryGetValue("message", out var messageElement))
        {
            return ToolResult.Error("缺少 message 参数");
        }
        
        var message = messageElement.GetString();
        var result = new { echo = message };
        
        return ToolResult.Success(JsonSerializer.SerializeToElement(result));
    }
}创建 MCP 客户端 
csharp
using ModelContextProtocol.Sdk.Client;
using ModelContextProtocol.Sdk.Transport;
using System.Text.Json;
namespace MyMcpClient;
public class Program
{
    public static async Task Main(string[] args)
    {
        // 创建传输层
        var transport = new StdioTransport();
        
        // 创建客户端
        var client = new McpClientBuilder()
            .WithTransport(transport)
            .WithConnectTimeout(TimeSpan.FromSeconds(10))
            .WithRequestTimeout(TimeSpan.FromSeconds(30))
            .Build();
        
        try
        {
            // 连接到服务器
            await client.ConnectAsync();
            
            // 列出可用工具
            var tools = await client.ListToolsAsync();
            Console.WriteLine($"可用工具: {string.Join(", ", tools.Select(t => t.Name))}");
            
            // 调用工具
            var args = new Dictionary<string, JsonElement>
            {
                ["message"] = JsonSerializer.SerializeToElement("Hello from C#!")
            };
            
            var result = await client.CallToolAsync("echo", args);
            Console.WriteLine($"工具调用结果: {result}");
        }
        finally
        {
            await client.CloseAsync();
        }
    }
}核心功能 
服务器功能 
工具注册 
csharp
// 简单计算器工具
public class CalculatorTool : ITool
{
    public string Name => "calculator";
    public string Description => "执行基本数学运算";
    
    public JsonSchema InputSchema => JsonSchema.CreateObject()
        .WithProperty("operation", JsonSchema.CreateString()
            .WithEnum("add", "subtract", "multiply", "divide"))
        .WithProperty("a", JsonSchema.CreateNumber()
            .WithDescription("第一个数字"))
        .WithProperty("b", JsonSchema.CreateNumber()
            .WithDescription("第二个数字"))
        .WithRequired("operation", "a", "b");
    
    public async Task<ToolResult> CallAsync(ToolCall call, CancellationToken cancellationToken = default)
    {
        var operation = call.Arguments["operation"].GetString();
        var a = call.Arguments["a"].GetDouble();
        var b = call.Arguments["b"].GetDouble();
        
        var result = operation switch
        {
            "add" => a + b,
            "subtract" => a - b,
            "multiply" => a * b,
            "divide" when b != 0 => a / b,
            "divide" => throw new InvalidOperationException("除数不能为零"),
            _ => throw new ArgumentException($"不支持的运算: {operation}")
        };
        
        return ToolResult.Success(JsonSerializer.SerializeToElement(new { result }));
    }
}
// 注册工具
server.RegisterTool<CalculatorTool>();
// 或者注册实例
server.RegisterTool(new CalculatorTool());资源管理 
csharp
using ModelContextProtocol.Sdk.Resources;
public class FileResourceProvider : IResourceProvider
{
    private readonly string _basePath;
    
    public FileResourceProvider(string basePath)
    {
        _basePath = basePath;
    }
    
    public async Task<Resource> GetResourceAsync(ResourceUri uri, CancellationToken cancellationToken = default)
    {
        var filePath = Path.Combine(_basePath, uri.Path.TrimStart('/'));
        
        if (!File.Exists(filePath))
        {
            throw new FileNotFoundException($"资源不存在: {uri}");
        }
        
        var content = await File.ReadAllTextAsync(filePath, cancellationToken);
        
        return new Resource
        {
            Uri = uri,
            MimeType = "text/plain",
            Content = content
        };
    }
    
    public async Task<IEnumerable<ResourceUri>> ListResourcesAsync(CancellationToken cancellationToken = default)
    {
        var files = Directory.GetFiles(_basePath, "*", SearchOption.AllDirectories);
        
        return files.Select(file =>
        {
            var relativePath = Path.GetRelativePath(_basePath, file);
            return new ResourceUri($"file:///{relativePath.Replace('\\', '/')}");
        });
    }
}
// 注册资源提供者
server.RegisterResourceProvider(new FileResourceProvider("/path/to/files"));提示模板 
csharp
using ModelContextProtocol.Sdk.Prompts;
public class CodeReviewPromptProvider : IPromptProvider
{
    public async Task<Prompt> GetPromptAsync(string name, Dictionary<string, JsonElement> arguments, CancellationToken cancellationToken = default)
    {
        return name switch
        {
            "code-review" => await CreateCodeReviewPrompt(arguments, cancellationToken),
            _ => throw new ArgumentException($"未知提示: {name}")
        };
    }
    
    public Task<IEnumerable<string>> ListPromptsAsync(CancellationToken cancellationToken = default)
    {
        return Task.FromResult<IEnumerable<string>>(new[] { "code-review" });
    }
    
    private async Task<Prompt> CreateCodeReviewPrompt(Dictionary<string, JsonElement> arguments, CancellationToken cancellationToken)
    {
        if (!arguments.TryGetValue("code", out var codeElement))
        {
            throw new ArgumentException("缺少 code 参数");
        }
        
        var code = codeElement.GetString();
        var language = arguments.TryGetValue("language", out var langElement) 
            ? langElement.GetString() 
            : "unknown";
        
        var content = $"""
            请审查以下 {language} 代码并提供改进建议:
            
            ```{language}
            {code}
            ```
            """;
        
        return new Prompt
        {
            Name = "code-review",
            Description = "代码审查提示",
            Content = content
        };
    }
}
// 注册提示提供者
server.RegisterPromptProvider(new CodeReviewPromptProvider());客户端功能 
连接管理 
csharp
// 自动重连客户端
var client = new McpClientBuilder()
    .WithTransport(transport)
    .WithAutoReconnect(true)
    .WithMaxReconnectAttempts(5)
    .WithReconnectDelay(TimeSpan.FromSeconds(2))
    .Build();
// 连接状态事件
client.Connected += (sender, e) => Console.WriteLine("已连接到服务器");
client.Disconnected += (sender, e) => Console.WriteLine("与服务器断开连接");
client.Error += (sender, e) => Console.WriteLine($"连接错误: {e.Exception.Message}");批量操作 
csharp
// 并发调用多个工具
var tasks = new[]
{
    client.CallToolAsync("tool1", args1),
    client.CallToolAsync("tool2", args2),
    client.CallToolAsync("tool3", args3)
};
var results = await Task.WhenAll(tasks);
foreach (var (result, index) in results.Select((r, i) => (r, i)))
{
    Console.WriteLine($"结果 {index + 1}: {result}");
}传输协议 
Stdio 传输 
csharp
var transport = new StdioTransportBuilder()
    .WithCommand("python")
    .WithArguments("server.py")
    .WithWorkingDirectory("/path/to/server")
    .WithEnvironmentVariable("ENV_VAR", "value")
    .Build();WebSocket 传输 
csharp
var transport = new WebSocketTransportBuilder()
    .WithUri("ws://localhost:8080/mcp")
    .WithHeader("Authorization", "Bearer token")
    .WithConnectTimeout(TimeSpan.FromSeconds(10))
    .Build();HTTP SSE 传输 
csharp
var transport = new SseTransportBuilder()
    .WithUri("http://localhost:8080/mcp")
    .WithHeader("Authorization", "Bearer token")
    .WithReadTimeout(TimeSpan.FromSeconds(30))
    .Build();高级特性 
依赖注入支持 
csharp
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
public class Program
{
    public static async Task Main(string[] args)
    {
        var host = Host.CreateDefaultBuilder(args)
            .ConfigureServices(services =>
            {
                // 注册 MCP 服务
                services.AddMcp(options =>
                {
                    options.ServerName = "my-server";
                    options.ServerVersion = "1.0.0";
                });
                
                // 注册工具
                services.AddScoped<ITool, DatabaseTool>();
                services.AddScoped<ITool, EmailTool>();
                
                // 注册资源提供者
                services.AddScoped<IResourceProvider, FileResourceProvider>();
                
                // 注册其他服务
                services.AddScoped<IEmailService, EmailService>();
                services.AddDbContext<AppDbContext>();
            })
            .Build();
        
        await host.RunAsync();
    }
}
// 带依赖注入的工具
public class DatabaseTool : ITool
{
    private readonly AppDbContext _context;
    private readonly ILogger<DatabaseTool> _logger;
    
    public DatabaseTool(AppDbContext context, ILogger<DatabaseTool> logger)
    {
        _context = context;
        _logger = logger;
    }
    
    public string Name => "database-query";
    public string Description => "执行数据库查询";
    
    public JsonSchema InputSchema => JsonSchema.CreateObject()
        .WithProperty("query", JsonSchema.CreateString()
            .WithDescription("SQL 查询语句"));
    
    public async Task<ToolResult> CallAsync(ToolCall call, CancellationToken cancellationToken = default)
    {
        var query = call.Arguments["query"].GetString();
        
        _logger.LogInformation("执行查询: {Query}", query);
        
        // 执行查询逻辑
        var results = await _context.Database.SqlQueryRaw<object>(query).ToListAsync(cancellationToken);
        
        return ToolResult.Success(JsonSerializer.SerializeToElement(results));
    }
}中间件支持 
csharp
public class LoggingMiddleware : IMiddleware
{
    private readonly ILogger<LoggingMiddleware> _logger;
    
    public LoggingMiddleware(ILogger<LoggingMiddleware> logger)
    {
        _logger = logger;
    }
    
    public async Task<Response> HandleAsync(Request request, MiddlewareDelegate next, CancellationToken cancellationToken = default)
    {
        _logger.LogInformation("处理请求: {Method}", request.Method);
        var stopwatch = Stopwatch.StartNew();
        
        try
        {
            var response = await next(request, cancellationToken);
            
            stopwatch.Stop();
            _logger.LogInformation("请求完成,耗时: {Duration}ms", stopwatch.ElapsedMilliseconds);
            
            return response;
        }
        catch (Exception ex)
        {
            stopwatch.Stop();
            _logger.LogError(ex, "请求处理失败,耗时: {Duration}ms", stopwatch.ElapsedMilliseconds);
            throw;
        }
    }
}
// 注册中间件
services.AddMcp(options =>
{
    options.UseMiddleware<LoggingMiddleware>();
    options.UseMiddleware<AuthenticationMiddleware>();
    options.UseMiddleware<RateLimitingMiddleware>();
});配置管理 
csharp
// appsettings.json
{
  "Mcp": {
    "Server": {
      "Name": "my-server",
      "Version": "1.0.0",
      "Description": "我的 MCP 服务器",
      "MaxConnections": 100,
      "RequestTimeout": "00:00:30"
    },
    "Logging": {
      "Level": "Information",
      "File": "/var/log/mcp-server.log"
    },
    "Transport": {
      "Type": "Stdio",
      "Options": {
        "BufferSize": 8192
      }
    }
  }
}
// 配置类
public class McpOptions
{
    public ServerOptions Server { get; set; } = new();
    public LoggingOptions Logging { get; set; } = new();
    public TransportOptions Transport { get; set; } = new();
}
public class ServerOptions
{
    public string Name { get; set; } = "";
    public string Version { get; set; } = "";
    public string Description { get; set; } = "";
    public int MaxConnections { get; set; } = 100;
    public TimeSpan RequestTimeout { get; set; } = TimeSpan.FromSeconds(30);
}
// 使用配置
services.Configure<McpOptions>(configuration.GetSection("Mcp"));
services.AddMcp();测试 
单元测试 
csharp
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Xunit;
public class EchoToolTests
{
    [Fact]
    public async Task CallAsync_WithValidMessage_ReturnsEcho()
    {
        // Arrange
        var tool = new EchoTool();
        var call = new ToolCall
        {
            Name = "echo",
            Arguments = new Dictionary<string, JsonElement>
            {
                ["message"] = JsonSerializer.SerializeToElement("test")
            }
        };
        
        // Act
        var result = await tool.CallAsync(call);
        
        // Assert
        Assert.True(result.IsSuccess);
        Assert.Equal("test", result.Content.GetProperty("echo").GetString());
    }
    
    [Fact]
    public async Task CallAsync_WithMissingMessage_ReturnsError()
    {
        // Arrange
        var tool = new EchoTool();
        var call = new ToolCall
        {
            Name = "echo",
            Arguments = new Dictionary<string, JsonElement>()
        };
        
        // Act
        var result = await tool.CallAsync(call);
        
        // Assert
        Assert.True(result.IsError);
        Assert.Contains("缺少 message 参数", result.ErrorMessage);
    }
}集成测试 
csharp
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Xunit;
public class McpIntegrationTests : IAsyncLifetime
{
    private IHost _host;
    private McpClient _client;
    
    public async Task InitializeAsync()
    {
        // 启动测试服务器
        _host = Host.CreateDefaultBuilder()
            .ConfigureServices(services =>
            {
                services.AddMcp(options =>
                {
                    options.ServerName = "test-server";
                });
                services.AddScoped<ITool, EchoTool>();
            })
            .Build();
        
        await _host.StartAsync();
        
        // 创建客户端
        var transport = new StdioTransport();
        _client = new McpClientBuilder()
            .WithTransport(transport)
            .Build();
        
        await _client.ConnectAsync();
    }
    
    public async Task DisposeAsync()
    {
        await _client?.CloseAsync();
        await _host?.StopAsync();
        _host?.Dispose();
    }
    
    [Fact]
    public async Task CallTool_Echo_ReturnsExpectedResult()
    {
        // Arrange
        var args = new Dictionary<string, JsonElement>
        {
            ["message"] = JsonSerializer.SerializeToElement("test")
        };
        
        // Act
        var result = await _client.CallToolAsync("echo", args);
        
        // Assert
        Assert.Equal("test", result.GetProperty("echo").GetString());
    }
}部署 
ASP.NET Core 集成 
csharp
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
var builder = WebApplication.CreateBuilder(args);
// 添加 MCP 服务
builder.Services.AddMcp();
builder.Services.AddScoped<ITool, WebApiTool>();
var app = builder.Build();
// 配置 MCP 端点
app.MapMcp("/mcp");
// 启动应用
app.Run();Docker 部署 
dockerfile
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
EXPOSE 80
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY ["MyMcpServer.csproj", "."]
RUN dotnet restore "MyMcpServer.csproj"
COPY . .
WORKDIR "/src"
RUN dotnet build "MyMcpServer.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "MyMcpServer.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "MyMcpServer.dll"]Windows 服务 
csharp
using Microsoft.Extensions.Hosting.WindowsServices;
var builder = Host.CreateApplicationBuilder(args);
// 配置为 Windows 服务
builder.Services.AddWindowsService();
// 添加 MCP 服务
builder.Services.AddMcp();
builder.Services.AddHostedService<McpServerService>();
var host = builder.Build();
await host.RunAsync();
public class McpServerService : BackgroundService
{
    private readonly McpServer _server;
    
    public McpServerService(McpServer server)
    {
        _server = server;
    }
    
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        await _server.StartAsync(stoppingToken);
    }
}