mcp-web-print-pdf 0.0.0-stage → 0.2.0
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.
- package/LICENSE +21 -0
- package/README.md +440 -2
- package/README_EN.md +468 -0
- package/bin/mcp.js +8 -0
- package/package.json +51 -4
- package/src/options.js +240 -0
- package/src/server.js +382 -0
- package/src/webprint-client.js +140 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 mcp-web-print-pdf contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,441 @@
|
|
|
1
|
-
#
|
|
1
|
+
# mcp-web-print-pdf
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**中文** | [English](README_EN.md)
|
|
4
|
+
|
|
5
|
+
让 AI agent(Claude Desktop / Cursor / dsh)把 HTML、网页、PDF、图片打印到本机打印机。
|
|
6
|
+
|
|
7
|
+
它**不改**「Web打印专家」客户端,也不改 `web-print-pdf` 浏览器库——它只是给客户端已有的
|
|
8
|
+
`ws://127.0.0.1:16794/websocket/standard` 再加一个客户端,并把 `web-print-pdf@2.x` 的公开 API
|
|
9
|
+
一对一映射成 MCP 工具。
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
Claude / dsh ──stdio──> mcp-web-print-pdf ──ws──> Web打印专家客户端 ──> 打印机
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## 安装
|
|
16
|
+
|
|
17
|
+
宿主会自动通过 `npx -y mcp-web-print-pdf` 拉取,不需要全局安装。
|
|
18
|
+
|
|
19
|
+
从源码开发:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## 配置
|
|
26
|
+
|
|
27
|
+
所有宿主都通过 stdio 启动同一个 MCP server,统一用:
|
|
28
|
+
|
|
29
|
+
```json
|
|
30
|
+
{ "command": "npx", "args": ["-y", "mcp-web-print-pdf"] }
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
> 从源码调试时,把 `command` 换成 `node`、`args` 换成 `["<repo>/bin/mcp.js"]` 即可,其余字段不变。
|
|
34
|
+
|
|
35
|
+
### Claude Desktop
|
|
36
|
+
|
|
37
|
+
`%APPDATA%\Claude\claude_desktop_config.json`:
|
|
38
|
+
|
|
39
|
+
```json
|
|
40
|
+
{
|
|
41
|
+
"mcpServers": {
|
|
42
|
+
"webprint": {
|
|
43
|
+
"command": "npx",
|
|
44
|
+
"args": ["-y", "mcp-web-print-pdf"],
|
|
45
|
+
"env": { "WEBPRINT_PORT": "16794" }
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Cursor
|
|
52
|
+
|
|
53
|
+
项目级 `.cursor/mcp.json`(只对当前项目生效),或全局 `~/.cursor/mcp.json`:
|
|
54
|
+
|
|
55
|
+
```json
|
|
56
|
+
{
|
|
57
|
+
"mcpServers": {
|
|
58
|
+
"webprint": {
|
|
59
|
+
"command": "npx",
|
|
60
|
+
"args": ["-y", "mcp-web-print-pdf"],
|
|
61
|
+
"env": { "WEBPRINT_PORT": "16794" }
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
改完在 Cursor 的 **Settings → MCP** 里确认 `webprint` 是绿灯;工具会出现在 Agent 的工具列表里。
|
|
68
|
+
|
|
69
|
+
### DeepSeek Harness(dsh)
|
|
70
|
+
|
|
71
|
+
dsh 用 `@deepseek-ai/dsh-mcp-client` 挂载外部 MCP。编辑当前 profile 的
|
|
72
|
+
`~/.dsh/profiles/<profile>/cordis.patch.yml`,追加一段 `insert`:
|
|
73
|
+
|
|
74
|
+
```yaml
|
|
75
|
+
- insert:
|
|
76
|
+
- id: mcp-webprint
|
|
77
|
+
name: '@deepseek-ai/dsh-mcp-client'
|
|
78
|
+
config:
|
|
79
|
+
serverName: webprint
|
|
80
|
+
transport: stdio
|
|
81
|
+
command: npx
|
|
82
|
+
args:
|
|
83
|
+
- '-y'
|
|
84
|
+
- 'mcp-web-print-pdf'
|
|
85
|
+
toolCallTimeoutMs: 180000
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
保存后 dsh 会热加载(`serverName` 需匹配 `[A-Za-z0-9_-]{1,32}`,且同一 profile 内唯一)。
|
|
89
|
+
模型侧看到的工具名带命名空间:`mcp__webprint__printHtml`、`mcp__webprint__getPrinterList`、
|
|
90
|
+
`mcp__webprint__batchPrint` …
|
|
91
|
+
|
|
92
|
+
### Claude Code
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
claude mcp add --scope user webprint -- npx -y mcp-web-print-pdf
|
|
96
|
+
claude mcp list
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
`--scope user` 全局可用;去掉则只对当前项目生效。团队共享可以提交项目根的 `.mcp.json`:
|
|
100
|
+
|
|
101
|
+
```json
|
|
102
|
+
{
|
|
103
|
+
"mcpServers": {
|
|
104
|
+
"webprint": {
|
|
105
|
+
"type": "stdio",
|
|
106
|
+
"command": "npx",
|
|
107
|
+
"args": ["-y", "mcp-web-print-pdf"]
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### VS Code + GitHub Copilot
|
|
114
|
+
|
|
115
|
+
`.vscode/mcp.json`(注意顶层是 `servers`,不是 `mcpServers`):
|
|
116
|
+
|
|
117
|
+
```json
|
|
118
|
+
{
|
|
119
|
+
"servers": {
|
|
120
|
+
"webprint": {
|
|
121
|
+
"type": "stdio",
|
|
122
|
+
"command": "npx",
|
|
123
|
+
"args": ["-y", "mcp-web-print-pdf"]
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
命令面板运行 **MCP: List Servers** 可启动 / 重启 / 看输出;便携格式 `.mcp.json` 则用 `mcpServers`。
|
|
130
|
+
|
|
131
|
+
### OpenAI Codex CLI
|
|
132
|
+
|
|
133
|
+
`~/.codex/config.toml`:
|
|
134
|
+
|
|
135
|
+
```toml
|
|
136
|
+
[mcp_servers.webprint]
|
|
137
|
+
command = "npx"
|
|
138
|
+
args = ["-y", "mcp-web-print-pdf"]
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Cline / Roo Code / Kilo Code
|
|
142
|
+
|
|
143
|
+
Cline 面板 → MCP Servers → Configure → Configure MCP Servers,编辑 `cline_mcp_settings.json`:
|
|
144
|
+
|
|
145
|
+
```json
|
|
146
|
+
{
|
|
147
|
+
"mcpServers": {
|
|
148
|
+
"webprint": {
|
|
149
|
+
"command": "npx",
|
|
150
|
+
"args": ["-y", "mcp-web-print-pdf"],
|
|
151
|
+
"disabled": false
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Roo Code / Kilo Code 是 Cline 的分叉,配置结构相同,只是文件路径不同。
|
|
158
|
+
|
|
159
|
+
### Cherry Studio
|
|
160
|
+
|
|
161
|
+
设置 → **MCP 服务器** → **添加服务器**:
|
|
162
|
+
|
|
163
|
+
- 类型:`STDIO`
|
|
164
|
+
- 命令:`npx`
|
|
165
|
+
- 参数:`-y mcp-web-print-pdf`
|
|
166
|
+
|
|
167
|
+
保存后回到聊天框,打开输入框旁的 MCP 开关即可。
|
|
168
|
+
|
|
169
|
+
### Trae
|
|
170
|
+
|
|
171
|
+
设置 → **MCP** → **手动添加**,粘贴:
|
|
172
|
+
|
|
173
|
+
```json
|
|
174
|
+
{
|
|
175
|
+
"mcpServers": {
|
|
176
|
+
"webprint": {
|
|
177
|
+
"command": "npx",
|
|
178
|
+
"args": ["-y", "mcp-web-print-pdf"]
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
项目级配置放在 `.trae/mcp.json`(需先在设置里打开「项目级 MCP」)。
|
|
185
|
+
|
|
186
|
+
### 其它宿主
|
|
187
|
+
|
|
188
|
+
| 宿主 | 配置位置 | 顶层键 |
|
|
189
|
+
|---|---|---|
|
|
190
|
+
| CodeBuddy | `settings.json` | `mcpServers`(加 `"disabled": false`) |
|
|
191
|
+
| Qoder | `~/.qoder/settings.json` | `mcpServers`(或 `qoder mcp add webprint -- npx -y mcp-web-print-pdf`) |
|
|
192
|
+
| JetBrains AI Assistant | Settings → Tools → AI Assistant → MCP → Add | `mcpServers`(也可直接 Import from Claude) |
|
|
193
|
+
| Windsurf | `~/.codeium/windsurf/mcp_config.json` | `mcpServers` |
|
|
194
|
+
| GitHub Copilot CLI | `~/.copilot/mcp-config.json` | `mcpServers` |
|
|
195
|
+
|
|
196
|
+
> ChatGPT / claude.ai 网页版只接受远程 HTTP MCP,不能直连本机的 stdio server;要支持它们需要再加一层
|
|
197
|
+
> HTTP 桥(本项目暂未提供)。Gemini CLI 个人版已转向 Antigravity,这里不再单列。
|
|
198
|
+
|
|
199
|
+
> 客户端端口默认 `16794`,可用 `WEBPRINT_PORT` 覆盖;WebSocket 请求超时默认 120s,可用
|
|
200
|
+
> `WEBPRINT_TIMEOUT`(毫秒)覆盖。
|
|
201
|
+
|
|
202
|
+
## 工具
|
|
203
|
+
|
|
204
|
+
工具名与 `web-print-pdf@2.x` 的方法名一一对应(`utils.` 前缀不能出现在 MCP 工具名里,故省略)。
|
|
205
|
+
只有 `printFile` 是本仓库额外加的——上游没有「按本机路径打印」的方法。
|
|
206
|
+
|
|
207
|
+
### 状态与打印机
|
|
208
|
+
|
|
209
|
+
| 工具 | 对应 | 作用 |
|
|
210
|
+
|---|---|---|
|
|
211
|
+
| `getConnectStatus` | `utils.getConnectStatus` | 检查客户端是否在线 |
|
|
212
|
+
| `getPrinterList` | `utils.getPrinterList` | 列出本机打印机(名称 + 驱动) |
|
|
213
|
+
| `getPrinterPapers` | `utils.getPrinterPapers` | 查询某台打印机支持的纸张,用于填 `paper_format` / `print_options.bin` |
|
|
214
|
+
|
|
215
|
+
### 打印
|
|
216
|
+
|
|
217
|
+
所有打印工具默认 `dry_run: true`:只渲染预览、不出纸;要真正打印必须显式传 `dry_run: false`
|
|
218
|
+
(或 `extra_options.action: "print"`)。
|
|
219
|
+
|
|
220
|
+
> 不传 `paper_format` 时,PDF 渲染默认用 A4,但打印阶段会沿用客户端默认打印机的纸张。
|
|
221
|
+
> 要固定纸张(比如热敏 80mm、面单 100×150),请显式传 `paper_format` / `pdf_options`。
|
|
222
|
+
|
|
223
|
+
| 工具 | 作用 |
|
|
224
|
+
|---|---|
|
|
225
|
+
| `printHtml` | 打印 HTML 字符串 |
|
|
226
|
+
| `printHtmlByUrl` | 抓取网页后打印 |
|
|
227
|
+
| `printHtmlByBase64` | 打印 Base64 HTML |
|
|
228
|
+
| `printPdfByUrl` | 打印 PDF 链接 |
|
|
229
|
+
| `printPdfByBase64` | 打印 Base64 PDF |
|
|
230
|
+
| `printImageByUrl` | 打印图片链接 |
|
|
231
|
+
| `printImageByBase64` | 打印 Base64 图片 |
|
|
232
|
+
| `printFile` | 按扩展名自动选通道,打印本机 `.pdf` / `.html` / 图片(额外提供) |
|
|
233
|
+
| `batchPrint` | 一次提交多个混合任务 |
|
|
234
|
+
|
|
235
|
+
> `batchPrint` 的任务格式以客户端为准:每项是 `{ type, data, pdfOptions?, printOptions?, extraOptions? }`,
|
|
236
|
+
> **不是**上游 README 示例里的 `content` / `url` / `base64`。`data` 按 `type` 解释:`printHtml` 放 HTML,
|
|
237
|
+
> `…ByUrl` 放地址,`…ByBase64` 放 base64。
|
|
238
|
+
|
|
239
|
+
### 客户端设置
|
|
240
|
+
|
|
241
|
+
| 工具 | 对应 | 说明 |
|
|
242
|
+
|---|---|---|
|
|
243
|
+
| `setTitle` | `utils.setTitle(title \| null)` | 设置窗口标题 |
|
|
244
|
+
| `setThemeColor` | `utils.setThemeColor(color \| null)` | 设置主题色 |
|
|
245
|
+
| `switchTabsVisibility` | `utils.switchTabsVisibility(tabs \| null)` | 切换标签页显隐 |
|
|
246
|
+
| `setContactUsTabInnerHtml` | `utils.setContactUsTabInnerHtml(html \| null)` | 设置「联系我们」页面 |
|
|
247
|
+
|
|
248
|
+
这四个都支持 `reset: true` 恢复默认——有些宿主会把 JSON `null` 序列化成字符串 `"null"`,这时用
|
|
249
|
+
`reset: true` 比传 `null` 稳。
|
|
250
|
+
|
|
251
|
+
> 0.1.0 用的是 snake_case(`print_status` / `list_printers` / `print_html` / `print_pdf_url`),
|
|
252
|
+
> 0.2.0 起统一改成上游方法名,对应关系:`print_status` → `getConnectStatus`、`list_printers` →
|
|
253
|
+
> `getPrinterList`、`print_html` → `printHtml`、`print_pdf_url` → `printPdfByUrl`。
|
|
254
|
+
|
|
255
|
+
## 参数
|
|
256
|
+
|
|
257
|
+
打印工具共用一套参数,与上游四个实参一一对应:
|
|
258
|
+
|
|
259
|
+
| MCP 参数 | 对应 | 说明 |
|
|
260
|
+
|---|---|---|
|
|
261
|
+
| 内容字段 | 第 1 个实参 | `html` / `url` / `base64` / `path` / `tasks` |
|
|
262
|
+
| `pdf_options` | `pdfOptions` | 排版成 PDF:纸张、边距、页眉页脚、背景、水印、页码… |
|
|
263
|
+
| `print_options` | `printOptions` | 投递打印机:打印机名、份数、单双面、缩放、纸盒、热敏锐化… |
|
|
264
|
+
| `extra_options` | `extraOptions` | `action`、`requestTimeout`、`cookies`、`httpHeaders`、`localStorages`… |
|
|
265
|
+
| `dry_run` | — | 便捷开关,默认只预览;显式 `action` 优先 |
|
|
266
|
+
| `paper_format` | — | 便捷参数,等价于 `print_options.paperFormat` |
|
|
267
|
+
| `printer_name` | — | 便捷参数,等价于 `print_options.printerName` |
|
|
268
|
+
| `copies` | — | 便捷参数,等价于 `print_options.copies` |
|
|
269
|
+
|
|
270
|
+
三个 options 对象中,`pdf_options` / `print_options` 走客户端白名单校验(字段名写错会直接报错);
|
|
271
|
+
`extra_options` 允许任意自定义键,会原样透传并在响应里返回。
|
|
272
|
+
|
|
273
|
+
合并规则:**对象里显式写的字段优先**,便捷参数只补空缺。
|
|
274
|
+
|
|
275
|
+
### `pdf_options`
|
|
276
|
+
|
|
277
|
+
`paperFormat`、`width`、`height`、`displayHeaderFooter`、`headerTemplate`、`footerTemplate`、
|
|
278
|
+
`landscape`、`margin{top,right,bottom,left}`、`pageRanges[{from,to}]`、`preferCSSPageSize`、
|
|
279
|
+
`printBackground`、`scale`、`outline`、`tagged`、`watermark`、`pageNumber`。
|
|
280
|
+
|
|
281
|
+
> `pdfOptions.paperFormat` 只认固定枚举(A0–A6 / Letter / Legal / Tabloid / Ledger)。
|
|
282
|
+
> 80mm 小票、100×150 面单这类自定义尺寸请改用 `width` + `height`,不要设 `paperFormat`。
|
|
283
|
+
|
|
284
|
+
### `print_options`
|
|
285
|
+
|
|
286
|
+
`paperFormat`(任意纸名,含打印机专有尺寸)、`colorful`、`landscape`、`printerName`、
|
|
287
|
+
`pageRanges`、`copies`、`duplexMode`(`simplex` / `duplex` / `duplexshort` / `duplexlong`)、
|
|
288
|
+
`scaleMode`(`noscale` / `shrink` / `fit`)、`subset`(`odd` / `even`)、`bin`、`sharp`、
|
|
289
|
+
`dpi` / `threshold`(`sharp: true` 时的光栅参数,默认 203 / 160)。
|
|
290
|
+
|
|
291
|
+
### `extra_options`
|
|
292
|
+
|
|
293
|
+
`action`(`print` / `preview`)、`requestTimeout`(秒)、`devtool`、`cookies`、`httpHeaders`、
|
|
294
|
+
`localStorages`、`sessionStorages`,以及任意自定义键(会随响应原样返回)。
|
|
295
|
+
|
|
296
|
+
## 示例
|
|
297
|
+
|
|
298
|
+
预览一张 A4 发票(不出纸):
|
|
299
|
+
|
|
300
|
+
```json
|
|
301
|
+
{
|
|
302
|
+
"tool": "printHtml",
|
|
303
|
+
"arguments": {
|
|
304
|
+
"html": "<h1>发票 #12345</h1><p>合计 ¥99.99</p>",
|
|
305
|
+
"paper_format": "A4",
|
|
306
|
+
"pdf_options": { "printBackground": true, "margin": { "top": "10mm", "bottom": "10mm" } }
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
真正打印到指定打印机、双面、两份:
|
|
312
|
+
|
|
313
|
+
```json
|
|
314
|
+
{
|
|
315
|
+
"tool": "printHtml",
|
|
316
|
+
"arguments": {
|
|
317
|
+
"html": "<h1>对账单</h1>",
|
|
318
|
+
"dry_run": false,
|
|
319
|
+
"printer_name": "财务室激光",
|
|
320
|
+
"copies": 2,
|
|
321
|
+
"print_options": { "duplexMode": "duplex", "colorful": false }
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
打印 80mm 热敏小票(自定义纸宽):
|
|
327
|
+
|
|
328
|
+
```json
|
|
329
|
+
{
|
|
330
|
+
"tool": "printHtml",
|
|
331
|
+
"arguments": {
|
|
332
|
+
"html": "<div style='width:72mm'>小票内容</div>",
|
|
333
|
+
"dry_run": false,
|
|
334
|
+
"pdf_options": { "width": "80mm", "height": "297mm", "margin": { "top": "0", "bottom": "0", "left": "2mm", "right": "2mm" } },
|
|
335
|
+
"print_options": { "paperFormat": "80mm", "sharp": true }
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
打印本机 PDF 文件:
|
|
341
|
+
|
|
342
|
+
```json
|
|
343
|
+
{ "tool": "printFile", "arguments": { "path": "<path-to-pdf>", "dry_run": false } }
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
批量混合任务:
|
|
347
|
+
|
|
348
|
+
```json
|
|
349
|
+
{
|
|
350
|
+
"tool": "batchPrint",
|
|
351
|
+
"arguments": {
|
|
352
|
+
"dry_run": false,
|
|
353
|
+
"printer_name": "仓库标签机",
|
|
354
|
+
"tasks": [
|
|
355
|
+
{ "type": "printHtml", "data": "<h1>面单 1</h1>" },
|
|
356
|
+
{ "type": "printPdfByUrl", "data": "https://example.com/a.pdf" },
|
|
357
|
+
{ "type": "printHtmlByUrl", "data": "https://example.com/report" }
|
|
358
|
+
]
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
> 批量任务里每个 `extraOptions.action` 必须一致(客户端在浅合并后会校验),所以别在单个任务里
|
|
364
|
+
> 混用 `print` 和 `preview`;统一用顶层 `dry_run` 控制即可。
|
|
365
|
+
|
|
366
|
+
## 大文件怎么打
|
|
367
|
+
|
|
368
|
+
MCP 的 stdio 通道单条消息默认上限 **10MB**(SDK 的 `ReadBuffer`),所以:
|
|
369
|
+
|
|
370
|
+
- `printHtmlByBase64` / `printPdfByBase64` / `printImageByBase64` 只适合小文件——
|
|
371
|
+
约 7MB 以内的 base64(≈5MB 原始文件)。超过后连接会被直接关闭,工具里来不及报错。
|
|
372
|
+
- 大 PDF / 图片 / HTML 请用 `printFile`:由 MCP server 在本机读取文件,再通过 WebSocket 发给
|
|
373
|
+
客户端,绕开 MCP 的消息上限。
|
|
374
|
+
- 也可以先把文件挂到 HTTP 地址,用 `printPdfByUrl` / `printImageByUrl` / `printHtmlByUrl`。
|
|
375
|
+
|
|
376
|
+
## 与 `web-print-pdf@2.1.9` 的覆盖对照
|
|
377
|
+
|
|
378
|
+
| 上游公开 API | 本 MCP |
|
|
379
|
+
|---|---|
|
|
380
|
+
| `printHtml` / `printHtmlByUrl` / `printHtmlByBase64` | ✅ 同名 |
|
|
381
|
+
| `printPdfByUrl` / `printPdfByBase64` | ✅ 同名 |
|
|
382
|
+
| `printImageByUrl` / `printImageByBase64` | ✅ 同名 |
|
|
383
|
+
| `batchPrint` | ✅ 同名 |
|
|
384
|
+
| `utils.getConnectStatus` / `utils.getPrinterList` / `utils.getPrinterPapers` | ✅ 去掉 `utils.` 前缀后同名 |
|
|
385
|
+
| `utils.setTitle` / `utils.setThemeColor` / `utils.switchTabsVisibility` / `utils.setContactUsTabInnerHtml` | ✅ 去掉 `utils.` 前缀后同名 |
|
|
386
|
+
| `utils.onResponse` / `utils.onError` | — 事件回调,MCP 里每个调用都有返回值,不需要 |
|
|
387
|
+
| `_printByRawMessage` | — 下划线私有 API,未纳入 |
|
|
388
|
+
|
|
389
|
+
外加一个上游没有的方法:`printFile`(按本机路径打印,避免把大文件塞进 MCP 消息)。
|
|
390
|
+
|
|
391
|
+
## 实现要点
|
|
392
|
+
|
|
393
|
+
- 请求字段放在消息**顶层**(`content` / `url` / `printOptions` …),不在 `data` 里;这是客户端
|
|
394
|
+
`websocket/standard/index.js` 的约定,与 `web-print-pdf` 的 `dist/index.js` 一致。
|
|
395
|
+
- 响应形如 `{ id, type, timestamp, success, data }`,`data` 里通常有 `pdfFileName` /
|
|
396
|
+
`pdfUrl` / `printPreviewUrl` / `pdfPath`。
|
|
397
|
+
- `extraOptions.action = 'preview'` 时,客户端走 `core/printPdf._printPreview()`,只渲染不送印,
|
|
398
|
+
也**不检查授权**;`action = 'print'` 才会检查 `NOTALLOWUSE`。
|
|
399
|
+
- `pdfOptions.paperFormat` 只认固定枚举;`printOptions.paperFormat` 认任意纸名——代码里对两者分别处理。
|
|
400
|
+
- 客户端对 `pdfOptions` / `printOptions` 做**白名单校验**,未知字段直接报错;`extraOptions` 允许自定义键。
|
|
401
|
+
- HTML / PDF 的 Base64 入参会去掉 `data:...;base64,` 前缀和空白字符;图片通道相反——客户端要求
|
|
402
|
+
`data:image/...;base64,` 前缀并把它原样塞进 `<img src>`,所以服务端会对裸 base64 按文件头补前缀。
|
|
403
|
+
- stdout 是 MCP 协议通道,日志一律走 stderr。
|
|
404
|
+
- 客户端侧实现见 `ElctronPrintWeb` 仓库:消息入口在 `electronApp/server/websocket/standard/`,
|
|
405
|
+
参数白名单在 `core/generatePdf` 与 `core/printPdf`。
|
|
406
|
+
|
|
407
|
+
## 本地验证(没装客户端也能跑)
|
|
408
|
+
|
|
409
|
+
```bash
|
|
410
|
+
# 终端 1:假客户端(覆盖全部消息类型)
|
|
411
|
+
node test/mock-server.js
|
|
412
|
+
|
|
413
|
+
# 终端 2:端到端冒烟,会走一遍 16 个工具
|
|
414
|
+
node test/smoke.js
|
|
415
|
+
|
|
416
|
+
# 或交互式调试
|
|
417
|
+
npx @modelcontextprotocol/inspector node bin/mcp.js
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
装好宿主后也可以直接用模型验证:dsh 下工具名是 `mcp__webprint__printHtml` 这种带命名空间的形式,
|
|
421
|
+
先 `getConnectStatus` 探活,再 `printHtml` + `dry_run: true` 看预览是否生成即可。
|
|
422
|
+
|
|
423
|
+
## 已知边界
|
|
424
|
+
|
|
425
|
+
- 只支持本机已启动的客户端;没有云端中继。
|
|
426
|
+
- 打印是异步队列,返回的是「已提交」,不是「已出纸」。
|
|
427
|
+
- 「已提交」只代表进了 Windows 打印队列;打印机暂停 / 离线 / 缺纸时队列会停住。可用
|
|
428
|
+
`Get-PrintJob -PrinterName "<打印机名>"` 看作业状态,别只看工具返回值。
|
|
429
|
+
- 未授权时 `dry_run: false` 会报 `Not allowed to use, please purchase authorization`。
|
|
430
|
+
- 预览返回的是 URL,agent 看不到图;要「给模型看图」还需把 PDF 转 PNG。
|
|
431
|
+
- `printFile` 会读取 agent 指定的本机文件,只应在可信环境里启用。
|
|
432
|
+
- 走 Base64 的工具受 MCP stdio 10MB 单条消息上限约束,大文件用 `printFile` 或 URL 通道。
|
|
433
|
+
- 批量任务的所有 `extraOptions.action` 必须一致,否则客户端报错。
|
|
434
|
+
- MCP 宿主一般给单次工具调用 60s 左右超时;批量或大文件可能被宿主掐断,需要调大宿主超时或拆批。
|
|
435
|
+
- 预览模式下非法的 `printerName` 可能被客户端忽略而不报错,正式出纸前建议用 `action: "print"` 验证。
|
|
436
|
+
- 参数与消息结构按 `ElctronPrintWeb`(客户端 1.0.9)源码校准:`batchPrint` 任务用 `data` 字段,
|
|
437
|
+
不是 `web-print-pdf` README 示例里的 `content` / `url` / `base64`。
|
|
438
|
+
|
|
439
|
+
## License
|
|
440
|
+
|
|
441
|
+
MIT
|