Skip to content

03 · 封装为 MCP

第 2 章的读库层已经是几个干净的 Python 函数。这一章把它们暴露成 MCP 工具, 让任意支持 MCP 的客户端(Claude Code、Codex、NoCannoBB 等)都能调用。配套代码: code/wechat_mcp/server.py

什么是 MCP,为什么用它

MCP(Model Context Protocol)是一套「让 AI 客户端发现并调用外部工具」的标准协议。 你写一个 MCP Server,声明几个工具(名字、参数、返回),客户端启动它、把工具列表交给 模型,模型就能在对话中按需调用。

对我们来说,MCP 是那道闸门:模型只能看到我们声明的这几个只读工具,看不到密钥, 也发不出任意 SQL。

安装

powershell
cd course/wechat-ai-assistant/code
pip install -r wechat_mcp/requirements.txt   # mcp[cli] + pycryptodome + zstandard

用 FastMCP 声明工具

mcp 官方 SDK 提供 FastMCP,用装饰器就能把一个函数变成工具,docstring 会成为模型 看到的说明,类型注解会成为参数 schema:

python
from mcp.server.fastmcp import FastMCP
from wechat_win import db_reader_win as reader

mcp = FastMCP("wechat-local")

@mcp.tool()
def search_messages(keyword: str, limit: int = 30) -> list[dict]:
    """在所有会话里按关键字搜索消息(子串匹配,时间倒序)。"""
    db = _require_msg()
    ...

server.py 一共声明四个工具,和第 2 章的四个动作一一对应:

工具说明
list_conversations(limit)列会话及其消息表
list_contacts(limit)列联系人
read_chat_history(conversation, limit)读某会话最近消息
search_messages(keyword, limit)全局关键字搜

刻意不声明的:execute_sql()dump_key()export_all_messages()。能力面越小越安全。

两种数据来源(密钥怎么处理)

server.py 启动时用 _resolve_plain_paths() 决定读哪个明文库,支持两种配置:

A. 指向已导出的明文库(推荐,MCP 层完全不碰密钥)

先用第 1 章的 CLI 导出一次明文库:

powershell
python -m wechat_win.main_win --out C:\temp\wx_plain

再让 MCP 指向它:

WECHAT_PLAIN_DIR=C:\temp\wx_plain

MCP 只读这个目录里的 message_0.db / contact.db协议里、日志里、返回值里都不会出现 密钥。这是最干净的分层。

B. 指向加密库 + 显式密钥(MCP 启动时解密到临时文件)

WECHAT_ENC_MSG_DB=E:\xwechat_files\<wxid>\db_storage\message\message_0.db
WECHAT_ENC_CONTACT_DB=E:\xwechat_files\<wxid>\db_storage\contact\contact.db
WECHAT_MSG_KEY=<64位hex>

密钥只通过环境变量传入,server.py 用它在启动阶段解密到临时明文文件,之后运行期 只读临时库。密钥永不打印、不写日志、不进返回值。进程退出时 atexit 自动删除临时库:

python
_TMP_FILES: list[str] = []
def _cleanup():
    for f in _TMP_FILES:
        try: os.remove(f)
        except OSError: pass
atexit.register(_cleanup)

默认脱敏

SANITIZE=1 时,返回结果里的 wxid / 群 id 会打码(_mask_wxid),昵称/备注保留可读。 适合把结果贴给别人看、或在录屏演示时用。

本地自测

不接客户端,直接用官方 inspector 手动点一遍工具:

powershell
# 以来源 A 为例
$env:WECHAT_PLAIN_DIR="C:\temp\wx_plain"
python -m mcp dev wechat_mcp/server.py       # 打开 MCP Inspector,逐个工具试
# 或直接以 stdio 方式跑(供客户端拉起)
python -m wechat_mcp.server

看到四个工具、list_contacts 能返回数据,就说明 MCP 层通了。

客户端注册(第 5 章还会细讲)

以 Claude Code / Codex 为例,在 MCP 配置里加一项,指向本 server(把 cwd 设为 code/ 目录以便 import wechat_win):

json
{
  "mcpServers": {
    "wechat-local": {
      "command": "python",
      "args": ["-m", "wechat_mcp.server"],
      "cwd": "D:/SynologyDrive/workspace/sub2api-product/course/wechat-ai-assistant/code",
      "env": { "WECHAT_PLAIN_DIR": "C:/temp/wx_plain", "SANITIZE": "0" }
    }
  }
}

注册后,客户端里的模型就能看到 wechat-local 的四个工具了。下一章我们写一个 Skill, 让模型知道什么时候、怎么用它们。


上一章:02 · 只读读库层 | 下一章:04 · NoCannoBB Skill