内容
我的第一个MCP服务器
一个用C# / .NET 9编写的小型[模型上下文协议](https://modelcontextprotocol.io)(MCP)服务器公开了一组**工具**,AI客户端(Claude Code、Claude Desktop、VS Code等)可以通过**标准输入输出**调用。
工具包括简单的演示(`add`、`greet`)和一个完整的**基于SQLite的CRUD API**,用于`Book`表,
以便AI可以在本地数据库中存储和管理书籍。
---
## 功能特点
- **标准输入输出传输** — 服务器通过标准输入输出使用JSON-RPC,这是MCP客户端启动本地服务器的标准方式。
- **自动发现工具** — 任何标记为`[McpServerTool]`的方法都会自动注册。
- **SQLite持久化** — 书籍存储在`books.db`文件中,该文件在重启后仍然存在。
- **参数化SQL** — 所有查询都使用绑定参数(无SQL注入)。
---
## 工具列表
| 工具(AI看到的) | 参数 | 返回值 | 描述 |
|--------------------------|-----------|---------|-------------|
| `add` | `a: double`, `b: double` double` |数字。 |
|reet` | ` string` | `string` | 返回友好的问 |
| `get_books` — | `Book[]` | 列出所有书籍。 |
| `get_book` | `id: long` Book \| null` | 按ID获取一本书。 |
| `add_book` |: string`, `price: | `Book` | 插入一本书,并返回生成的`id`。 |
update_book` | `id: longname: string`, `price: double` | `string | 更新一本书;返回状态消息。 |
| `delete | `id: long | `string` | 删除一本书;返回状态消息。 |
> **命名说明:**方法名称小写并使用下划线分隔。C#方法`AddBook`被公开add_book`,
> `GetBooks`被公开为``,依此类推直接输入这些 — 你用自然AI,
> 它正确的工具。
### `Book
```jsonc
"id": 1 // long, 自动生成的主键
"name":Dune", // string "price": 19 // double
}
```
---
## 项目布局
```
MycpServer/
├─McpServer.sln
README.md
├─cp/
│ └─ mcp.json # 示例客户端stdio)
└─ MycpServer/
├─ Program 主机设置 + 数据库初始化 + 标准输入输出 ├─ Tools.cs 演示工具:add, greet
├─ Book.cs 模型
├─.cs # SQLite数据(架构 + CRUD)
BookTools.cs #存储库的MCP工具 ├─ Dockerfile
└─ MyFirstMcpServer.csproj
```
---
## 先
- [.NET SDK.0](https://dotnet/download) 或更高版本## 构建和运行bash
cd MyFirstMcpServer
dotnet build
dotnet run-launch-profile
```
服务器从**标准输入**读取PC,并将响应写入输出**。
它不打算在终端中交互使用 — MCP客户端为您启动它(请参见下文)。
启动时,它会在构建的程序集旁边创建`books.db`,如果它不存在。
> **为什么使用 `--no-launch-profile`?** 使用标准输入输出传输,**标准输出必须仅包含JSON-RPC消息**。
> 普通 run`会在标准输出`Using launch settings`横幅,这协议流。
>-launch-profile`。(本项目中的所有记录都已路由到**输出**,原因相同---
## 连接到客户端 Claude Code(CLI)服务器:
```bash
claude mcp add myFirstMcp --transport stdio -- dotnet run --no-la --project "D\practice\MyFirstServer\MyFirstMcpMyFirstMcpServer"
```
验证连接:
```bash
claude mcp list
# myFirstM dotnet run --no-launch-profile --project ... - ✓
```
然后**用自然语言与Claude交互** — 您不需要自己输入工具名称```bash
claude # 交互式
>本书,名为Dune19.99
> 列书籍
> 修改书籍129.99
书籍1
```
或交互式:
```claude -p "添加一本书,名为The Hobbit12.50,然后列出所有书籍"
```
**跳提示**,在`~/.claude/settings.json`中允许服务器:
```json "permissions": {
"allow": ["mcp__myFirstMcp"]
```
`mcp__myFirstMcp`(之后没有工具名称)允许来自此服务器的所有工具。编辑设置后重启Claude。
### 其他客户端(,Claude Desktop等将客户端的MCP配置指向项目。参见[connect/mcp.json](connectMcp/mcp.json):
```{
"serversmyFirstM {
"type":",
"command": "dotnet",
"args": [
"run", "--no-launch-profile",
"--project", "D:\\workspace\\practice\\MyFirstMcpServer\\MycpServer\\MyFirstMcpServer.csproj"
}
}
}
```
手动测试协议
通过管道传输JSON-R驱动服务器(对于调试很有保持标准输入输出打开足够长的时间,以便它响应```bash
cd MycpServer
{
jsonrpc":"2.01,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"t","version":"1"}}}'
echo '{"jsonrpc":"2.0","method":"notifications/initialized"}'
echo '{"jsonrpc":"2.0","id":2,"method":"","params":{"name_book","arguments":{"name":"Dune","price.99}}}'
echo '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"get_books","arguments":{}}}'
sleep 5
} | dotnet run --no-launch-profile 2>/dev/null
```
您应该在标准输出上看到干净的JSON-RPC响应 — 新增的书籍,然后是完整的列表。
---
## 添加您自己的工具
1. 在标记为`[McpServerToolType]`的类中添加一个`public static`方法(例如`Tools.cs`或`BookTools.cs`)。
2. 将方法标记为`[McpServerTool]`并给予一个`[Description]`。
3. 用`[Description]`描述每个参数 — AI使用这些来填充参数。
```csharp
[McpServerTool, Description("统计存储的书籍数量。")]
public static int CountBooks() => BookRepository.GetAll().Count;
```
重新构建后,工具将在下次启动时自动发现 — 无需注册。
---
## 数据库
- **文件:** `books.db`,在构建的程序集旁边创建(`bin/Debug/net9.0/books.db`)。
- **重置:** 删除文件;它将在下一次运行时重新创建为空。
- **架构:
CREATE TABLE EXISTS Book (
Id AUTOINCREMENT,
Name TEXT NOT Price REAL NOT );
```
技术栈
- .9 (`net9.- [`ModelContextProtocol://www.nuget.org/packages/ModelContextProtocol) 4.0
Microsoft.Data.Sqlite`](https://www.nuget.org/packages/Microsoft.Data.Sqlite)
- `.Hosting`