内容
# MCP 学习项目
一个最小的端到端 **模型上下文协议** 示例,使用 **.NET 9** 编写,展示协议的双方:
- `SimpleMcpServer` — 一个基于 `ModelContextProtocol.AspNetCore` 的 ASP.NET Core MCP 服务器,公开工具、资源和提示。
- `SimpleMcpClient` — 一个基于 `ModelContextProtocol` 的控制台客户端,通过可流式 HTTP 连接,列出服务器宣传的每个功能,并调用每个功能。
## 仓库布局
```
MCP/
├── SimpleMcpServer/ # ASP.NET Core MCP 服务器(HTTP 传输)
│ ├── Program.cs # 服务器启动 + 服务器信息/说明
│ ├── appsettings.json # 日志配置
│ ├── Tools/
│ │ ├── CalculatorTools.cs # calc_add, calc_subtract, calc_multiply,
│ │ │ # calc_divide, calc_power, calc_sqrt
│ │ ├── TextTools.cs # text_echo, text_reverse, text_word_count,
│ │ │ # text_to_upper, text_to_lower
│ │ └── TimeTools.cs # time_now_utc, time_now_in_zone,
│ │ # time_diff_seconds
│ ├── Resources/
│ │ └── AppResources.cs # info://server (静态)
│ │ # greeting://{name}, echo://{message} (模板)
│ └── Prompts/
│ └── AppPrompts.cs # code_review, summarize, explain_like_im_five
│
└── SimpleMcpClient/ # 控制台 MCP 客户端
└── Program.cs # 连接,列出并调用每个功能
```
## 要求
- .NET 9 SDK
- Windows、macOS 或 Linux
NuGet 包(已引用):
| 项目 | 包 | 版本 |
|---|---|---|
| `SimpleMcpServer` | `ModelContextProtocol.AspNetCore` | `1.3.0` |
| `SimpleMcpClient` | `ModelContextProtocol` | `1.3.0` |
## 运行服务器
```powershell
cd SimpleMcpServer
dotnet run --launch-profile http
```
服务器监听 `http://localhost:5116/`。MCP 可流式 HTTP 端点由 `app.MapMcp()` 映射到根路径(`/`)。
服务器向客户端公开的身份:
```json
{
"name": "SimpleMcpServer",
"version": "1.0.0",
"instructions": "一个演示 MCP 服务器,提供计算器、文本和时间工具,静态和模板资源,以及可重用的提示模板。"
}
```
## 运行客户端
在第二个终端中,服务器已经运行时:
```powershell
cd SimpleMcpClient
dotnet run # 使用默认 http://localhost:5116/
dotnet run -- http://localhost:5116/ # 或传递自定义端点
```
预期输出(缩略):
```
已连接。服务器:SimpleMcpServer v1.0.0
== 工具 ==
calc_add 添加两个数字并返回总和。
...
-> calc_add(2, 3)
-> 5
-> text_reverse("Hello, MCP!")
-> !PCM ,olleH
-> calc_divide(10, 0) // 预期失败
(服务器报告工具错误)
-> 调用 'calc_divide' 时发生错误:无法除以零。
== 资源 ==
info://server 服务器的静态元数据(名称、版本、构建主机)。
== 资源模板 ==
greeting://{name} 返回给定名称的友好问候。
echo://{message} 将 URI 的消息段回显给调用者。
```
## 服务器功能
### 工具(14)
| 名称 | 描述 |
|---|---|
| `calc_add`, `calc_subtract`, `calc_multiply`, `calc_divide`, `calc_power`, `calc_sqrt` | 基本算术;`calc_divide` 和 `calc_sqrt` 验证输入并在参数错误时抛出 `McpException`。 |
| `text_echo`, `text_reverse`, `text_word_count`, `text_to_upper`, `text_to_lower` | 字符串实用程序。 |
| `time_now_utc`, `time_now_in_zone`, `time_diff_seconds` | 时间助手;`time_now_in_zone` 接受 IANA 或 Windows 时区 ID。 |
### 资源
- **静态**:`info://server` 返回 JSON 元数据(服务器名称、版本、主机、运行时)。
- **模板**:`greeting://{name}` 和 `echo://{message}` 返回从 URI 段计算的文本。
### 提示
- `code_review(code, language="csharp")` — 发出结构化的代码审查提示。
- `summarize(text, maxSentences=3)` — 发出总结提示。
- `explain_like_im_five(topic)` — 发出 ELI5 提示。
## 如何连接
### 服务器注册 (`SimpleMcpServer/Program.cs`)
```csharp
builder.Services
.AddMcpServer(options =>
{
options.ServerInfo = new Implementation { Name = "SimpleMcpServer", Version = "1.0.0" };
options.ServerInstructions = "...";
})
.WithHttpTransport()
.WithToolsFromAssembly()
.WithPromptsFromAssembly()
.WithResourcesFromAssembly();
app.MapMcp();
```
`WithToolsFromAssembly()` (以及提示/资源等效项)自动注册每个使用 `[McpServerToolType]` / `[McpServerPromptType]` / `[McpServerResourceType]` 标记的类。添加新文件是新增功能所需的唯一步骤;不需要手动注册。
### 工具编写模式
```csharp
[McpServerToolType]
public sealed class CalculatorTools
{
[McpServerTool(Name = "calc_add"), Description("添加两个数字。")]
public double Add(
[Description("第一个加数。")] double a,
[Description("第二个加数。")] double b) => a + b;
}
```
`[Description]` 属性流入客户端接收到的 JSON 模式 — 这就是让 LLM 选择正确的工具并正确填写其参数的原因。
### 客户端连接 (`SimpleMcpClient/Program.cs`)
```csharp
var transport = new HttpClientTransport(new HttpClientTransportOptions
{
Endpoint = new Uri("http://localhost:5116/"),
Name = "SimpleMcpClient"
// TransportMode 默认值为 AutoDetect:
// 尝试流式 HTTP,退回到 SSE
});
await using var client = await McpClient.CreateAsync(transport, new McpClientOptions
{
ClientInfo = new Implementation { Name = "SimpleMcpClient", Version = "1.0.0" }
});
var tools = await client.ListToolsAsync();
var result = await client.CallToolAsync("calc_add",
new Dictionary<string, object?> { ["a"] = 2, ["b"] = 3 });
```
## 从 MCP 感知工具使用服务器
### 游标 (`~/.cursor/mcp.json`)
```json
{
"mcpServers": {
"SimpleMcp": {
"type": "http",
"url": "http://localhost:5116/"
}
}
}
```
### 克劳德代码
```powershell
claude mcp add --transport http simple http://localhost:5116/
```
> **关于 HTTPS 的说明**:项目随附一个 `http` 启动配置文件,位于 `localhost:5116`。如果您切换到 `https://localhost:7297`,大多数 MCP 客户端将拒绝 ASP.NET 开发证书。或者继续使用 `http` 进行本地开发,或运行 `dotnet dev-certs https --trust` 并确保证书位于客户端信任存储中。
## 错误处理
工具因无效参数(例如除零、错误时区、格式错误的 timestamp)而引发 `McpException`。 `ModelContextProtocol.Core` 1.3.0 仅公开 `McpException` 的标准 `Exception` 构造函数,因此错误代码未显式指定 — 消息作为 `IsError=true` 工具结果到达客户端。
## 许可证
用于学习/演示目的。无保证。