.NET MCP 示例

服务器端示例

基础服务器

以下是一个基础的 MCP 服务器示例,它使用标准输入输出(stdio)作为传输方式,并实现了一个简单的回显工具:

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using ModelContextProtocol.Server;
using System.ComponentModel;

namespace BasicMcpServer
{
    public class Program
    {
        public static async Task Main(string[] args)
        {
            var builder = Host.CreateApplicationBuilder(args);
            
            // 配置日志输出到标准错误
            builder.Logging.AddConsole(consoleLogOptions =>
            {
                consoleLogOptions.LogToStandardErrorThreshold = LogLevel.Trace;
            });
            
            // 配置 MCP 服务器
            builder.Services
                .AddMcpServer()
                .WithStdioServerTransport()
                .WithToolsFromAssembly();
                
            await builder.Build().RunAsync();
        }
    }
    
    [McpServerToolType]
    public static class BasicTools
    {
        [McpServerTool, Description("Echoes the message back to the client.")]
        public static string Echo(string message) => $"You said: {message}";
        
        [McpServerTool, Description("Adds two numbers together.")]
        public static double Add(
            [Description("First number to add")] double a, 
            [Description("Second number to add")] double b) => a + b;
            
        [McpServerTool, Description("Gets the current date and time.")]
        public static string GetDateTime() => DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
    }
}

这个示例展示了如何创建一个基本的 MCP 服务器,它包含三个简单的工具:回显消息、加法计算和获取当前日期时间。

文件操作工具

以下是一个实现文件操作功能的 MCP 工具示例:

[McpServerToolType]
public static class FileTools
{
    [McpServerTool, Description("Reads the content of a text file.")]
    public static async Task ReadTextFile(
        [Description("Path to the file to read")] string filePath,
        CancellationToken cancellationToken)
    {
        if (!File.Exists(filePath))
        {
            throw new FileNotFoundException($"File not found: {filePath}");
        }
        
        return await File.ReadAllTextAsync(filePath, cancellationToken);
    }
    
    [McpServerTool, Description("Writes text content to a file.")]
    public static async Task WriteTextFile(
        [Description("Path to the file to write")] string filePath,
        [Description("Content to write to the file")] string content,
        [Description("Whether to append to the file instead of overwriting")] bool append = false,
        CancellationToken cancellationToken = default)
    {
        try
        {
            if (append)
            {
                await File.AppendAllTextAsync(filePath, content, cancellationToken);
            }
            else
            {
                await File.WriteAllTextAsync(filePath, content, cancellationToken);
            }
            
            return $"Successfully wrote {content.Length} characters to {filePath}";
        }
        catch (Exception ex)
        {
            return $"Error writing to file: {ex.Message}";
        }
    }
    
    [McpServerTool, Description("Lists files in a directory.")]
    public static string[] ListFiles(
        [Description("Directory path to list files from")] string directoryPath,
        [Description("File pattern to match (e.g., *.txt)")] string pattern = "*.*")
    {
        if (!Directory.Exists(directoryPath))
        {
            throw new DirectoryNotFoundException($"Directory not found: {directoryPath}");
        }
        
        return Directory.GetFiles(directoryPath, pattern)
            .Select(Path.GetFileName)
            .ToArray();
    }
}

这个示例实现了三个文件操作工具:读取文本文件、写入文本文件和列出目录中的文件。这些工具可以帮助 AI 模型访问和操作本地文件系统。

Web 请求工具

以下是一个实现 Web 请求功能的 MCP 工具示例:

[McpServerToolType]
public static class WebTools
{
    [McpServerTool, Description("Fetches content from a URL.")]
    public static async Task FetchUrl(
        HttpClient httpClient,
        [Description("URL to fetch content from")] string url,
        CancellationToken cancellationToken)
    {
        try
        {
            var response = await httpClient.GetAsync(url, cancellationToken);
            response.EnsureSuccessStatusCode();
            return await response.Content.ReadAsStringAsync(cancellationToken);
        }
        catch (Exception ex)
        {
            return $"Error fetching URL: {ex.Message}";
        }
    }
    
    [McpServerTool, Description("Performs a web search and returns results.")]
    public static async Task WebSearch(
        HttpClient httpClient,
        [Description("Search query")] string query,
        [Description("Maximum number of results to return")] int maxResults = 5,
        CancellationToken cancellationToken = default)
    {
        // 注意:这是一个示例实现,实际应用中应该使用真实的搜索 API
        var encodedQuery = Uri.EscapeDataString(query);
        var url = $"https://api.example.com/search?q={encodedQuery}&limit={maxResults}";
        
        try
        {
            var response = await httpClient.GetAsync(url, cancellationToken);
            response.EnsureSuccessStatusCode();
            var content = await response.Content.ReadAsStringAsync(cancellationToken);
            
            // 解析搜索结果(示例)
            return $"Search results for '{query}':\n{content}";
        }
        catch (Exception ex)
        {
            return $"Error performing web search: {ex.Message}";
        }
    }
    
