belindoc-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.
Files changed (36) hide show
  1. belindoc_mcp-0.1.0/PKG-INFO +296 -0
  2. belindoc_mcp-0.1.0/README.md +270 -0
  3. belindoc_mcp-0.1.0/pyproject.toml +64 -0
  4. belindoc_mcp-0.1.0/setup.cfg +4 -0
  5. belindoc_mcp-0.1.0/src/belindoc_mcp.egg-info/PKG-INFO +296 -0
  6. belindoc_mcp-0.1.0/src/belindoc_mcp.egg-info/SOURCES.txt +34 -0
  7. belindoc_mcp-0.1.0/src/belindoc_mcp.egg-info/dependency_links.txt +1 -0
  8. belindoc_mcp-0.1.0/src/belindoc_mcp.egg-info/entry_points.txt +4 -0
  9. belindoc_mcp-0.1.0/src/belindoc_mcp.egg-info/requires.txt +9 -0
  10. belindoc_mcp-0.1.0/src/belindoc_mcp.egg-info/top_level.txt +1 -0
  11. belindoc_mcp-0.1.0/src/trans_mcp/__init__.py +3 -0
  12. belindoc_mcp-0.1.0/src/trans_mcp/client.py +2699 -0
  13. belindoc_mcp-0.1.0/src/trans_mcp/http_server.py +257 -0
  14. belindoc_mcp-0.1.0/src/trans_mcp/i18n.py +926 -0
  15. belindoc_mcp-0.1.0/src/trans_mcp/server.py +53 -0
  16. belindoc_mcp-0.1.0/src/trans_mcp/tools.py +1548 -0
  17. belindoc_mcp-0.1.0/tests/test_account_quota.py +130 -0
  18. belindoc_mcp-0.1.0/tests/test_base_url.py +58 -0
  19. belindoc_mcp-0.1.0/tests/test_client.py +109 -0
  20. belindoc_mcp-0.1.0/tests/test_doc_layouts.py +216 -0
  21. belindoc_mcp-0.1.0/tests/test_http_pool.py +102 -0
  22. belindoc_mcp-0.1.0/tests/test_http_streamable.py +200 -0
  23. belindoc_mcp-0.1.0/tests/test_i18n.py +111 -0
  24. belindoc_mcp-0.1.0/tests/test_key_errors.py +173 -0
  25. belindoc_mcp-0.1.0/tests/test_model_list.py +111 -0
  26. belindoc_mcp-0.1.0/tests/test_ocr_detect.py +351 -0
  27. belindoc_mcp-0.1.0/tests/test_order_family.py +103 -0
  28. belindoc_mcp-0.1.0/tests/test_rewrite_and_limits.py +123 -0
  29. belindoc_mcp-0.1.0/tests/test_rewrite_confirm.py +104 -0
  30. belindoc_mcp-0.1.0/tests/test_submit_confirm.py +269 -0
  31. belindoc_mcp-0.1.0/tests/test_terminology.py +107 -0
  32. belindoc_mcp-0.1.0/tests/test_upload_failure_note.py +67 -0
  33. belindoc_mcp-0.1.0/tests/test_upload_kind.py +66 -0
  34. belindoc_mcp-0.1.0/tests/test_wait_backoff.py +83 -0
  35. belindoc_mcp-0.1.0/tests/test_wait_progress.py +123 -0
  36. belindoc_mcp-0.1.0/tests/test_wait_repeat.py +59 -0
