
微软官方定义如下:
模型上下文协议(MCP)是一种开放协议,旨在标准化 AI 应用与外部工具和数据源之间的集成。 通过使用 MCP,开发人员可以增强 AI 模型的功能,使他们能够生成更准确、更相关和上下文感知的响应。
整体设计如下(来自微软官方):
Server
项目引入Microsoft.Extensions.Hosting
和 ModelContextProtocol
。
前者用于构建主机环境
,后者用于提供MCP SDK
相关函数。
xml
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.0-rc.1.25451.107" />
<PackageReference Include="ModelContextProtocol" Version="0.4.0-preview.2" />
</ItemGroup>
stdio
通过命令行实现服务的创建,适用于同主机范围内,工具的直接调用。
引入服务MCP
服务并指定为stdio
方式。
cs
internal class Program
{
static async Task Main(string[] args)
{
// 创建主机构建器实例
var builder = Host.CreateApplicationBuilder(args);
// 引入控制台日志输出
builder.Logging.AddConsole(consoleLogOptions =>
{
// 配置所有日志输出到stderr
consoleLogOptions.LogToStandardErrorThreshold = LogLevel.Trace;
});
// 添加MCPServer服务
builder.Services
.AddMcpServer() // 注册Mcp服务
.WithStdioServerTransport() // 添加stdio传输配置用于接收控制台输入输出流
.WithToolsFromAssembly(); // 配置Mcp工具通过当前程序集获取
// 运行宿主应用
await builder.Build().RunAsync();
}
}
http
与sse
需要注意的是对于http
与sse
实际都是使用的AspNetCore
,对应需要引入Nuget
包ModelContextProtocol.AspNetCore
。
xml
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.0-rc.1.25451.107" />
<PackageReference Include="ModelContextProtocol" Version="0.4.0-preview.2" />
<PackageReference Include="ModelContextProtocol.AspNetCore" Version="0.4.0-preview.2" />
</ItemGroup>
对应Host
的构建器转换为WebApplication.CreateBuilder(args)
,而不是Host.CreateApplicationBuilder(args)
。
cs
static async Task Main(string[] args)
{
// 创建主机构建器实例
var builder = WebApplication.CreateBuilder(args);
// 引入控制台日志输出
builder.Logging.AddConsole(consoleLogOptions =>
{
// 配置所有日志输出到stderr
consoleLogOptions.LogToStandardErrorThreshold = LogLevel.Trace;
});
// 添加MCPServer服务
builder.Services
.AddMcpServer() // 注册Mcp服务
//.WithStdioServerTransport() // 添加stdio传输配置用于接收控制台输入输出流
.WithHttpTransport() // 添加http传输配置用于接收http请求输入输出
.WithToolsFromAssembly(); // 配置Mcp工具通过当前程序集获取
// 运行宿主应用
var app = builder.Build();
app.MapMcp(); // streamable http(http://[ip]:[port]/) 与 sse (http://[ip]:[port]/sse)
await app.RunAsync();
}
运行服务,本地访问地址为http://localhost:5000
。
bash
info: Microsoft.Hosting.Lifetime[14]
Now listening on: http://localhost:5000
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
Hosting environment: Production
info: Microsoft.Hosting.Lifetime[0]
连接类型转换为SSE
或者 Streamable http
,需要注意的是,选择SSE
时,以当前服务为例,连接时,访问地址默认应该为http://localhost:5000/sse
;选择Streamable HTTP
时,访问地址为http://localhost:5000/
。也可以按照自身需求进行调整。
SSE
:
Streamable HTTP
:
工具列表:
MCP
服务调试
npx
可以通过npx
执行@modelcontextprotocol/inspector
以及程序运行指令用于调试Server
端。
node
版本为15.x
及其以上。否则会出现AbortController is not defined
。
查看版本。
bash
node --version
切换目录到项目根目录,运行dotnet run --project <project_name>.csproj
;实际生产环境直接执行应用程序集,与控制台执行命令行无差异。
bash
>npx @modelcontextprotocol/inspector dotnet run --project <project_name>.csproj
Need to install the following packages:
@modelcontextprotocol/inspector@0.17.0
Ok to proceed? (y) y
或者。
bash
>npx -y @modelcontextprotocol/inspector dotnet run --project <project_name>.csproj
Need to install the following packages:
@modelcontextprotocol/inspector@0.17.0
也可以直接运行npx -y @modelcontextprotocol/inspector
,进入页面后再进行连接配置。
运行效果如下:
左侧点击连接,连接成功,右侧内容将显示出来,包括Tools
、Ping
等。
点击工具,获取工具列表,选择工具项,可对工具进行交互测试。