    [McpServerTool, Description("Posts data to a URL and returns the response.")]
    public static async Task PostToUrl(
        HttpClient httpClient,
        [Description("URL to post data to")] string url,
        [Description("JSON data to post")] string jsonData,
        CancellationToken cancellationToken)
    {
        try
        {
            var content = new StringContent(jsonData, System.Text.Encoding.UTF8, "application/json");
            var response = await httpClient.PostAsync(url, content, cancellationToken);
            response.EnsureSuccessStatusCode();
            return await response.Content.ReadAsStringAsync(cancellationToken);
        }
        catch (Exception ex)
        {
            return $"Error posting to URL: {ex.Message}";
        }
    }
}

这个示例实现了三个 Web 请求工具:获取 URL 内容、执行 Web 搜索和向 URL 发送 POST 请求。这些工具可以帮助 AI 模型访问互联网上的信息。

注册 HttpClient:

要使用上述 Web 工具,需要在服务配置中注册 HttpClient:

builder.Services.AddHttpClient();

数据库工具

以下是一个实现数据库操作功能的 MCP 工具示例(使用 Entity Framework Core):

// 数据库上下文
public class AppDbContext : DbContext
{
    public AppDbContext(DbContextOptions options) : base(options) { }
    
    public DbSet Products { get; set; }
}

// 产品实体
public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
    public int Stock { get; set; }
}

// 数据库工具
[McpServerToolType]
public class DatabaseTools
{
    private readonly AppDbContext _dbContext;
    
    public DatabaseTools(AppDbContext dbContext)
    {
        _dbContext = dbContext;
    }
    
    [McpServerTool, Description("Gets a list of products.")]
    public async Task GetProducts(
        [Description("Maximum number of products to return")] int limit = 10,
        CancellationToken cancellationToken = default)
    {
        var products = await _dbContext.Products
            .Take(limit)
            .ToListAsync(cancellationToken);
            
        return JsonSerializer.Serialize(products, new JsonSerializerOptions
        {
            WriteIndented = true
        });
    }
    
    [McpServerTool, Description("Searches for products by name.")]
    public async Task SearchProducts(
        [Description("Product name to search for")] string name,
        CancellationToken cancellationToken = default)
    {
        var products = await _dbContext.Products
            .Where(p => p.Name.Contains(name))
            .ToListAsync(cancellationToken);
            
        return JsonSerializer.Serialize(products, new JsonSerializerOptions
        {
            WriteIndented = true
        });
    }
    
    [McpServerTool, Description("Adds a new product.")]
    public async Task AddProduct(
        [Description("Product name")] string name,
        [Description("Product price")] decimal price,
        [Description("Product stock")] int stock,
        CancellationToken cancellationToken = default)
    {
        var product = new Product
        {
            Name = name,
            Price = price,
            Stock = stock
        };
        
        _dbContext.Products.Add(product);
        await _dbContext.SaveChangesAsync(cancellationToken);
        
        return $"Product added successfully with ID: {product.Id}";
    }
}

这个示例实现了三个数据库操作工具:获取产品列表、搜索产品和添加新产品。这些工具可以帮助 AI 模型访问和操作数据库。

注册数据库上下文:

要使用上述数据库工具,需要在服务配置中注册数据库上下文:

builder.Services.AddDbContext(options =>
    options.UseSqlite("Data Source=app.db"));
    
// 注册数据库工具
builder.Services.AddTransient();

客户端示例

基础客户端

以下是一个基础的 MCP 客户端示例,它连接到 MCP 服务器并列出可用的工具:

using ModelContextProtocol.Client;
using ModelContextProtocol.Protocol.Transport;

namespace BasicMcpClient
{
    public class Program
    {
        public static async Task Main(string[] args)
        {
            // 解析命令行参数
            var (command, arguments) = GetCommandAndArguments(args);
            
            // 创建 MCP 客户端
            await using var mcpClient = await McpClientFactory.CreateAsync(new()
            {
                Id = "demo-server",
                Name = "Demo Server",
                TransportType = TransportTypes.StdIo,
                TransportOptions = new()
                {
                    ["command"] = command,
                    ["arguments"] = arguments,
                }
            });
            
            // 列出可用工具
            var tools = await mcpClient.ListToolsAsync();
            
            Console.WriteLine("Available tools:");
            foreach (var tool in tools)
            {
                Console.WriteLine($"- {tool.Name}: {tool.Description}");
                
                if (tool.Parameters?.Any() == true)
                {
                    Console.WriteLine("  Parameters:");
                    foreach (var param in tool.Parameters)
                    {
                        Console.WriteLine($"  - {param.Name}: {param.Description} ({param.Type})");
                    }
                }
                
                Console.WriteLine();
            }
            
            // 保持程序运行,等待用户输入
            Console.WriteLine("Press Enter to exit...");
            Console.ReadLine();
        }
        
        private static (string, string) GetCommandAndArguments(string[] args)
        {
            // 解析命令行参数的逻辑
            // ...
            
            // 示例返回值
            return ("dotnet", "run --project ../BasicMcpServer/BasicMcpServer.csproj");
        }
    }
}

这个示例展示了如何创建一个基本的 MCP 客户端,连接到 MCP 服务器,并列出可用的工具及其参数。

工具发现与调用

以下是一个展示如何发现和调用 MCP 工具的示例:

