redfox-mcp 0.1.0__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.
@@ -0,0 +1,6 @@
1
+ __pycache__/
2
+ *.pyc
3
+ .venv/
4
+ dist/
5
+ *.egg-info/
6
+ .DS_Store
@@ -0,0 +1,113 @@
1
+ Metadata-Version: 2.5
2
+ Name: redfox-mcp
3
+ Version: 0.1.0
4
+ Summary: RedFoxHub MCP server: Douyin/Xiaohongshu/WeChat/Bilibili/Toutiao/TikTok data APIs + AI search, image and video generation tools
5
+ Project-URL: Homepage, https://github.com/redfox-data/redfox-mcp
6
+ Project-URL: Website, https://redfox.hk/apis/?source=mcp
7
+ License-Expression: MIT
8
+ Keywords: bilibili,douyin,mcp,redfox,tiktok,toutiao,wechat,xiaohongshu
9
+ Requires-Python: >=3.10
10
+ Requires-Dist: cryptography<49; platform_machine == 'x86_64' and sys_platform == 'darwin'
11
+ Requires-Dist: fastmcp>=2.0
12
+ Requires-Dist: httpx>=0.24
13
+ Requires-Dist: redfox-python-sdk
14
+ Description-Content-Type: text/markdown
15
+
16
+ <p align="center">
17
+ <a href="https://redfox.hk/?source=github"><img src="https://lyy.redfox.hk/page/logo-redfox-name.png" alt="RedFox Logo" width="200"></a>
18
+ </p>
19
+
20
+ <p align="right">
21
+ <a href="https://github.com/redfox-data/redfox-mcp/blob/main/README.zh.md">中文</a>
22
+ English
23
+ </p>
24
+
25
+ # redfox-mcp
26
+
27
+ RedFoxHub MCP Server — turns the data APIs of 6 major content platforms plus AI search / generation capabilities into 40 MCP tools, ready for any MCP client such as dsh, Claude Code or Cursor.
28
+
29
+ ## Tools (40)
30
+
31
+ | Category | Tools | Notes |
32
+ |---|---|---|
33
+ | Douyin | `douyin_search_articles` / `douyin_search_users` / `douyin_get_user` / `douyin_get_user_works` / `douyin_get_work` / `douyin_search_ai_articles` | work search, account search, account info, work lists, work detail, AI-work feed |
34
+ | Xiaohongshu | `xiaohongshu_search_articles` / `xiaohongshu_search_users` / `xiaohongshu_get_account` / `xiaohongshu_get_work` / `xiaohongshu_search_ai_articles` | note search, creator search, account info, note detail, AI-note feed |
35
+ | WeChat Official Accounts | `wechat_search_articles` / `wechat_search_users` / `wechat_get_account` / `wechat_get_user_works` / `wechat_get_work` / `wechat_get_article_detail` / `wechat_search_ai_articles` | article search (incl. full-text detail), account search, article lists, AI-article feed |
36
+ | Bilibili | `bilibili_search_articles` / `bilibili_search_users` / `bilibili_get_account` / `bilibili_get_user_works` / `bilibili_get_work` | video search, UP-master search / info / videos, video detail |
37
+ | Toutiao | `toutiao_search_works` / `toutiao_get_work` | content search, work detail (realtime) |
38
+ | TikTok | `tiktok_search_users` | account search |
39
+ | AI search | `ai_search_kimi` / `ai_search_doubao` / `ai_search_deepseek` | one call submits the query and waits for the full answer |
40
+ | AI generation | `gpt_image_generate` / `doubao_image_pro_generate` / `doubao_image_lite_generate` / `doubao_video_generate` | text-to-image / image-to-image / image sets / text-to-video, one call submits and waits |
41
+ | Task follow-up | `ai_search_*_result` / `gpt_image_result` / `doubao_image_*_result` / `doubao_video_result` (7 in total) | when an async tool times out it returns a `taskId`; use the matching result tool to fetch the outcome |
42
+
43
+ Async tools (AI search / generation) poll internally: submit → wait → return the full result, with no manual `taskId` handling. If the wait exceeds `timeout_seconds` (default 240s, 480s for video), a `taskId` is returned for the matching result tool.
44
+
45
+ ## Authentication
46
+
47
+ All APIs require a RedFoxHub API key:
48
+
49
+ 1. Get one at <https://redfox.hk/settings/api-keys>
50
+ 2. Set the environment variable:
51
+
52
+ ```bash
53
+ export REDFOX_API_KEY="YOUR_API_KEY"
54
+ ```
55
+
56
+ Without a key, every tool returns a structured message explaining how to obtain one.
57
+
58
+ ## Install & Run
59
+
60
+ Python ≥ 3.10 required. Recommended via [uv](https://docs.astral.sh/uv/):
61
+
62
+ ```bash
63
+ uvx redfox-mcp
64
+ ```
65
+
66
+ or:
67
+
68
+ ```bash
69
+ pip install redfox-mcp
70
+ redfox-mcp
71
+ ```
72
+
73
+ The server runs on stdio transport.
74
+
75
+ ## Client Configuration
76
+
77
+ ### dsh (DeepSeek Harness)
78
+
79
+ Install the official bundle plugin [redfox-community-dsh](https://github.com/redfox-data/redfox-community-dsh) — it registers this MCP server out of the box, exposing tools as `mcp__redfox__*`:
80
+
81
+ ```bash
82
+ dsh plugin --profile web add -w github:redfox-data/redfox-community-dsh
83
+ ```
84
+
85
+ ### Claude Code
86
+
87
+ ```bash
88
+ claude mcp add redfox --env REDFOX_API_KEY=YOUR_API_KEY -- uvx redfox-mcp
89
+ ```
90
+
91
+ ### Cursor / other MCP clients
92
+
93
+ Add to your MCP configuration:
94
+
95
+ ```json
96
+ {
97
+ "mcpServers": {
98
+ "redfox": {
99
+ "command": "uvx",
100
+ "args": ["redfox-mcp"],
101
+ "env": { "REDFOX_API_KEY": "YOUR_API_KEY" }
102
+ }
103
+ }
104
+ }
105
+ ```
106
+
107
+ ## Under the Hood
108
+
109
+ Built on the official SDK [redfox-python-sdk](https://github.com/redfox-data/redfox-python-sdk). API docs: <https://redfox.hk>.
110
+
111
+ ## License
112
+
113
+ MIT
@@ -0,0 +1,98 @@
1
+ <p align="center">
2
+ <a href="https://redfox.hk/?source=github"><img src="https://lyy.redfox.hk/page/logo-redfox-name.png" alt="RedFox Logo" width="200"></a>
3
+ </p>
4
+
5
+ <p align="right">
6
+ <a href="https://github.com/redfox-data/redfox-mcp/blob/main/README.zh.md">中文</a>
7
+ English
8
+ </p>
9
+
10
+ # redfox-mcp
11
+
12
+ RedFoxHub MCP Server — turns the data APIs of 6 major content platforms plus AI search / generation capabilities into 40 MCP tools, ready for any MCP client such as dsh, Claude Code or Cursor.
13
+
14
+ ## Tools (40)
15
+
16
+ | Category | Tools | Notes |
17
+ |---|---|---|
18
+ | Douyin | `douyin_search_articles` / `douyin_search_users` / `douyin_get_user` / `douyin_get_user_works` / `douyin_get_work` / `douyin_search_ai_articles` | work search, account search, account info, work lists, work detail, AI-work feed |
19
+ | Xiaohongshu | `xiaohongshu_search_articles` / `xiaohongshu_search_users` / `xiaohongshu_get_account` / `xiaohongshu_get_work` / `xiaohongshu_search_ai_articles` | note search, creator search, account info, note detail, AI-note feed |
20
+ | WeChat Official Accounts | `wechat_search_articles` / `wechat_search_users` / `wechat_get_account` / `wechat_get_user_works` / `wechat_get_work` / `wechat_get_article_detail` / `wechat_search_ai_articles` | article search (incl. full-text detail), account search, article lists, AI-article feed |
21
+ | Bilibili | `bilibili_search_articles` / `bilibili_search_users` / `bilibili_get_account` / `bilibili_get_user_works` / `bilibili_get_work` | video search, UP-master search / info / videos, video detail |
22
+ | Toutiao | `toutiao_search_works` / `toutiao_get_work` | content search, work detail (realtime) |
23
+ | TikTok | `tiktok_search_users` | account search |
24
+ | AI search | `ai_search_kimi` / `ai_search_doubao` / `ai_search_deepseek` | one call submits the query and waits for the full answer |
25
+ | AI generation | `gpt_image_generate` / `doubao_image_pro_generate` / `doubao_image_lite_generate` / `doubao_video_generate` | text-to-image / image-to-image / image sets / text-to-video, one call submits and waits |
26
+ | Task follow-up | `ai_search_*_result` / `gpt_image_result` / `doubao_image_*_result` / `doubao_video_result` (7 in total) | when an async tool times out it returns a `taskId`; use the matching result tool to fetch the outcome |
27
+
28
+ Async tools (AI search / generation) poll internally: submit → wait → return the full result, with no manual `taskId` handling. If the wait exceeds `timeout_seconds` (default 240s, 480s for video), a `taskId` is returned for the matching result tool.
29
+
30
+ ## Authentication
31
+
32
+ All APIs require a RedFoxHub API key:
33
+
34
+ 1. Get one at <https://redfox.hk/settings/api-keys>
35
+ 2. Set the environment variable:
36
+
37
+ ```bash
38
+ export REDFOX_API_KEY="YOUR_API_KEY"
39
+ ```
40
+
41
+ Without a key, every tool returns a structured message explaining how to obtain one.
42
+
43
+ ## Install & Run
44
+
45
+ Python ≥ 3.10 required. Recommended via [uv](https://docs.astral.sh/uv/):
46
+
47
+ ```bash
48
+ uvx redfox-mcp
49
+ ```
50
+
51
+ or:
52
+
53
+ ```bash
54
+ pip install redfox-mcp
55
+ redfox-mcp
56
+ ```
57
+
58
+ The server runs on stdio transport.
59
+
60
+ ## Client Configuration
61
+
62
+ ### dsh (DeepSeek Harness)
63
+
64
+ Install the official bundle plugin [redfox-community-dsh](https://github.com/redfox-data/redfox-community-dsh) — it registers this MCP server out of the box, exposing tools as `mcp__redfox__*`:
65
+
66
+ ```bash
67
+ dsh plugin --profile web add -w github:redfox-data/redfox-community-dsh
68
+ ```
69
+
70
+ ### Claude Code
71
+
72
+ ```bash
73
+ claude mcp add redfox --env REDFOX_API_KEY=YOUR_API_KEY -- uvx redfox-mcp
74
+ ```
75
+
76
+ ### Cursor / other MCP clients
77
+
78
+ Add to your MCP configuration:
79
+
80
+ ```json
81
+ {
82
+ "mcpServers": {
83
+ "redfox": {
84
+ "command": "uvx",
85
+ "args": ["redfox-mcp"],
86
+ "env": { "REDFOX_API_KEY": "YOUR_API_KEY" }
87
+ }
88
+ }
89
+ }
90
+ ```
91
+
92
+ ## Under the Hood
93
+
94
+ Built on the official SDK [redfox-python-sdk](https://github.com/redfox-data/redfox-python-sdk). API docs: <https://redfox.hk>.
95
+
96
+ ## License
97
+
98
+ MIT
@@ -0,0 +1,32 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "redfox-mcp"
7
+ version = "0.1.0"
8
+ description = "RedFoxHub MCP server: Douyin/Xiaohongshu/WeChat/Bilibili/Toutiao/TikTok data APIs + AI search, image and video generation tools"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = "MIT"
12
+ keywords = ["mcp", "redfox", "douyin", "xiaohongshu", "wechat", "bilibili", "toutiao", "tiktok"]
13
+ dependencies = [
14
+ "fastmcp>=2.0",
15
+ # Intel Mac 上 cryptography 49+ 无预编译 wheel 会触发源码构建,钉住 48.x
16
+ "cryptography<49; platform_machine == 'x86_64' and sys_platform == 'darwin'",
17
+ "redfox-python-sdk",
18
+ "httpx>=0.24",
19
+ ]
20
+
21
+ [project.urls]
22
+ Homepage = "https://github.com/redfox-data/redfox-mcp"
23
+ Website = "https://redfox.hk/apis/?source=mcp"
24
+
25
+ [project.scripts]
26
+ redfox-mcp = "redfox_mcp.server:main"
27
+
28
+ [tool.hatch.build.targets.wheel]
29
+ packages = ["src/redfox_mcp"]
30
+
31
+ [tool.hatch.build.targets.sdist]
32
+ include = ["src/redfox_mcp", "README.md"]
@@ -0,0 +1,3 @@
1
+ """RedFox MCP Server — 红狐数据平台 MCP 工具服务"""
2
+
3
+ __version__ = "0.1.0"
@@ -0,0 +1,6 @@
1
+ """支持 python -m redfox_mcp 启动"""
2
+
3
+ from redfox_mcp.server import main
4
+
5
+ if __name__ == "__main__":
6
+ main()
@@ -0,0 +1,520 @@
1
+ """RedFox MCP Server
2
+
3
+ 将 RedFoxHub(红狐数据平台)的 40 个 API 能力暴露为 MCP 工具:
4
+ - 6 大内容平台数据查询(抖音/小红书/公众号/B站/头条/TikTok,26 个同步工具)
5
+ - AI 搜索(Kimi/豆包/Deepseek,3 个自动轮询工具 + 3 个结果查询工具)
6
+ - AI 生成(GPT 图片/豆包图片 Pro/Lite/豆包视频,4 个自动轮询工具 + 4 个结果查询工具)
7
+
8
+ 认证:环境变量 REDFOX_API_KEY(获取地址 https://redfox.hk/settings/api-keys?source=mcp)
9
+ """
10
+
11
+ import time
12
+ from typing import Any, Dict, List, Optional
13
+
14
+ from fastmcp import FastMCP
15
+ from redfox import RedFoxClient
16
+ from redfox.exceptions import RedFoxAPIError, RedFoxAuthError, RedFoxRateLimitError
17
+
18
+ mcp = FastMCP("redfox")
19
+
20
+ API_KEY_GUIDE = (
21
+ "REDFOX_API_KEY 未配置或无效。请前往 "
22
+ "https://redfox.hk/settings/api-keys?source=mcp 注册并获取 API Key,"
23
+ "然后设置环境变量 REDFOX_API_KEY 后重启本服务。"
24
+ )
25
+
26
+ TASK_PENDING_MSG = (
27
+ "任务仍在进行中,已超过本次等待时间。"
28
+ "请稍后使用对应的 result 工具并传入此 taskId 查询结果。"
29
+ )
30
+
31
+ TERMINAL_STATUSES = {
32
+ "succeeded", "success", "completed", "complete", "done",
33
+ "failed", "error", "cancelled", "canceled",
34
+ }
35
+
36
+ _client: Optional[RedFoxClient] = None
37
+
38
+
39
+ def _get_client() -> RedFoxClient:
40
+ global _client
41
+ if _client is None:
42
+ _client = RedFoxClient() # 零配置:自动读环境变量 REDFOX_API_KEY
43
+ return _client
44
+
45
+
46
+ def _call(fn_factory, **kwargs) -> Dict[str, Any]:
47
+ """统一调用 SDK 方法并把异常转为结构化结果,agent 可直接读取出错引导"""
48
+ try:
49
+ return fn_factory()(**{k: v for k, v in kwargs.items() if v is not None})
50
+ except (RedFoxAuthError, ValueError):
51
+ return {"error": "auth_failed", "message": API_KEY_GUIDE}
52
+ except RedFoxRateLimitError:
53
+ return {"error": "rate_limited", "message": "请求频率超限,请稍后重试"}
54
+ except RedFoxAPIError as e:
55
+ return {"error": "api_error", "code": e.code, "message": e.message}
56
+
57
+
58
+ def _is_done(res: Any) -> bool:
59
+ """判断异步任务是否到达终态(兼容各品类不同的响应结构)"""
60
+ if not isinstance(res, dict):
61
+ return True
62
+ if res.get("error"):
63
+ return True
64
+ if res.get("completed") is True:
65
+ return True
66
+ status = res.get("status")
67
+ if isinstance(status, str) and status.lower() in TERMINAL_STATUSES:
68
+ return True
69
+ for field in ("content", "imagePaths", "images", "videoUrl", "videoUrls", "video"):
70
+ if res.get(field):
71
+ return True
72
+ return False
73
+
74
+
75
+ def _poll(result_fn, task_id: str, timeout_seconds: int, interval: float = 3.0) -> Dict[str, Any]:
76
+ deadline = time.monotonic() + timeout_seconds
77
+ while True:
78
+ res = _call(result_fn, task_id=task_id)
79
+ if _is_done(res):
80
+ return res
81
+ if time.monotonic() >= deadline:
82
+ return {"completed": False, "taskId": task_id, "message": TASK_PENDING_MSG}
83
+ time.sleep(interval)
84
+
85
+
86
+ def _run_task(submit_fn, result_fn, timeout_seconds: int, **kwargs) -> Dict[str, Any]:
87
+ """提交异步任务并自动轮询至完成;超时则返回 taskId 供 result 工具后续查询"""
88
+ submitted = _call(submit_fn, **kwargs)
89
+ if not isinstance(submitted, dict) or submitted.get("error"):
90
+ return submitted
91
+ task_id = submitted.get("taskId") or submitted.get("task_id")
92
+ if not task_id:
93
+ return submitted
94
+ return _poll(result_fn, task_id, timeout_seconds)
95
+
96
+
97
+ # ─── 抖音 ────────────────────────────────────────────────
98
+
99
+
100
+ @mcp.tool()
101
+ def douyin_search_articles(keyword: str, offset: int = 0,
102
+ sort_type: Optional[str] = None) -> Dict[str, Any]:
103
+ """搜索抖音作品(优质库)。keyword 必填;offset 分页偏移从 0 开始、每次 +20;
104
+ sort_type 排序方式,如 "default"。返回含 total/hasMore/list。"""
105
+ return _call(lambda: _get_client().douyin.search_articles,
106
+ keyword=keyword, offset=offset, sort_type=sort_type)
107
+
108
+
109
+ @mcp.tool()
110
+ def douyin_search_users(keyword: str, offset: int = 0,
111
+ sort_type: Optional[str] = None) -> Dict[str, Any]:
112
+ """搜索抖音账号(优质库)。keyword 必填;offset 分页偏移从 0 开始。"""
113
+ return _call(lambda: _get_client().douyin.search_users,
114
+ keyword=keyword, offset=offset, sort_type=sort_type)
115
+
116
+
117
+ @mcp.tool()
118
+ def douyin_get_user(account_id: str) -> Dict[str, Any]:
119
+ """获取抖音账号信息(优质库)。account_id 为抖音账号 ID,
120
+ 支持 unique_id、short_id、uid 任一匹配。"""
121
+ return _call(lambda: _get_client().douyin.get_user, account_id=account_id)
122
+
123
+
124
+ @mcp.tool()
125
+ def douyin_get_user_works(account_id: Optional[str] = None,
126
+ author_url: Optional[str] = None,
127
+ sec_user_id: Optional[str] = None,
128
+ offset: int = 0,
129
+ sort_type: Optional[str] = None) -> Dict[str, Any]:
130
+ """获取抖音账号作品列表(优质库)。account_id(抖音号)/ author_url(主页链接)/
131
+ sec_user_id 至少传一个;offset 每页 +20;sort_type:0=默认,2=最新,4=最热。"""
132
+ return _call(lambda: _get_client().douyin.get_user_works,
133
+ account_id=account_id, author_url=author_url,
134
+ sec_user_id=sec_user_id, offset=offset, sort_type=sort_type)
135
+
136
+
137
+ @mcp.tool()
138
+ def douyin_get_work(work_id: Optional[str] = None,
139
+ work_url: Optional[str] = None) -> Dict[str, Any]:
140
+ """获取抖音作品详情(优质库)。work_id 与 work_url(作品链接)至少传一个,
141
+ 返回互动数据、作者信息等。"""
142
+ return _call(lambda: _get_client().douyin.get_work, work_id=work_id, work_url=work_url)
143
+
144
+
145
+ @mcp.tool()
146
+ def douyin_search_ai_articles(keyword: str, page_num: int = 1, page_size: int = 20,
147
+ start_time: Optional[str] = None,
148
+ end_time: Optional[str] = None) -> Dict[str, Any]:
149
+ """搜索抖音 AI 相关作品(优质库)。keyword 必填;
150
+ start_time/end_time 格式如 "2026-06-01 00:00:00"。"""
151
+ return _call(lambda: _get_client().douyin.search_ai_articles,
152
+ keyword=keyword, page_num=page_num, page_size=page_size,
153
+ start_time=start_time, end_time=end_time)
154
+
155
+
156
+ # ─── 小红书 ──────────────────────────────────────────────
157
+
158
+
159
+ @mcp.tool()
160
+ def xiaohongshu_search_articles(keyword: str, offset: int = 0,
161
+ sort_type: Optional[str] = None) -> Dict[str, Any]:
162
+ """搜索小红书笔记(优质库)。keyword 必填;offset 分页偏移。"""
163
+ return _call(lambda: _get_client().xiaohongshu.search_articles,
164
+ keyword=keyword, offset=offset, sort_type=sort_type)
165
+
166
+
167
+ @mcp.tool()
168
+ def xiaohongshu_search_users(keyword: str, offset: int = 0,
169
+ sort_type: Optional[str] = None) -> Dict[str, Any]:
170
+ """搜索小红书博主账号(优质库)。keyword 必填;offset 分页偏移。"""
171
+ return _call(lambda: _get_client().xiaohongshu.search_users,
172
+ keyword=keyword, offset=offset, sort_type=sort_type)
173
+
174
+
175
+ @mcp.tool()
176
+ def xiaohongshu_get_account(account_id: str,
177
+ user_id: Optional[str] = None) -> Dict[str, Any]:
178
+ """获取小红书账号信息(优质库)。account_id 为小红书号(必填),user_id 可选。"""
179
+ return _call(lambda: _get_client().xiaohongshu.get_account,
180
+ account_id=account_id, user_id=user_id)
181
+
182
+
183
+ @mcp.tool()
184
+ def xiaohongshu_get_work(work_id: Optional[str] = None,
185
+ work_link: Optional[str] = None) -> Dict[str, Any]:
186
+ """获取小红书笔记详情(优质库)。work_id 与 work_link(笔记链接)至少传一个。"""
187
+ return _call(lambda: _get_client().xiaohongshu.get_work,
188
+ work_id=work_id, work_link=work_link)
189
+
190
+
191
+ @mcp.tool()
192
+ def xiaohongshu_search_ai_articles(keyword: str, page_num: int = 1,
193
+ page_size: int = 20,
194
+ start_time: Optional[str] = None,
195
+ end_time: Optional[str] = None,
196
+ source: Optional[str] = None) -> Dict[str, Any]:
197
+ """搜索小红书 AI 创作相关笔记(优质库)。keyword 必填;
198
+ start_time/end_time 格式如 "2026-06-01 00:00:00";source 为来源平台(可选)。"""
199
+ return _call(lambda: _get_client().xiaohongshu.search_ai_articles,
200
+ keyword=keyword, page_num=page_num, page_size=page_size,
201
+ start_time=start_time, end_time=end_time, source=source)
202
+
203
+
204
+ # ─── 公众号 ──────────────────────────────────────────────
205
+
206
+
207
+ @mcp.tool()
208
+ def wechat_search_articles(keyword: str, offset: int = 0,
209
+ sort_type: Optional[str] = None) -> Dict[str, Any]:
210
+ """搜索公众号文章(优质库)。keyword 必填;offset 从 0 开始、每页 +20。"""
211
+ return _call(lambda: _get_client().wechat.search_articles,
212
+ keyword=keyword, offset=offset, sort_type=sort_type)
213
+
214
+
215
+ @mcp.tool()
216
+ def wechat_search_users(keyword: str, offset: int = 0,
217
+ sort_type: Optional[str] = None) -> Dict[str, Any]:
218
+ """搜索公众号账号(优质库)。keyword 必填;sort_type:_0=默认,_2=最新,_4=最热。"""
219
+ return _call(lambda: _get_client().wechat.search_users,
220
+ keyword=keyword, offset=offset, sort_type=sort_type)
221
+
222
+
223
+ @mcp.tool()
224
+ def wechat_get_account(account: str,
225
+ account_name: Optional[str] = None) -> Dict[str, Any]:
226
+ """获取公众号账号信息(优质库)。account 为公众号微信号(必填),
227
+ account_name 为公众号名称(可选)。"""
228
+ return _call(lambda: _get_client().wechat.get_account,
229
+ account=account, account_name=account_name)
230
+
231
+
232
+ @mcp.tool()
233
+ def wechat_get_user_works(account: str, account_name: Optional[str] = None,
234
+ offset: int = 0, sort_type: Optional[str] = None,
235
+ publish_time_start: Optional[str] = None,
236
+ publish_time_end: Optional[str] = None) -> Dict[str, Any]:
237
+ """获取公众号文章列表(优质库)。account 为公众号微信号(必填);
238
+ sort_type:_0=默认,_2=最新,_4=最热;publish_time_start/end 格式如 "2026-07-01"。"""
239
+ return _call(lambda: _get_client().wechat.get_user_works,
240
+ account=account, account_name=account_name, offset=offset,
241
+ sort_type=sort_type, publish_time_start=publish_time_start,
242
+ publish_time_end=publish_time_end)
243
+
244
+
245
+ @mcp.tool()
246
+ def wechat_get_work(work_uuid: str) -> Dict[str, Any]:
247
+ """根据作品 UUID 获取公众号文章元数据(优质库)。"""
248
+ return _call(lambda: _get_client().wechat.get_work, work_uuid=work_uuid)
249
+
250
+
251
+ @mcp.tool()
252
+ def wechat_get_article_detail(url: str) -> Dict[str, Any]:
253
+ """根据文章链接获取公众号文章详情,支持全文内容(优质库)。
254
+ url 形如 https://mp.weixin.qq.com/s/..."""
255
+ return _call(lambda: _get_client().wechat.get_article_detail, url=url)
256
+
257
+
258
+ @mcp.tool()
259
+ def wechat_search_ai_articles(keyword: str, page_num: int = 1, page_size: int = 20,
260
+ start_time: Optional[str] = None,
261
+ end_time: Optional[str] = None) -> Dict[str, Any]:
262
+ """搜索公众号 AI 创作相关文章(优质库)。keyword 必填;
263
+ start_time/end_time 格式如 "2026-06-01 00:00:00"。"""
264
+ return _call(lambda: _get_client().wechat.search_ai_articles,
265
+ keyword=keyword, page_num=page_num, page_size=page_size,
266
+ start_time=start_time, end_time=end_time)
267
+
268
+
269
+ # ─── B 站 ────────────────────────────────────────────────
270
+
271
+
272
+ @mcp.tool()
273
+ def bilibili_search_articles(keyword: str, page: int = 1,
274
+ page_size: Optional[int] = None,
275
+ order: Optional[str] = None) -> Dict[str, Any]:
276
+ """搜索 B 站视频(优质库)。keyword 必填;page 从 1 开始;page_size 默认 10、最大 50;
277
+ order:time=发布时间 / play=播放数 / like=点赞数 / comment=评论数 / favorite=收藏数。"""
278
+ return _call(lambda: _get_client().bilibili.search_articles,
279
+ keyword=keyword, page=page, page_size=page_size, order=order)
280
+
281
+
282
+ @mcp.tool()
283
+ def bilibili_search_users(keyword: str, page: int = 1,
284
+ page_size: Optional[int] = None,
285
+ order: Optional[str] = None) -> Dict[str, Any]:
286
+ """搜索 B 站 UP 主(优质库)。keyword 必填;
287
+ order:follower=粉丝数 / like=获赞数,默认按相关性。"""
288
+ return _call(lambda: _get_client().bilibili.search_users,
289
+ keyword=keyword, page=page, page_size=page_size, order=order)
290
+
291
+
292
+ @mcp.tool()
293
+ def bilibili_get_account(mid: str) -> Dict[str, Any]:
294
+ """获取 B 站 UP 主信息(优质库)。mid 为 B 站用户唯一 ID。"""
295
+ return _call(lambda: _get_client().bilibili.get_account, mid=mid)
296
+
297
+
298
+ @mcp.tool()
299
+ def bilibili_get_user_works(mid: Optional[str] = None,
300
+ account_url: Optional[str] = None, page: int = 1,
301
+ page_size: Optional[int] = None,
302
+ order: Optional[str] = None) -> Dict[str, Any]:
303
+ """获取 B 站 UP 主视频列表(优质库)。mid 与 account_url(主页链接)至少传一个;
304
+ order:time=发布时间 / play=播放数 / like=点赞数。"""
305
+ return _call(lambda: _get_client().bilibili.get_user_works,
306
+ mid=mid, account_url=account_url, page=page,
307
+ page_size=page_size, order=order)
308
+
309
+
310
+ @mcp.tool()
311
+ def bilibili_get_work(bvid: Optional[str] = None,
312
+ work_url: Optional[str] = None) -> Dict[str, Any]:
313
+ """获取 B 站视频详情(优质库)。bvid 与 work_url 至少传一个,
314
+ work_url 支持 bilibili.com/video/BVxxx 或 b23.tv 短链。"""
315
+ return _call(lambda: _get_client().bilibili.get_work, bvid=bvid, work_url=work_url)
316
+
317
+
318
+ # ─── 今日头条 ────────────────────────────────────────────
319
+
320
+
321
+ @mcp.tool()
322
+ def toutiao_search_works(keyword: str, offset: int = 0) -> Dict[str, Any]:
323
+ """搜索今日头条内容(实时)。keyword 必填;offset 翻页偏移从 0 开始、每页 +1。"""
324
+ return _call(lambda: _get_client().toutiao.search_works, keyword=keyword, offset=offset)
325
+
326
+
327
+ @mcp.tool()
328
+ def toutiao_get_work(opus_id: str) -> Dict[str, Any]:
329
+ """获取今日头条作品详情(实时)。opus_id 为作品 ID。"""
330
+ return _call(lambda: _get_client().toutiao.get_work, opus_id=opus_id)
331
+
332
+
333
+ # ─── TikTok ──────────────────────────────────────────────
334
+
335
+
336
+ @mcp.tool()
337
+ def tiktok_search_users(keyword: str, cursor: int = 0,
338
+ rid: Optional[str] = None) -> Dict[str, Any]:
339
+ """搜索 TikTok 账号。keyword 必填;cursor 翻页游标第一页为 0、每页 +10;
340
+ rid 为上一页数据返回的 rid,翻页时传入。返回含 cursor/hasMore/userList。"""
341
+ return _call(lambda: _get_client().tiktok.search_users,
342
+ keyword=keyword, cursor=cursor, rid=rid)
343
+
344
+
345
+ # ─── AI 搜索(自动轮询)──────────────────────────────────
346
+
347
+
348
+ @mcp.tool()
349
+ def ai_search_kimi(inquiry_text: str, timeout_seconds: int = 240) -> Dict[str, Any]:
350
+ """Kimi 联网 AI 搜索,提交后自动等待并返回完整结果(含 content/webPages)。
351
+ inquiry_text 为搜索提问文本;超时未完成时返回 taskId,可用 ai_search_kimi_result 再查。"""
352
+ return _run_task(lambda: _get_client().ai_search.kimi_submit,
353
+ lambda: _get_client().ai_search.kimi_result,
354
+ timeout_seconds, inquiry_text=inquiry_text)
355
+
356
+
357
+ @mcp.tool()
358
+ def ai_search_doubao(inquiry_text: str, timeout_seconds: int = 240) -> Dict[str, Any]:
359
+ """豆包联网 AI 搜索,提交后自动等待并返回完整结果。
360
+ inquiry_text 为搜索提问文本;超时未完成时返回 taskId,可用 ai_search_doubao_result 再查。"""
361
+ return _run_task(lambda: _get_client().ai_search.doubao_submit,
362
+ lambda: _get_client().ai_search.doubao_result,
363
+ timeout_seconds, inquiry_text=inquiry_text)
364
+
365
+
366
+ @mcp.tool()
367
+ def ai_search_deepseek(inquiry_text: str, timeout_seconds: int = 240) -> Dict[str, Any]:
368
+ """Deepseek 联网 AI 搜索,提交后自动等待并返回完整结果。
369
+ inquiry_text 为搜索提问文本;超时未完成时返回 taskId,可用 ai_search_deepseek_result 再查。"""
370
+ return _run_task(lambda: _get_client().ai_search.deepseek_submit,
371
+ lambda: _get_client().ai_search.deepseek_result,
372
+ timeout_seconds, inquiry_text=inquiry_text)
373
+
374
+
375
+ @mcp.tool()
376
+ def ai_search_kimi_result(task_id: str) -> Dict[str, Any]:
377
+ """查询 Kimi 搜索任务结果。仅在 ai_search_kimi 超时返回 taskId 后使用。"""
378
+ return _call(lambda: _get_client().ai_search.kimi_result, task_id=task_id)
379
+
380
+
381
+ @mcp.tool()
382
+ def ai_search_doubao_result(task_id: str) -> Dict[str, Any]:
383
+ """查询豆包搜索任务结果。仅在 ai_search_doubao 超时返回 taskId 后使用。"""
384
+ return _call(lambda: _get_client().ai_search.doubao_result, task_id=task_id)
385
+
386
+
387
+ @mcp.tool()
388
+ def ai_search_deepseek_result(task_id: str) -> Dict[str, Any]:
389
+ """查询 Deepseek 搜索任务结果。仅在 ai_search_deepseek 超时返回 taskId 后使用。"""
390
+ return _call(lambda: _get_client().ai_search.deepseek_result, task_id=task_id)
391
+
392
+
393
+ # ─── AI 生成(自动轮询)──────────────────────────────────
394
+
395
+
396
+ @mcp.tool()
397
+ def gpt_image_generate(prompt: str, n: int = 1, size: str = "1024x1024",
398
+ quality: str = "medium", background: str = "auto",
399
+ output_format: str = "png",
400
+ output_compression: Optional[int] = None,
401
+ model_name: str = "gpt-image-2",
402
+ operation: str = "generate",
403
+ input_fidelity: Optional[str] = None,
404
+ images: Optional[List[Dict[str, str]]] = None,
405
+ timeout_seconds: int = 240) -> Dict[str, Any]:
406
+ """GPT 图片生成(gpt-image-2),提交后自动等待并返回 imagePaths。
407
+ operation:generate=文生图 / edit=图生图(edit 时 images 必填,
408
+ 形如 [{"url": "https://..."}],input_fidelity 支持 high/low);
409
+ quality:low/medium/high/auto;background:transparent/opaque/auto;
410
+ output_format:png/jpeg/webp。超时返回 taskId,可用 gpt_image_result 再查。"""
411
+ return _run_task(lambda: _get_client().gpt_image.submit,
412
+ lambda: _get_client().gpt_image.result,
413
+ timeout_seconds, prompt=prompt, n=n, size=size, quality=quality,
414
+ background=background, output_format=output_format,
415
+ output_compression=output_compression, model_name=model_name,
416
+ operation=operation, input_fidelity=input_fidelity, images=images)
417
+
418
+
419
+ @mcp.tool()
420
+ def gpt_image_result(task_id: str) -> Dict[str, Any]:
421
+ """查询 GPT 图片生成任务结果(含 status/imagePaths/failReason)。
422
+ 仅在 gpt_image_generate 超时返回 taskId 后使用。"""
423
+ return _call(lambda: _get_client().gpt_image.result, task_id=task_id)
424
+
425
+
426
+ @mcp.tool()
427
+ def doubao_image_pro_generate(prompt: str, size: str = "2048x2048",
428
+ image: Optional[Any] = None,
429
+ output_format: str = "jpeg",
430
+ response_format: str = "url",
431
+ watermark: bool = True,
432
+ optimize_prompt: bool = False,
433
+ optimize_mode: str = "standard",
434
+ timeout_seconds: int = 240) -> Dict[str, Any]:
435
+ """豆包 Seedream 5.0 Pro 图片生成,提交后自动等待结果。
436
+ size 支持 "1K"/"2K" 或像素值如 "2048x2048";image 为图生图输入(URL 或 Base64,
437
+ 可传单个字符串或字符串列表);optimize_prompt 开启提示词优化(standard/fast)。
438
+ 超时返回 taskId,可用 doubao_image_pro_result 再查。"""
439
+ return _run_task(lambda: _get_client().doubao_image.pro_submit,
440
+ lambda: _get_client().doubao_image.pro_result,
441
+ timeout_seconds, prompt=prompt, size=size, image=image,
442
+ output_format=output_format, response_format=response_format,
443
+ watermark=watermark, optimize_prompt=optimize_prompt,
444
+ optimize_mode=optimize_mode)
445
+
446
+
447
+ @mcp.tool()
448
+ def doubao_image_pro_result(task_id: str) -> Dict[str, Any]:
449
+ """查询 Seedream 5.0 Pro 任务结果。仅在 doubao_image_pro_generate 超时返回 taskId 后使用。"""
450
+ return _call(lambda: _get_client().doubao_image.pro_result, task_id=task_id)
451
+
452
+
453
+ @mcp.tool()
454
+ def doubao_image_lite_generate(prompt: str, size: str = "2048x2048",
455
+ image: Optional[Any] = None,
456
+ output_format: str = "jpeg",
457
+ response_format: str = "url",
458
+ watermark: bool = True,
459
+ sequential: str = "disabled",
460
+ max_images: int = 4,
461
+ optimize_prompt: bool = False,
462
+ optimize_mode: str = "standard",
463
+ timeout_seconds: int = 240) -> Dict[str, Any]:
464
+ """豆包 Seedream 5.0 Lite 图片生成,支持组图,提交后自动等待结果。
465
+ size 支持 "2K"/"3K"/"4K" 或像素值;sequential 设为 "auto" 时生成组图,
466
+ max_images 控制组图数量(1~10)。超时返回 taskId,可用 doubao_image_lite_result 再查。"""
467
+ return _run_task(lambda: _get_client().doubao_image.lite_submit,
468
+ lambda: _get_client().doubao_image.lite_result,
469
+ timeout_seconds, prompt=prompt, size=size, image=image,
470
+ output_format=output_format, response_format=response_format,
471
+ watermark=watermark, sequential=sequential, max_images=max_images,
472
+ optimize_prompt=optimize_prompt, optimize_mode=optimize_mode)
473
+
474
+
475
+ @mcp.tool()
476
+ def doubao_image_lite_result(task_id: str) -> Dict[str, Any]:
477
+ """查询 Seedream 5.0 Lite 任务结果。仅在 doubao_image_lite_generate 超时返回 taskId 后使用。"""
478
+ return _call(lambda: _get_client().doubao_image.lite_result, task_id=task_id)
479
+
480
+
481
+ @mcp.tool()
482
+ def doubao_video_generate(content: List[Dict[str, Any]],
483
+ model: Optional[str] = None,
484
+ resolution: str = "720p",
485
+ ratio: str = "adaptive",
486
+ duration: int = 5,
487
+ seed: int = -1,
488
+ watermark: bool = False,
489
+ generate_audio: bool = True,
490
+ return_last_frame: bool = False,
491
+ timeout_seconds: int = 480) -> Dict[str, Any]:
492
+ """豆包 Seedance 2.0 视频生成,提交后自动等待结果。
493
+ content 为输入内容列表(必填),每项形如:
494
+ {"type": "text", "text": "描述文字"};
495
+ {"type": "image_url", "imageUrl": "图片URL", "imageRole": "first_frame/reference_image"};
496
+ {"type": "video_url", "videoUrl": "视频URL", "videoRole": "reference_video"};
497
+ {"type": "audio_url", "audioUrl": "音频URL", "audioRole": "reference_audio"}。
498
+ resolution:480p/720p/1080p;ratio:adaptive/16:9/4:3/1:1/3:4/9:16/21:9;
499
+ duration 秒数 [4,15] 或 -1 智能。超时返回 taskId,可用 doubao_video_result 再查。"""
500
+ return _run_task(lambda: _get_client().doubao_video.submit,
501
+ lambda: _get_client().doubao_video.result,
502
+ timeout_seconds, content=content, model=model,
503
+ resolution=resolution, ratio=ratio, duration=duration,
504
+ seed=seed, watermark=watermark, generate_audio=generate_audio,
505
+ return_last_frame=return_last_frame)
506
+
507
+
508
+ @mcp.tool()
509
+ def doubao_video_result(task_id: str) -> Dict[str, Any]:
510
+ """查询豆包视频生成任务结果。仅在 doubao_video_generate 超时返回 taskId 后使用。"""
511
+ return _call(lambda: _get_client().doubao_video.result, task_id=task_id)
512
+
513
+
514
+ def main() -> None:
515
+ """以 stdio transport 启动 MCP server"""
516
+ mcp.run()
517
+
518
+
519
+ if __name__ == "__main__":
520
+ main()