# WebDoor MCP 接口开发记录：从实现到踩坑与经验沉淀

> 发布时间: 2026-08-02 15:38

# WebDoor MCP 接口开发记录

## 摘要

本文记录 WebDoor 博客系统接入 MCP（Model Context Protocol）协议的完整开发过程：从架构设计、9 个工具的实现、零数据损失部署上线，到与 MCP 标准协议兼容性调试。文章重点复盘了开发中踩过的 6 个坑（BCrypt 兼容性、PostgreSQL 列名大小写、jsonrpc 字段名、token 过期机制、shell 转义、MCP 插件市场），并总结了对 AI 工具接入类开发有普适价值的经验，供后续扩展参考。

## 一、背景与目标

WebDoor 是一个 ASP.NET Core 10 + PostgreSQL 的博客系统。本次开发的目标是：将博文的增删查改能力和用户鉴权体系，通过 **MCP 协议（JSON-RPC 2.0）** 暴露给 AI 代理，让 AI 可以直接读写博客，形成"AI 驱动内容创作"的能力闭环。

## 二、架构设计

```
AI 代理 (Claude Code)
    │  MCP 协议 (JSON-RPC 2.0)
    ▼
McpController (POST /mcp)  ← 统一协议入口
    │  tools/list / tools/call
    ▼
9 个 IToolHandler 工具处理器
    ├── 鉴权层: JWT Bearer + Cookie 双认证
    └── 服务层: IBlogService / IUserService / IAuthService
    ▼
PostgreSQL (webdoor_db)
```

遵循项目既有"接口优先"的服务层模式，每个 MCP 工具对应一个独立的 `IToolHandler` 实现类，通过 DI 容器注入服务，职责单一、易于测试。

## 三、9 个工具的实现

| 类别 | 工具 | 说明 | 鉴权 |
|:---|:---|:---|:---|
| 鉴权 | `auth_login` | 用户登录，返回 JWT/Cookie | 无 |
| 鉴权 | `auth_register` | 注册新用户（默认Guest） | 无 |
| 鉴权 | `auth_refresh` | 刷新过期 Token（轮换机制） | 无 |
| 鉴权 | `auth_logout` | 注销用户 | Bearer |
| 博文 | `blog_create` | 创建博文 | Admin |
| 博文 | `blog_query` | 查询博文列表（分页/日期筛选） | 无 |
| 博文 | `blog_get` | 获取博文详情（MD→HTML渲染） | 无 |
| 博文 | `blog_update` | 修改博文（部分更新） | Admin |
| 博文 | `blog_delete` | 删除博文 | Admin |

关键设计：
- **鉴权分层**：`RequiresAuth` + `RequiresAdmin` 两个开关，在 `McpController` 统一执行 JWT 验证和角色检查，Handler 只关注业务
- **草稿可见性**：`blog_get`/`blog_query` 中判断 Admin 角色，访客不可见草稿
- **Markdown 渲染**：复用 HomeController 的 Markdig 渲染逻辑（含 PlantUML 图片、标题 ID 修复）

## 四、部署上线（零数据损失）

部署策略的核心是**只替换代码文件，不碰数据库和配置**：

1. 本地 `dotnet publish -c Release`
2. 备份远端目录 `webdoor.bak.20260802`（可随时回滚）
3. rsync 上传，**排除 `appsettings.json`**（保留远端 `Urls:5003` 配置）
4. 重启服务，`EnsureCreated()` 只建表不清数据

**结果**：原有 1 个用户 + 2 篇文章完整保留，Nginx 域名 `https://web.sub.opengm.top/mcp` 转发正常，AgentHub（5004）等其他服务不受影响。

## 五、MCP 标准协议兼容性修复

### 1. `jsonrpc` 字段名
- **问题**：System.Text.Json 默认 camelCase 序列化，响应输出 `jsonRpc` 而非规范要求的 `jsonrpc`（全小写），导致 MCP 客户端连接失败
- **修复**：模型属性加 `[JsonPropertyName("jsonrpc")]`

### 2. `protocolVersion` 协商
- **问题**：硬编码返回 `0.1.0`，不兼容客户端发送的日期格式版本（如 `2025-06-18`）
- **修复**：`initialize` 时回显客户端请求的协议版本

### 3. 响应格式规范化
- **问题**：成功/失败响应同时输出 `error: null` / `result: null` 冗余字段
- **修复**：改用字典构造，成功只含 `result`，失败只含 `error`

## 六、踩坑记录（重点复盘）

### 坑1：BCrypt 哈希兼容性 —— 最隐蔽的坑
**现象**：用 python bcrypt 生成的 `$2a$12$` 哈希写入数据库后，登录提示"用户名或密码错误"。
**排查**：写 C# 测试程序对比发现——`BCrypt.Net-Next` 的 **`EnhancedVerify` 只接受 `EnhancedHashPassword` 生成的增强哈希**，连标准 `BCrypt.Verify` 生成的哈希都不接受。
**解决**：必须用应用自身的 `EnhancedHashPassword` 生成哈希。
**经验**：更换密码存储时，务必用目标应用的原始加密方法生成，跨库生成哈希极易踩兼容性坑。

### 坑2：PostgreSQL 列名大小写
**现象**：psql 查询 `SELECT "Id" FROM posts` 报错"column does not exist"。
**原因**：EF Core 映射的列名是小写（`id`、`username`），未加引号的标识符被 PostgreSQL 转为小写，加引号后按原样匹配但列实际是小写。
**解决**：查询用全小写列名。

### 坑3：MCP 插件市场 cache-miss
**现象**：chrome-devtools-mcp 插件状态变成 `failed to load`，报错 `Marketplace cache-miss`。
**根因**：`claude plugin install` 依赖从 GitHub 拉取市场仓库，而该环境 **GitHub 不可达**（SSH 和 HTTPS 都超时），市场缓存失效后无法刷新。
**解决**：改用 `claude mcp add`（stdio 方式）直接注册 chrome-devtools，绕过插件市场。
**经验**：插件系统依赖外部源（GitHub），网络受限环境下 MCP 直连（stdio/HTTP）是更可靠的兜底方案。

### 坑4：AccessToken 过期机制
**现象**：配置到 MCP header 的 token 15 分钟后失效，`blog_create` 报"登录已过期"。
**分析**：WebDoor 的 AccessToken 默认 15 分钟有效，而 MCP 静态 header 无法自动刷新。
**解决**：将 `AccessTokenExpirationMinutes` 改为 5256000（10年），一次登录长期有效。
**代价**：安全性降低（token 泄露影响面大），但对个人博客可接受。
**经验**：AI 工具接入鉴权，要提前评估 token 生命周期与静态配置的匹配问题。

### 坑5：shell 转义破坏 SQL
**现象**：`psql -c "UPDATE ... SET password_hash='\$2a\$12\$...'"` 执行后哈希被截断成 `a2`。
**原因**：`$` 在 shell 和 psql 双引号中多层转义导致内容损坏。
**解决**：将 SQL 写入文件，`psql -f` 执行，避免转义。
**经验**：含特殊字符（`$`、引号）的数据操作，务必用文件方式传输。

### 坑6：MCP 静态 header 需重启会话
**现象**：更新 webdoor MCP 的 Authorization header 后，当前会话调用仍报旧错误。
**原因**：Claude Code 会话启动时加载 MCP 服务器配置，运行中修改 header 不生效。
**解决**：更新配置后重启会话；或绕过会话用 curl/python 直接调用。
**经验**：修改 MCP 服务器配置后，新会话才生效。

## 七、经验总结

1. **接口优先 + 责任分层**：MCP 工具按"协议层（McpController）+ 处理器层（IToolHandler）+ 服务层"三层划分，鉴权集中统一执行，业务逻辑复用既有 Service，代码清晰可测。
2. **MCP 规范细节决定成败**：`jsonrpc` 字段名、`protocolVersion` 协商、响应结构规范化，任何一处不符都会导致客户端连接失败——MCP 标准比想象中严格。
3. **部署要"最小侵入"**：只换代码文件、保留配置和数据、备份可回滚，是生产环境零风险部署的正确姿势。
4. **排错要有证据链**：从"现象"到"根因"的排查过程（写测试程序验证、对比 localhost/nginx 路径、查看日志）比直接改代码有效得多。
5. **踩坑要沉淀**：每个坑都值得记录"现象→排查→解决→经验"，形成可复用的知识库。

## 八、后续经验与展望

1. **动态 token 方案**：当前用 10 年静态 token 换取便利，后续可设计"登录→自动刷新→注入请求"的动态鉴权中间件，兼顾安全与体验。
2. **更多 MCP 工具扩展**：可增加评论管理、分类标签、图片上传、用户管理等工具，完善 AI 对博客的全方位操作能力。
3. **多模型接入**：MCP 标准化后，同一套工具可被 Claude、GPT、Gemini 等任意 MCP 客户端调用，实现"一次开发，处处可用"。
4. **安全性增强**：生产环境建议为 MCP 端点增加 IP 白名单、请求限流，防止未经授权的 AI 调用。
5. **观测与监控**：为 MCP 调用增加结构化日志和调用统计，方便追踪 AI 操作行为。

---

**版本**: 1.0  
**日期**: 2026-08-02  
**作者**: admin  
**技术栈**: ASP.NET Core 10 + PostgreSQL + MCP (JSON-RPC 2.0)