MCP
服务资源
作为MCP
服务器,暴露给模型上下文的资源,可以是文本,二进制文件,数据库记录,API 响应,实时系统数据,截图和图像以及更多;每个资源都由唯一的 URI(统一资源标识符)标识。
bash
[协议]://[主机]/[路径]
[protocol]://[host]/[path]
使用[McpServerResourceType]
作为资源类型,[McpServerResource]
配置资源。
创建一个资源生成器ResourceGenerator
,用于模拟资源,直接拷贝的官方案例代码。
cs
static class ResourceGenerator
{
private static readonly List<Resource> _resources = Enumerable.Range(1, 100).Select(i =>
{
var uri = $"test://template/resource/{i}";
if (i % 2 != 0)
{
return new Resource
{
Uri = uri,
Name = $"Resource {i}",
MimeType = "text/plain",
Description = $"Resource {i}: This is a plaintext resource"
};
}
else
{
var buffer = System.Text.Encoding.UTF8.GetBytes($"Resource {i}: This is a base64 blob");
return new Resource
{
Uri = uri,
Name = $"Resource {i}",
MimeType = "application/octet-stream",
Description = Convert.ToBase64String(buffer)
};
}
}).ToList();
public static IReadOnlyList<Resource> Resources => _resources;
}
创建服务资源MyResources
。
cs
/// <summary>
/// 自定义资源
/// </summary>
[McpServerResourceType]
internal class MyResources
{
[McpServerResource(UriTemplate = "test://direct/text/resource", Name = "定向文本资源", MimeType = "text/plain")]
//[Description("一个定向文本资源")]
public static string DirectTextResource() => "这是一个定向文本资源";
[McpServerResource(UriTemplate = "test://template/resource/{id}", Name = "通过id获取资源的模板资源")]
//[Description("通过id获取资源的资源模板")]
public static ResourceContents TemplateResource(RequestContext<ReadResourceRequestParams> requestContext, int id)
{
int index = id - 1;
if ((uint)index >= ResourceGenerator.Resources.Count)
{
throw new NotSupportedException($"Unknown resource: {requestContext.Params?.Uri}");
}
var resource = ResourceGenerator.Resources[index];
return resource.MimeType == "text/plain" ?
new TextResourceContents
{
Text = resource.Description!,
MimeType = resource.MimeType,
Uri = resource.Uri,
} :
new BlobResourceContents
{
Blob = resource.Description!,
MimeType = resource.MimeType,
Uri = resource.Uri,
};
}
}
程序集注册(自动)
使用WithResourcesFromAssembly()
进行自动注册。
bash
// 添加MCPServer服务
builder.Services
.AddMcpServer() // 注册Mcp服务
//.WithStdioServerTransport() // 添加stdio传输配置用于接收控制台输入输出流
.WithHttpTransport() // 添加http传输配置用于接收http请求输入输出
//---------------------------通过程序集加载资源------------------------
.WithResourcesFromAssembly()
//---------------------------通过程序集加载资源------------------------
手动配置
也可以通过WithResources
进行手动注册资源类型。
cs
// 添加MCPServer服务
builder.Services
.AddMcpServer() // 注册Mcp服务
//.WithStdioServerTransport() // 添加stdio传输配置用于接收控制台输入输出流
.WithHttpTransport() // 添加http传输配置用于接收http请求输入输出
//---------------------------通过程序集加载资源------------------------
//.WithResourcesFromAssembly()
//---------------------------通过程序集加载资源------------------------
//---------------------------通过手动配置工具------------------------
.WithTools<CommonTools>()
//---------------------------通过手动配置工具------------------------
//---------------------------手动配置提示词------------------------
.WithPrompts<MyPrompts>()
//---------------------------手动配置提示词------------------------
//---------------------------手动配置访问资源------------------------
.WithResources<MyResources>()
//---------------------------手动配置访问资源------------------------
运行效果如下:
定向资源。
模板资源。
服务提示词
使用[McpServerPromptType]
实现对服务端特定提示词类型的自定义声明,使用McpServerPrompt
用于定义对应的服务提示词。
cs
/// <summary>
/// 服务端提示词
/// </summary>
[McpServerPromptType]
internal class MyPrompts
{
[McpServerPrompt, Description("创建一个提示词获取天气模板提供给大模型.")]
public static ChatMessage Weather([Description("需要获取天气的地点")] string address) =>
new(ChatRole.User, $"获取:{address}当前天气");
}
程序集注册(自动)
在Program
的主函数中使用.WithPromptsFromAssembly()
实现程序集注册Prompt
。
cs
// 添加MCPServer服务
builder.Services
.AddMcpServer() // 注册Mcp服务
.WithHttpTransport() // 添加http传输配置用于接收http请求输入输出
//---------------------------通过程序集加载提示词------------------------
//.WithToolsFromAssembly() // 配置Mcp工具通过当前程序集获取
//---------------------------通过程序集加载提示词------------------------
.WithPromptsFromAssembly()
;
手动配置
也可以使用WithPrompts
实现提示词类型手动配置。
cs
// 添加MCPServer服务
builder.Services
.AddMcpServer() // 注册Mcp服务
//.WithStdioServerTransport() // 添加stdio传输配置用于接收控制台输入输出流
.WithHttpTransport() // 添加http传输配置用于接收http请求输入输出
//---------------------------通过程序集加载工具------------------------
//.WithToolsFromAssembly() // 配置Mcp工具通过当前程序集获取
//---------------------------通过程序集加载工具------------------------
//---------------------------通过程序集加载提示词------------------------
//.WithPromptsFromAssembly()
//---------------------------通过程序集加载提示词------------------------
//---------------------------通过手动配置工具------------------------
.WithTools<CommonTools>()
//---------------------------通过手动配置工具------------------------
//---------------------------手动配置提示词------------------------
.WithPrompts<MyPrompts>()
//---------------------------手动配置提示词------------------------
调测效果如下:
工具编写与注册
创建工具类,需要注意的是类顶部需要添加特性[McpServerToolType]
,工具函数添加[McpServerTool]
,工具函数描述尽可能描述清晰,.WithToolsFromAssembly()
简化了工具的注册和解析过程。
cs
/// <summary>
/// 通用命令工具
/// </summary>
[McpServerToolType]
internal class CommonTools
{
/// <summary>
/// Echo 输出工具
/// </summary>
/// <param name="message">客户端发送信息</param>
/// <returns></returns>
[McpServerTool, Description("Echo 输出工具,将客户端发送进行返回输出")]
public static string Echo(string message) => $"你好 {message}";
/// <summary>
/// 获取当前天气
/// </summary>
/// <returns></returns>
[McpServerTool, Description("获取当前天气,通过调用为客户端返回当前天气")]
internal static string GetCurrentWeather() => Random.Shared.NextDouble() > 0.5 ? "It's sunny" : "It's raining";
}
程序集注册(自动)
cs
// 添加MCPServer服务
builder.Services
.AddMcpServer() // 注册Mcp服务
.WithStdioServerTransport()
.WithToolsFromAssembly(); // 配置Mcp工具通过当前程序集获取
// 运行宿主应用
await builder.Build().RunAsync();
项目运行如下:
bash
info: ModelContextProtocol.Server.StdioServerTransport[857250842]
Server (stream) (EchoMcpServer) transport reading messages.
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
Hosting environment: Production
info: Microsoft.Hosting.Lifetime[0]
手动配置
手动配置通过WithTools<>()
配置[McpServerToolType]
实现类。
cs
static async Task Main(string[] args)
{
// 省略不变部分
// 添加MCPServer服务
builder.Services
.AddMcpServer() // 注册Mcp服务
//.WithStdioServerTransport() // 添加stdio传输配置用于接收控制台输入输出流
.WithHttpTransport() // 添加http传输配置用于接收http请求输入输出
//---------------------------通过程序集加载工具------------------------
//.WithToolsFromAssembly() // 配置Mcp工具通过当前程序集获取
//---------------------------通过程序集加载工具------------------------
//---------------------------通过手动配置工具------------------------
.WithTools<CommonTools>()
//---------------------------通过手动配置工具------------------------
;
// 运行宿主应用
var app = builder.Build();
app.MapMcp(); // streamable http(http://[ip]:[port]/) 与 sse (http://[ip]:[port]/sse)
await app.RunAsync();
}
依赖注入与请求参数
工具函数为静态函数,官方库也支持通过函数方式
实现服务的依赖注入,前提条件为服务已经注册;请求参数通过json/form方式进行接收,对应描述使用[Description]
,希望后续能支持注释。
Program
中注册服务。
cs
internal class Program
{
static async Task Main(string[] args)
{
// 创建主机构建器实例
var builder = WebApplication.CreateBuilder(args);
// 注册HttpClient服务(用于依赖注入)
builder.Services.AddHttpClient();
// 添加MCPServer服务
builder.Services
.AddMcpServer(); // 注册Mcp服务
// 省略不变内容
}
}
请求实体类RequestBody
属性如下:
cs
/// <summary>
/// 请求体
/// </summary>
[Description("请求体")]
internal class RequestBody
{
/// <summary>
/// 用户Id
/// </summary>
[Required]
[Description("用户Id,不允许值为0")]
public int UserId { get; set; }
/// <summary>
/// 用户名
/// </summary>
[MaxLength(10)]
[Description("用户名称")]
public string UserName { get; set; }
}
工具函数中进行依赖注入。
cs
[McpServerTool, Description("获取客户端信息,通过调用该工具返回当前服务与客户端信息")]
public static string GetClientInfo(McpServer mcpServer,
HttpClient httpClient,
[Description("这是请求下载对应请求参数")]
RequestBody requestBody,
[Description("这是一个用于动态下载的请求连接")]
string url) {
return $"{mcpServer.SessionId}:{url}";
}
使用测试工具连接后,效果如下: