An open API service indexing awesome lists of open source software.

https://github.com/andyleimc-source/wecom-crm-mcp

WeCom (企业微信) External Contact (客户联系) MCP server — Python SDK + MCP covering customers, tags, moments, mass-send, group chats, transfers, statistics (11 modules, 60+ APIs).
https://github.com/andyleimc-source/wecom-crm-mcp

Last synced: 23 days ago
JSON representation

WeCom (企业微信) External Contact (客户联系) MCP server — Python SDK + MCP covering customers, tags, moments, mass-send, group chats, transfers, statistics (11 modules, 60+ APIs).

Awesome Lists containing this project

README

          

# wecom-crm-mcp

> WeCom (企业微信) **客户联系 / External Contact** MCP Server — a Python SDK + Model Context Protocol server that covers the full customer-contact API surface so an LLM can manage customers, tags, group chats, moments, and mass-send messages on your behalf.

[![PyPI](https://img.shields.io/pypi/v/wecom-crm-mcp.svg)](https://pypi.org/project/wecom-crm-mcp/)
[![Python](https://img.shields.io/pypi/pyversions/wecom-crm-mcp.svg)](https://pypi.org/project/wecom-crm-mcp/)
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)

## Why this exists

GitHub has plenty of WeCom group-bot **webhook** MCP servers. None covered the real 私域运营 / CRM surface exposed by 企业微信's 「客户联系」 API: customers, tags, group chats, 朋友圈, 群发, transfer-on-handover, acquisition links. This does — 11 modules, 63 actions, 1:1 with the [official docs](https://developer.work.weixin.qq.com/document/path/90664).

## Coverage

| # | Module | MCP tool | Key actions |
|---|---|---|---|
| 1 | 客户管理 | `wecom_customer` | `list_followers`, `list`, `get`, `batch_get`, `remark` |
| 2 | 客户标签 | `wecom_tag` | `list_corp_tags`, `add_corp_tag`, `edit_corp_tag`, `del_corp_tag`, `mark_tag` |
| 3 | 在职继承 | `wecom_transfer_active` | `transfer_customer`, `transfer_result`, `group_chat_transfer` |
| 4 | 离职继承 | `wecom_transfer_resigned` | `get_unassigned_list`, `resigned_transfer_customer`, `resigned_transfer_result`, `groupchat_transfer` |
| 5 | 客户群 | `wecom_group_chat` | `list`, `get`, `opengid_to_chatid` |
| 6 | 联系我 / 加入群聊 | `wecom_contact_way` | `add`, `get`, `list`, `update`, `del`, `close_temp_chat`, `groupchat_*_join_way` |
| 7 | 客户朋友圈 | `wecom_moment` | `add_moment_task`, `get_moment_task_result`, `cancel_moment_task`, `get_moment_list`, `get_moment_task`, `get_moment_customer_list` |
| 8 | 获客助手 | `wecom_acquisition` | `create_link`, `list_links`, `get_link`, `update_link`, `delete_link`, `list_customers`, `get_quota`, `get_statistic` |
| 9 | 消息推送 / 群发 | `wecom_msg_template` | `add_msg_template`, `send_welcome_msg`, `get_groupmsg_list_v2`, `get_groupmsg_task`, `get_groupmsg_send_result` |
| 10 | 统计管理 | `wecom_statistics` | `get_user_behavior_data`, `groupchat_statistic`, `groupchat_statistic_group_by_day` |
| 11 | 附加功能 | `wecom_misc` | `product_album_*`, `*_intercept_rule`, `get_new_external_userid` |

Plus two helpers: `wecom_upload_media` (temporary media for attachments) and `wecom_describe_action` (list the actions each tool supports, so the LLM can self-introspect).

## Install

```bash
pip install wecom-crm-mcp
```

## Setup — 企业微信 Side

> This is the part that trips most people up. Do it **before** you put credentials into the MCP config; otherwise you'll get `errcode=60020 "not allow to access from your ip"` on every call.

### 1. Find your 客户联系 secret

1. Log into [work.weixin.qq.com](https://work.weixin.qq.com/) as an admin
2. **客户联系** → **客户** → page bottom: **API** section
3. Click **配置** next to "API 接口" → you'll see **Secret**. Click **查看** and copy it. This is your `WECOM_CORPSECRET`.
4. In the same page, find your **企业ID (CorpID)** from **我的企业** → bottom of the page. This is your `WECOM_CORPID`.

### 2. Add your server IP to the 可信 IP list

WeCom enforces IP whitelisting on the 客户联系 API. **Every IP that calls the API must be whitelisted**, including your laptop if you run the MCP locally.

The whitelist lives in the **same 客户联系 → API** page where you got the secret (not in the generic "应用管理 → 企业可信IP" — that one asks for a filed domain and is for self-built apps, not 客户联系).

Find your current public IP with:

```bash
curl https://ipinfo.io/ip
```

Paste it in, separated by `;` if multiple.

> Running from a laptop on home Wi‑Fi / VPN means your IP will change. Either (a) pin a stable exit via a cloud VM and run the MCP there, or (b) re-add the IP every time it changes. See [deploy/README.md](deploy/README.md) for the cloud-VM pattern.

### 3. Give the secret access to the employees whose customers it should manage

Still on **客户联系 → API** → **可调用接口的应用** → add the employees/departments whose customer list you want the API to see. The secret can only read customers serviced by these people.

## Setup — Client Side

### Claude Desktop / Claude Code

Add to `~/.claude.json` (or `~/Library/Application Support/Claude/claude_desktop_config.json` for Claude Desktop):

```json
{
"mcpServers": {
"wecom-crm": {
"command": "wecom-crm-mcp",
"env": {
"WECOM_CORPID": "ww...",
"WECOM_CORPSECRET": "...",
"WECOM_AGENTID": "1000001"
}
}
}
}
```

`WECOM_AGENTID` is only required for mass-send (`wecom_msg_template`); everything else works without it.

Restart the client and you should see a `wecom-crm` server with 13 tools.

### Plain Python

```python
import asyncio
from wecom_crm_mcp import WecomClient, WecomConfig
from wecom_crm_mcp.modules.customer import CustomerModule

async def main():
cfg = WecomConfig.from_env() # reads WECOM_CORPID / WECOM_CORPSECRET
async with WecomClient(cfg) as c:
customers = await CustomerModule(c).list_followers()
print(customers)

asyncio.run(main())
```

## Example LLM sessions

```
User: 列出所有带"VIP"标签的客户
Claude → wecom_tag (list_corp_tags)
→ wecom_customer (batch_get)
→ returns list
```

```
User: 帮我给所有客户发朋友圈,文案"春节快乐",附张 /tmp/banner.jpg
Claude → wecom_upload_media (attachment_type=2)
→ wecom_moment (add_moment_task, with media_id from above)
→ returns jobid
```

```
User: 我们销售小王离职了,把他的所有客户转给小李
Claude → wecom_transfer_resigned (get_unassigned_list)
→ wecom_transfer_resigned (resigned_transfer_customer)
```

## Error codes you'll actually hit

| errcode | Meaning | Fix |
|---|---|---|
| `60011` | no permission on this customer | The customer isn't served by any user listed in 可调用接口的应用 |
| `60020` | IP not allowed | Add your current IP to the 可信 IP list |
| `42001` / `40014` | token expired / invalid | Handled automatically — the client refreshes and retries once |
| `40003` | invalid external_userid | You passed an app-scoped openid, not an external_userid — convert with `wecom_misc action=get_new_external_userid` |

## Architecture

```
┌──────────────────┐ stdio ┌──────────────────────┐
│ Claude / LLM │ ─────── MCP ─────────────▶ │ wecom-crm-mcp │
└──────────────────┘ │ (FastMCP server) │
│ │
│ ┌────────────────┐ │
│ │ 11 Tool routers│──┼─▶ action → SDK method
│ └────────────────┘ │
│ ┌────────────────┐ │
│ │ WecomClient │──┼─▶ httpx.AsyncClient
│ │ • token cache │ │ + diskcache
│ │ • retry 42001 │ │
│ └────────────────┘ │
└──────────┬───────────┘
│ HTTPS

qyapi.weixin.qq.com
```

## Development

```bash
git clone https://github.com/andyleimc-source/wecom-crm-mcp.git
cd wecom-crm-mcp
uv venv && source .venv/bin/activate
uv pip install -e ".[dev]"
uv run pytest -q
```

All tests mock HTTP with `pytest-httpx` — no network, no credentials needed.

## Contributing

Issues and PRs welcome. If you add an endpoint, the pattern is:

1. Add the method to the relevant `src/wecom_crm_mcp/modules/*.py`
2. Add one test in `tests/modules/test_*.py` asserting the JSON body or query params
3. If it's a new user-facing action, add it to the action table in `src/wecom_crm_mcp/server.py`

## License

MIT — see [LICENSE](LICENSE).

## Disclaimer

This is an independent community project. Not affiliated with Tencent or 企业微信. Use at your own risk and stay within the [企业微信 API rate limits and policies](https://developer.work.weixin.qq.com/document/path/90313).