@@ -0,0 +1,296 @@
1
+ Metadata-Version: 2.4
2
+ Name: belindoc-mcp
3
+ Version: 0.1.0
4
+ Summary: Belindoc 文档 / 视频翻译的 MCP 服务
5
+ Author: zhangjun
6
+ License: MIT
7
+ Project-URL: Homepage, https://belindoc.com
8
+ Keywords: mcp,translation,document,video,subtitle
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.10
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Classifier: Topic :: Text Processing :: Linguistic
16
+ Requires-Python: >=3.10
17
+ Description-Content-Type: text/markdown
18
+ Requires-Dist: mcp>=2.0.0
19
+ Requires-Dist: httpx>=0.25.0
20
+ Requires-Dist: pydantic>=2.0.0
21
+ Requires-Dist: starlette>=0.37.0
22
+ Requires-Dist: uvicorn>=0.27.0
23
+ Provides-Extra: dev
24
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
25
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
26
+
27
+ # Trans MCP Server
28
+
29
+ Belindoc 翻译开放 API 的 MCP 服务:文档(PDF / Word / Excel / Markdown / 图片)和视频翻译、
30
+ 字幕改写。
31
+
32
+ ## 两种运行方式
33
+
34
+ | | stdio | HTTP 远程 |
35
+ |---|---|---|
36
+ | 入口 | `belindoc-mcp` | `trans-mcp-http` |
37
+ | 跑在哪 | 用户自己的机器上 | 一台服务器上,多人共用 |
38
+ | API Key | 服务端从 `BELINDOC_API_KEY` 读 | 每个客户端自己带 `Authorization: Bearer <key>`,服务器不存任何密钥 |
39
+ | 传输 | stdio | Streamable HTTP(SSE + `Mcp-Session-Id`) |
40
+
41
+ 两种方式的工具、行为完全一致,包括服务端直接向用户弹窗确认(elicitation)和等待期间的
42
+ 进度通知。部署 HTTP 模式看 [DEPLOY.md](DEPLOY.md)。
43
+
44
+ ## 安装
45
+
46
+ 从 PyPI 装即可,不用 clone 源码:
47
+
48
+ ```bash
49
+ uvx belindoc-mcp # 试跑一下;客户端配置里也直接这么写,不用预装
50
+ # 或者
51
+ pipx install belindoc-mcp
52
+ ```
53
+
54
+ 从源码装(开发、或要改代码)见 [开发](#开发)。
55
+
56
+ ## 环境变量
57
+
58
+ | 变量 | 用在哪 | 说明 |
59
+ |------|--------|------|
60
+ | `BELINDOC_API_KEY` | stdio | 必需。格式 `ft_` + 40 位随机串,共 43 字符 |
61
+ | `BELINDOC_API_BASE_URL` | 都 | 上游地址。不设即生产 `https://belindoc.com/api`;要打到别的环境才需要设 |
62
+ | `MCP_HOST` / `MCP_PORT` | HTTP | 监听地址与端口,默认 `0.0.0.0:8080` |
63
+ | `MCP_PATH` | HTTP | MCP 服务端点路径,默认 `/mcp`。同域名下落地页占了 `/mcp` 时挪开 |
64
+ | `MCP_LOCALE` | 都 | 用户可见文案的语言,默认 `zh`。见下方「输出语言」 |
65
+
66
+ HTTP 模式**不读** `BELINDOC_API_KEY`——别把真实 key 写进服务器的 `.env`。
67
+ 完整注释见 [.env.example](.env.example)。
68
+
69
+ ### 获取 API Key
70
+
71
+ 登录 https://belindoc.com → 「开放平台」→「API Key 管理」→ 创建。
72
+
73
+ ## 客户端接入
74
+
75
+ ### stdio
76
+
77
+ ```json
78
+ {
79
+ "mcpServers": {
80
+ "trans-mcp": {
81
+ "command": "uvx",
82
+ "args": ["belindoc-mcp"],
83
+ "env": {
84
+ "BELINDOC_API_KEY": "ft_你的API密钥"
85
+ }
86
+ }
87
+ }
88
+ }
89
+ ```
90
+
91
+ 配置文件位置:Claude Desktop 是 `~/Library/Application Support/Claude/claude_desktop_config.json`,
92
+ Codex 是 `~/.codex/config.json`。
93
+
94
+ `uvx` 会自己拉包、自己建隔离环境,用户不用预装,也不用管路径。前提是机器上有 uv
95
+ (`curl -LsSf https://astral.sh/uv/install.sh | sh`)。
96
+
97
+ **从源码装的话**,`command` 必须填绝对路径——`pip install -e .` 之后 venv 里会生成
98
+ `belindoc-mcp` 这个可执行文件,填它的完整路径(形如
99
+ `/path/to/trans-mcp/.venv/bin/belindoc-mcp`)。客户端不走登录 shell,`PATH` 里通常没有
100
+ 这个 venv,写裸命令名会起不来。
101
+
102
+ 不想把 key 写进客户端配置的话,也可以放进项目根目录的 `.env`,启动时自己加载:
103
+
104
+ ```bash
105
+ cp .env.example .env # 填入 API Key
106
+ source .env && belindoc-mcp
107
+ ```
108
+
109
+ ### HTTP 远程
110
+
111
+ ```json
112
+ {
113
+ "mcpServers": {
114
+ "belindoc": {
115
+ "type": "streamablehttp",
116
+ "url": "http://mcp.belindoc.com/mcp",
117
+ "headers": {
118
+ "Authorization": "Bearer ft_你的API密钥"
119
+ }
120
+ }
121
+ }
122
+ }
123
+ ```
124
+
125
+ Codex CLI 的 HTTP MCP 发不了自定义请求头,只能用 Bearer;走 `~/.codex/config.toml` 的话:
126
+
127
+ ```toml
128
+ [mcp_servers.belindoc]
129
+ url = "http://mcp.belindoc.com/mcp"
130
+ bearer_token_env_var = "BELINDOC_API_KEY"
131
+ ```
132
+
133
+ ### 接上之后
134
+
135
+ 调一次 `get_account_status` 验证密钥通不通,顺便看余额。想知道这个客户端支不支持服务端
136
+ 弹窗确认(关系到视频提交走一步还是两步),调一次 `probe_elicitation`——它不翻译、不提交
137
+ 任务、不扣额度。
138
+
139
+ ## 典型流程
140
+
141
+ **文档**:`upload_document` 取预签名链接 → 按返回的 `uploadCommand` 上传 →
142
+ (PDF 才要)`check_pdf_ocr` 看是不是扫描件 → `translate_document` 提交 →
143
+ `wait_for_translation` 跟进 → `get_document_translation_result` 取下载链接。
144
+
145
+ **视频**:`upload_video` → 上传 → `calculate_video_translation_quota` 试算 →
146
+ `translate_video` 提交(两步确认,见下)→ `wait_for_video_translation` 跟进。
147
+ 想改字幕重出一版:`get_video_subtitles` → `calculate_rewrite_quota` →
148
+ `rewrite_video_subtitles` → `get_video_rewrite_status`。
149
+
150
+ 上传由调用方自己执行返回的 `uploadCommand`,服务端不碰用户机器上的文件;下载给的是
151
+ 签名链接,问号后面的签名参数一个字符都不能改,截掉就是 403。
152
+
153
+ ## 工具列表
154
+
155
+ ### 账户与元信息
156
+ | 工具 | 说明 |
157
+ |------|------|
158
+ | `get_supported_languages` | 支持的语言列表(79 种,语言码 → 显示名) |
159
+ | `get_model_list` | 当前账户可用的翻译模型 |
160
+ | `get_account_status` | 可用额度、会员档位、各项限额(单视频时长 / 并发数 / 单文件大小) |
161
+
162
+ ### 文档翻译
163
+ | 工具 | 说明 |
164
+ |------|------|
165
+ | `upload_document` | 取文档的预签名上传链接 |
166
+ | `check_pdf_ocr` | 判断已上传的 PDF 是不是扫描件 / 双层 PDF |
167
+ | `translate_document` | 提交文档翻译任务 |
168
+ | `wait_for_translation` | 等待任务完成,进度一有变化就返回 |
169
+ | `get_document_translation_status` | 查单个任务状态 |
170
+ | `get_document_translation_result` | 取译文下载链接 |
171
+ | `list_document_translations` | 分页查任务列表 |
172
+ | `get_document_translation_by_batch` | 按批次号查任务 |
173
+
174
+ ### 视频翻译
175
+ | 工具 | 说明 |
176
+ |------|------|
177
+ | `upload_video` | 取视频的预签名上传地址 |
178
+ | `calculate_video_translation_quota` | 试算要花多少额度,不扣费 |
179
+ | `translate_video` | 提交视频翻译任务(会真扣额度,两步确认) |
180
+ | `wait_for_video_translation` | 等待任务完成,进度一有变化就返回 |
181
+ | `get_video_translation_status` | 查单个任务状态 |
182
+ | `list_video_translations` | 分页查任务列表(只有最近 15 天) |
183
+ | `cancel_video_translation` | 取消任务 |
184
+
185
+ ### 字幕改写
186
+ | 工具 | 说明 |
187
+ |------|------|
188
+ | `get_video_subtitles` | 取原文与译文字幕下载地址 |
189
+ | `calculate_rewrite_quota` | 试算改写要花多少额度,不扣费 |
190
+ | `rewrite_video_subtitles` | 用编辑后的字幕重新生成视频(会真扣额度,两步确认) |
191
+ | `get_video_rewrite_status` | 查改写进度 |
192
+
193
+ ### 排查
194
+ | 工具 | 说明 |
195
+ |------|------|
196
+ | `probe_elicitation` | 自检:这个客户端到底吃不吃 elicitation。不翻译、不提交、不扣额度 |
197
+
198
+ ## 扣费确认
199
+
200
+ `translate_video` 和 `rewrite_video_subtitles` 会真扣额度,所以提交是**两步**,第一次
201
+ 一定不会提交:
202
+
203
+ - 客户端支持 **elicitation** 时,服务端直接弹窗问用户,一次调用即可;
204
+ - 不支持时退回**确认码**:第一次调用返回 409 + 一段给用户看的话 + 一张菜单(配音 ×
205
+ 字幕的各种组合,每格自带额度和 `confirmToken`),把菜单原样给用户看、他挑了哪一项,
206
+ 就用那一项的 `confirmToken` 重调一次,这一次才真的提交。
207
+
208
+ 之所以不能只信一个 `user_confirmed=true`:那种布尔量永远是模型自己填的,服务端无法验证
209
+ 背后到底有没有问过人。想知道某个客户端走哪条路,调一次 `probe_elicitation`。
210
+
211
+ ## 输出语言
212
+
213
+ 会被念给用户听的那部分文案(任务状态、产出说明、进度行、失败原因、下载说明)支持九种
214
+ 语言:`zh` / `zh-Hant` / `en` / `ja` / `ko` / `de` / `fr` / `ru` / `ar`。工具描述和给模型
215
+ 的操作指令始终是中文——那是写给模型的。
216
+
217
+ 优先级:工具参数 `locale` > 服务端 `MCP_LOCALE` > `zh`。
218
+
219
+ ## 故障排除
220
+
221
+ ### 认证失败 (10004)
222
+
223
+ API Key 不对、没注册、或格式错(必须 `ft_` 开头共 43 字符)。先 `echo $BELINDOC_API_KEY`
224
+ 确认,再去平台看 key 的状态。
225
+
226
+ ### 密钥类错误码 (30306 / 30307 / 30308 / 30309 / 30312)
227
+
228
+ 这几个上游一律用 HTTP 200 送回来,业务码在响应体里。工具会把它们翻成一句可执行的话
229
+ (key 没复制全 / 被禁用要重新启用 / 已过期 / IP 不在白名单 / 需联系客服),并明确标注
230
+ **重试、换参数、重新上传都没有用**。只有 30311 是该退避重试的。
231
+
232
+ ### 接口不存在 (404)
233
+
234
+ 返回里会写明「接口 X 在当前服务地址(Y)上不存在」。这不是网络故障,是该功能在这个环境
235
+ 没部署,或者 `BELINDOC_API_BASE_URL` 指错了环境。重试无用。
236
+
237
+ ### 连接超时
238
+
239
+ 检查后端是否在跑、网络是否通、防火墙是否放行。
240
+
241
+ ## 开发
242
+
243
+ ```bash
244
+ cd /path/to/trans-mcp
245
+ python3 -m venv .venv
246
+ source .venv/bin/activate
247
+ pip install -e ".[dev]"
248
+ pytest tests/
249
+ ```
250
+
251
+ ### 发布到 PyPI
252
+
253
+ ```bash
254
+ pip install build twine
255
+ python -m build # 出 dist/*.whl 和 dist/*.tar.gz
256
+ twine upload dist/*
257
+ ```
258
+
259
+ 发之前先把 `pyproject.toml` 的 `version` 加上去——PyPI 的同一版本号只能传一次。
260
+ `python -m build` 之前先 `rm -rf dist/`,否则旧版本会跟着一起传上去。
261
+
262
+ 包是公开的,所以别往仓库里放任何只该留在内部的东西:`README.md` 会原样变成 PyPI
263
+ 首页,`tests/` 会进 sdist。加内容前对着 `tar tzf dist/*.tar.gz` 看一眼。
264
+
265
+ 根目录的 `test_api.py` / `test_upload.py` 是手动连真实 API 的冒烟脚本,不是用例,
266
+ pytest 只收集 `tests/`。
267
+
268
+ ### 项目结构
269
+
270
+ PyPI 包名是 `belindoc-mcp`,仓库目录和 Python 模块仍叫 `trans-mcp` / `trans_mcp`——
271
+ 后两个用户看不见,跟着改要动 Dockerfile、systemd 单元和已在跑的服务器的升级路径。
272
+ `trans-mcp` / `trans-mcp-http` 这两个命令也照旧留着,部署脚本在调它们。
273
+
274
+ ```
275
+ trans-mcp/
276
+ ├── README.md # 本文件
277
+ ├── DEPLOY.md # HTTP 远程模式的部署
278
+ ├── INTEGRATION.md # 客户端配置速查
279
+ ├── CONFIG.md # 环境变量速查
280
+ ├── pyproject.toml
281
+ ├── .env.example
282
+ ├── src/trans_mcp/
283
+ │ ├── server.py # stdio 入口
284
+ │ ├── http_server.py # HTTP 入口(Streamable HTTP)
285
+ │ ├── tools.py # 工具定义与处理器(两种模式共用)
286
+ │ ├── client.py # 上游 API 客户端
287
+ │ └── i18n.py # 用户可见文案的九种语言
288
+ ├── tests/
289
+ ├── deploy.sh # Docker 部署
290
+ ├── deploy-linux.sh # systemd 部署
291
+ └── server.sh # 本机起停
292
+ ```
293
+
294
+ ## 许可证
295
+
296
+ MIT License
@@ -0,0 +1,270 @@
1
+ # Trans MCP Server
2
+
3
+ Belindoc 翻译开放 API 的 MCP 服务:文档(PDF / Word / Excel / Markdown / 图片)和视频翻译、
4
+ 字幕改写。
5
+
6
+ ## 两种运行方式
7
+
8
+ | | stdio | HTTP 远程 |
9
+ |---|---|---|
10
+ | 入口 | `belindoc-mcp` | `trans-mcp-http` |
11
+ | 跑在哪 | 用户自己的机器上 | 一台服务器上,多人共用 |
12
+ | API Key | 服务端从 `BELINDOC_API_KEY` 读 | 每个客户端自己带 `Authorization: Bearer <key>`,服务器不存任何密钥 |
13
+ | 传输 | stdio | Streamable HTTP(SSE + `Mcp-Session-Id`) |
14
+
15
+ 两种方式的工具、行为完全一致,包括服务端直接向用户弹窗确认(elicitation)和等待期间的
16
+ 进度通知。部署 HTTP 模式看 [DEPLOY.md](DEPLOY.md)。
17
+
18
+ ## 安装
19
+
20
+ 从 PyPI 装即可,不用 clone 源码:
21
+
22
+ ```bash
23
+ uvx belindoc-mcp # 试跑一下;客户端配置里也直接这么写,不用预装
24
+ # 或者
25
+ pipx install belindoc-mcp
26
+ ```
27
+
28
+ 从源码装(开发、或要改代码)见 [开发](#开发)。
29
+
30
+ ## 环境变量
31
+
32
+ | 变量 | 用在哪 | 说明 |
33
+ |------|--------|------|
34
+ | `BELINDOC_API_KEY` | stdio | 必需。格式 `ft_` + 40 位随机串,共 43 字符 |
35
+ | `BELINDOC_API_BASE_URL` | 都 | 上游地址。不设即生产 `https://belindoc.com/api`;要打到别的环境才需要设 |
36
+ | `MCP_HOST` / `MCP_PORT` | HTTP | 监听地址与端口,默认 `0.0.0.0:8080` |
37
+ | `MCP_PATH` | HTTP | MCP 服务端点路径,默认 `/mcp`。同域名下落地页占了 `/mcp` 时挪开 |
38
+ | `MCP_LOCALE` | 都 | 用户可见文案的语言,默认 `zh`。见下方「输出语言」 |
39
+
40
+ HTTP 模式**不读** `BELINDOC_API_KEY`——别把真实 key 写进服务器的 `.env`。
41
+ 完整注释见 [.env.example](.env.example)。
42
+
43
+ ### 获取 API Key
44
+
45
+ 登录 https://belindoc.com → 「开放平台」→「API Key 管理」→ 创建。
46
+
47
+ ## 客户端接入
48
+
49
+ ### stdio
50
+
51
+ ```json
52
+ {
53
+ "mcpServers": {
54
+ "trans-mcp": {
55
+ "command": "uvx",
56
+ "args": ["belindoc-mcp"],
57
+ "env": {
58
+ "BELINDOC_API_KEY": "ft_你的API密钥"
59
+ }
60
+ }
61
+ }
62
+ }
63
+ ```
64
+
65
+ 配置文件位置:Claude Desktop 是 `~/Library/Application Support/Claude/claude_desktop_config.json`,
66
+ Codex 是 `~/.codex/config.json`。
67
+
68
+ `uvx` 会自己拉包、自己建隔离环境,用户不用预装,也不用管路径。前提是机器上有 uv
69
+ (`curl -LsSf https://astral.sh/uv/install.sh | sh`)。
70
+
71
+ **从源码装的话**,`command` 必须填绝对路径——`pip install -e .` 之后 venv 里会生成
72
+ `belindoc-mcp` 这个可执行文件,填它的完整路径(形如
73
+ `/path/to/trans-mcp/.venv/bin/belindoc-mcp`)。客户端不走登录 shell,`PATH` 里通常没有
74
+ 这个 venv,写裸命令名会起不来。
75
+
76
+ 不想把 key 写进客户端配置的话,也可以放进项目根目录的 `.env`,启动时自己加载:
77
+
78
+ ```bash
79
+ cp .env.example .env # 填入 API Key
80
+ source .env && belindoc-mcp
81
+ ```
82
+
83
+ ### HTTP 远程
84
+
85
+ ```json
86
+ {
87
+ "mcpServers": {
88
+ "belindoc": {
89
+ "type": "streamablehttp",
90
+ "url": "http://mcp.belindoc.com/mcp",
91
+ "headers": {
92
+ "Authorization": "Bearer ft_你的API密钥"
93
+ }
94
+ }
95
+ }
96
+ }
97
+ ```
98
+
99
+ Codex CLI 的 HTTP MCP 发不了自定义请求头,只能用 Bearer;走 `~/.codex/config.toml` 的话:
100
+
101
+ ```toml
102
+ [mcp_servers.belindoc]
103
+ url = "http://mcp.belindoc.com/mcp"
104
+ bearer_token_env_var = "BELINDOC_API_KEY"
105
+ ```
106
+
107
+ ### 接上之后
108
+
109
+ 调一次 `get_account_status` 验证密钥通不通,顺便看余额。想知道这个客户端支不支持服务端
110
+ 弹窗确认(关系到视频提交走一步还是两步),调一次 `probe_elicitation`——它不翻译、不提交
111
+ 任务、不扣额度。
112
+
113
+ ## 典型流程
114
+
115
+ **文档**:`upload_document` 取预签名链接 → 按返回的 `uploadCommand` 上传 →
116
+ (PDF 才要)`check_pdf_ocr` 看是不是扫描件 → `translate_document` 提交 →
117
+ `wait_for_translation` 跟进 → `get_document_translation_result` 取下载链接。
118
+
119
+ **视频**:`upload_video` → 上传 → `calculate_video_translation_quota` 试算 →
120
+ `translate_video` 提交(两步确认,见下)→ `wait_for_video_translation` 跟进。
121
+ 想改字幕重出一版:`get_video_subtitles` → `calculate_rewrite_quota` →
122
+ `rewrite_video_subtitles` → `get_video_rewrite_status`。
123
+
124
+ 上传由调用方自己执行返回的 `uploadCommand`,服务端不碰用户机器上的文件;下载给的是
125
+ 签名链接,问号后面的签名参数一个字符都不能改,截掉就是 403。
126
+
127
+ ## 工具列表
128
+
129
+ ### 账户与元信息
130
+ | 工具 | 说明 |
131
+ |------|------|
132
+ | `get_supported_languages` | 支持的语言列表(79 种,语言码 → 显示名) |
133
+ | `get_model_list` | 当前账户可用的翻译模型 |
134
+ | `get_account_status` | 可用额度、会员档位、各项限额(单视频时长 / 并发数 / 单文件大小) |
135
+
136
+ ### 文档翻译
137
+ | 工具 | 说明 |
138
+ |------|------|
139
+ | `upload_document` | 取文档的预签名上传链接 |
140
+ | `check_pdf_ocr` | 判断已上传的 PDF 是不是扫描件 / 双层 PDF |
141
+ | `translate_document` | 提交文档翻译任务 |
142
+ | `wait_for_translation` | 等待任务完成,进度一有变化就返回 |
143
+ | `get_document_translation_status` | 查单个任务状态 |
144
+ | `get_document_translation_result` | 取译文下载链接 |
145
+ | `list_document_translations` | 分页查任务列表 |
146
+ | `get_document_translation_by_batch` | 按批次号查任务 |
147
+
148
+ ### 视频翻译
149
+ | 工具 | 说明 |
150
+ |------|------|
151
+ | `upload_video` | 取视频的预签名上传地址 |
152
+ | `calculate_video_translation_quota` | 试算要花多少额度,不扣费 |
153
+ | `translate_video` | 提交视频翻译任务(会真扣额度,两步确认) |
154
+ | `wait_for_video_translation` | 等待任务完成,进度一有变化就返回 |
155
+ | `get_video_translation_status` | 查单个任务状态 |
156
+ | `list_video_translations` | 分页查任务列表(只有最近 15 天) |
157
+ | `cancel_video_translation` | 取消任务 |
158
+
159
+ ### 字幕改写
160
+ | 工具 | 说明 |
161
+ |------|------|
162
+ | `get_video_subtitles` | 取原文与译文字幕下载地址 |
163
+ | `calculate_rewrite_quota` | 试算改写要花多少额度,不扣费 |
164
+ | `rewrite_video_subtitles` | 用编辑后的字幕重新生成视频(会真扣额度,两步确认) |
165
+ | `get_video_rewrite_status` | 查改写进度 |
166
+
167
+ ### 排查
168
+ | 工具 | 说明 |
169
+ |------|------|
170
+ | `probe_elicitation` | 自检:这个客户端到底吃不吃 elicitation。不翻译、不提交、不扣额度 |
171
+
172
+ ## 扣费确认
173
+
174
+ `translate_video` 和 `rewrite_video_subtitles` 会真扣额度,所以提交是**两步**,第一次
175
+ 一定不会提交:
176
+
177
+ - 客户端支持 **elicitation** 时,服务端直接弹窗问用户,一次调用即可;
178
+ - 不支持时退回**确认码**:第一次调用返回 409 + 一段给用户看的话 + 一张菜单(配音 ×
179
+ 字幕的各种组合,每格自带额度和 `confirmToken`),把菜单原样给用户看、他挑了哪一项,
180
+ 就用那一项的 `confirmToken` 重调一次,这一次才真的提交。
181
+
182
+ 之所以不能只信一个 `user_confirmed=true`:那种布尔量永远是模型自己填的,服务端无法验证
183
+ 背后到底有没有问过人。想知道某个客户端走哪条路,调一次 `probe_elicitation`。
184
+
185
+ ## 输出语言
186
+
187
+ 会被念给用户听的那部分文案(任务状态、产出说明、进度行、失败原因、下载说明)支持九种
188
+ 语言:`zh` / `zh-Hant` / `en` / `ja` / `ko` / `de` / `fr` / `ru` / `ar`。工具描述和给模型
189
+ 的操作指令始终是中文——那是写给模型的。
190
+
191
+ 优先级:工具参数 `locale` > 服务端 `MCP_LOCALE` > `zh`。
192
+
193
+ ## 故障排除
194
+
195
+ ### 认证失败 (10004)
196
+
197
+ API Key 不对、没注册、或格式错(必须 `ft_` 开头共 43 字符)。先 `echo $BELINDOC_API_KEY`
198
+ 确认,再去平台看 key 的状态。
199
+
200
+ ### 密钥类错误码 (30306 / 30307 / 30308 / 30309 / 30312)
201
+
202
+ 这几个上游一律用 HTTP 200 送回来,业务码在响应体里。工具会把它们翻成一句可执行的话
203
+ (key 没复制全 / 被禁用要重新启用 / 已过期 / IP 不在白名单 / 需联系客服),并明确标注
204
+ **重试、换参数、重新上传都没有用**。只有 30311 是该退避重试的。
205
+
206
+ ### 接口不存在 (404)
207
+
208
+ 返回里会写明「接口 X 在当前服务地址(Y)上不存在」。这不是网络故障,是该功能在这个环境
209
+ 没部署,或者 `BELINDOC_API_BASE_URL` 指错了环境。重试无用。
210
+
211
+ ### 连接超时
212
+
213
+ 检查后端是否在跑、网络是否通、防火墙是否放行。
214
+
215
+ ## 开发
216
+
217
+ ```bash
218
+ cd /path/to/trans-mcp
219
+ python3 -m venv .venv
220
+ source .venv/bin/activate
221
+ pip install -e ".[dev]"
222
+ pytest tests/
223
+ ```
224
+
225
+ ### 发布到 PyPI
226
+
227
+ ```bash
228
+ pip install build twine
229
+ python -m build # 出 dist/*.whl 和 dist/*.tar.gz
230
+ twine upload dist/*
231
+ ```
232
+
233
+ 发之前先把 `pyproject.toml` 的 `version` 加上去——PyPI 的同一版本号只能传一次。
234
+ `python -m build` 之前先 `rm -rf dist/`,否则旧版本会跟着一起传上去。
235
+
236
+ 包是公开的,所以别往仓库里放任何只该留在内部的东西:`README.md` 会原样变成 PyPI
237
+ 首页,`tests/` 会进 sdist。加内容前对着 `tar tzf dist/*.tar.gz` 看一眼。
238
+
239
+ 根目录的 `test_api.py` / `test_upload.py` 是手动连真实 API 的冒烟脚本,不是用例,
240
+ pytest 只收集 `tests/`。
241
+
242
+ ### 项目结构
243
+
244
+ PyPI 包名是 `belindoc-mcp`,仓库目录和 Python 模块仍叫 `trans-mcp` / `trans_mcp`——
245
+ 后两个用户看不见,跟着改要动 Dockerfile、systemd 单元和已在跑的服务器的升级路径。
246
+ `trans-mcp` / `trans-mcp-http` 这两个命令也照旧留着,部署脚本在调它们。
247
+
248
+ ```
249
+ trans-mcp/
250
+ ├── README.md # 本文件
251
+ ├── DEPLOY.md # HTTP 远程模式的部署
252
+ ├── INTEGRATION.md # 客户端配置速查
253
+ ├── CONFIG.md # 环境变量速查
254
+ ├── pyproject.toml
255
+ ├── .env.example
256
+ ├── src/trans_mcp/
257
+ │ ├── server.py # stdio 入口
258
+ │ ├── http_server.py # HTTP 入口(Streamable HTTP)
259
+ │ ├── tools.py # 工具定义与处理器(两种模式共用)
260
+ │ ├── client.py # 上游 API 客户端
261
+ │ └── i18n.py # 用户可见文案的九种语言
262
+ ├── tests/
263
+ ├── deploy.sh # Docker 部署
264
+ ├── deploy-linux.sh # systemd 部署
265
+ └── server.sh # 本机起停
266
+ ```
267
+
268
+ ## 许可证
269
+
270
+ MIT License
@@ -0,0 +1,64 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "belindoc-mcp"
7
+ version = "0.1.0"
8
+ description = "Belindoc 文档 / 视频翻译的 MCP 服务"
9
+ readme = "README.md"
10
+ license = {text = "MIT"}
11
+ requires-python = ">=3.10"
12
+ authors = [{name = "zhangjun"}]
13
+ keywords = ["mcp", "translation", "document", "video", "subtitle"]
14
+ classifiers = [
15
+ "License :: OSI Approved :: MIT License",
16
+ "Programming Language :: Python :: 3",
17
+ "Programming Language :: Python :: 3.10",
18
+ "Programming Language :: Python :: 3.11",
19
+ "Programming Language :: Python :: 3.12",
20
+ "Programming Language :: Python :: 3.13",
21
+ "Topic :: Text Processing :: Linguistic",
22
+ ]
23
+ dependencies = [
24
+ "mcp>=2.0.0",
25
+ "httpx>=0.25.0",
26
+ "pydantic>=2.0.0",
27
+ # HTTP 模式的传输层:MCP SDK 的 Streamable HTTP 管理器是 ASGI 的,
28
+ # 挂在 Starlette 上、由 uvicorn 跑。(之前手搓的那套用的是 aiohttp)
29
+ "starlette>=0.37.0",
30
+ "uvicorn>=0.27.0",
31
+ ]
32
+
33
+ [project.optional-dependencies]
34
+ dev = [
35
+ "pytest>=7.0.0",
36
+ "pytest-asyncio>=0.21.0",
37
+ ]
38
+
39
+ [project.urls]
40
+ Homepage = "https://belindoc.com"
41
+
42
+ # PyPI 包名是 belindoc-mcp,仓库目录和模块仍叫 trans-mcp / trans_mcp——后两个用户
43
+ # 看不见,跟着改要动 Dockerfile 的 CMD、systemd 的 ExecStart 和已在跑的服务器的升级
44
+ # 路径,不值当。
45
+ #
46
+ # belindoc-mcp 是给外部用户的 stdio 入口,名字和包名一致,客户端里直接 uvx belindoc-mcp。
47
+ # trans-mcp / trans-mcp-http 原样留着:start.sh、Dockerfile、systemd 单元都在调它们。
48
+ [project.scripts]
49
+ belindoc-mcp = "trans_mcp.server:main"
50
+ trans-mcp = "trans_mcp.server:main"
51
+ trans-mcp-http = "trans_mcp.http_server:main"
52
+
53
+ # 显式声明要打的包。原先靠自动发现,而 src/ 下有个空的 __init__.py,setuptools
54
+ # 把它当成了一个顶层模块——egg-info 的 top_level.txt 里真有一行 `__init__`。
55
+ # 自用无所谓,发到 PyPI 就是往每个用户的 site-packages 里塞一个叫 __init__ 的
56
+ # 顶层模块。那个空文件已经删掉,这里再钉死一遍,防止以后又被误收。
57
+ [tool.setuptools.packages.find]
58
+ where = ["src"]
59
+ include = ["trans_mcp*"]
60
+
61
+ [tool.pytest.ini_options]
62
+ # 根目录的 test_api.py / test_upload.py 是手动连真实 API 的冒烟脚本,
63
+ # 不是用例,只收集 tests/ 避免被误收集
64
+ testpaths = ["tests"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+