.NET MCP Server 开发教程
本教程基于实际项目经验,(注意:该教程基于实际项目反向使用ai生成,难免留有遗漏)详细介绍如何使用 .NET 8 开发 Model Context Protocol (MCP) 服务器。
目录
环境准备
1. 开发环境要求
- .NET 8.0 SDK: 确保安装了 .NET 8.0 或更高版本
 - IDE: Visual Studio 2022 或 Visual Studio Code
 - 操作系统: Windows 10/11 (推荐,某些库可能需要)
 
2. 验证 .NET 环境
            
            
              bash
              
              
            
          
          dotnet --version
# 应显示: 8.0.x 或更高版本
        项目创建
1. 创建新的控制台项目
            
            
              bash
              
              
            
          
          dotnet new console -n MyMcpServer -f net8.0
cd MyMcpServer
        2. 添加必要的 NuGet 包
            
            
              xml
              
              
            
          
          <Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <AssemblyName>MyMcpServer</AssemblyName>
    <RootNamespace>MyMcpServer</RootNamespace>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="McpToolkit" Version="0.1.3" />
    <PackageReference Include="McpToolkit.Server" Version="0.1.3" />
    <PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.8" />
    <PackageReference Include="ModelContextProtocol-SemanticKernel" Version="0.3.0" />
    <PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
  </ItemGroup>
</Project>
        MCP 基础概念
1. Model Context Protocol (MCP)
MCP 是一种标准化的协议,用于 AI 模型与外部工具和数据源之间的通信。
2. 核心组件
- MCP Server: 提供工具和资源的服务器
 - MCP Client: 使用工具和资源的客户端
 - Tools: 可执行的功能方法
 - Resources: 可访问的数据源
 - stdio: 标准输入输出通信协议
 
3. 通信方式
MCP 使用 stdio 进行通信:
- 输入: JSON-RPC 2.0 请求
 - 输出: JSON-RPC 2.0 响应
 
项目结构
MyMcpServer/
├── Program.cs                 # 主程序入口
├── MyTools.cs                 # 工具方法实现
├── MyMcpServer.csproj         # 项目文件
├── appsettings.json          # 配置文件
├── Models/                    # 数据模型
│   ├── ToolResult.cs
│   └── ...
└── Services/                  # 服务层
    └── ...
        开发步骤
1. 创建主程序入口
            
            
              csharp
              
              
            
          
          // Program.cs
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using McpToolkit.Server;
using System.ComponentModel;
namespace MyMcpServer;
class Program
{
    static async Task Main(string[] args)
    {
        var builder = Host.CreateApplicationBuilder(args);
        // 配置 MCP 服务
        builder.Services.AddMcpServer(options =>
        {
            // 配置服务器信息
            options.ServerInfo = new()
            {
                Name = "My MCP Server",
                Version = "1.0.0"
            };
        });
        // 注册工具类型
        builder.Services.AddMcpServerToolType<MyTools>();
        var host = builder.Build();
        // 启动 MCP 服务器
        await host.RunMcpAsync();
    }
}
        2. 创建工具类
            
            
              csharp
              
              
            
          
          // MyTools.cs
using ModelContextProtocol.Server;
using System.ComponentModel;
namespace MyMcpServer;
[McpServerToolType]
public static class MyTools
{
    [McpServerTool, Description("简单的问候工具")]
    public static string Greet(
        [Description("要问候的名字")] string name)
    {
        return $"你好, {name}! 欢迎使用 MCP 服务器。";
    }
    [McpServerTool, Description("计算两个数字的和")]
    public static int Add(
        [Description("第一个数字")] int a,
        [Description("第二个数字")] int b)
    {
        return a + b;
    }
    [McpServerTool, Description("获取当前时间")]
    public static string GetCurrentTime()
    {
        return DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
    }
}
        工具方法实现
1. 基本工具方法
            
            
              csharp
              
              
            
          
          [McpServerTool, Description("工具描述")]
public static ReturnType ToolName(
    [Description("参数描述")] ParameterType parameterName,
    CancellationToken cancellationToken = default)
{
    try
    {
        // 实现逻辑
        var result = new ResultType
        {
            Success = true,
            Data = processData(parameterName)
        };
        return result;
    }
    catch (Exception ex)
    {
        return new ResultType
        {
            Success = false,
            ErrorMessage = ex.Message
        };
    }
}
        2. 异步工具方法
            
            
              csharp
              
              
            
          
          [McpServerTool, Description("异步工具示例")]
public static Task<AsyncResult> AsyncTool(
    [Description("输入数据")] string input,
    CancellationToken cancellationToken = default)
{
    return Task.Run(() =>
    {
        // 模拟异步操作
        Task.Delay(1000, cancellationToken);
        return new AsyncResult
        {
            Success = true,
            ProcessedData = input.ToUpper()
        };
    }, cancellationToken);
}
        3. 文件处理工具
            
            
              csharp
              
              
            
          
          [McpServerTool, Description("读取文件内容")]
public static FileResult ReadFile(
    [Description("文件路径")] string filePath)
{
    var result = new FileResult { Success = false };
    try
    {
        if (!File.Exists(filePath))
        {
            result.ErrorMessage = $"文件不存在: {filePath}";
            return result;
        }
        var content = File.ReadAllText(filePath);
        result.Success = true;
        result.Content = content;
        result.FileSize = new FileInfo(filePath).Length;
    }
    catch (Exception ex)
    {
        result.ErrorMessage = $"读取文件失败: {ex.Message}";
    }
    return result;
}
        错误处理和日志
1. 错误处理模式
            
            
              csharp
              
              
            
          
          public static ResultType SafeOperation(string input)
{
    var result = new ResultType { Success = false };
    try
    {
        // 参数验证
        if (string.IsNullOrEmpty(input))
        {
            result.ErrorMessage = "输入参数不能为空";
            return result;
        }
        // 业务逻辑
        var processed = ProcessInput(input);
        result.Success = true;
        result.Data = processed;
        return result;
    }
    catch (ArgumentException ex)
    {
        result.ErrorMessage = $"参数错误: {ex.Message}";
        return result;
    }
    catch (InvalidOperationException ex)
    {
        result.ErrorMessage = $"操作无效: {ex.Message}";
        return result;
    }
    catch (Exception ex)
    {
        // 记录未预期的错误
        LogError($"未预期的错误: {ex}");
        result.ErrorMessage = "系统错误,请稍后重试";
        return result;
    }
}
        2. 日志记录
            
            
              csharp
              
              
            
          
          public static class Logger
{
    private static readonly string LogPath = Path.Combine(
        AppDomain.CurrentDomain.BaseDirectory,
        "mcp_server.log");
    public static void LogInfo(string message)
    {
        LogToFile("INFO", message);
    }
    public static void LogError(string message)
    {
        LogToFile("ERROR", message);
        // 同时输出到 stderr (MCP 标准)
        Console.Error.WriteLine($"[ERROR] {message}");
    }
    private static void LogToFile(string level, string message)
    {
        try
        {
            var timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
            var logMessage = $"[{timestamp}] [{level}] {message}";
            File.AppendAllText(LogPath, logMessage + Environment.NewLine);
        }
        catch
        {
            // 忽略日志写入错误
        }
    }
}
        数据模型定义
1. 基础结果模型
            
            
              csharp
              
              
            
          
          // Models/OperationResult.cs
public class OperationResult
{
    public bool Success { get; set; }
    public string? ErrorMessage { get; set; }
    public long ElapsedMilliseconds { get; set; }
}
public class DataResult<T> : OperationResult
{
    public T? Data { get; set; }
}
public class FileResult : OperationResult
{
    public string? Content { get; set; }
    public long FileSize { get; set; }
    public string? FileName { get; set; }
}
        2. 复杂数据模型
            
            
              csharp
              
              
            
          
          // Models/TextBlock.cs
public class TextBlock
{
    public string Text { get; set; } = string.Empty;
    public double Confidence { get; set; }
    public BoundingBox BoundingBox { get; set; } = new();
}
public class BoundingBox
{
    public int X { get; set; }
    public int Y { get; set; }
    public int Width { get; set; }
    public int Height { get; set; }
}
        部署和测试
1. 编译项目
            
            
              bash
              
              
            
          
          # Release 编译
dotnet build --configuration Release
# 发布自包含应用
dotnet publish --configuration Release --self-contained -r win-x64
        2. 本地测试
            
            
              bash
              
              
            
          
          # 直接运行
./bin/Release/net8.0/MyMcpServer.exe
# 或使用 dotnet 运行
dotnet run --configuration Release
        3. Claude Code 配置
在 Claude Code 的配置文件中添加你的 MCP 服务器:
            
            
              json
              
              
            
          
          {
  "mcpServers": {
    "myMcpServer": {
      "command": "D:\\path\\to\\MyMcpServer.exe",
      "args": []
    }
  }
}
        最佳实践
1. 代码组织
- 单一职责: 每个工具方法只做一件事
 - 命名规范: 使用清晰的方法和参数名
 - 文档注释: 为所有工具方法添加 Description 特性
 
2. 错误处理
- 输入验证: 总是验证输入参数
 - 异常捕获: 捕获并处理预期的异常
 - 错误信息: 提供有意义的错误消息
 
3. 性能考虑
- 异步操作: 对于耗时操作使用异步方法
 - 资源管理: 正确使用 using 语句管理资源
 - 缓存: 对于重复计算考虑使用缓存
 
4. 安全考虑
- 输入验证: 防止注入攻击
 - 路径验证: 验证文件路径的合法性
 - 权限检查: 确保只访问授权的资源
 
常见问题
1. 编译错误
问题 : 找不到 McpToolkit 相关类型
解决: 确保正确安装了 NuGet 包
            
            
              xml
              
              
            
          
          <PackageReference Include="McpToolkit" Version="0.1.3" />
