news 2026/6/10 19:33:25

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ASP.NET Core WebApi 集成 MCP 协议完全指南

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. 详细的参数描述

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/9 19:52:30

Yii2-Swoole 快速入门

Yii2-Swoole 快速入门让你的 Yii2 应用性能提升 10-100 倍&#xff01;本教程将教你如何在 yii2-app-basic 中快速集成 yii2-swoole。为什么使用 yii2-swoole&#xff1f;⚡ 比 PHP-FPM 快 10-100 倍&#x1f504; 数据库和 Redis 连接池自动管理&#x1f680; 协程并发处理请求…

作者头像 李华
网站建设 2026/6/9 15:36:49

计算机Java毕设实战-基于springboot的养宠物指南服务平台系统的设计与实现基于Java SpringBoot的宠物社区互动平台的设计与【完整源码+LW+部署说明+演示视频,全bao一条龙等】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/6/10 12:24:09

Java毕设选题推荐:基于SpringBoot的演唱会售票系统设计与实现基于springboot的演唱会购票系统的设计与实现【附源码、mysql、文档、调试+代码讲解+全bao等】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/6/10 14:03:42

零极点对消:原理、作用与风险

这是一个自动控制原理中的核心概念。我们来详细解释一下零极点对消的原理、作用以及需要注意的关键点。一、原理从数学本质上讲&#xff0c;零极点对消就是在系统传递函数的分子和分母中&#xff0c;消除具有相同数值的零点和极点。传递函数&#xff1a;线性时不变系统通常用传…

作者头像 李华
网站建设 2026/6/9 16:41:59

计算机Java毕设实战-基于springboot6+vue的校园智能物流包裹领取寄送管理系统的设计与实现【完整源码+LW+部署说明+演示视频,全bao一条龙等】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/6/10 6:52:05

22、oracle导入数据,sys_user表数据错误

项目场景&#xff1a; oracle导入数据&#xff0c;sys_user表数据错误问题描述原因分析&#xff1a; 熊小二 使用oracle客户端工具&#xff0c;导入数据&#xff0c;导入成功之后&#xff0c;发现有几张表的数据错误&#xff0c;当时也纳闷&#xff0c;为什么界面的菜单显示不对…

作者头像 李华