// 连接到 MCP 服务器
await using var mcpClient = await McpClientFactory.CreateAsync(new()
{
    Id = "demo-server",
    Name = "Demo Server",
    TransportType = TransportTypes.StdIo,
    TransportOptions = new()
    {
        ["command"] = command,
        ["arguments"] = arguments,
    }
});

// 列出可用工具
var tools = await mcpClient.ListToolsAsync();
Console.WriteLine($"Found {tools.Count} tools:");
foreach (var tool in tools)
{
    Console.WriteLine($"- {tool.Name}");
}

// 调用 Echo 工具
Console.WriteLine("\nCalling Echo tool...");
var echoResult = await mcpClient.CallToolAsync(
    "echo",
    new Dictionary() { ["message"] = "Hello MCP!" },
    CancellationToken.None);
Console.WriteLine($"Echo result: {echoResult.Content.First(c => c.Type == "text").Text}");

// 调用 Add 工具
Console.WriteLine("\nCalling Add tool...");
var addResult = await mcpClient.CallToolAsync(
    "add",
    new Dictionary() 
    { 
        ["a"] = 5, 
        ["b"] = 7 
    },
    CancellationToken.None);
Console.WriteLine($"Add result: {addResult.Content.First(c => c.Type == "text").Text}");

// 调用 GetDateTime 工具
Console.WriteLine("\nCalling GetDateTime tool...");
var dateTimeResult = await mcpClient.CallToolAsync(
    "getDateTime",
    new Dictionary(),
    CancellationToken.None);
Console.WriteLine($"DateTime result: {dateTimeResult.Content.First(c => c.Type == "text").Text}");

这个示例展示了如何列出可用的 MCP 工具,并调用不同类型的工具,包括带参数和不带参数的工具。

错误处理

以下是一个展示如何处理 MCP 工具调用错误的示例:

try
{
    // 尝试调用不存在的工具
    var result = await mcpClient.CallToolAsync(
        "nonExistentTool",
        new Dictionary(),
        CancellationToken.None);
}
catch (McpException ex)
{
    Console.WriteLine($"MCP Error: {ex.Message}");
    Console.WriteLine($"Error Code: {ex.Code}");
    Console.WriteLine($"Error Data: {ex.Data}");
}

try
{
    // 尝试调用工具但缺少必要参数
    var result = await mcpClient.CallToolAsync(
        "echo",
        new Dictionary(),  // 缺少 message 参数
        CancellationToken.None);
}
catch (McpException ex)
{
    Console.WriteLine($"MCP Error: {ex.Message}");
}

try
{
    // 尝试调用工具但参数类型错误
    var result = await mcpClient.CallToolAsync(
        "add",
        new Dictionary() 
        { 
            ["a"] = "not a number", 
            ["b"] = 7 
        },
        CancellationToken.None);
}
catch (McpException ex)
{
    Console.WriteLine($"MCP Error: {ex.Message}");
}

这个示例展示了如何处理 MCP 工具调用中可能出现的各种错误,包括调用不存在的工具、缺少必要参数和参数类型错误。

LLM 集成示例

Claude 集成

以下是一个将 MCP 工具与 Claude 模型集成的示例:

using Anthropic.SDK;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using ModelContextProtocol.Client;
using ModelContextProtocol.Protocol.Transport;

var builder = Host.CreateApplicationBuilder(args);
builder.Configuration
    .AddEnvironmentVariables()
    .AddUserSecrets();

// 创建 MCP 客户端
var (command, arguments) = GetCommandAndArguments(args);
await using var mcpClient = await McpClientFactory.CreateAsync(new()
{
    Id = "demo-server",
    Name = "Demo Server",
    TransportType = TransportTypes.StdIo,
    TransportOptions = new()
    {
        ["command"] = command,
        ["arguments"] = arguments,
    }
});

// 获取可用工具
var tools = await mcpClient.ListToolsAsync();
Console.WriteLine($"Connected to server with {tools.Count} tools");

// 创建 Claude 客户端
var anthropicClient = new AnthropicClient(new APIAuthentication(builder.Configuration["ANTHROPIC_API_KEY"]))
    .Messages
    .AsBuilder()
    .UseFunctionInvocation()
    .Build();

// 配置聊天选项
var options = new ChatOptions
{
    MaxOutputTokens = 1000,
    ModelId = "claude-3-5-sonnet-20240229",
    Tools = [.. tools]
};

Console.WriteLine("Chat with Claude (type 'exit' to quit):");
while (true)
{
    Console.Write("> ");
    var query = Console.ReadLine();
    
    if (string.IsNullOrWhiteSpace(query) || query.Equals("exit", StringComparison.OrdinalIgnoreCase))
    {
        break;
    }
    
    // 使用 Claude 处理查询
    await foreach (var message in anthropicClient.GetStreamingResponseAsync(query, options))
    {
        Console.Write(message);
    }
    
    Console.WriteLine("\n");
}

这个示例展示了如何创建一个聊天应用,将 MCP 工具与 Claude 模型集成,使用户能够通过自然语言与 Claude 交互,而 Claude 能够使用 MCP 工具来完成任务。

OpenAI 集成

以下是一个将 MCP 工具与 OpenAI 模型集成的示例:

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using ModelContextProtocol.Client;
using ModelContextProtocol.Protocol.Transport;
using OpenAI_API;
using OpenAI_API.Chat;
using System.Text.Json;

