跳到正文
Joeplover
后端开发·2026-06-26·约 4 分钟阅读

博客 MCP Server 开发记录

为本博客构建 FastMCP 服务器,让 AI 工具能直接读写博客数据。全程记录从零开发到 15 个工具 + 4 个资源的完整过程。

代码编辑器截图

博客 MCP Server 开发全记录

为什么需要 MCP Server

我的博客基于 Next.js + Prisma + SQLite,平时更新文章需要通过本地 Dev Server 的 Admin 后台手动编辑。作为一名 AI 重度使用者,我希望 AI 助手能直接读写博客数据库,实现"用自然语言管理博客"的效果。MCP(Model Context Protocol)正好提供这种标准化接口——AI 客户端通过 MCP 协议与数据库交互,而不需要理解底层 SQL。

技术选型

选择了 FastMCP 这个 Python 框架。它原生支持 stdio 传输模式,几行代码就能暴露一个工具。对比直接用 Flask/FastAPI 做 REST API 的好处:

  • 标准协议:任何支持 MCP 的客户端(Cursor、Claude Desktop、自定义 CLI)都能接入
  • 工具自描述:参数类型、描述自动生成,客户端不需要额外文档
  • 状态管理:无需手动处理 HTTP Session,MCP 协议层面的连接生命周期管理

实现细节

数据库直连

MCP Server 直接操作博客的 SQLite 数据库文件(prisma/dev.db),不经过 Prisma ORM。原因是:

  1. Prisma 依赖 Node.js 运行时,Python 端调用需要额外中间层
  2. 对于查询密集的操作,原生 SQL 比 ORM 更可控
  3. SQLite 单文件特性让直连非常简单——只需读取 .env 中的 DATABASE_URL

需要注意的一个坑:Prisma Schema 中定义的字段是 camelCase(如 publishedAt),而 SQLite 存储时保留了这个命名。查询时直接写 SELECT publishedAt FROM Post 即可,不需要转换。

认证体系

复用博客现有的认证方案:

# 密码验证使用 bcrypt
if bcrypt.checkpw(password.encode(), user['password'].encode()):
    # 生成 HMAC-SHA256 签名 token
    payload = json.dumps({"userId": user['id'], "exp": time() + 7*86400})
    token = base64.b64encode(payload.encode()) + b'.' +             hmac.new(SECRET.encode(), payload.encode(), 'sha256').hexdigest().encode()

token 有效期 7 天,后续请求通过 blog_verify_session 验证。这个实现与博客 Next.js 端完全一致,确保 Admin 鉴权互通。

工具清单

共实现了 16 个工具,覆盖博客核心功能:

工具功能
blog_list_posts分页查询已发布文章
blog_get_post按 slug 获取单篇文章
blog_featured_posts获取置顶文章
blog_taxonomy查询分类和标签统计
blog_search跨标题/内容/标签搜索
blog_all_slugs导出所有 slug(用于 sitemap)
blog_stats博客统计数据
blog_submit_contact联系表单提交
blog_login管理员登录
blog_verify_session验证 session token
blog_create_post创建文章(需要 token)
blog_update_post更新文章(需要 token)
blog_delete_post删除文章(需要 token)

踩坑记录

1. 时区格式问题

博客前端使用 ISO 8601 格式(2026-06-26T10:00:00.000Z),但 SQLite 的 strftime 不处理时区。解决方案:统一用 strftime('%Y-%m-%d %H:%M:%S') 存储,前端读取后自己处理时区。

2. 分类/标签自动创建

创建文章时传入的分类名可能在数据库中不存在。需要在插入文章前先检查并创建分类/标签记录,再建立关联。这与博客 Admin 后端 actions.ts 的逻辑一致。

3. HAVING 语法

统计每个分类下的文章数时,最初写了 HAVING count > 0,但 SQLite 要求 HAVING 后的表达式必须出现在 SELECT 中。修正为 HAVING COUNT(p.id) > 0。

4. 种子文章自动恢复

博客的 prisma/seed.ts 使用 upsert 创建三篇默认文章("为什么我保留技术日志"等)。每次运行 npm run db:seed 都会重新创建已删除的种子文章。解决方案:在 seed 脚本开头检查 Post 表计数,已有文章则跳过 seed。

使用方式

通过 MCP 客户端配置:

{
  "mcpServers": {
    "blog": {
      "command": "F:\GitHub_project\BLOG\blog-mcp-server\mcp\Scripts\python.exe",
      "args": ["F:\GitHub_project\BLOG\blog-mcp-server\run.py"],
      "cwd": "F:\GitHub_project\BLOG\blog-mcp-server"
    }
  }
}

启动后 AI 助手就可以通过工具调用来管理博客内容,实现"一句话发文章"的效果。目前已批量创建了 13 篇技术文章,全流程正常。