找回密码
 立即注册
首页 业界区 业界 ASP.NET Core WebApi 集成 MCP 协议完全指南

ASP.NET Core WebApi 集成 MCP 协议完全指南

坠矜 3 天前
前言

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 包
  1. dotnet add package ModelContextProtocol.AspNetCore --version 0.4.0-preview.3
复制代码
第二步:配置 MCP 服务

在 Program.cs 中添加 MCP 配置:
  1. using ModelContextProtocol.Server;
  2. var builder = WebApplication.CreateBuilder(args);
  3. builder.Services.AddControllers();
  4. // 添加 MCP 服务器(支持 HTTP 和 Stdio 双模式)
  5. builder.Services
  6.     .AddMcpServer(options =>
  7.     {
  8.         options.ServerInfo = new ModelContextProtocol.Protocol.Implementation
  9.         {
  10.             Name = "Weather API",
  11.             Version = "1.0.0"
  12.         };
  13.     })
  14.     .WithHttpTransport()           // HTTP 模式:用于 Web 客户端
  15.     .WithStdioServerTransport()    // Stdio 模式:用于 Kiro IDE 等本地工具
  16.     .WithToolsFromAssembly();
  17. var app = builder.Build();
  18. // 添加认证中间件(可选)
  19. app.UseMiddleware<McpAuthenticationMiddleware>();
  20. app.UseAuthorization();
  21. app.MapControllers();
  22. // 映射 MCP 端点
  23. app.MapMcp("/mcp");
  24. app.Run();
复制代码
第三步:定义 MCP 工具

创建 Tools/WeatherTools.cs:
  1. using System.ComponentModel;
  2. using ModelContextProtocol.Server;
  3. [McpServerToolType]
  4. public static class WeatherTools
  5. {
  6.     [McpServerTool]
  7.     [Description("Get weather forecast for the next 5 days")]
  8.     public static IEnumerable<WeatherForecast> GetWeatherForecast()
  9.     {
  10.         var rng = new Random();
  11.         return Enumerable.Range(1, 5).Select(index => new WeatherForecast
  12.         {
  13.             Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
  14.             TemperatureC = rng.Next(-20, 55),
  15.             Summary = Summaries[rng.Next(Summaries.Length)]
  16.         }).ToArray();
  17.     }
  18.     [McpServerTool]
  19.     [Description("Get current weather for a specific city")]
  20.     public static WeatherForecast GetWeatherByCity(
  21.         [Description("The name of the city")] string city)
  22.     {
  23.         var rng = new Random();
  24.         return new WeatherForecast
  25.         {
  26.             Date = DateOnly.FromDateTime(DateTime.Now),
  27.             TemperatureC = rng.Next(-20, 55),
  28.             Summary = $"Weather in {city}: {Summaries[rng.Next(Summaries.Length)]}"
  29.         };
  30.     }
  31.     private static readonly string[] Summaries = new[]
  32.     {
  33.         "Freezing", "Bracing", "Chilly", "Cool", "Mild",
  34.         "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
  35.     };
  36. }
复制代码
第四步:配置认证(可选)

在 appsettings.json 中配置:
  1. {
  2.   "McpAuth": {
  3.     "Enabled": true,
  4.     "ValidTokens": ["your-secret-token-here"]
  5.   }
  6. }
复制代码
开发环境可以禁用认证(appsettings.Development.json):
  1. {
  2.   "McpAuth": {
  3.     "Enabled": false
  4.   }
  5. }
复制代码
第五步:运行和测试
  1. dotnet run
复制代码
应用启动后,可以访问:

  • Swagger UI: http://localhost:5000/swagger
  • WebApi: http://localhost:5000/weatherforecast
  • MCP 端点: http://localhost:5000/mcp
传输模式详解

HTTP 模式

适用于 Web 应用、Claude Desktop、远程访问等场景。
测试示例
  1. # 列出所有工具
  2. curl -X POST http://localhost:5000/mcp \
  3.   -H "Content-Type: application/json" \
  4.   -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
  5. # 调用工具
  6. curl -X POST http://localhost:5000/mcp \
  7.   -H "Authorization: Bearer your-secret-token-here" \
  8.   -H "Content-Type: application/json" \
  9.   -d '{
  10.     "jsonrpc":"2.0",
  11.     "id":2,
  12.     "method":"tools/call",
  13.     "params":{
  14.       "name":"GetWeatherForecast",
  15.       "arguments":{}
  16.     }
  17.   }'
复制代码
Claude Desktop 配置
编辑配置文件(Windows: %APPDATA%\Claude\claude_desktop_config.json):
  1. {
  2.   "mcpServers": {
  3.     "weather-api": {
  4.       "url": "http://localhost:5000/mcp",
  5.       "headers": {
  6.         "Authorization": "Bearer your-secret-token-here"
  7.       }
  8.     }
  9.   }
  10. }
复制代码
Stdio 模式

适用于 Kiro IDE、本地命令行工具等场景,无需网络端口。
Kiro IDE 配置
编辑 .kiro/settings/mcp.json:
  1. {
  2.   "mcpServers": {
  3.     "weather-api": {
  4.       "command": "dotnet",
  5.       "args": ["run", "--project", "path/to/NetCoreApiMcpDemo.csproj"],
  6.       "env": {
  7.         "ASPNETCORE_ENVIRONMENT": "Development"
  8.       }
  9.     }
  10.   }
  11. }
复制代码
模式对比

特性HTTP 模式Stdio 模式传输方式HTTP POST标准输入/输出适用场景Web 应用、远程访问本地工具、IDE 集成认证HTTP Header环境变量/配置网络需要网络端口无需网络性能网络开销进程间通信,更快认证和授权

实现认证中间件

创建 Middleware/McpAuthenticationMiddleware.cs:
  1. public class McpAuthenticationMiddleware
  2. {
  3.     private readonly RequestDelegate _next;
  4.     private readonly IConfiguration _configuration;
  5.     private readonly ILogger<McpAuthenticationMiddleware> _logger;
  6.     public McpAuthenticationMiddleware(
  7.         RequestDelegate next,
  8.         IConfiguration configuration,
  9.         ILogger<McpAuthenticationMiddleware> logger)
  10.     {
  11.         _next = next;
  12.         _configuration = configuration;
  13.         _logger = logger;
  14.     }
  15.     public async Task InvokeAsync(HttpContext context)
  16.     {
  17.         // 只对 MCP 端点进行认证
  18.         if (!context.Request.Path.StartsWithSegments("/mcp"))
  19.         {
  20.             await _next(context);
  21.             return;
  22.         }
  23.         // 检查是否启用认证
  24.         var authEnabled = _configuration.GetValue<bool>("McpAuth:Enabled");
  25.         if (!authEnabled)
  26.         {
  27.             await _next(context);
  28.             return;
  29.         }
  30.         // 验证 Token
  31.         var authHeader = context.Request.Headers["Authorization"].FirstOrDefault();
  32.         if (string.IsNullOrEmpty(authHeader) || !authHeader.StartsWith("Bearer "))
  33.         {
  34.             context.Response.StatusCode = 401;
  35.             await context.Response.WriteAsJsonAsync(new { error = "Unauthorized" });
  36.             return;
  37.         }
  38.         var token = authHeader.Substring("Bearer ".Length).Trim();
  39.         var validTokens = _configuration.GetSection("McpAuth:ValidTokens").Get<string[]>();
  40.         if (validTokens == null || !validTokens.Contains(token))
  41.         {
  42.             context.Response.StatusCode = 401;
  43.             await context.Response.WriteAsJsonAsync(new { error = "Invalid token" });
  44.             return;
  45.         }
  46.         await _next(context);
  47.     }
  48. }
复制代码
安全最佳实践


  • 使用强 Token:至少 32 字符的随机字符串
  • 定期轮换:定期更换 Token
  • 使用 HTTPS:生产环境必须使用 HTTPS
  • 环境隔离:开发和生产使用不同的 Token
  • 日志安全:不要在日志中记录完整 Token
客户端集成示例