var builder = Host.CreateApplicationBuilder(args);
builder.Configuration
    .AddEnvironmentVariables()
    .AddUserSecrets();

// 创建 MCP 客户端
var (command, arguments) = GetCommandAndArguments(args);
await using var mcpClient = await McpClientFactory.CreateAsync(new()
{
    Id = "demo-server",
    Name = "Demo Server",
    TransportType = TransportTypes.StdIo,
    TransportOptions = new()
    {
        ["command"] = command,
        ["arguments"] = arguments,
    }
});

// 获取可用工具
var tools = await mcpClient.ListToolsAsync();
Console.WriteLine($"Connected to server with {tools.Count} tools");

// 创建 OpenAI 客户端
var openAiApi = new OpenAIAPI(builder.Configuration["OPENAI_API_KEY"]);

// 转换 MCP 工具为 OpenAI 工具格式
var openAiTools = tools.Select(tool => new OpenAI_API.Tool
{
    Type = "function",
    Function = new OpenAI_API.Function
    {
        Name = tool.Name,
        Description = tool.Description,
        Parameters = new
        {
            Type = "object",
            Properties = tool.Parameters?.ToDictionary(
                p => p.Name,
                p => new
                {
                    Type = ConvertToJsonSchemaType(p.Type),
                    Description = p.Description
                }
            ) ?? new Dictionary(),
            Required = tool.Parameters?.Where(p => p.Required).Select(p => p.Name).ToArray() ?? Array.Empty()
        }
    }
}).ToList();

// 创建聊天会话
var chat = openAiApi.Chat.CreateConversation();
chat.Model = "gpt-4o";
chat.RequestParameters.Tools = openAiTools;

Console.WriteLine("Chat with GPT (type 'exit' to quit):");
while (true)
{
    Console.Write("> ");
    var query = Console.ReadLine();
    
    if (string.IsNullOrWhiteSpace(query) || query.Equals("exit", StringComparison.OrdinalIgnoreCase))
    {
        break;
    }
    
    // 添加用户消息
    chat.AppendUserInput(query);
    
    // 获取 GPT 响应
    var response = await chat.GetResponseFromChatbotAsync();
    Console.WriteLine(response);
    
    // 处理工具调用
    if (chat.ResponseParameters.ToolCalls?.Any() == true)
    {
        foreach (var toolCall in chat.ResponseParameters.ToolCalls)
        {
            if (toolCall.Type == "function")
            {
                Console.WriteLine($"\nCalling tool: {toolCall.Function.Name}");
                
                // 解析参数
                var parameters = JsonSerializer.Deserialize>(
                    toolCall.Function.Arguments);
                
                // 调用 MCP 工具
                var result = await mcpClient.CallToolAsync(
                    toolCall.Function.Name,
                    parameters,
                    CancellationToken.None);
                
                var resultText = result.Content.First(c => c.Type == "text").Text;
                Console.WriteLine($"Tool result: {resultText}");
                
                // 将工具结果添加到对话
                chat.AppendToolResult(resultText, toolCall.Id);
            }
        }
        
        // 获取 GPT 对工具结果的响应
        var finalResponse = await chat.GetResponseFromChatbotAsync();
        Console.WriteLine($"\nFinal response: {finalResponse}");
    }
    
    Console.WriteLine("\n");
}

// 辅助方法:将 MCP 类型转换为 JSON Schema 类型
string ConvertToJsonSchemaType(string mcpType)
{
    return mcpType.ToLower() switch
    {
        "string" => "string",
        "integer" => "integer",
        "number" => "number",
        "boolean" => "boolean",
        "array" => "array",
        "object" => "object",
        _ => "string"
    };
}

这个示例展示了如何创建一个聊天应用,将 MCP 工具与 OpenAI 的 GPT 模型集成,使用户能够通过自然语言与 GPT 交互,而 GPT 能够使用 MCP 工具来完成任务。

Semantic Kernel 集成

以下是一个将 MCP 工具与 Microsoft Semantic Kernel 集成的示例:

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.SemanticKernel;
using ModelContextProtocol.Client;
using ModelContextProtocol.Protocol.Transport;

var builder = Host.CreateApplicationBuilder(args);
builder.Configuration
    .AddEnvironmentVariables()
    .AddUserSecrets();

// 创建 MCP 客户端
var (command, arguments) = GetCommandAndArguments(args);
await using var mcpClient = await McpClientFactory.CreateAsync(new()
{
    Id = "demo-server",
    Name = "Demo Server",
    TransportType = TransportTypes.StdIo,
    TransportOptions = new()
    {
        ["command"] = command,
        ["arguments"] = arguments,
    }
});

// 获取可用工具
var tools = await mcpClient.ListToolsAsync();
Console.WriteLine($"Connected to server with {tools.Count} tools");

// 创建 Semantic Kernel
var kernel = Kernel.CreateBuilder()
    .AddAzureOpenAIChatCompletion(
        deploymentName: builder.Configuration["AZURE_OPENAI_DEPLOYMENT_NAME"],
        endpoint: builder.Configuration["AZURE_OPENAI_ENDPOINT"],
        apiKey: builder.Configuration["AZURE_OPENAI_API_KEY"])
    .Build();

