.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 服务器项目,你可以参考完整的实现代码。

相关推荐
何解忧113 小时前
.NET 中的新增功能系列文章—— .NET MAUI 中的新增功能
.net
仙宇觉尘1 天前
一款基于 .NET 开源美观、功能丰富的串口调试工具
开源·.net
仙宇觉尘1 天前
记一次 .NET 某中医药附属医院门诊系统 崩溃分析
数据库·oracle·.net
丙氨酸長鏈1 天前
关于.net发布单体exe程序无法打开问题详解
.net
鲜花飘飘扬1 天前
C# 与 .NET 跨平台开发实战(第一章:开发环境搭建与.NET概述-上篇)
开发语言·c#·.net
风样滴男人哟2 天前
基于 .NET 开源、功能齐全的分布式作业调度系统
分布式·开源·.net
心念枕惊2 天前
OpenClaw.NET 重大更新:Goal 机制登场,让 AI Agent 不再“半途而废“
.net
geovindu2 天前
CSharp:Chain of Responsibility Pattern
开发语言·后端·设计模式·c#·.net·责任链模式·行为模式
TDengine (老段)2 天前
TDengine Node.js 与 C# 连接器 — Web 服务与 .NET 集成
大数据·数据库·node.js·c#·.net·时序数据库·tdengine