C# 客户端
  1. using ModelContextProtocol;
  2. using ModelContextProtocol.Client;
  3. var transport = new HttpClientTransport(new HttpClientTransportOptions
  4. {
  5.     BaseUrl = new Uri("http://localhost:5000/mcp"),
  6.     Headers = new Dictionary<string, string>
  7.     {
  8.         ["Authorization"] = "Bearer your-secret-token-here"
  9.     }
  10. });
  11. var client = await McpClient.CreateAsync(transport);
  12. await client.InitializeAsync(new InitializeParams
  13. {
  14.     ProtocolVersion = "2025-06-18",
  15.     ClientInfo = new Implementation
  16.     {
  17.         Name = "MyApp",
  18.         Version = "1.0.0"
  19.     }
  20. });
  21. // 列出工具
  22. var tools = await client.ListToolsAsync();
  23. // 调用工具
  24. var result = await client.CallToolAsync(
  25.     "GetWeatherForecast",
  26.     new Dictionary<string, object?>()
  27. );
复制代码
JavaScript/Vue 客户端
  1. [/code][size=5]MCP Tools 最佳实践[/size]
  2. 让 AI 更准确地使用你的工具是成功的关键。以下是经过实践验证的最佳实践。
  3. [size=4]核心原则[/size]
  4. AI 通过以下信息决定是否使用你的工具:
  5. [list=1]
  6. [*][b]工具名称[/b] - 清晰、描述性
  7. [*][b]Description[/b] - 详细的功能说明
  8. [*][b]参数描述[/b] - 明确的参数用途
  9. [*][b]使用场景[/b] - 何时应该使用这个工具
  10. [/list][size=4]1. 使用清晰的命名[/size]
  11. [code]// ❌ 不好 - 名称模糊
  12. [McpServerTool]
  13. public static string Get() { }
  14. // ✅ 好 - 动词开头,描述清晰
  15. [McpServerTool]
  16. public static string GetWeatherForecast() { }
  17. // ✅ 更好 - 包含具体信息
  18. [McpServerTool]
  19. public static string GetWeatherForecastForNextDays() { }
复制代码
命名建议:

  • 使用动词开头:Get, Search, Calculate, Compare, Analyze
  • 包含操作对象:Weather, Temperature, Forecast
  • 避免缩写和简称
  • 使用 PascalCase
2. 编写详细的 Description(最重要!)

这是最关键的部分!AI 主要通过 Description 判断是否使用工具。
  1. // ❌ 不好 - 太简短
  2. [Description("Get weather")]
  3. // ⚠️ 一般 - 有基本信息但不够
  4. [Description("Get weather forecast for the next 5 days")]
  5. // ✅ 好 - 包含详细信息和使用场景
  6. [Description(@"Get detailed weather forecast for the next several days including temperature, weather conditions, and trends.
  7. Use this tool when users ask about:
  8. - Future weather (tomorrow, next week, upcoming days)
  9. - Weather predictions or forecasts
  10. - Planning activities based on weather
  11. - Temperature trends
  12. Examples of user queries:
  13. - 'What's the weather forecast for the next 5 days?'
  14. - 'Will it rain this week?'
  15. - 'What's the temperature trend?'")]
复制代码
Description 应该包含:

  • 功能说明 - 工具做什么
  • 使用场景 - 何时使用("Use this tool when...")
  • 示例查询 - 用户可能的提问方式
  • 支持的功能 - 特殊能力或限制
3. 详细的参数描述
  1. [McpServerTool]
  2. public static string GetWeatherByCity(
  3.     // ❌ 不好
  4.     [Description("city")] string city,
  5.     // ✅ 好
  6.     [Description("The name of the city in English or Chinese (e.g., 'Beijing', '北京', 'Shanghai', 'New York')")]
  7.     string city,
  8.     // ✅ 更好 - 包含默认值说明
  9.     [Description("Number of days to forecast (1-7 days). Default is 5 days if not specified.")]
  10.     int days = 5
  11. )
复制代码
参数描述应该包含:

  • 参数的用途
  • 支持的格式或值范围
  • 示例值
  • 默认值(如果有)
4. 返回格式化、易读的结果

[code]// ❌ 不好 - 返回原始对象public static WeatherForecast GetWeather(string city){    return new WeatherForecast { ... };}// ✅ 好 - 返回格式化的文本public static string GetWeather(string city){    var weather = GetWeatherData(city);    return $@"
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

8 小时前

举报

过来提前占个楼
您需要登录后才可以回帖 登录 | 立即注册