// 注册 MCP 工具为 Semantic Kernel 函数
foreach (var tool in tools)
{
    kernel.ImportPluginFromObject(new McpToolWrapper(mcpClient, tool), tool.Name);
}

// 创建聊天历史
var chatHistory = new ChatHistory();

Console.WriteLine("Chat with Semantic Kernel (type 'exit' to quit):");
while (true)
{
    Console.Write("> ");
    var query = Console.ReadLine();
    
    if (string.IsNullOrWhiteSpace(query) || query.Equals("exit", StringComparison.OrdinalIgnoreCase))
    {
        break;
    }
    
    // 添加用户消息到聊天历史
    chatHistory.AddUserMessage(query);
    
    // 获取 AI 响应
    var response = await kernel.InvokePromptAsync(chatHistory.ToString());
    Console.WriteLine(response);
    
    // 添加 AI 响应到聊天历史
    chatHistory.AddAssistantMessage(response);
    
    Console.WriteLine("\n");
}

// MCP 工具包装类
public class McpToolWrapper
{
    private readonly IMcpClient _mcpClient;
    private readonly McpTool _tool;
    
    public McpToolWrapper(IMcpClient mcpClient, McpTool tool)
    {
        _mcpClient = mcpClient;
        _tool = tool;
    }
    
    [KernelFunction]
    public async Task ExecuteAsync(Dictionary parameters)
    {
        var result = await _mcpClient.CallToolAsync(
            _tool.Name,
            parameters,
            CancellationToken.None);
            
        return result.Content.First(c => c.Type == "text").Text;
    }
}

这个示例展示了如何创建一个聊天应用,将 MCP 工具与 Microsoft Semantic Kernel 集成,使用户能够通过自然语言与 AI 交互,而 AI 能够使用 MCP 工具来完成任务。

应用场景

文档分析

以下是一个使用 MCP 工具进行文档分析的示例:

[McpServerToolType]
public static class DocumentTools
{
    [McpServerTool, Description("Analyzes a document and extracts key information.")]
    public static async Task AnalyzeDocument(
        HttpClient httpClient,
        [Description("URL of the document to analyze")] string documentUrl,
        [Description("Type of analysis to perform (summary, entities, sentiment)")] string analysisType = "summary",
        CancellationToken cancellationToken = default)
    {
        try
        {
            // 下载文档
            var response = await httpClient.GetAsync(documentUrl, cancellationToken);
            response.EnsureSuccessStatusCode();
            var content = await response.Content.ReadAsStringAsync(cancellationToken);
            
            // 根据分析类型执行不同的分析
            return analysisType.ToLower() switch
            {
                "summary" => await GenerateSummary(content, cancellationToken),
                "entities" => await ExtractEntities(content, cancellationToken),
                "sentiment" => await AnalyzeSentiment(content, cancellationToken),
                _ => throw new ArgumentException($"Unsupported analysis type: {analysisType}")
            };
        }
        catch (Exception ex)
        {
            return $"Error analyzing document: {ex.Message}";
        }
    }
    
    private static async Task GenerateSummary(string content, CancellationToken cancellationToken)
    {
        // 实现文档摘要生成逻辑
        // 这里可以使用 NLP 库或调用外部 API
        
        // 示例实现
        var summary = $"Document summary (length: {content.Length} characters):\n";
        summary += "This is a placeholder for the actual document summary.";
        
        return summary;
    }
    
    private static async Task ExtractEntities(string content, CancellationToken cancellationToken)
    {
        // 实现实体提取逻辑
        // 这里可以使用 NLP 库或调用外部 API
        
        // 示例实现
        var entities = "Extracted entities:\n";
        entities += "- Entity 1 (Person)\n";
        entities += "- Entity 2 (Organization)\n";
        entities += "- Entity 3 (Location)";
        
        return entities;
    }
    
    private static async Task AnalyzeSentiment(string content, CancellationToken cancellationToken)
    {
        // 实现情感分析逻辑
        // 这里可以使用 NLP 库或调用外部 API
        
        // 示例实现
        var sentiment = "Sentiment analysis:\n";
        sentiment += "- Overall sentiment: Positive\n";
        sentiment += "- Confidence score: 0.85\n";
        sentiment += "- Key positive phrases: [...]\n";
        sentiment += "- Key negative phrases: [...]";
        
        return sentiment;
    }
}

这个示例展示了如何实现文档分析工具,包括生成摘要、提取实体和分析情感。这些工具可以帮助 AI 模型分析和理解文档内容。

数据处理

以下是一个使用 MCP 工具进行数据处理的示例:

