Post to WeChat Moments via ADB automation. Controls an Android phone running WeChat using a deterministic FSM — no LLM required for UI interaction.
- Python 3.12+
- Android phone with USB debugging enabled, WeChat installed
Note: ADBKeyboard is required for Chinese text input and will be installed automatically on first use.
pipx install wechat-momentsuv tool install wechat-momentsbrew tap vangie/formula
brew install wechat-momentsTo integrate with OpenClaw or other MCP clients:
If the MCP client and Android phone are on the same machine, use stdio transport (recommended):
Add to your MCP client config (e.g., ~/.mcporter/mcporter.json):
{
"mcpServers": {
"wechat-moments": {
"command": "wx-pyq-mcp"
}
}
}If the Android phone is connected to a different machine:
- On the machine with the phone, start the MCP server:
wx-pyq-mcp --transport sse --host 0.0.0.0 --port 8765- On the remote machine, configure the MCP client:
{
"mcpServers": {
"wechat-moments": {
"baseUrl": "http://<phone-machine-ip>:8765/sse",
"transport": "sse"
}
}
}# Check device connection
wx-pyq status
# Post with text only
wx-pyq post "今天天气真好"
# Post with images (local paths or URLs, max 9)
wx-pyq post "周末出游" -i photo1.jpg -i photo2.jpg
# Post without preview confirmation prompt
wx-pyq post "自动发布" -i photo.jpg --no-preview
# Collect FSM test fixtures (run once with phone connected)
wx-pyq collect-fixtures -o tests/fsm/fixtures/
# Clean up expired staging / archive dirs
wx-pyq cleanupThe MCP server exposes tools for AI agents to post to WeChat Moments.
# Start MCP server (stdio transport, for local use)
wx-pyq-mcp
# Start MCP server with SSE transport (for remote access)
wx-pyq-mcp --transport sse --host 0.0.0.0 --port 8765| Tool | Description |
|---|---|
prepare_post(text, images) |
Stage assets, generate preview image, return post_id |
submit_post(post_id) |
Execute ADB flow and publish to Moments |
get_device_status() |
Check ADB connection and app installation |
take_screenshot() |
Capture current phone screen for debugging |
prepare_post("text", ["image.jpg"])
→ returns { post_id, preview_path, ... }
→ show preview_path to user for confirmation (optional)
submit_post(post_id)
→ returns { status: "success", archive_path: "..." }
CLI / MCP Server
│
preview.py ← prepare_post: stage images, generate layout preview
│
submit.py ← execute_submit: lock + FSM + archive + history
│
┌───┴──────────────────────────────────┐
│ UI FSM (poster.py) │ ← concurrent with ↓
│ LAUNCH → DETECT_TAB → NAV_DISCOVER │
│ → OPEN_MOMENTS → [DISCARD_DIALOG] │
│ → SELECT_IMAGES → INPUT_TEXT → DONE │
└──────────────────────────────────────┘
│ Image FSM (images.py, background thread)
│ IDLE → PUSHING → SCANNING → READY → CLEANUP
│
adb.py ← ADB commands (screenshot, tap, dump UI, push files)
cv.py ← tab detection, checkmark counting
ime.py ← ADBKeyboard Chinese text input
UI coordinates are stored in profiles/<device_serial>.json. Huawei defaults are in profiles/huawei_default.json. Run wx-pyq calibrate to create a profile for a new device.
~/.local/share/wechat-moments/
├── history.jsonl # append-only event log
├── submit.lock # global mutex
├── staging/<post_id>/ # active/pending posts
└── archive/<post_id>/ # completed posts (preview + meta kept 30 days)
MIT