@docxkit/mcp 0.3.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 +18 -0
- package/dist/index.d.ts +1301 -0
- package/dist/index.js +793 -0
- package/package.json +49 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,793 @@
|
|
|
1
|
+
import { BUILTIN_TEMPLATES } from "@docxkit/ai";
|
|
2
|
+
//#region src/resources/schema.ts
|
|
3
|
+
/**
|
|
4
|
+
* MCP resource: DocxSchema JSON Schema.
|
|
5
|
+
*
|
|
6
|
+
* Provides a complete JSON Schema for the DocxSchema type,
|
|
7
|
+
* enabling LLMs to understand the expected document structure.
|
|
8
|
+
*
|
|
9
|
+
* @module mcp-server/resources/schema
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* DocxSchema JSON Schema for MCP resource exposure.
|
|
13
|
+
*
|
|
14
|
+
* This schema describes the expected structure of a
|
|
15
|
+
* docx-kit document schema, suitable for LLM reference.
|
|
16
|
+
*/
|
|
17
|
+
const docxSchemaResource = {
|
|
18
|
+
mimeType: "application/json",
|
|
19
|
+
name: "docx-kit://schema",
|
|
20
|
+
description: "The complete docx-kit DocxSchema JSON Schema. Describes all node types, their required fields, and how they combine to form a document.",
|
|
21
|
+
schema: {
|
|
22
|
+
$id: "docx-kit://schema",
|
|
23
|
+
$schema: "http://json-schema.org/draft-07/schema#",
|
|
24
|
+
description: "A docx-kit document schema",
|
|
25
|
+
required: ["content"],
|
|
26
|
+
title: "DocxSchema",
|
|
27
|
+
type: "object",
|
|
28
|
+
definitions: {
|
|
29
|
+
blockNode: { oneOf: [
|
|
30
|
+
{
|
|
31
|
+
description: "A bullet list",
|
|
32
|
+
required: ["type", "items"],
|
|
33
|
+
type: "object",
|
|
34
|
+
properties: {
|
|
35
|
+
type: { const: "bulletList" },
|
|
36
|
+
items: {
|
|
37
|
+
items: { type: "string" },
|
|
38
|
+
type: "array"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
description: "A heading (h1–h6)",
|
|
44
|
+
required: [
|
|
45
|
+
"type",
|
|
46
|
+
"level",
|
|
47
|
+
"text"
|
|
48
|
+
],
|
|
49
|
+
type: "object",
|
|
50
|
+
properties: {
|
|
51
|
+
className: { type: "string" },
|
|
52
|
+
level: {
|
|
53
|
+
enum: [
|
|
54
|
+
1,
|
|
55
|
+
2,
|
|
56
|
+
3,
|
|
57
|
+
4,
|
|
58
|
+
5,
|
|
59
|
+
6
|
|
60
|
+
],
|
|
61
|
+
type: "number"
|
|
62
|
+
},
|
|
63
|
+
style: {
|
|
64
|
+
additionalProperties: true,
|
|
65
|
+
type: "object"
|
|
66
|
+
},
|
|
67
|
+
text: { type: "string" },
|
|
68
|
+
type: { const: "heading" }
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
description: "A hyperlink",
|
|
73
|
+
required: [
|
|
74
|
+
"type",
|
|
75
|
+
"url",
|
|
76
|
+
"children"
|
|
77
|
+
],
|
|
78
|
+
type: "object",
|
|
79
|
+
properties: {
|
|
80
|
+
type: { const: "hyperlink" },
|
|
81
|
+
url: { type: "string" },
|
|
82
|
+
children: {
|
|
83
|
+
items: { type: "string" },
|
|
84
|
+
type: "array"
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
description: "An image",
|
|
90
|
+
required: ["type", "data"],
|
|
91
|
+
type: "object",
|
|
92
|
+
properties: {
|
|
93
|
+
alt: { type: "string" },
|
|
94
|
+
data: { type: "string" },
|
|
95
|
+
height: { type: "number" },
|
|
96
|
+
type: { const: "image" },
|
|
97
|
+
width: { type: "number" },
|
|
98
|
+
imageType: {
|
|
99
|
+
enum: [
|
|
100
|
+
"png",
|
|
101
|
+
"jpeg",
|
|
102
|
+
"jpg",
|
|
103
|
+
"gif",
|
|
104
|
+
"bmp"
|
|
105
|
+
],
|
|
106
|
+
type: "string"
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
description: "A numbered list",
|
|
112
|
+
required: ["type", "items"],
|
|
113
|
+
type: "object",
|
|
114
|
+
properties: {
|
|
115
|
+
type: { const: "numberedList" },
|
|
116
|
+
items: {
|
|
117
|
+
items: { type: "string" },
|
|
118
|
+
type: "array"
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
description: "A page break",
|
|
124
|
+
properties: { type: { const: "pageBreak" } },
|
|
125
|
+
required: ["type"],
|
|
126
|
+
type: "object"
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
description: "A paragraph of text",
|
|
130
|
+
required: ["type"],
|
|
131
|
+
type: "object",
|
|
132
|
+
properties: {
|
|
133
|
+
className: { type: "string" },
|
|
134
|
+
style: {
|
|
135
|
+
additionalProperties: true,
|
|
136
|
+
type: "object"
|
|
137
|
+
},
|
|
138
|
+
text: { type: "string" },
|
|
139
|
+
type: { const: "paragraph" },
|
|
140
|
+
children: {
|
|
141
|
+
items: {
|
|
142
|
+
additionalProperties: true,
|
|
143
|
+
type: "object"
|
|
144
|
+
},
|
|
145
|
+
type: "array"
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
description: "A plugin invocation",
|
|
151
|
+
required: [
|
|
152
|
+
"type",
|
|
153
|
+
"name",
|
|
154
|
+
"options"
|
|
155
|
+
],
|
|
156
|
+
type: "object",
|
|
157
|
+
properties: {
|
|
158
|
+
name: { type: "string" },
|
|
159
|
+
options: {
|
|
160
|
+
additionalProperties: true,
|
|
161
|
+
type: "object"
|
|
162
|
+
},
|
|
163
|
+
type: { const: "plugin" }
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
description: "A section break",
|
|
168
|
+
required: ["type"],
|
|
169
|
+
type: "object",
|
|
170
|
+
properties: {
|
|
171
|
+
config: {
|
|
172
|
+
additionalProperties: true,
|
|
173
|
+
type: "object"
|
|
174
|
+
},
|
|
175
|
+
type: { const: "sectionBreak" }
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
description: "A data table",
|
|
180
|
+
required: [
|
|
181
|
+
"type",
|
|
182
|
+
"columns",
|
|
183
|
+
"data"
|
|
184
|
+
],
|
|
185
|
+
type: "object",
|
|
186
|
+
properties: {
|
|
187
|
+
header: { type: "boolean" },
|
|
188
|
+
striped: { type: "boolean" },
|
|
189
|
+
type: { const: "table" },
|
|
190
|
+
columns: {
|
|
191
|
+
type: "array",
|
|
192
|
+
items: {
|
|
193
|
+
required: ["key", "title"],
|
|
194
|
+
type: "object",
|
|
195
|
+
properties: {
|
|
196
|
+
key: { type: "string" },
|
|
197
|
+
title: { type: "string" },
|
|
198
|
+
width: { type: "string" },
|
|
199
|
+
align: {
|
|
200
|
+
enum: [
|
|
201
|
+
"left",
|
|
202
|
+
"center",
|
|
203
|
+
"right"
|
|
204
|
+
],
|
|
205
|
+
type: "string"
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
},
|
|
210
|
+
data: {
|
|
211
|
+
items: {
|
|
212
|
+
additionalProperties: true,
|
|
213
|
+
type: "object"
|
|
214
|
+
},
|
|
215
|
+
type: "array"
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
] },
|
|
220
|
+
styleRule: {
|
|
221
|
+
additionalProperties: true,
|
|
222
|
+
description: "CSS-like style properties for a node",
|
|
223
|
+
type: "object",
|
|
224
|
+
properties: {
|
|
225
|
+
backgroundColor: { type: "string" },
|
|
226
|
+
borderBottom: { type: "string" },
|
|
227
|
+
borderLeft: { type: "string" },
|
|
228
|
+
borderRight: { type: "string" },
|
|
229
|
+
borderTop: { type: "string" },
|
|
230
|
+
color: { type: "string" },
|
|
231
|
+
fontFamily: { type: "string" },
|
|
232
|
+
fontSize: { type: "number" },
|
|
233
|
+
fontWeight: {
|
|
234
|
+
enum: [
|
|
235
|
+
"bold",
|
|
236
|
+
"normal",
|
|
237
|
+
"semibold"
|
|
238
|
+
],
|
|
239
|
+
type: "string"
|
|
240
|
+
},
|
|
241
|
+
lineHeight: { type: "number" },
|
|
242
|
+
marginBottom: { type: "number" },
|
|
243
|
+
marginLeft: { type: "number" },
|
|
244
|
+
marginTop: { type: "number" },
|
|
245
|
+
textAlign: {
|
|
246
|
+
enum: [
|
|
247
|
+
"center",
|
|
248
|
+
"justify",
|
|
249
|
+
"left",
|
|
250
|
+
"right"
|
|
251
|
+
],
|
|
252
|
+
type: "string"
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
},
|
|
257
|
+
properties: {
|
|
258
|
+
content: {
|
|
259
|
+
description: "Ordered array of block nodes",
|
|
260
|
+
items: { $ref: "#/definitions/blockNode" },
|
|
261
|
+
type: "array"
|
|
262
|
+
},
|
|
263
|
+
page: {
|
|
264
|
+
description: "Page configuration",
|
|
265
|
+
type: "object",
|
|
266
|
+
properties: {
|
|
267
|
+
margin: { type: "string" },
|
|
268
|
+
orientation: {
|
|
269
|
+
enum: ["landscape", "portrait"],
|
|
270
|
+
type: "string"
|
|
271
|
+
},
|
|
272
|
+
size: {
|
|
273
|
+
enum: [
|
|
274
|
+
"A3",
|
|
275
|
+
"A4",
|
|
276
|
+
"Legal",
|
|
277
|
+
"Letter"
|
|
278
|
+
],
|
|
279
|
+
type: "string"
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
},
|
|
283
|
+
plugins: {
|
|
284
|
+
description: "Plugin sources to load before rendering",
|
|
285
|
+
type: "array",
|
|
286
|
+
items: {
|
|
287
|
+
required: ["type"],
|
|
288
|
+
type: "object",
|
|
289
|
+
properties: {
|
|
290
|
+
plugin: {
|
|
291
|
+
description: "Inline plugin instance",
|
|
292
|
+
type: "object"
|
|
293
|
+
},
|
|
294
|
+
type: {
|
|
295
|
+
enum: [
|
|
296
|
+
"inline",
|
|
297
|
+
"npm",
|
|
298
|
+
"url",
|
|
299
|
+
"local"
|
|
300
|
+
],
|
|
301
|
+
type: "string"
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
},
|
|
306
|
+
styles: {
|
|
307
|
+
additionalProperties: { $ref: "#/definitions/styleRule" },
|
|
308
|
+
description: "Named stylesheet entries",
|
|
309
|
+
type: "object"
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
};
|
|
314
|
+
//#endregion
|
|
315
|
+
//#region src/tools/applyTemplate.ts
|
|
316
|
+
/**
|
|
317
|
+
* MCP tool: generate a document from a template + data.
|
|
318
|
+
*
|
|
319
|
+
* @module mcp-server/tools/applyTemplate
|
|
320
|
+
*/
|
|
321
|
+
/**
|
|
322
|
+
* MCP tool definition for `apply_template`.
|
|
323
|
+
*
|
|
324
|
+
* Generates a DocxSchema from a named template + data params.
|
|
325
|
+
*/
|
|
326
|
+
const applyTemplateToolDefinition = {
|
|
327
|
+
name: "apply_template",
|
|
328
|
+
description: "Generate a docx-kit document schema from an AI template and provided data parameters.",
|
|
329
|
+
inputSchema: {
|
|
330
|
+
required: ["template", "data"],
|
|
331
|
+
type: "object",
|
|
332
|
+
properties: {
|
|
333
|
+
data: {
|
|
334
|
+
description: "Template parameter values (must match template schema)",
|
|
335
|
+
type: "object"
|
|
336
|
+
},
|
|
337
|
+
template: {
|
|
338
|
+
type: "string",
|
|
339
|
+
description: "Name of the template to apply (report, invoice, resume, letter)"
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
};
|
|
344
|
+
/**
|
|
345
|
+
* Apply a template with given data to produce a DocxSchema.
|
|
346
|
+
*
|
|
347
|
+
* @param templateName - — Template name (e.g. 'report')
|
|
348
|
+
* @param data - — Template parameters
|
|
349
|
+
* @returns Generated DocxSchema and template name, or null if template not found
|
|
350
|
+
*/
|
|
351
|
+
function applyTemplate(templateName, data) {
|
|
352
|
+
const template = BUILTIN_TEMPLATES.find((t) => t.name === templateName);
|
|
353
|
+
if (!template) return null;
|
|
354
|
+
return {
|
|
355
|
+
schema: template.generate(data),
|
|
356
|
+
templateName
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
//#endregion
|
|
360
|
+
//#region src/tools/createDocx.ts
|
|
361
|
+
/**
|
|
362
|
+
* MCP tool definition for `create_document`.
|
|
363
|
+
*
|
|
364
|
+
* Creates a new .docx file from a docx-kit JSON schema.
|
|
365
|
+
* Takes an `outputPath` and a `schema` (DocxSchema JSON object).
|
|
366
|
+
*
|
|
367
|
+
* @remarks Used by the MCP server as a tool registration.
|
|
368
|
+
*/
|
|
369
|
+
const createDocxToolDefinition = {
|
|
370
|
+
name: "create_document",
|
|
371
|
+
description: "Create a new .docx document from a docx-kit JSON schema. The schema defines content nodes, styles, and page configuration.",
|
|
372
|
+
inputSchema: {
|
|
373
|
+
required: ["schema", "outputPath"],
|
|
374
|
+
type: "object",
|
|
375
|
+
properties: {
|
|
376
|
+
outputPath: {
|
|
377
|
+
description: "File path for the output .docx file",
|
|
378
|
+
type: "string"
|
|
379
|
+
},
|
|
380
|
+
schema: {
|
|
381
|
+
type: "object",
|
|
382
|
+
description: "A docx-kit DocxSchema object with content, styles, and page config"
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
};
|
|
387
|
+
//#endregion
|
|
388
|
+
//#region src/tools/getPluginHelp.ts
|
|
389
|
+
/**
|
|
390
|
+
* MCP tool definition for `get_plugin_help`.
|
|
391
|
+
*
|
|
392
|
+
* Returns usage help and option schema for a named plugin.
|
|
393
|
+
*/
|
|
394
|
+
const getPluginHelpToolDefinition = {
|
|
395
|
+
name: "get_plugin_help",
|
|
396
|
+
description: "Get usage help and option details for a specific docx-kit plugin.",
|
|
397
|
+
inputSchema: {
|
|
398
|
+
required: ["pluginName"],
|
|
399
|
+
type: "object",
|
|
400
|
+
properties: { pluginName: {
|
|
401
|
+
description: "The name of the plugin to get help for",
|
|
402
|
+
type: "string"
|
|
403
|
+
} }
|
|
404
|
+
}
|
|
405
|
+
};
|
|
406
|
+
/**
|
|
407
|
+
* Build help info for a plugin.
|
|
408
|
+
*
|
|
409
|
+
* Provides a usage example based on the plugin name,
|
|
410
|
+
* referencing a built-in map of known plugins.
|
|
411
|
+
*
|
|
412
|
+
* @param plugin - — The DocxPlugin to build help for
|
|
413
|
+
* @returns PluginHelpInfo with description, name, and usage example
|
|
414
|
+
*/
|
|
415
|
+
function buildPluginHelp(plugin) {
|
|
416
|
+
return {
|
|
417
|
+
description: `Built-in docx-kit plugin: ${plugin.name}. Renders ${plugin.name} content in the document.`,
|
|
418
|
+
name: plugin.name,
|
|
419
|
+
usageExample: {
|
|
420
|
+
pageNumber: "{ type: \"plugin\", name: \"pageNumber\", options: {} }",
|
|
421
|
+
callout: "{ type: \"plugin\", name: \"callout\", options: { title: \"Note\", variant: \"info\", text: \"Important message\" } }",
|
|
422
|
+
codeBlock: "{ type: \"plugin\", name: \"codeBlock\", options: { code: \"console.log('hello')\", language: \"javascript\" } }",
|
|
423
|
+
coverPage: "{ type: \"plugin\", name: \"coverPage\", options: { title: \"Annual Report\", author: \"John Doe\", date: \"2026-06-12\" } }",
|
|
424
|
+
dataTable: "{ type: \"plugin\", name: \"dataTable\", options: { columns: [...], data: [...], striped: true } }",
|
|
425
|
+
echarts: "{ type: \"plugin\", name: \"echarts\", options: { option: { ...echarts config... }, width: 400, height: 300 } }",
|
|
426
|
+
meetingMinutes: "{ type: \"plugin\", name: \"meetingMinutes\", options: { title: \"Team Meeting\", date: \"2026-06-12\", attendees: [\"Alice\", \"Bob\"] } }",
|
|
427
|
+
propertyTable: "{ type: \"plugin\", name: \"propertyTable\", options: { items: [{ key: \"Name\", value: \"Alice\" }] } }",
|
|
428
|
+
qrcode: "{ type: \"plugin\", name: \"qrcode\", options: { text: \"https://example.com\", width: 100 } }",
|
|
429
|
+
signatureBlock: "{ type: \"plugin\", name: \"signatureBlock\", options: { parties: [{ name: \"Alice\", role: \"Manager\" }] } }",
|
|
430
|
+
timeline: "{ type: \"plugin\", name: \"timeline\", options: { events: [{ date: \"2026-01\", title: \"Kickoff\" }] } }",
|
|
431
|
+
watermark: "{ type: \"plugin\", name: \"watermark\", options: { text: \"CONFIDENTIAL\", opacity: 0.3 } }"
|
|
432
|
+
}[plugin.name] ?? `{ type: "plugin", name: "${plugin.name}", options: { ... } }`
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
//#endregion
|
|
436
|
+
//#region src/tools/listPlugins.ts
|
|
437
|
+
/**
|
|
438
|
+
* MCP tool definition for `list_plugins`.
|
|
439
|
+
*
|
|
440
|
+
* Returns metadata for all registered plugins.
|
|
441
|
+
*/
|
|
442
|
+
const listPluginsToolDefinition = {
|
|
443
|
+
name: "list_plugins",
|
|
444
|
+
description: "List all available docx-kit plugins with their names and descriptions.",
|
|
445
|
+
inputSchema: {
|
|
446
|
+
type: "object",
|
|
447
|
+
properties: { filter: {
|
|
448
|
+
description: "Optional name filter pattern",
|
|
449
|
+
type: "string"
|
|
450
|
+
} }
|
|
451
|
+
}
|
|
452
|
+
};
|
|
453
|
+
/**
|
|
454
|
+
* Build plugin info from a list of DocxPlugin instances.
|
|
455
|
+
*
|
|
456
|
+
* Optionally filters by a case-insensitive name substring.
|
|
457
|
+
*
|
|
458
|
+
* @param plugins - — Registered plugins
|
|
459
|
+
* @param filter - — Optional name filter pattern (case-insensitive)
|
|
460
|
+
* @returns Array of PluginInfo objects
|
|
461
|
+
*/
|
|
462
|
+
function buildPluginInfoList(plugins, filter) {
|
|
463
|
+
const allInfo = plugins.map((p) => ({
|
|
464
|
+
description: `Built-in docx-kit plugin: ${p.name}`,
|
|
465
|
+
name: p.name
|
|
466
|
+
}));
|
|
467
|
+
if (filter) return allInfo.filter((p) => p.name.toLowerCase().includes(filter.toLowerCase()));
|
|
468
|
+
return allInfo;
|
|
469
|
+
}
|
|
470
|
+
//#endregion
|
|
471
|
+
//#region src/tools/listTemplates.ts
|
|
472
|
+
/**
|
|
473
|
+
* MCP tool: list and apply AI templates.
|
|
474
|
+
*
|
|
475
|
+
* @module mcp-server/tools/listTemplates
|
|
476
|
+
*/
|
|
477
|
+
/**
|
|
478
|
+
* MCP tool definition for `list_templates`.
|
|
479
|
+
*
|
|
480
|
+
* Returns all available docx-kit AI templates.
|
|
481
|
+
*/
|
|
482
|
+
const listTemplatesToolDefinition = {
|
|
483
|
+
name: "list_templates",
|
|
484
|
+
description: "List all available docx-kit AI templates for document generation.",
|
|
485
|
+
inputSchema: {
|
|
486
|
+
properties: {},
|
|
487
|
+
type: "object"
|
|
488
|
+
}
|
|
489
|
+
};
|
|
490
|
+
/**
|
|
491
|
+
* Build template info list from built-in templates.
|
|
492
|
+
*
|
|
493
|
+
* @returns Array of template info (without generator)
|
|
494
|
+
*/
|
|
495
|
+
function buildTemplateInfoList() {
|
|
496
|
+
return BUILTIN_TEMPLATES.map((t) => ({
|
|
497
|
+
description: t.description,
|
|
498
|
+
name: t.name,
|
|
499
|
+
schema: t.schema,
|
|
500
|
+
systemPrompt: t.systemPrompt
|
|
501
|
+
}));
|
|
502
|
+
}
|
|
503
|
+
//#endregion
|
|
504
|
+
//#region src/tools/validateSchema.ts
|
|
505
|
+
/**
|
|
506
|
+
* MCP tool definition for `validate_schema`.
|
|
507
|
+
*
|
|
508
|
+
* Validates a docx-kit JSON schema and returns
|
|
509
|
+
* detailed error information.
|
|
510
|
+
*/
|
|
511
|
+
const validateSchemaToolDefinition = {
|
|
512
|
+
name: "validate_schema",
|
|
513
|
+
description: "Validate a docx-kit JSON schema. Checks node types, required fields, and structural correctness.",
|
|
514
|
+
inputSchema: {
|
|
515
|
+
required: ["schema"],
|
|
516
|
+
type: "object",
|
|
517
|
+
properties: { schema: {
|
|
518
|
+
description: "The DocxSchema JSON object to validate",
|
|
519
|
+
type: "object"
|
|
520
|
+
} }
|
|
521
|
+
}
|
|
522
|
+
};
|
|
523
|
+
/**
|
|
524
|
+
* Validate a DocxSchema object.
|
|
525
|
+
*
|
|
526
|
+
* Checks for:
|
|
527
|
+
* - Required `content` array
|
|
528
|
+
* - Valid node types in content
|
|
529
|
+
* - Required fields per node type
|
|
530
|
+
*
|
|
531
|
+
* @param schema - — The schema to validate
|
|
532
|
+
* @returns Validation result with errors
|
|
533
|
+
*/
|
|
534
|
+
function validateSchema(schema) {
|
|
535
|
+
const errors = [];
|
|
536
|
+
const content = schema?.content;
|
|
537
|
+
if (!content) errors.push({
|
|
538
|
+
message: "Required field \"content\" is missing",
|
|
539
|
+
path: "/content"
|
|
540
|
+
});
|
|
541
|
+
else if (Array.isArray(content)) {
|
|
542
|
+
const validNodeTypes = new Set([
|
|
543
|
+
"bulletList",
|
|
544
|
+
"heading",
|
|
545
|
+
"hyperlink",
|
|
546
|
+
"image",
|
|
547
|
+
"numberedList",
|
|
548
|
+
"pageBreak",
|
|
549
|
+
"paragraph",
|
|
550
|
+
"plugin",
|
|
551
|
+
"sectionBreak",
|
|
552
|
+
"table"
|
|
553
|
+
]);
|
|
554
|
+
for (const [i, element] of content.entries()) {
|
|
555
|
+
const node = element;
|
|
556
|
+
if (typeof node !== "object" || node === null) {
|
|
557
|
+
errors.push({
|
|
558
|
+
message: `Node at index ${i} must be an object`,
|
|
559
|
+
path: `/content/${i}`
|
|
560
|
+
});
|
|
561
|
+
continue;
|
|
562
|
+
}
|
|
563
|
+
const nodeType = node.type;
|
|
564
|
+
if (!nodeType) {
|
|
565
|
+
errors.push({
|
|
566
|
+
message: `Node at index ${i} missing required "type" field`,
|
|
567
|
+
path: `/content/${i}/type`
|
|
568
|
+
});
|
|
569
|
+
continue;
|
|
570
|
+
}
|
|
571
|
+
if (!validNodeTypes.has(nodeType)) errors.push({
|
|
572
|
+
message: `Invalid node type "${nodeType}" at index ${i}`,
|
|
573
|
+
path: `/content/${i}/type`
|
|
574
|
+
});
|
|
575
|
+
if (nodeType === "heading" && !node.text) errors.push({
|
|
576
|
+
message: `Heading node at index ${i} missing required "text" field`,
|
|
577
|
+
path: `/content/${i}/text`
|
|
578
|
+
});
|
|
579
|
+
if (nodeType === "heading" && !node.level) errors.push({
|
|
580
|
+
message: `Heading node at index ${i} missing required "level" field`,
|
|
581
|
+
path: `/content/${i}/level`
|
|
582
|
+
});
|
|
583
|
+
if (nodeType === "paragraph" && !node.text && !node.children) errors.push({
|
|
584
|
+
message: `Paragraph node at index ${i} must have "text" or "children"`,
|
|
585
|
+
path: `/content/${i}`
|
|
586
|
+
});
|
|
587
|
+
if (nodeType === "plugin" && !node.name) errors.push({
|
|
588
|
+
message: `Plugin node at index ${i} missing required "name" field`,
|
|
589
|
+
path: `/content/${i}/name`
|
|
590
|
+
});
|
|
591
|
+
if (nodeType === "table" && !node.columns) errors.push({
|
|
592
|
+
message: `Table node at index ${i} missing required "columns" field`,
|
|
593
|
+
path: `/content/${i}/columns`
|
|
594
|
+
});
|
|
595
|
+
if (nodeType === "table" && !node.data) errors.push({
|
|
596
|
+
message: `Table node at index ${i} missing required "data" field`,
|
|
597
|
+
path: `/content/${i}/data`
|
|
598
|
+
});
|
|
599
|
+
}
|
|
600
|
+
} else errors.push({
|
|
601
|
+
message: "Field \"content\" must be an array",
|
|
602
|
+
path: "/content"
|
|
603
|
+
});
|
|
604
|
+
return {
|
|
605
|
+
errors,
|
|
606
|
+
valid: errors.length === 0
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
//#endregion
|
|
610
|
+
//#region src/index.ts
|
|
611
|
+
/**
|
|
612
|
+
* docx-kit MCP server — AI agent integration via
|
|
613
|
+
* Model Context Protocol.
|
|
614
|
+
*
|
|
615
|
+
* Provides tools for document creation, validation,
|
|
616
|
+
* plugin discovery, template application, and schema resources.
|
|
617
|
+
*
|
|
618
|
+
* The server uses `@modelcontextprotocol/sdk` (optional peer dep)
|
|
619
|
+
* for MCP protocol handling. If the SDK is not installed,
|
|
620
|
+
* individual tool/resource definitions and execution logic
|
|
621
|
+
* can still be used programmatically.
|
|
622
|
+
*
|
|
623
|
+
* @module mcp-server
|
|
624
|
+
*/
|
|
625
|
+
/**
|
|
626
|
+
* All MCP tool definitions for docx-kit.
|
|
627
|
+
*/
|
|
628
|
+
const TOOL_DEFINITIONS = [
|
|
629
|
+
applyTemplateToolDefinition,
|
|
630
|
+
createDocxToolDefinition,
|
|
631
|
+
getPluginHelpToolDefinition,
|
|
632
|
+
listPluginsToolDefinition,
|
|
633
|
+
listTemplatesToolDefinition,
|
|
634
|
+
validateSchemaToolDefinition
|
|
635
|
+
];
|
|
636
|
+
/**
|
|
637
|
+
* All MCP resource definitions for docx-kit.
|
|
638
|
+
*/
|
|
639
|
+
const RESOURCE_DEFINITIONS = [docxSchemaResource];
|
|
640
|
+
/**
|
|
641
|
+
* Create a docx-kit MCP server.
|
|
642
|
+
*
|
|
643
|
+
* Uses `@modelcontextprotocol/sdk` to create a fully compliant
|
|
644
|
+
* MCP server with all docx-kit tools and resources registered.
|
|
645
|
+
*
|
|
646
|
+
* Requires `@modelcontextprotocol/sdk` to be installed.
|
|
647
|
+
* Connect via `StdioServerTransport` for CLI usage or
|
|
648
|
+
* `StreamableHTTPServerTransport` for HTTP access.
|
|
649
|
+
*
|
|
650
|
+
* @returns An MCP server instance ready to connect
|
|
651
|
+
*
|
|
652
|
+
* @example
|
|
653
|
+
* ```ts
|
|
654
|
+
* import { createDocxKitServer } from 'docx-kit/mcp'
|
|
655
|
+
* import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
|
|
656
|
+
*
|
|
657
|
+
* const server = createDocxKitServer()
|
|
658
|
+
* const transport = new StdioServerTransport()
|
|
659
|
+
* await server.connect(transport)
|
|
660
|
+
* ```
|
|
661
|
+
*/
|
|
662
|
+
async function createDocxKitServer() {
|
|
663
|
+
const { McpServer } = await import("@modelcontextprotocol/sdk/server/mcp.js");
|
|
664
|
+
const { z } = await import("zod");
|
|
665
|
+
const server = new McpServer({
|
|
666
|
+
name: "docx-kit",
|
|
667
|
+
version: "0.2.0"
|
|
668
|
+
});
|
|
669
|
+
server.registerTool("create_document", {
|
|
670
|
+
description: "Create a new .docx document from a docx-kit JSON schema",
|
|
671
|
+
inputSchema: {
|
|
672
|
+
outputPath: z.string().describe("File path for the output .docx file"),
|
|
673
|
+
schema: z.record(z.string(), z.unknown()).describe("A docx-kit DocxSchema JSON object")
|
|
674
|
+
}
|
|
675
|
+
}, async (input) => {
|
|
676
|
+
const docSchema = input.schema;
|
|
677
|
+
const validation = validateSchema(docSchema);
|
|
678
|
+
if (!validation.valid) return {
|
|
679
|
+
isError: true,
|
|
680
|
+
content: [{
|
|
681
|
+
text: `Schema validation failed:\n${validation.errors.map((e) => ` ${e.path}: ${e.message}`).join("\n")}`,
|
|
682
|
+
type: "text"
|
|
683
|
+
}]
|
|
684
|
+
};
|
|
685
|
+
return { content: [{
|
|
686
|
+
text: `Document schema is valid. Use renderDocx() to generate the document and save to: ${input.outputPath}`,
|
|
687
|
+
type: "text"
|
|
688
|
+
}] };
|
|
689
|
+
});
|
|
690
|
+
server.registerTool("validate_schema", {
|
|
691
|
+
description: "Validate a docx-kit JSON schema for correctness",
|
|
692
|
+
inputSchema: { schema: z.record(z.string(), z.unknown()).describe("The DocxSchema JSON object to validate") }
|
|
693
|
+
}, async (input) => {
|
|
694
|
+
const result = validateSchema(input.schema);
|
|
695
|
+
return { content: [{
|
|
696
|
+
type: "text",
|
|
697
|
+
text: result.valid ? "Schema is valid ✓" : `Validation errors:\n${result.errors.map((e) => ` ${e.path}: ${e.message}`).join("\n")}`
|
|
698
|
+
}] };
|
|
699
|
+
});
|
|
700
|
+
server.registerTool("list_plugins", {
|
|
701
|
+
description: "List all available docx-kit plugins",
|
|
702
|
+
inputSchema: { filter: z.string().optional().describe("Optional name filter pattern") }
|
|
703
|
+
}, async (input) => {
|
|
704
|
+
const infoList = [
|
|
705
|
+
"callout",
|
|
706
|
+
"codeBlock",
|
|
707
|
+
"coverPage",
|
|
708
|
+
"dataTable",
|
|
709
|
+
"echarts",
|
|
710
|
+
"meetingMinutes",
|
|
711
|
+
"pageNumber",
|
|
712
|
+
"propertyTable",
|
|
713
|
+
"qrcode",
|
|
714
|
+
"signatureBlock",
|
|
715
|
+
"timeline",
|
|
716
|
+
"watermark"
|
|
717
|
+
].map((name) => ({
|
|
718
|
+
description: `Built-in docx-kit plugin: ${name}`,
|
|
719
|
+
name
|
|
720
|
+
}));
|
|
721
|
+
const filtered = input.filter ? infoList.filter((p) => p.name.toLowerCase().includes(input.filter.toLowerCase())) : infoList;
|
|
722
|
+
return { content: [{
|
|
723
|
+
text: JSON.stringify(filtered, null, 2),
|
|
724
|
+
type: "text"
|
|
725
|
+
}] };
|
|
726
|
+
});
|
|
727
|
+
server.registerTool("get_plugin_help", {
|
|
728
|
+
description: "Get usage help for a specific docx-kit plugin",
|
|
729
|
+
inputSchema: { pluginName: z.string().describe("The plugin name") }
|
|
730
|
+
}, async (input) => {
|
|
731
|
+
const helpInfo = {
|
|
732
|
+
description: `Built-in docx-kit plugin: ${input.pluginName}`,
|
|
733
|
+
name: input.pluginName,
|
|
734
|
+
usageExample: `{ type: "plugin", name: "${input.pluginName}", options: { ... } }`
|
|
735
|
+
};
|
|
736
|
+
const usageExamples = {
|
|
737
|
+
pageNumber: "{ type: \"plugin\", name: \"pageNumber\", options: {} }",
|
|
738
|
+
callout: "{ type: \"plugin\", name: \"callout\", options: { title: \"Note\", variant: \"info\", text: \"Important message\" } }",
|
|
739
|
+
codeBlock: "{ type: \"plugin\", name: \"codeBlock\", options: { code: \"console.log('hello')\", language: \"javascript\" } }",
|
|
740
|
+
coverPage: "{ type: \"plugin\", name: \"coverPage\", options: { title: \"Annual Report\", author: \"John Doe\", date: \"2026-06-12\" } }",
|
|
741
|
+
dataTable: "{ type: \"plugin\", name: \"dataTable\", options: { columns: [...], data: [...], striped: true } }",
|
|
742
|
+
echarts: "{ type: \"plugin\", name: \"echarts\", options: { option: { ...echarts config... }, width: 400, height: 300 } }",
|
|
743
|
+
meetingMinutes: "{ type: \"plugin\", name: \"meetingMinutes\", options: { title: \"Team Meeting\", date: \"2026-06-12\", attendees: [\"Alice\", \"Bob\"] } }",
|
|
744
|
+
propertyTable: "{ type: \"plugin\", name: \"propertyTable\", options: { items: [{ key: \"Name\", value: \"Alice\" }] } }",
|
|
745
|
+
qrcode: "{ type: \"plugin\", name: \"qrcode\", options: { text: \"https://example.com\", width: 100 } }",
|
|
746
|
+
signatureBlock: "{ type: \"plugin\", name: \"signatureBlock\", options: { parties: [{ name: \"Alice\", role: \"Manager\" }] } }",
|
|
747
|
+
timeline: "{ type: \"plugin\", name: \"timeline\", options: { events: [{ date: \"2026-01\", title: \"Kickoff\" }] } }",
|
|
748
|
+
watermark: "{ type: \"plugin\", name: \"watermark\", options: { text: \"CONFIDENTIAL\", opacity: 0.3 } }"
|
|
749
|
+
};
|
|
750
|
+
if (usageExamples[input.pluginName]) helpInfo.usageExample = usageExamples[input.pluginName];
|
|
751
|
+
return { content: [{
|
|
752
|
+
text: JSON.stringify(helpInfo, null, 2),
|
|
753
|
+
type: "text"
|
|
754
|
+
}] };
|
|
755
|
+
});
|
|
756
|
+
server.registerTool("list_templates", { description: "List all available docx-kit AI templates" }, async () => {
|
|
757
|
+
const templates = buildTemplateInfoList();
|
|
758
|
+
return { content: [{
|
|
759
|
+
text: JSON.stringify(templates, null, 2),
|
|
760
|
+
type: "text"
|
|
761
|
+
}] };
|
|
762
|
+
});
|
|
763
|
+
server.registerTool("apply_template", {
|
|
764
|
+
description: "Generate a document schema from an AI template + data",
|
|
765
|
+
inputSchema: {
|
|
766
|
+
data: z.record(z.string(), z.unknown()).describe("Template parameter values"),
|
|
767
|
+
template: z.string().describe("Template name (report, invoice, resume, letter)")
|
|
768
|
+
}
|
|
769
|
+
}, async (input) => {
|
|
770
|
+
const result = applyTemplate(input.template, input.data);
|
|
771
|
+
if (!result) return {
|
|
772
|
+
isError: true,
|
|
773
|
+
content: [{
|
|
774
|
+
text: `Template "${input.template}" not found. Available: report, invoice, resume, letter`,
|
|
775
|
+
type: "text"
|
|
776
|
+
}]
|
|
777
|
+
};
|
|
778
|
+
return { content: [{
|
|
779
|
+
text: JSON.stringify(result.schema, null, 2),
|
|
780
|
+
type: "text"
|
|
781
|
+
}] };
|
|
782
|
+
});
|
|
783
|
+
server.registerResource("docx-kit-schema", "docx-kit://schema", {}, async (uri) => {
|
|
784
|
+
return { contents: [{
|
|
785
|
+
mimeType: "application/json",
|
|
786
|
+
text: JSON.stringify(docxSchemaResource.schema, null, 2),
|
|
787
|
+
uri: uri.href
|
|
788
|
+
}] };
|
|
789
|
+
});
|
|
790
|
+
return server;
|
|
791
|
+
}
|
|
792
|
+
//#endregion
|
|
793
|
+
export { RESOURCE_DEFINITIONS, TOOL_DEFINITIONS, applyTemplate, applyTemplateToolDefinition, buildPluginHelp, buildPluginInfoList, buildTemplateInfoList, createDocxKitServer, createDocxToolDefinition, docxSchemaResource, getPluginHelpToolDefinition, listPluginsToolDefinition, listTemplatesToolDefinition, validateSchema, validateSchemaToolDefinition };
|