[McpServerToolType]
public static class DataProcessingTools
{
    [McpServerTool, Description("Processes CSV data and performs analysis.")]
    public static async Task ProcessCsvData(
        [Description("URL of the CSV file to process")] string csvUrl,
        [Description("Type of analysis to perform (stats, filter, transform)")] string analysisType = "stats",
        [Description("Additional parameters for the analysis (e.g., filter criteria)")] string parameters = "",
        CancellationToken cancellationToken = default)
    {
        try
        {
            // 下载 CSV 文件
            using var httpClient = new HttpClient();
            var response = await httpClient.GetAsync(csvUrl, cancellationToken);
            response.EnsureSuccessStatusCode();
            var csvContent = await response.Content.ReadAsStringAsync(cancellationToken);
            
            // 解析 CSV 数据
            var data = ParseCsv(csvContent);
            
            // 根据分析类型执行不同的处理
            return analysisType.ToLower() switch
            {
                "stats" => CalculateStatistics(data),
                "filter" => FilterData(data, parameters),
                "transform" => TransformData(data, parameters),
                _ => throw new ArgumentException($"Unsupported analysis type: {analysisType}")
            };
        }
        catch (Exception ex)
        {
            return $"Error processing CSV data: {ex.Message}";
        }
    }
    
    private static List> ParseCsv(string csvContent)
    {
        var result = new List>();
        var lines = csvContent.Split('\n');
        
        if (lines.Length < 2)
        {
            return result;
        }
        
        var headers = lines[0].Split(',').Select(h => h.Trim()).ToArray();
        
        for (int i = 1; i < lines.Length; i++)
        {
            var line = lines[i].Trim();
            if (string.IsNullOrEmpty(line))
            {
                continue;
            }
            
            var values = line.Split(',').Select(v => v.Trim()).ToArray();
            var row = new Dictionary();
            
            for (int j = 0; j < Math.Min(headers.Length, values.Length); j++)
            {
                row[headers[j]] = values[j];
            }
            
            result.Add(row);
        }
        
        return result;
    }
    
    private static string CalculateStatistics(List> data)
    {
        if (data.Count == 0)
        {
            return "No data to analyze.";
        }
        
        var result = "Data Statistics:\n";
        result += $"- Row count: {data.Count}\n";
        result += $"- Column count: {data[0].Count}\n";
        result += "- Columns: " + string.Join(", ", data[0].Keys);
        
        return result;
    }
    
    private static string FilterData(List> data, string parameters)
    {
        // 解析过滤参数
        // 格式:column=value
        var filterParams = parameters.Split('=');
        if (filterParams.Length != 2)
        {
            return "Invalid filter parameters. Format should be 'column=value'.";
        }
        
        var column = filterParams[0].Trim();
        var value = filterParams[1].Trim();
        
        // 应用过滤
        var filteredData = data.Where(row => row.ContainsKey(column) && row[column] == value).ToList();
        
        var result = $"Filtered data (where {column} = {value}):\n";
        result += $"- Matching rows: {filteredData.Count}\n\n";
        
        // 显示前 5 行
        for (int i = 0; i < Math.Min(5, filteredData.Count); i++)
        {
            result += $"Row {i + 1}:\n";
            foreach (var kvp in filteredData[i])
            {
                result += $"  {kvp.Key}: {kvp.Value}\n";
            }
            result += "\n";
        }
        
        return result;
    }
    
    private static string TransformData(List> data, string parameters)
    {
        // 解析转换参数
        // 格式:operation:column
        var transformParams = parameters.Split(':');
        if (transformParams.Length != 2)
        {
            return "Invalid transform parameters. Format should be 'operation:column'.";
        }
        
        var operation = transformParams[0].Trim().ToLower();
        var column = transformParams[1].Trim();
        
        // 检查列是否存在
        if (data.Count > 0 && !data[0].ContainsKey(column))
        {
            return $"Column '{column}' not found in data.";
        }
        
        // 应用转换
        var result = $"Transformed data ({operation} on {column}):\n\n";
        
        switch (operation)
        {
            case "uppercase":
                foreach (var row in data)
                {
                    if (row.ContainsKey(column))
                    {
                        row[column] = row[column].ToUpper();
                    }
                }
                break;
                
            case "lowercase":
                foreach (var row in data)
                {
                    if (row.ContainsKey(column))
                    {
                        row[column] = row[column].ToLower();
                    }
                }
                break;
                
            default:
                return $"Unsupported operation: {operation}";
        }
        
        // 显示前 5 行
        for (int i = 0; i < Math.Min(5, data.Count); i++)
        {
            result += $"Row {i + 1}:\n";
            foreach (var kvp in data[i])
            {
                result += $"  {kvp.Key}: {kvp.Value}\n";
            }
            result += "\n";
        }
        
        return result;
    }
}

这个示例展示了如何实现数据处理工具,包括计算统计信息、过滤数据和转换数据。这些工具可以帮助 AI 模型处理和分析结构化数据。

代码生成

以下是一个使用 MCP 工具进行代码生成的示例:

[McpServerToolType]
public static class CodeGenerationTools
{
    [McpServerTool, Description("Generates code based on a description.")]
    public static string GenerateCode(
        [Description("Description of the code to generate")] string description,
        [Description("Programming language (csharp, python, javascript)")] string language = "csharp",
        [Description("Additional options (e.g., framework, style)")] string options = "")
    {
        // 根据语言选择代码生成模板
        var codeTemplate = language.ToLower() switch
        {
            "csharp" => GenerateCSharpCode(description, options),
            "python" => GeneratePythonCode(description, options),
            "javascript" => GenerateJavaScriptCode(description, options),
            _ => throw new ArgumentException($"Unsupported language: {language}")
        };
        
        return codeTemplate;
    }
    
