wechatmp-mcp 0.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- wechatmp_mcp-0.0.1/.gitignore +148 -0
- wechatmp_mcp-0.0.1/PKG-INFO +136 -0
- wechatmp_mcp-0.0.1/README.md +106 -0
- wechatmp_mcp-0.0.1/pyproject.toml +52 -0
- wechatmp_mcp-0.0.1/src/wechat_mcp/__init__.py +3 -0
- wechatmp_mcp-0.0.1/src/wechat_mcp/__main__.py +3 -0
- wechatmp_mcp-0.0.1/src/wechat_mcp/config.py +53 -0
- wechatmp_mcp-0.0.1/src/wechat_mcp/constants.py +27 -0
- wechatmp_mcp-0.0.1/src/wechat_mcp/errors.py +41 -0
- wechatmp_mcp-0.0.1/src/wechat_mcp/infrastructure/__init__.py +1 -0
- wechatmp_mcp-0.0.1/src/wechat_mcp/infrastructure/api/__init__.py +3 -0
- wechatmp_mcp-0.0.1/src/wechat_mcp/infrastructure/api/wechat_client.py +227 -0
- wechatmp_mcp-0.0.1/src/wechat_mcp/infrastructure/browser/__init__.py +4 -0
- wechatmp_mcp-0.0.1/src/wechat_mcp/infrastructure/browser/browser_manager.py +29 -0
- wechatmp_mcp-0.0.1/src/wechat_mcp/infrastructure/browser/login_flow.py +248 -0
- wechatmp_mcp-0.0.1/src/wechat_mcp/infrastructure/storage/__init__.py +3 -0
- wechatmp_mcp-0.0.1/src/wechat_mcp/infrastructure/storage/auth_store.py +69 -0
- wechatmp_mcp-0.0.1/src/wechat_mcp/logging.py +41 -0
- wechatmp_mcp-0.0.1/src/wechat_mcp/mcp/__init__.py +1 -0
- wechatmp_mcp-0.0.1/src/wechat_mcp/mcp/tools/__init__.py +9 -0
- wechatmp_mcp-0.0.1/src/wechat_mcp/mcp/tools/account_tools.py +148 -0
- wechatmp_mcp-0.0.1/src/wechat_mcp/mcp/tools/article_tools.py +123 -0
- wechatmp_mcp-0.0.1/src/wechat_mcp/mcp/tools/mp_tools.py +129 -0
- wechatmp_mcp-0.0.1/src/wechat_mcp/server.py +133 -0
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[codz]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
.Python
|
|
7
|
+
build/
|
|
8
|
+
develop-eggs/
|
|
9
|
+
dist/
|
|
10
|
+
downloads/
|
|
11
|
+
eggs/
|
|
12
|
+
.eggs/
|
|
13
|
+
lib/
|
|
14
|
+
lib64/
|
|
15
|
+
parts/
|
|
16
|
+
sdist/
|
|
17
|
+
var/
|
|
18
|
+
wheels/
|
|
19
|
+
share/python-wheels/
|
|
20
|
+
*.egg-info/
|
|
21
|
+
.installed.cfg
|
|
22
|
+
*.egg
|
|
23
|
+
MANIFEST
|
|
24
|
+
|
|
25
|
+
# PyInstaller
|
|
26
|
+
*.manifest
|
|
27
|
+
*.spec
|
|
28
|
+
|
|
29
|
+
# Installer logs
|
|
30
|
+
pip-log.txt
|
|
31
|
+
pip-delete-this-directory.txt
|
|
32
|
+
|
|
33
|
+
# Unit test / coverage reports
|
|
34
|
+
htmlcov/
|
|
35
|
+
.tox/
|
|
36
|
+
.nox/
|
|
37
|
+
.coverage
|
|
38
|
+
.coverage.*
|
|
39
|
+
.cache
|
|
40
|
+
nosetests.xml
|
|
41
|
+
coverage.xml
|
|
42
|
+
*.cover
|
|
43
|
+
*.py.cover
|
|
44
|
+
.hypothesis/
|
|
45
|
+
.pytest_cache/
|
|
46
|
+
cover/
|
|
47
|
+
|
|
48
|
+
# Translations
|
|
49
|
+
*.mo
|
|
50
|
+
*.pot
|
|
51
|
+
|
|
52
|
+
# Django
|
|
53
|
+
*.log
|
|
54
|
+
local_settings.py
|
|
55
|
+
db.sqlite3
|
|
56
|
+
db.sqlite3-journal
|
|
57
|
+
|
|
58
|
+
# Flask
|
|
59
|
+
instance/
|
|
60
|
+
.webassets-cache
|
|
61
|
+
|
|
62
|
+
# Scrapy
|
|
63
|
+
.scrapy
|
|
64
|
+
|
|
65
|
+
# Sphinx
|
|
66
|
+
docs/_build/
|
|
67
|
+
|
|
68
|
+
# PyBuilder
|
|
69
|
+
.pybuilder/
|
|
70
|
+
target/
|
|
71
|
+
|
|
72
|
+
# Jupyter Notebook
|
|
73
|
+
.ipynb_checkpoints
|
|
74
|
+
|
|
75
|
+
# IPython
|
|
76
|
+
profile_default/
|
|
77
|
+
ipython_config.py
|
|
78
|
+
|
|
79
|
+
# Virtual environments
|
|
80
|
+
.env
|
|
81
|
+
.envrc
|
|
82
|
+
.venv
|
|
83
|
+
env/
|
|
84
|
+
venv/
|
|
85
|
+
ENV/
|
|
86
|
+
env.bak/
|
|
87
|
+
venv.bak/
|
|
88
|
+
|
|
89
|
+
# Package managers
|
|
90
|
+
.pdm-python
|
|
91
|
+
.pdm-build/
|
|
92
|
+
.pixi
|
|
93
|
+
__pypackages__/
|
|
94
|
+
|
|
95
|
+
# Celery
|
|
96
|
+
celerybeat-schedule
|
|
97
|
+
celerybeat.pid
|
|
98
|
+
|
|
99
|
+
# SageMath
|
|
100
|
+
*.sage.py
|
|
101
|
+
|
|
102
|
+
# Type checkers
|
|
103
|
+
.mypy_cache/
|
|
104
|
+
.dmypy.json
|
|
105
|
+
dmypy.json
|
|
106
|
+
.pyre/
|
|
107
|
+
.pytype/
|
|
108
|
+
cython_debug/
|
|
109
|
+
.ruff_cache/
|
|
110
|
+
|
|
111
|
+
# Spyder / Rope
|
|
112
|
+
.spyderproject
|
|
113
|
+
.spyproject
|
|
114
|
+
.ropeproject
|
|
115
|
+
|
|
116
|
+
# mkdocs
|
|
117
|
+
/site
|
|
118
|
+
|
|
119
|
+
# Abstra
|
|
120
|
+
.abstra/
|
|
121
|
+
|
|
122
|
+
# Marimo
|
|
123
|
+
marimo/_static/
|
|
124
|
+
marimo/_lsp/
|
|
125
|
+
__marimo__/
|
|
126
|
+
|
|
127
|
+
# PyPI
|
|
128
|
+
.pypirc
|
|
129
|
+
|
|
130
|
+
# IDE
|
|
131
|
+
.idea/
|
|
132
|
+
.vscode/
|
|
133
|
+
*.swp
|
|
134
|
+
*.swo
|
|
135
|
+
*~
|
|
136
|
+
|
|
137
|
+
# Cursor
|
|
138
|
+
.cursorignore
|
|
139
|
+
.cursorindexingignore
|
|
140
|
+
|
|
141
|
+
# Project-specific
|
|
142
|
+
browser_data/
|
|
143
|
+
screenshots/
|
|
144
|
+
logs/
|
|
145
|
+
|
|
146
|
+
# OS
|
|
147
|
+
.DS_Store
|
|
148
|
+
Thumbs.db
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: wechatmp-mcp
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: MCP service for WeChat Official Account (微信公众号) content retrieval
|
|
5
|
+
Author: wechatmp-mcp
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Keywords: mcp,playwright,wechat,weixin,公众号,微信
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Requires-Python: >=3.10
|
|
16
|
+
Requires-Dist: beautifulsoup4>=4.12.0
|
|
17
|
+
Requires-Dist: html2text>=2020.1.16
|
|
18
|
+
Requires-Dist: httpx>=0.25.0
|
|
19
|
+
Requires-Dist: mcp>=1.0.0
|
|
20
|
+
Requires-Dist: playwright>=1.40.0
|
|
21
|
+
Requires-Dist: pydantic-settings>=2.0.0
|
|
22
|
+
Requires-Dist: pydantic>=2.0.0
|
|
23
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
24
|
+
Requires-Dist: starlette>=0.37.0
|
|
25
|
+
Requires-Dist: uvicorn>=0.24.0
|
|
26
|
+
Provides-Extra: dev
|
|
27
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
|
|
28
|
+
Requires-Dist: pytest>=7.0.0; extra == 'dev'
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
|
|
31
|
+
# wechatmp-mcp
|
|
32
|
+
|
|
33
|
+
`wechatmp-mcp` 是一个面向 MCP 客户端使用者的微信公众号 MCP Server。它通过微信公众号后台接口,提供扫码登录、搜索公众号、获取文章列表、读取文章正文、批量抓取多账号近期文章等能力。
|
|
34
|
+
|
|
35
|
+
你可以把它接入支持 MCP 的客户端,例如 Claude Code、Cline、MCP Inspector,或任何兼容 `stdio` 的 MCP 工具。
|
|
36
|
+
|
|
37
|
+
## 它能做什么
|
|
38
|
+
|
|
39
|
+
- 获取微信公众号后台登录二维码,扫码完成登录,自动保存登录态到本地
|
|
40
|
+
- 登录态保存在 `~/.wechat-mcp/`,重启后无需重新登录
|
|
41
|
+
- 按关键词搜索公众号,获取 fakeid、昵称、简介等信息
|
|
42
|
+
- 获取指定公众号的文章列表(标题、链接、摘要、封面、发布时间)
|
|
43
|
+
- 读取指定文章 URL 的正文,以 Markdown 格式返回
|
|
44
|
+
- 批量获取多个公众号的近期文章摘要
|
|
45
|
+
|
|
46
|
+
当前项目实际注册了 **7 个 MCP tools**。
|
|
47
|
+
|
|
48
|
+
## 环境要求
|
|
49
|
+
|
|
50
|
+
- Python 3.10 或更高版本
|
|
51
|
+
- 能访问微信公众号网页(mp.weixin.qq.com)
|
|
52
|
+
|
|
53
|
+
## 通过 uvx 使用(推荐)
|
|
54
|
+
|
|
55
|
+
无需手动安装,uvx 会自动处理。
|
|
56
|
+
|
|
57
|
+
### Claude Code 配置
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
claude mcp add wechat -- uvx wechatmp-mcp
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### 快速调试
|
|
64
|
+
|
|
65
|
+
```sh
|
|
66
|
+
npx @modelcontextprotocol/inspector uvx wechatmp-mcp
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
> ⚠️ **注意:** 请务必先使用 `get_login_qrcode` + `check_login_status` 完成登录后再使用其他工具!
|
|
70
|
+
|
|
71
|
+
## MCP 客户端配置
|
|
72
|
+
|
|
73
|
+
### Claude Code
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
claude mcp add wechat -- uvx wechatmp-mcp
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Cline / JSON 配置
|
|
80
|
+
|
|
81
|
+
```json
|
|
82
|
+
{
|
|
83
|
+
"mcpServers": {
|
|
84
|
+
"wechatmp-mcp": {
|
|
85
|
+
"command": "uvx",
|
|
86
|
+
"args": ["wechatmp-mcp"]
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Tools 一览
|
|
93
|
+
|
|
94
|
+
### 账号登录
|
|
95
|
+
|
|
96
|
+
- `get_login_qrcode`:获取微信公众号后台登录二维码,图片保存到本地,返回文件路径
|
|
97
|
+
- `check_login_status`:检查登录状态;若用户已扫码则完成登录并保存 auth,否则验证已保存 auth 是否有效
|
|
98
|
+
- `logout`:清除本地保存的 auth(token + cookies),退出登录
|
|
99
|
+
|
|
100
|
+
### 公众号搜索
|
|
101
|
+
|
|
102
|
+
- `search_account`:按关键词搜索公众号,返回 fakeid、nickname、alias、intro、avatar
|
|
103
|
+
|
|
104
|
+
### 文章获取
|
|
105
|
+
|
|
106
|
+
- `get_account_articles`:获取指定公众号的文章列表(按发布时间倒序),支持按 fakeid 或公众号名称查询,支持翻页
|
|
107
|
+
- `get_article_content`:传入文章 URL,返回清洗后的 Markdown 正文
|
|
108
|
+
- `batch_get_articles`:传入公众号名称列表,批量获取近期文章摘要
|
|
109
|
+
|
|
110
|
+
## 发布新版本到 PyPI
|
|
111
|
+
|
|
112
|
+
修改代码后,更新 `src/wechat_mcp/__init__.py` 中的版本号,然后:
|
|
113
|
+
|
|
114
|
+
```sh
|
|
115
|
+
# 安装构建工具(首次需要)
|
|
116
|
+
pip install hatch twine -i https://pypi.org/simple/
|
|
117
|
+
|
|
118
|
+
# 构建
|
|
119
|
+
hatch build
|
|
120
|
+
|
|
121
|
+
# 上传到 PyPI
|
|
122
|
+
# Username: __token__
|
|
123
|
+
# Password: 在 https://pypi.org/manage/account/ 的 API tokens 中创建
|
|
124
|
+
python -m twine upload dist/*
|
|
125
|
+
|
|
126
|
+
# 验证上传成功
|
|
127
|
+
uvx wechatmp-mcp==<新版本号> --help
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
> 注意:上传后 PyPI 同步约需 1-2 分钟,验证前稍等片刻。
|
|
131
|
+
|
|
132
|
+
## 使用建议
|
|
133
|
+
|
|
134
|
+
- 使用其他工具前,请先通过 `get_login_qrcode` 获取二维码并扫码,再调用 `check_login_status` 完成登录
|
|
135
|
+
- 登录态保存在 `~/.wechat-mcp/`,重启服务后无需重新登录
|
|
136
|
+
- `get_account_articles` 需要先通过 `search_account` 获取公众号的 `fakeid`
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# wechatmp-mcp
|
|
2
|
+
|
|
3
|
+
`wechatmp-mcp` 是一个面向 MCP 客户端使用者的微信公众号 MCP Server。它通过微信公众号后台接口,提供扫码登录、搜索公众号、获取文章列表、读取文章正文、批量抓取多账号近期文章等能力。
|
|
4
|
+
|
|
5
|
+
你可以把它接入支持 MCP 的客户端,例如 Claude Code、Cline、MCP Inspector,或任何兼容 `stdio` 的 MCP 工具。
|
|
6
|
+
|
|
7
|
+
## 它能做什么
|
|
8
|
+
|
|
9
|
+
- 获取微信公众号后台登录二维码,扫码完成登录,自动保存登录态到本地
|
|
10
|
+
- 登录态保存在 `~/.wechat-mcp/`,重启后无需重新登录
|
|
11
|
+
- 按关键词搜索公众号,获取 fakeid、昵称、简介等信息
|
|
12
|
+
- 获取指定公众号的文章列表(标题、链接、摘要、封面、发布时间)
|
|
13
|
+
- 读取指定文章 URL 的正文,以 Markdown 格式返回
|
|
14
|
+
- 批量获取多个公众号的近期文章摘要
|
|
15
|
+
|
|
16
|
+
当前项目实际注册了 **7 个 MCP tools**。
|
|
17
|
+
|
|
18
|
+
## 环境要求
|
|
19
|
+
|
|
20
|
+
- Python 3.10 或更高版本
|
|
21
|
+
- 能访问微信公众号网页(mp.weixin.qq.com)
|
|
22
|
+
|
|
23
|
+
## 通过 uvx 使用(推荐)
|
|
24
|
+
|
|
25
|
+
无需手动安装,uvx 会自动处理。
|
|
26
|
+
|
|
27
|
+
### Claude Code 配置
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
claude mcp add wechat -- uvx wechatmp-mcp
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### 快速调试
|
|
34
|
+
|
|
35
|
+
```sh
|
|
36
|
+
npx @modelcontextprotocol/inspector uvx wechatmp-mcp
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
> ⚠️ **注意:** 请务必先使用 `get_login_qrcode` + `check_login_status` 完成登录后再使用其他工具!
|
|
40
|
+
|
|
41
|
+
## MCP 客户端配置
|
|
42
|
+
|
|
43
|
+
### Claude Code
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
claude mcp add wechat -- uvx wechatmp-mcp
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Cline / JSON 配置
|
|
50
|
+
|
|
51
|
+
```json
|
|
52
|
+
{
|
|
53
|
+
"mcpServers": {
|
|
54
|
+
"wechatmp-mcp": {
|
|
55
|
+
"command": "uvx",
|
|
56
|
+
"args": ["wechatmp-mcp"]
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Tools 一览
|
|
63
|
+
|
|
64
|
+
### 账号登录
|
|
65
|
+
|
|
66
|
+
- `get_login_qrcode`:获取微信公众号后台登录二维码,图片保存到本地,返回文件路径
|
|
67
|
+
- `check_login_status`:检查登录状态;若用户已扫码则完成登录并保存 auth,否则验证已保存 auth 是否有效
|
|
68
|
+
- `logout`:清除本地保存的 auth(token + cookies),退出登录
|
|
69
|
+
|
|
70
|
+
### 公众号搜索
|
|
71
|
+
|
|
72
|
+
- `search_account`:按关键词搜索公众号,返回 fakeid、nickname、alias、intro、avatar
|
|
73
|
+
|
|
74
|
+
### 文章获取
|
|
75
|
+
|
|
76
|
+
- `get_account_articles`:获取指定公众号的文章列表(按发布时间倒序),支持按 fakeid 或公众号名称查询,支持翻页
|
|
77
|
+
- `get_article_content`:传入文章 URL,返回清洗后的 Markdown 正文
|
|
78
|
+
- `batch_get_articles`:传入公众号名称列表,批量获取近期文章摘要
|
|
79
|
+
|
|
80
|
+
## 发布新版本到 PyPI
|
|
81
|
+
|
|
82
|
+
修改代码后,更新 `src/wechat_mcp/__init__.py` 中的版本号,然后:
|
|
83
|
+
|
|
84
|
+
```sh
|
|
85
|
+
# 安装构建工具(首次需要)
|
|
86
|
+
pip install hatch twine -i https://pypi.org/simple/
|
|
87
|
+
|
|
88
|
+
# 构建
|
|
89
|
+
hatch build
|
|
90
|
+
|
|
91
|
+
# 上传到 PyPI
|
|
92
|
+
# Username: __token__
|
|
93
|
+
# Password: 在 https://pypi.org/manage/account/ 的 API tokens 中创建
|
|
94
|
+
python -m twine upload dist/*
|
|
95
|
+
|
|
96
|
+
# 验证上传成功
|
|
97
|
+
uvx wechatmp-mcp==<新版本号> --help
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
> 注意:上传后 PyPI 同步约需 1-2 分钟,验证前稍等片刻。
|
|
101
|
+
|
|
102
|
+
## 使用建议
|
|
103
|
+
|
|
104
|
+
- 使用其他工具前,请先通过 `get_login_qrcode` 获取二维码并扫码,再调用 `check_login_status` 完成登录
|
|
105
|
+
- 登录态保存在 `~/.wechat-mcp/`,重启服务后无需重新登录
|
|
106
|
+
- `get_account_articles` 需要先通过 `search_account` 获取公众号的 `fakeid`
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "wechatmp-mcp"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "MCP service for WeChat Official Account (微信公众号) content retrieval"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
requires-python = ">=3.10"
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "wechatmp-mcp" }
|
|
14
|
+
]
|
|
15
|
+
keywords = ["mcp", "wechat", "weixin", "微信", "公众号", "playwright"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 3 - Alpha",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"License :: OSI Approved :: MIT License",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3.10",
|
|
22
|
+
"Programming Language :: Python :: 3.11",
|
|
23
|
+
"Programming Language :: Python :: 3.12",
|
|
24
|
+
]
|
|
25
|
+
dependencies = [
|
|
26
|
+
"mcp>=1.0.0",
|
|
27
|
+
"starlette>=0.37.0",
|
|
28
|
+
"uvicorn>=0.24.0",
|
|
29
|
+
"playwright>=1.40.0",
|
|
30
|
+
"httpx>=0.25.0",
|
|
31
|
+
"beautifulsoup4>=4.12.0",
|
|
32
|
+
"html2text>=2020.1.16",
|
|
33
|
+
"python-dotenv>=1.0.0",
|
|
34
|
+
"pydantic>=2.0.0",
|
|
35
|
+
"pydantic-settings>=2.0.0",
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
[project.optional-dependencies]
|
|
39
|
+
dev = [
|
|
40
|
+
"pytest>=7.0.0",
|
|
41
|
+
"pytest-asyncio>=0.21.0",
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
[project.scripts]
|
|
45
|
+
wechatmp-mcp = "wechat_mcp.server:main"
|
|
46
|
+
|
|
47
|
+
[tool.hatch.version]
|
|
48
|
+
path = "src/wechat_mcp/__init__.py"
|
|
49
|
+
validate-bump = false
|
|
50
|
+
|
|
51
|
+
[tool.hatch.build.targets.wheel]
|
|
52
|
+
packages = ["src/wechat_mcp"]
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"""Configuration management using pydantic-settings."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Literal, Optional
|
|
5
|
+
|
|
6
|
+
from pydantic import Field
|
|
7
|
+
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Settings(BaseSettings):
|
|
11
|
+
model_config = SettingsConfigDict(
|
|
12
|
+
env_file=".env",
|
|
13
|
+
env_file_encoding="utf-8",
|
|
14
|
+
extra="ignore",
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
# Browser (used only for login QR code)
|
|
18
|
+
headless: bool = Field(default=False, description="Run browser in headless mode (False to show QR code)")
|
|
19
|
+
page_timeout: int = Field(default=30000, description="Page timeout in milliseconds")
|
|
20
|
+
|
|
21
|
+
# Storage
|
|
22
|
+
data_dir: Path = Field(
|
|
23
|
+
default=Path.home() / ".wechat-mcp",
|
|
24
|
+
description="Directory for auth store and screenshots",
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
# Logging
|
|
28
|
+
log_level: str = Field(default="INFO", description="Logging level")
|
|
29
|
+
|
|
30
|
+
# MCP transport
|
|
31
|
+
mcp_transport: Literal["stdio", "streamable_http"] = Field(default="stdio")
|
|
32
|
+
mcp_tool_timeout_seconds: float = Field(default=60.0, gt=0)
|
|
33
|
+
mcp_http_host: str = Field(default="127.0.0.1")
|
|
34
|
+
mcp_http_port: int = Field(default=18001, ge=1, le=65535)
|
|
35
|
+
mcp_streamable_http_path: str = Field(default="/mcp")
|
|
36
|
+
|
|
37
|
+
@property
|
|
38
|
+
def screenshots_dir(self) -> Path:
|
|
39
|
+
return self.data_dir / "screenshots"
|
|
40
|
+
|
|
41
|
+
@property
|
|
42
|
+
def auth_file(self) -> Path:
|
|
43
|
+
return self.data_dir / "auth.json"
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
_settings: Optional[Settings] = None
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def get_settings() -> Settings:
|
|
50
|
+
global _settings
|
|
51
|
+
if _settings is None:
|
|
52
|
+
_settings = Settings()
|
|
53
|
+
return _settings
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""Constants for WeChat MCP."""
|
|
2
|
+
|
|
3
|
+
BASE_URL = "https://mp.weixin.qq.com"
|
|
4
|
+
LOGIN_URL = f"{BASE_URL}/"
|
|
5
|
+
|
|
6
|
+
USER_AGENTS = [
|
|
7
|
+
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
|
|
8
|
+
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
|
|
9
|
+
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/120.0",
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
# API paths
|
|
13
|
+
SEARCHBIZ_URL = f"{BASE_URL}/cgi-bin/searchbiz"
|
|
14
|
+
APPMSG_URL = f"{BASE_URL}/cgi-bin/appmsg"
|
|
15
|
+
BIZLOGIN_START_URL = f"{BASE_URL}/cgi-bin/bizlogin?action=startlogin"
|
|
16
|
+
BIZLOGIN_URL = f"{BASE_URL}/cgi-bin/bizlogin?action=login"
|
|
17
|
+
SCANLOGIN_URL = f"{BASE_URL}/cgi-bin/scanloginqrcode"
|
|
18
|
+
|
|
19
|
+
# QR code status codes
|
|
20
|
+
QR_STATUS_WAITING = 0
|
|
21
|
+
QR_STATUS_SCANNED = 2
|
|
22
|
+
QR_STATUS_CONFIRMED = 4
|
|
23
|
+
QR_STATUS_SUCCESS_1 = 1
|
|
24
|
+
QR_STATUS_SUCCESS_3 = 3
|
|
25
|
+
QR_STATUS_SELECTING = 6
|
|
26
|
+
QR_STATUS_EXPIRED = 5
|
|
27
|
+
QR_STATUS_CANCELLED = -1
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""Error definitions for WeChat MCP service."""
|
|
2
|
+
|
|
3
|
+
from enum import Enum
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ErrorCode(str, Enum):
|
|
8
|
+
UNKNOWN_ERROR = "UNKNOWN_ERROR"
|
|
9
|
+
INTERNAL_ERROR = "INTERNAL_ERROR"
|
|
10
|
+
BROWSER_START_FAILED = "BROWSER_START_FAILED"
|
|
11
|
+
NOT_LOGGED_IN = "NOT_LOGGED_IN"
|
|
12
|
+
LOGIN_FAILED = "LOGIN_FAILED"
|
|
13
|
+
LOGIN_TIMEOUT = "LOGIN_TIMEOUT"
|
|
14
|
+
QRCODE_NOT_FOUND = "QRCODE_NOT_FOUND"
|
|
15
|
+
API_ERROR = "API_ERROR"
|
|
16
|
+
RATE_LIMITED = "RATE_LIMITED"
|
|
17
|
+
INVALID_PARAMETER = "INVALID_PARAMETER"
|
|
18
|
+
ARTICLE_FETCH_FAILED = "ARTICLE_FETCH_FAILED"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class WechatMCPError(Exception):
|
|
22
|
+
def __init__(
|
|
23
|
+
self,
|
|
24
|
+
message: str,
|
|
25
|
+
code: ErrorCode = ErrorCode.UNKNOWN_ERROR,
|
|
26
|
+
details: Optional[dict] = None,
|
|
27
|
+
):
|
|
28
|
+
super().__init__(message)
|
|
29
|
+
self.message = message
|
|
30
|
+
self.code = code
|
|
31
|
+
self.details = details or {}
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class LoginError(WechatMCPError):
|
|
35
|
+
def __init__(self, message: str, code: ErrorCode = ErrorCode.LOGIN_FAILED, details: Optional[dict] = None):
|
|
36
|
+
super().__init__(message, code, details)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class ApiError(WechatMCPError):
|
|
40
|
+
def __init__(self, message: str, code: ErrorCode = ErrorCode.API_ERROR, details: Optional[dict] = None):
|
|
41
|
+
super().__init__(message, code, details)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# infrastructure package
|