<PackageReference Include="McpToolkit.Server" Version="0.1.3" />
        2. 运行时错误
问题 : MCP 服务器无法启动
解决: 检查 Program.cs 中的服务配置
            
            
              csharp
              
              
            
          
          builder.Services.AddMcpServerToolType<MyTools>();
        3. 通信问题
问题 : Claude Code 无法连接到 MCP 服务器
解决:
- 确保服务器程序路径正确
 - 检查服务器是否正常输出 JSON-RPC 响应
 - 验证 stdio 通信是否正常
 
4. 工具调用失败
问题 : 工具方法返回错误
解决:
- 检查方法签名是否正确
 - 确保参数类型匹配
 - 添加详细的错误日志
 
实际项目示例
基于我们开发的 OCR MCP 服务器,这里展示一个完整的实际项目结构:
1. 项目文件 (OCRMCP.Server.csproj)
            
            
              xml
              
              
            
          
          <Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <AssemblyName>OCRMCP.Server</AssemblyName>
    <RootNamespace>OCRMCP.Server</RootNamespace>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="McpToolkit" Version="0.1.3" />
    <PackageReference Include="McpToolkit.Server" Version="0.1.3" />
    <PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.8" />
    <PackageReference Include="ModelContextProtocol-SemanticKernel" Version="0.3.0" />
    <PackageReference Include="PaddleOCRSharp" Version="5.1.0" />
    <PackageReference Include="PdfiumViewer" Version="2.13.0" />
    <PackageReference Include="SixLabors.ImageSharp" Version="3.1.5" />
    <PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
  </ItemGroup>
</Project>
        2. 主程序 (Program.cs)
            
            
              csharp
              
              
            
          
          using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using McpToolkit.Server;
namespace OCRMCP.Server;
class Program
{
    static async Task Main(string[] args)
    {
        var builder = Host.CreateApplicationBuilder(args);
        builder.Services.AddMcpServer(options =>
        {
            options.ServerInfo = new()
            {
                Name = "OCR MCP Server",
                Version = "1.0.0"
            };
        });
        builder.Services.AddMcpServerToolType<OCRTools>();
        var host = builder.Build();
        await host.RunMcpAsync();
    }
}
        3. 核心工具类 (OCRTools.cs)
            
            
              csharp
              
              
            
          
          using ModelContextProtocol.Server;
using System.ComponentModel;
using PaddleOCRSharp;
namespace OCRMCP.Server;
[McpServerToolType]
public static class OCRTools
{
    private static PaddleOCREngine? _ocrEngine;
    private static readonly object _lockObject = new object();
    private static bool _isInitialized = false;
    static OCRTools()
    {
        InitializeOCREngine();
    }
    [McpServerTool, Description("识别图片中的文本内容")]
    public static Task<OCRResult> RecognizeImage(
        [Description("图片文件路径")] string imagePath,
        [Description("是否预处理图片以提高识别率")] bool preprocess = true,
        CancellationToken cancellationToken = default)
    {
        var result = new OCRResult { Success = false };
        try
        {
            // 参数验证
            if (string.IsNullOrEmpty(imagePath))
            {
                result.ErrorMessage = "缺少必需参数:imagePath";
                return Task.FromResult(result);
            }
            if (!File.Exists(imagePath))
            {
                result.ErrorMessage = $"图片文件不存在: {imagePath}";
                return Task.FromResult(result);
            }
            // 初始化 OCR 引擎
            InitializeOCREngine();
            if (!_isInitialized || _ocrEngine == null)
            {
                result.ErrorMessage = "OCR引擎初始化失败";
                return Task.FromResult(result);
            }
            // 执行 OCR 识别
            var paddleResult = _ocrEngine.DetectText(imagePath);
            result = ConvertToOCRResult(paddleResult, imagePath);
            result.Success = true;
            return Task.FromResult(result);
        }
        catch (Exception ex)
        {
            result.Success = false;
            result.ErrorMessage = $"识别失败: {ex.Message}";
            return Task.FromResult(result);
        }
    }
    private static void InitializeOCREngine()
    {
        // OCR 引擎初始化逻辑
        // ...
    }
    private static OCRResult ConvertToOCRResult(PaddleOCRSharp.OCRResult paddleResult, string sourcePath)
    {
        // 结果转换逻辑
        // ...
    }
}
        总结
通过本教程,你应该能够:
- ✅ 创建一个基本的 .NET 8 MCP 服务器
 - ✅ 实现各种类型的工具方法
 - ✅ 处理错误和日志记录
 - ✅ 部署和测试 MCP 服务器
 - ✅ 遵循最佳实践开发高质量的服务器
 
MCP 服务器开发是一个不断发展的领域,建议持续关注官方文档和社区更新。希望这个教程对你有所帮助!
参考资源:
项目示例: 本教程基于实际的 OCR MCP 服务器项目,你可以参考完整的实现代码。