.NET MCP Server 开发教程

.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)
    {
        // 结果转换逻辑
        // ...
    }
}

总结

通过本教程,你应该能够:

  1. ✅ 创建一个基本的 .NET 8 MCP 服务器
  2. ✅ 实现各种类型的工具方法
  3. ✅ 处理错误和日志记录
  4. ✅ 部署和测试 MCP 服务器
  5. ✅ 遵循最佳实践开发高质量的服务器

MCP 服务器开发是一个不断发展的领域,建议持续关注官方文档和社区更新。希望这个教程对你有所帮助!


参考资源:

项目示例: 本教程基于实际的 OCR MCP 服务器项目,你可以参考完整的实现代码。

相关推荐
L X..11 小时前
Unity反射调用 ReactiveProperty<T>(泛型类型)内部方法时崩溃
unity·c#·游戏引擎·.net
CodeCraft Studio12 小时前
如何从 FastReport .NET 将报表导出为 JPEG / PNG / BMP / GIF / TIFF / EMF
windows·.net·报表开发·报表工具·fastreport·报表转图片
缺点内向14 小时前
C# 中 Excel 工作表打印前页面边距的设置方法
c#·.net·excel
喵叔哟15 小时前
6. 从0到上线:.NET 8 + ML.NET LTR 智能类目匹配实战--渐进式学习闭环:从反馈到再训练
学习·机器学习·.net
喵叔哟1 天前
4. 从0到上线:.NET 8 + ML.NET LTR 智能类目匹配实战--从业务到方案:数据与特征工程:从 CSV 到可训练的 LTR 样本
.net
@LetsTGBot搜索引擎机器人1 天前
用 Python 打造一个 Telegram 二手交易商城机器人
开发语言·python·搜索引擎·机器人·.net·facebook·twitter
追逐时光者2 天前
Everything替代工具,一款基于 .NET 开源免费、高效且用户友好文件搜索工具!
后端·.net
追逐时光者2 天前
推荐 12 款开源美观、简单易用的 WPF UI 控件库,让 WPF 应用界面焕然一新!
后端·.net
咕白m6252 天前
C# 合并多个PDF文档:高效解决方案
c#·.net