
微软官方定义如下:
模型上下文协议(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}";
}
使用测试工具连接后,效果如下:
