| 前言 
 Model Context Protocol (MCP) 是一个标准化协议,让 AI 客户端(如 Claude、ChatGPT 等)能够通过统一的接口调用你的 API。本文将详细介绍如何在 ASP.NET Core WebApi 项目中集成 MCP 支持,实现 AI 与你的服务无缝对接。
 什么是 MCP?
 
 MCP(Model Context Protocol)是一个开放协议,旨在标准化 AI 应用与外部工具、数据源之间的通信方式。通过 MCP,你的 API 可以:
 
 核心特性
 被 AI 助手自动发现和调用
提供标准化的工具描述和参数定义
支持多种传输模式(HTTP、Stdio)
实现安全的认证和授权
 
 本项目实现了以下功能:
 
 快速开始
 ✅ 使用官方 ModelContextProtocol.AspNetCore SDK
✅ 通过 [McpServerTool] 特性快速定义工具
✅ 自动参数绑定和 JSON Schema 生成
✅ 支持 HTTP 和 Stdio 双传输模式
✅ 基于 Token 的认证和授权
✅ 与现有 WebApi 完美共存
 
 第一步:安装 NuGet 包
 
 第二步:配置 MCP 服务复制代码dotnet add package ModelContextProtocol.AspNetCore --version 0.4.0-preview.3
 在 Program.cs 中添加 MCP 配置:
 第三步:定义 MCP 工具复制代码using ModelContextProtocol.Server;var builder = WebApplication.CreateBuilder(args);builder.Services.AddControllers();// 添加 MCP 服务器(支持 HTTP 和 Stdio 双模式)builder.Services    .AddMcpServer(options =>    {        options.ServerInfo = new ModelContextProtocol.Protocol.Implementation        {            Name = "Weather API",            Version = "1.0.0"        };    })    .WithHttpTransport()           // HTTP 模式:用于 Web 客户端    .WithStdioServerTransport()    // Stdio 模式:用于 Kiro IDE 等本地工具    .WithToolsFromAssembly();var app = builder.Build();// 添加认证中间件(可选)app.UseMiddleware<McpAuthenticationMiddleware>();app.UseAuthorization();app.MapControllers();// 映射 MCP 端点app.MapMcp("/mcp");app.Run();
 创建 Tools/WeatherTools.cs:
 第四步:配置认证(可选)复制代码using System.ComponentModel;using ModelContextProtocol.Server;[McpServerToolType]public static class WeatherTools{    [McpServerTool]    [Description("Get weather forecast for the next 5 days")]    public static IEnumerable<WeatherForecast> GetWeatherForecast()    {        var rng = new Random();        return Enumerable.Range(1, 5).Select(index => new WeatherForecast        {            Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),            TemperatureC = rng.Next(-20, 55),            Summary = Summaries[rng.Next(Summaries.Length)]        }).ToArray();    }    [McpServerTool]    [Description("Get current weather for a specific city")]    public static WeatherForecast GetWeatherByCity(        [Description("The name of the city")] string city)    {        var rng = new Random();        return new WeatherForecast        {            Date = DateOnly.FromDateTime(DateTime.Now),            TemperatureC = rng.Next(-20, 55),            Summary = $"Weather in {city}: {Summaries[rng.Next(Summaries.Length)]}"        };    }    private static readonly string[] Summaries = new[]    {        "Freezing", "Bracing", "Chilly", "Cool", "Mild",        "Warm", "Balmy", "Hot", "Sweltering", "Scorching"    };}
 在 appsettings.json 中配置:
 开发环境可以禁用认证(appsettings.Development.json):复制代码{  "McpAuth": {    "Enabled": true,    "ValidTokens": ["your-secret-token-here"]  }}
第五步:运行和测试复制代码{  "McpAuth": {    "Enabled": false  }}
应用启动后,可以访问:
 
 传输模式详解
 Swagger UI: http://localhost:5000/swagger
WebApi: http://localhost:5000/weatherforecast
MCP 端点: http://localhost:5000/mcp
 
 HTTP 模式
 
 适用于 Web 应用、Claude Desktop、远程访问等场景。
 测试示例:
 Claude Desktop 配置:复制代码# 列出所有工具curl -X POST http://localhost:5000/mcp \  -H "Content-Type: application/json" \  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'# 调用工具curl -X POST http://localhost:5000/mcp \  -H "Authorization: Bearer your-secret-token-here" \  -H "Content-Type: application/json" \  -d '{    "jsonrpc":"2.0",    "id":2,    "method":"tools/call",    "params":{      "name":"GetWeatherForecast",      "arguments":{}    }  }'
编辑配置文件(Windows: %APPDATA%\Claude\claude_desktop_config.json):
 Stdio 模式复制代码{  "mcpServers": {    "weather-api": {      "url": "http://localhost:5000/mcp",      "headers": {        "Authorization": "Bearer your-secret-token-here"      }    }  }}
 适用于 Kiro IDE、本地命令行工具等场景,无需网络端口。
 Kiro IDE 配置:
 编辑 .kiro/settings/mcp.json:
 模式对比复制代码{  "mcpServers": {    "weather-api": {      "command": "dotnet",      "args": ["run", "--project", "path/to/NetCoreApiMcpDemo.csproj"],      "env": {        "ASPNETCORE_ENVIRONMENT": "Development"      }    }  }}
 特性HTTP 模式Stdio 模式传输方式HTTP POST标准输入/输出适用场景Web 应用、远程访问本地工具、IDE 集成认证HTTP Header环境变量/配置网络需要网络端口无需网络性能网络开销进程间通信,更快认证和授权
 
 实现认证中间件
 
 创建 Middleware/McpAuthenticationMiddleware.cs:
 安全最佳实践复制代码public class McpAuthenticationMiddleware{    private readonly RequestDelegate _next;    private readonly IConfiguration _configuration;    private readonly ILogger<McpAuthenticationMiddleware> _logger;    public McpAuthenticationMiddleware(        RequestDelegate next,        IConfiguration configuration,        ILogger<McpAuthenticationMiddleware> logger)    {        _next = next;        _configuration = configuration;        _logger = logger;    }    public async Task InvokeAsync(HttpContext context)    {        // 只对 MCP 端点进行认证        if (!context.Request.Path.StartsWithSegments("/mcp"))        {            await _next(context);            return;        }        // 检查是否启用认证        var authEnabled = _configuration.GetValue<bool>("McpAuth:Enabled");        if (!authEnabled)        {            await _next(context);            return;        }        // 验证 Token        var authHeader = context.Request.Headers["Authorization"].FirstOrDefault();        if (string.IsNullOrEmpty(authHeader) || !authHeader.StartsWith("Bearer "))        {            context.Response.StatusCode = 401;            await context.Response.WriteAsJsonAsync(new { error = "Unauthorized" });            return;        }        var token = authHeader.Substring("Bearer ".Length).Trim();        var validTokens = _configuration.GetSection("McpAuth:ValidTokens").Get<string[]>();        if (validTokens == null || !validTokens.Contains(token))        {            context.Response.StatusCode = 401;            await context.Response.WriteAsJsonAsync(new { error = "Invalid token" });            return;        }        await _next(context);    }}
 
 客户端集成示例
 使用强 Token:至少 32 字符的随机字符串
定期轮换:定期更换 Token
使用 HTTPS:生产环境必须使用 HTTPS
环境隔离:开发和生产使用不同的 Token
日志安全:不要在日志中记录完整 Token
 
 C# 客户端
 
 JavaScript/Vue 客户端复制代码using ModelContextProtocol;using ModelContextProtocol.Client;var transport = new HttpClientTransport(new HttpClientTransportOptions{    BaseUrl = new Uri("http://localhost:5000/mcp"),    Headers = new Dictionary<string, string>    {        ["Authorization"] = "Bearer your-secret-token-here"    }});var client = await McpClient.CreateAsync(transport);await client.InitializeAsync(new InitializeParams{    ProtocolVersion = "2025-06-18",    ClientInfo = new Implementation    {        Name = "MyApp",        Version = "1.0.0"    }});// 列出工具var tools = await client.ListToolsAsync();// 调用工具var result = await client.CallToolAsync(    "GetWeatherForecast",    new Dictionary<string, object?>());
 命名建议:复制代码[/code][size=5]MCP Tools 最佳实践[/size]让 AI 更准确地使用你的工具是成功的关键。以下是经过实践验证的最佳实践。[size=4]核心原则[/size]AI 通过以下信息决定是否使用你的工具:[list=1][*][b]工具名称[/b] - 清晰、描述性[*][b]Description[/b] - 详细的功能说明[*][b]参数描述[/b] - 明确的参数用途[*][b]使用场景[/b] - 何时应该使用这个工具[/list][size=4]1. 使用清晰的命名[/size][code]// ❌ 不好 - 名称模糊[McpServerTool]public static string Get() { }// ✅ 好 - 动词开头,描述清晰[McpServerTool]public static string GetWeatherForecast() { }// ✅ 更好 - 包含具体信息[McpServerTool]public static string GetWeatherForecastForNextDays() { }
 2. 编写详细的 Description(最重要!)
 使用动词开头:Get, Search, Calculate, Compare, Analyze
包含操作对象:Weather, Temperature, Forecast
避免缩写和简称
使用 PascalCase
 
 这是最关键的部分!AI 主要通过 Description 判断是否使用工具。
 Description 应该包含:复制代码// ❌ 不好 - 太简短[Description("Get weather")]// ⚠️ 一般 - 有基本信息但不够[Description("Get weather forecast for the next 5 days")]// ✅ 好 - 包含详细信息和使用场景[Description(@"Get detailed weather forecast for the next several days including temperature, weather conditions, and trends.Use this tool when users ask about:- Future weather (tomorrow, next week, upcoming days)- Weather predictions or forecasts- Planning activities based on weather- Temperature trendsExamples of user queries:- 'What's the weather forecast for the next 5 days?'- 'Will it rain this week?'- 'What's the temperature trend?'")]
 3. 详细的参数描述
 功能说明 - 工具做什么
使用场景 - 何时使用("Use this tool when...")
示例查询 - 用户可能的提问方式
支持的功能 - 特殊能力或限制
 
 参数描述应该包含:复制代码[McpServerTool]public static string GetWeatherByCity(    // ❌ 不好    [Description("city")] string city,    // ✅ 好    [Description("The name of the city in English or Chinese (e.g., 'Beijing', '北京', 'Shanghai', 'New York')")]    string city,    // ✅ 更好 - 包含默认值说明    [Description("Number of days to forecast (1-7 days). Default is 5 days if not specified.")]    int days = 5)
 4. 返回格式化、易读的结果
 参数的用途
支持的格式或值范围
示例值
默认值(如果有)
 
 [code]// ❌ 不好 - 返回原始对象public static WeatherForecast GetWeather(string city){    return new WeatherForecast { ... };}// ✅ 好 - 返回格式化的文本public static string GetWeather(string city){    var weather = GetWeatherData(city);    return $@"
 来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
 |