    private static string GenerateCSharpCode(string description, string options)
    {
        // 这里应该实现实际的代码生成逻辑
        // 可以使用模板、规则或调用外部 API
        
        // 示例实现:生成一个简单的 C# 类
        var className = GetClassName(description);
        
        var code = $@"// Generated C# code based on: {description}
using System;
using System.Threading.Tasks;

namespace GeneratedCode
{{
    public class {className}
    {{
        public {className}()
        {{
            // Constructor
        }}
        
        public void Execute()
        {{
            Console.WriteLine(""Executing {className}..."");
            // TODO: Implement based on description
            // {description}
        }}
        
        public async Task ExecuteAsync()
        {{
            Console.WriteLine(""Executing {className} asynchronously..."");
            // TODO: Implement based on description
            // {description}
            await Task.CompletedTask;
        }}
    }}
}}";
        
        return code;
    }
    
    private static string GeneratePythonCode(string description, string options)
    {
        // 示例实现:生成一个简单的 Python 类
        var className = GetClassName(description);
        
        var code = $@"# Generated Python code based on: {description}
import asyncio

class {className}:
    def __init__(self):
        # Constructor
        pass
    
    def execute(self):
        print(f'Executing {className}...')
        # TODO: Implement based on description
        # {description}
    
    async def execute_async(self):
        print(f'Executing {className} asynchronously...')
        # TODO: Implement based on description
        # {description}
        await asyncio.sleep(0)

# Usage example
if __name__ == '__main__':
    obj = {className}()
    obj.execute()
    
    # Async usage
    # asyncio.run(obj.execute_async())";
        
        return code;
    }
    
    private static string GenerateJavaScriptCode(string description, string options)
    {
        // 示例实现:生成一个简单的 JavaScript 类
        var className = GetClassName(description);
        
        var code = $@"// Generated JavaScript code based on: {description}
class {className} {{
    constructor() {{
        // Constructor
    }}
    
    execute() {{
        console.log('Executing {className}...');
        // TODO: Implement based on description
        // {description}
    }}
    
    async executeAsync() {{
        console.log('Executing {className} asynchronously...');
        // TODO: Implement based on description
        // {description}
        await Promise.resolve();
    }}
}}

// Usage example
const obj = new {className}();
obj.execute();

// Async usage
// obj.executeAsync().then(() => console.log('Done'));";
        
        return code;
    }
    
    private static string GetClassName(string description)
    {
        // 从描述中提取类名
        // 这里使用一个简单的启发式方法
        var words = description.Split(' ')
            .Where(w => !string.IsNullOrEmpty(w))
            .Select(w => char.ToUpper(w[0]) + w.Substring(1).ToLower())
            .ToArray();
            
        return string.Join("", words).Replace(".", "").Replace(",", "");
    }
}

这个示例展示了如何实现代码生成工具,可以根据描述生成不同编程语言的代码。这些工具可以帮助 AI 模型生成可执行的代码示例。

自动化任务

以下是一个使用 MCP 工具进行自动化任务的示例:

[McpServerToolType]
public class AutomationTools
{
    private readonly ILogger _logger;
    
    public AutomationTools(ILogger logger)
    {
        _logger = logger;
    }
    
    [McpServerTool, Description("Schedules a task to run at a specified time.")]
    public string ScheduleTask(
        [Description("Description of the task to schedule")] string taskDescription,
        [Description("When to run the task (format: yyyy-MM-dd HH:mm:ss)")] string scheduledTime,
        [Description("Whether to repeat the task daily")] bool repeatDaily = false)
    {
        try
        {
            // 解析时间
            if (!DateTime.TryParse(scheduledTime, out var scheduleDateTime))
            {
                return $"Invalid date/time format: {scheduledTime}. Please use yyyy-MM-dd HH:mm:ss format.";
            }
            
            // 检查时间是否在未来
            if (scheduleDateTime <= DateTime.Now)
            {
                return "Scheduled time must be in the future.";
            }
            
            // 记录任务信息
            _logger.LogInformation($"Task scheduled: {taskDescription}");
            _logger.LogInformation($"Scheduled time: {scheduleDateTime}");
            _logger.LogInformation($"Repeat daily: {repeatDaily}");
            
            // 在实际应用中,这里应该将任务添加到调度系统
            // 例如使用 Quartz.NET 或其他任务调度库
            
            return $"Task scheduled successfully:\n" +
                   $"- Description: {taskDescription}\n" +
                   $"- Scheduled time: {scheduleDateTime}\n" +
                   $"- Repeat daily: {repeatDaily}";
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error scheduling task");
            return $"Error scheduling task: {ex.Message}";
        }
    }
    
