[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-2397":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":8,"htmlUrl":8,"language":9,"languages":8,"totalLinesOfCode":8,"stars":10,"forks":11,"watchers":12,"openIssues":13,"contributorsCount":13,"subscribersCount":13,"size":13,"stars1d":13,"stars7d":13,"stars30d":14,"stars90d":13,"forks30d":13,"starsTrendScore":13,"compositeScore":15,"rankGlobal":8,"rankLanguage":8,"license":8,"archived":16,"fork":16,"defaultBranch":17,"hasWiki":18,"hasPages":16,"topics":19,"createdAt":8,"pushedAt":8,"updatedAt":20,"readmeContent":21,"aiSummary":22,"trendingCount":13,"starSnapshotCount":13,"syncStatus":23,"lastSyncTime":24,"discoverSource":25},2397,"wechat-oap-api","igorwang\u002Fwechat-oap-api","igorwang",null,"Python",243,25,10,0,113,4.24,false,"main",true,[],"2026-06-12 02:00:40","# wechat-oap-api\n\n微信公众号（订阅号 \u002F 服务号）服务端 API 的 FastAPI 封装，同时通过 MCP 对 AI Agent 暴露。\nToken 自动缓存、鉴权内置、一条 `docker compose up` 即可部署。\n\n- **37 个 HTTP 接口**，覆盖发布端到端：基础接口 6 + 发布能力 5 + 草稿管理 8 + 素材管理 9 + 基础消息 10\n- **Access Token 自动管理**：asyncio 锁去重 + 文件持久化 + 40001\u002F42001 自动刷新\n- **MCP 暴露（故意收窄）**：只有 **草稿 + 素材 + healthz 共 18 个** tool 走 MCP；发布、群发、订阅消息等保留为 HTTP-only，避免 Agent 误触发。见 `main.py` 里的 `MCP_TOOLS` 白名单\n- **API Key 鉴权**：保护 `\u002Fwechat\u002F*` 与 `\u002Fmcp`，可关\n- **63 个测试** 全绿（httpx + respx + pytest-asyncio）\n\n---\n\n## 服务端安装\n\n需要：`python >= 3.13` 或 Docker。\n\n### 方式一：本地 uv 运行（开发）\n\n```bash\ncp .env.example .env          # 填 WECHAT_APPID \u002F WECHAT_APPSECRET\nuv sync\nuv run uvicorn main:app --reload\n```\n\n访问 http:\u002F\u002F127.0.0.1:8000\u002Fdocs 查看所有接口。\n\n### 方式二：Docker Compose（推荐部署）\n\nCompose 直接消费 Docker Hub 上已发布的 multi-arch 镜像 `igorwang\u002Fwechat-oap-api`（`linux\u002Famd64` + `linux\u002Farm64`），**不做本地构建**：\n\n```bash\ncp .env.example .env          # 填 WECHAT_APPID \u002F WECHAT_APPSECRET \u002F API_KEY\ndocker compose pull           # 拉最新镜像（本机架构自动匹配）\ndocker compose up -d\ndocker compose logs -f api\n```\n\n- 端口默认 `:8000`，用 `.env` 的 `PORT` 可改\n- Token 缓存挂载到 `token-cache` volume，容器重启不会重新申请\n- Healthcheck 每 30s 打 `\u002Fhealthz`，`docker compose ps` 能看到 `healthy` 状态\n- 固定版本：`IMAGE_TAG=0.1.0 docker compose up -d`\n\n### 构建并发布新镜像（仅维护者）\n\n```bash\ndocker login -u igorwang        # 需要写权限的 Docker Hub 账号\nscripts\u002Fdocker-push.sh          # 读 pyproject.toml 的 version，打 :latest + :$version\nscripts\u002Fdocker-push.sh v0.2.0   # 或手动指定 tag\n```\n\n脚本用 `docker buildx --platform linux\u002Famd64,linux\u002Farm64` 一次构建两架构并直接 push。\n\n### 环境变量\n\n| 变量 | 必填 | 默认 | 说明 |\n|---|---|---|---|\n| `WECHAT_APPID` | ✓ | — | 公众号 AppID |\n| `WECHAT_APPSECRET` | ✓ | — | 公众号 AppSecret |\n| `WECHAT_API_BASE` |  | `https:\u002F\u002Fapi.weixin.qq.com` | |\n| `WECHAT_TOKEN_CACHE_PATH` |  | `.wechat_token.json` | 置空禁用磁盘缓存 |\n| `API_KEY` |  | `\"\"` | 保护 `\u002Fwechat\u002F*` 与 `\u002Fmcp`，**置空 = 关闭鉴权**（本地开发） |\n| `API_KEY_HEADER` |  | `X-API-Key` | 鉴权 header 名 |\n| `PORT` |  | `8000` | compose 对外映射端口 |\n\n---\n\n## 鉴权\n\n启用鉴权只需在 `.env` 设 `API_KEY=some-long-random-string`，随后所有 `\u002Fwechat\u002F*` 和 `\u002Fmcp` 请求必须带 header：\n\n```\nX-API-Key: some-long-random-string\n```\n\n放行路径（不需要 key）：`\u002Fhealthz`, `\u002Fdocs`, `\u002Fredoc`, `\u002Fopenapi.json`。\n\n---\n\n## 接入 Claude Code（MCP 客户端）\n\n核心思路：**API Key 配在 MCP 客户端侧一次，之后任何 skill \u002F prompt \u002F subagent 调用工具都不用感知 key**。这样：\n\n- Skill 代码里不会出现 secret\n- 同一机器上多个 agent 共享同一套 MCP 配置\n- 轮换 key 只改一处\n\n### 方式 A（推荐）：项目级 `.mcp.json`\n\n本仓库已附带 `.mcp.json`：\n\n```json\n{\n  \"mcpServers\": {\n    \"wechat-oap\": {\n      \"type\": \"http\",\n      \"url\": \"http:\u002F\u002Flocalhost:8000\u002Fmcp\",\n      \"headers\": {\n        \"X-API-Key\": \"${WECHAT_OAP_API_KEY}\"\n      }\n    }\n  }\n}\n```\n\n使用步骤：\n\n1. 本地\u002F服务器上把服务跑起来（`docker compose up -d`）\n2. 在 shell 里 export key：`export WECHAT_OAP_API_KEY=...`（建议写进 `~\u002F.zshrc` 或 direnv）\n3. `cd` 进本仓库，Claude Code 首次会提示\"approve project MCP\"，同意即可\n4. `claude mcp list` 能看到 `wechat-oap`\n\n**优势**：\n- `.mcp.json` 可安全 commit（只引用 env 变量，不含真 key）\n- 团队成员 clone 仓库后只需 export 自己的 key 即可\n- URL 要改（部署到生产），直接改 `.mcp.json` 并 commit\n\n### 方式 B：全局 `~\u002F.claude.json`（其他项目也想用）\n\n如果多个仓库都想调这套 MCP，写到用户级配置：\n\n```json\n{\n  \"mcpServers\": {\n    \"wechat-oap\": {\n      \"type\": \"http\",\n      \"url\": \"https:\u002F\u002Fyour-production-host\u002Fmcp\",\n      \"headers\": {\n        \"X-API-Key\": \"real-key-here\"\n      }\n    }\n  }\n}\n```\n\n### 方式 C：`claude mcp add`\n\n```bash\nclaude mcp add \\\n  --transport http \\\n  --header \"X-API-Key: your-api-key\" \\\n  wechat-oap http:\u002F\u002Flocalhost:8000\u002Fmcp\n```\n\n### 验证\n\n进入 Claude Code 后问一句：\n\n> 用 wechat-oap 查一下当前 access_token\n\nClaude 会调用 MCP 工具 `get_access_token`。如果你配了 key，请求会自动带 `X-API-Key` 头；没配 key 或配错 → 401。\n\n### 安装 wechat-api Skill\n\n本仓库在 `skills\u002Fwechat-api\u002F` 下内置了一个 Skill,指导 Claude 通过 `wechat-oap` MCP 起草公众号图文、管理素材(scope 仅限草稿,不含发布\u002F群发)。\n\n**项目级安装**(只在当前项目生效):\n\n```bash\nmkdir -p .claude\u002Fskills\nnpx -y degit igorwang\u002Fwechat-oap-api\u002Fskills\u002Fwechat-api .claude\u002Fskills\u002Fwechat-api\n```\n\n**全局安装**(所有项目都能用):\n\n```bash\nnpx -y degit igorwang\u002Fwechat-oap-api\u002Fskills\u002Fwechat-api ~\u002F.claude\u002Fskills\u002Fwechat-api\n```\n\n安装完成后,在 Claude Code 里输入类似 \"帮我起草一篇公众号图文\" \u002F \"上传一张封面图\" 就会自动触发;也可以 `\u002Fwechat-api` 显式调用。\n\n> 前置:先完成上一节的 MCP 接入(方式 A\u002FB\u002FC 任一),否则 Skill 找不到 `draft_add`、`material_add` 等工具。\n\n### Skill 怎么用\n\nSkill 里**不用**写 key。直接调 MCP 工具名即可:\n\n```markdown\n---\nname: 微信发布\ndescription: 从草稿 media_id 发布图文到公众号\n---\n\n1. 调 `freepublish_submit`，传入用户给的 `media_id`\n2. 轮询 `freepublish_get` 直到 `publish_status` 终态\n3. 把结果返回给用户\n```\n\nMCP 客户端在调用 `freepublish_submit` 时会自动带上 `X-API-Key`，skill 本体见不到也不需要传递。\n\n---\n\n## 接口总览\n\n| 分组 | 路由前缀 | operation_id 前缀 | 数量 |\n|---|---|---|---:|\n| 基础接口 | `\u002Fwechat\u002F{token,stable-token,callback\u002Fcheck,api-domain-ip,callback-ip,clear-quota}` | — | 6 |\n| 发布能力 | `\u002Fwechat\u002Ffreepublish\u002F*` | `freepublish_*` | 5 |\n| 草稿管理 | `\u002Fwechat\u002Fdraft\u002F*` | `draft_*` | 8 |\n| 素材管理 | `\u002Fwechat\u002Fmaterial\u002F{permanent,temporary}\u002F*` | `material_*` | 9 |\n| 基础消息 | `\u002Fwechat\u002Fmessage\u002F{mass,subscribe,autoreply}\u002F*` | `message_*` | 10 |\n\n完整 schema 见 http:\u002F\u002Flocalhost:8000\u002Fdocs 。\n\n---\n\n## 开发\n\n```bash\nuv sync                       # 含 dev group\nuv run pytest                 # 63 tests\nuv run pytest -v tests\u002Ftest_auth.py   # 单文件\n```\n\n结构：\n\n```\napp\u002F\n├── config.py          # pydantic-settings, 读 .env\n├── wechat.py          # WeChatClient: token 缓存 + call_json \u002F call_multipart\n├── auth.py            # X-API-Key 中间件\n└── routers\u002F\n    ├── freepublish.py\n    ├── draft.py\n    ├── material.py\n    └── message.py\nmain.py                # FastAPI app + FastApiMCP 挂载\ntests\u002F                 # respx mock，不打真微信\n```\n\n---\n\n## License\n\nMIT\n","该项目提供了基于FastAPI的微信公众号（包括订阅号和服务号）服务端API封装，并通过MCP对AI Agent开放。它支持37个HTTP接口，覆盖了从基础功能到素材管理等全方位需求；实现了Access Token自动管理，使用asyncio锁去重和文件持久化技术确保Token的有效性；并且仅将草稿、素材管理和健康检查共18个工具暴露给MCP以减少误触发风险。此外，项目还内置了API Key鉴权机制来保护关键路径的安全性。该解决方案特别适合需要快速集成微信公众号功能的应用场景，尤其是那些希望利用现代化异步Web框架构建高效后端服务或计划与AI系统协作处理内容发布任务的企业和个人开发者。",2,"2026-06-11 02:49:48","CREATED_QUERY"]