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 包
dotnet add package ModelContextProtocol.AspNetCore --version 0.4.0-preview.3
第二步:配置 MCP 服务
在 Program.cs 中添加 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();
第三步:定义 MCP 工具
创建 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 中配置:
{
"McpAuth": {
"Enabled": true,
"ValidTokens": ["your-secret-token-here"]
}
}
开发环境可以禁用认证(appsettings.Development.json):
{
"McpAuth": {
"Enabled": false
}
}
第五步:运行和测试
dotnet run
应用启动后,可以访问:
Swagger UI: http://localhost:5000/swagger
WebApi: http://localhost:5000/weatherforecast
MCP 端点: http://localhost:5000/mcp
传输模式详解
HTTP 模式
适用于 Web 应用、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":{}
}
}'
Claude Desktop 配置:
编辑配置文件(Windows: %APPDATA%\Claude\claude_desktop_config.json):
{
"mcpServers": {
"weather-api": {
"url": "http://localhost:5000/mcp",
"headers": {
"Authorization": "Bearer your-secret-token-here"
}
}
}
}
Stdio 模式
适用于 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# 客户端
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?>()
);
JavaScript/Vue 客户端
<script setup>
import { ref } from 'vue';
const weather = ref('');
const MCP_URL = 'http://localhost:5000/mcp';
const TOKEN = 'your-secret-token-here';
const callMcp = async (method, params = {}) => {
const response = await fetch(MCP_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${TOKEN}`,
},
body: JSON.stringify({
jsonrpc: '2.0',
id: Date.now(),
method,
params,
}),
});
return response.json();
};
const getWeather = async () => {
const data = await callMcp('tools/call', {
name: 'GetWeatherForecast',
arguments: {},
});
weather.value = data.result.content[0].text;
};
</script>
MCP Tools 最佳实践
让 AI 更准确地使用你的工具是成功的关键。以下是经过实践验证的最佳实践。
核心原则
AI 通过以下信息决定是否使用你的工具:
工具名称 - 清晰、描述性
Description - 详细的功能说明
参数描述 - 明确的参数用途
使用场景 - 何时应该使用这个工具
1. 使用清晰的命名
// ❌ 不好 - 名称模糊
[McpServerTool]
public static string Get() { }
// ✅ 好 - 动词开头,描述清晰
[McpServerTool]
public static string GetWeatherForecast() { }
// ✅ 更好 - 包含具体信息
[McpServerTool]
public static string GetWeatherForecastForNextDays() { }
命名建议:
使用动词开头:Get, Search, Calculate, Compare, Analyze
包含操作对象:Weather, Temperature, Forecast
避免缩写和简称
使用 PascalCase
2. 编写详细的 Description(最重要!)
这是最关键的部分!AI 主要通过 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 trends
Examples of user queries:
- 'What's the weather forecast for the next 5 days?'
- 'Will it rain this week?'
- 'What's the temperature trend?'")]
Description 应该包含:
功能说明 - 工具做什么
使用场景 - 何时使用("Use this tool when...")
示例查询 - 用户可能的提问方式
支持的功能 - 特殊能力或限制
3. 详细的参数描述