    [McpServerTool, Description("Runs a command on the server.")]
    public async Task RunCommand(
        [Description("Command to run")] string command,
        [Description("Working directory for the command")] string workingDirectory = "",
        [Description("Timeout in seconds (0 for no timeout)")] int timeoutSeconds = 60,
        CancellationToken cancellationToken = default)
    {
        try
        {
            _logger.LogInformation($"Running command: {command}");
            
            // 设置工作目录
            var workDir = string.IsNullOrEmpty(workingDirectory)
                ? Directory.GetCurrentDirectory()
                : workingDirectory;
                
            // 检查工作目录是否存在
            if (!Directory.Exists(workDir))
            {
                return $"Working directory does not exist: {workDir}";
            }
            
            // 创建进程启动信息
            var processStartInfo = new ProcessStartInfo
            {
                FileName = "cmd.exe",
                Arguments = $"/c {command}",
                WorkingDirectory = workDir,
                RedirectStandardOutput = true,
                RedirectStandardError = true,
                UseShellExecute = false,
                CreateNoWindow = true
            };
            
            // 启动进程
            using var process = new Process { StartInfo = processStartInfo };
            process.Start();
            
            // 设置超时
            var timeoutTask = timeoutSeconds > 0
                ? Task.Delay(timeoutSeconds * 1000, cancellationToken)
                : Task.Delay(-1, cancellationToken);
                
            // 读取输出
            var outputTask = process.StandardOutput.ReadToEndAsync();
            var errorTask = process.StandardError.ReadToEndAsync();
            
            // 等待进程完成或超时
            var completedTask = await Task.WhenAny(
                Task.Run(() => process.WaitForExit(), cancellationToken),
                timeoutTask);
                
            // 检查是否超时
            if (completedTask == timeoutTask && !process.HasExited)
            {
                process.Kill();
                return $"Command timed out after {timeoutSeconds} seconds.";
            }
            
            // 获取输出
            var output = await outputTask;
            var error = await errorTask;
            
            // 返回结果
            return string.IsNullOrEmpty(error)
                ? $"Command executed successfully:\n{output}"
                : $"Command executed with errors:\n{error}\n\nOutput:\n{output}";
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error running command");
            return $"Error running command: {ex.Message}";
        }
    }
    
    [McpServerTool, Description("Monitors a file or directory for changes.")]
    public string MonitorFileChanges(
        [Description("Path to file or directory to monitor")] string path,
        [Description("Types of changes to monitor (Created, Deleted, Changed, Renamed)")] string changeTypes = "Created,Deleted,Changed,Renamed",
        [Description("Whether to include subdirectories")] bool includeSubdirectories = true)
    {
        try
        {
            // 检查路径是否存在
            if (!File.Exists(path) && !Directory.Exists(path))
            {
                return $"Path does not exist: {path}";
            }
            
            // 解析变更类型
            var watcherChangeTypes = ParseChangeTypes(changeTypes);
            
            // 创建文件系统监视器
            var watcher = new FileSystemWatcher
            {
                Path = Directory.Exists(path) ? path : Path.GetDirectoryName(path),
                Filter = Directory.Exists(path) ? "*.*" : Path.GetFileName(path),
                NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName,
                IncludeSubdirectories = includeSubdirectories
            };
            
            // 设置事件处理程序
            watcher.Changed += (sender, e) => _logger.LogInformation($"File changed: {e.FullPath}");
            watcher.Created += (sender, e) => _logger.LogInformation($"File created: {e.FullPath}");
            watcher.Deleted += (sender, e) => _logger.LogInformation($"File deleted: {e.FullPath}");
            watcher.Renamed += (sender, e) => _logger.LogInformation($"File renamed: {e.OldFullPath} to {e.FullPath}");
            
            // 启动监视器
            watcher.EnableRaisingEvents = true;
            
            // 在实际应用中,应该将监视器存储在某个地方,以便以后可以停止它
            
            return $"File monitoring started:\n" +
                   $"- Path: {path}\n" +
                   $"- Change types: {changeTypes}\n" +
                   $"- Include subdirectories: {includeSubdirectories}";
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error monitoring file changes");
            return $"Error monitoring file changes: {ex.Message}";
        }
    }
    
    private static NotifyFilters ParseChangeTypes(string changeTypes)
    {
        var result = NotifyFilters.LastWrite;
        
        foreach (var type in changeTypes.Split(',').Select(t => t.Trim()))
        {
            result |= type.ToLower() switch
            {
                "created" => NotifyFilters.FileName | NotifyFilters.DirectoryName,
                "deleted" => NotifyFilters.FileName | NotifyFilters.DirectoryName,
                "changed" => NotifyFilters.LastWrite,
                "renamed" => NotifyFilters.FileName | NotifyFilters.DirectoryName,
                _ => NotifyFilters.LastWrite
            };
        }
        
        return result;
    }
}

这个示例展示了如何实现自动化任务工具,包括调度任务、运行命令和监控文件变更。这些工具可以帮助 AI 模型自动化各种系统任务。

结论

本文档提供了丰富的 .NET MCP 示例,涵盖了服务器端实现、客户端实现、LLM 集成和各种应用场景。这些示例可以帮助开发者快速上手 MCP,并将其应用到实际项目中。

MCP 的强大之处在于它提供了一种标准化的方式,使 AI 模型能够安全地访问和操作各种数据源和工具。通过实现 MCP 服务器和客户端,开发者可以创建功能丰富的 AI 应用,使 AI 能够执行各种任务,从简单的文本处理到复杂的自动化操作。

随着 MCP 生态系统的不断发展,我们可以期待更多的功能和改进。官方的 C# SDK 提供了一个稳定的基础,使 .NET 开发者能够轻松地实现 MCP 服务器和客户端。