@tiwater/office-mcp 0.16.19 → 0.17.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/office/README.md CHANGED
@@ -17,8 +17,9 @@ OpenXML-internal identifiers, not filesystem arguments.
17
17
 
18
18
  ## Capability families
19
19
 
20
- - DOCX: inspect document/tables, export, compare, validate OpenXML, font, and table-of-contents styles
21
- policy, transform styles, and batch one fixed edit action.
20
+ - DOCX: inspect document/tables, export, compare, validate OpenXML, apply or validate font and
21
+ table-of-contents style policies, refresh document fields, replace object text, transform styles,
22
+ and batch one fixed edit action.
22
23
  - XLS/XLSX: convert legacy XLS with ET, inspect/export, validate, and batch
23
24
  one fixed workbook edit action.
24
25
  - PPTX: inspect/export, bind selected masters/layouts, apply text formatting,
@@ -0,0 +1,31 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "tiwater.office-mcp-input/docx_apply_font_policy",
4
+ "type": "object",
5
+ "properties": {
6
+ "targetDocument": {
7
+ "type": "object",
8
+ "properties": {
9
+ "input": { "type": "string", "minLength": 1, "x-tiwater-file-role": "read" },
10
+ "revision": { "type": "string", "pattern": "^docx-rev-v1-[0-9a-f]{64}$" }
11
+ },
12
+ "required": ["input", "revision"],
13
+ "additionalProperties": false
14
+ },
15
+ "policy": {
16
+ "type": "string",
17
+ "minLength": 1,
18
+ "x-tiwater-file-role": "read",
19
+ "description": "Path to the current caller-authorized tiwater.docx-font-policy/v1 JSON asset."
20
+ },
21
+ "output": { "type": "string", "minLength": 1, "x-tiwater-file-role": "write" },
22
+ "receiptOutput": {
23
+ "type": "string",
24
+ "minLength": 1,
25
+ "x-tiwater-file-role": "write",
26
+ "x-tiwater-file-effect": false
27
+ }
28
+ },
29
+ "required": ["targetDocument", "policy", "output", "receiptOutput"],
30
+ "additionalProperties": false
31
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "tiwater.office-mcp-input/docx_apply_toc_style_policy",
4
+ "type": "object",
5
+ "properties": {
6
+ "targetDocument": {
7
+ "type": "object",
8
+ "properties": {
9
+ "input": { "type": "string", "minLength": 1, "x-tiwater-file-role": "read" },
10
+ "revision": { "type": "string", "pattern": "^docx-rev-v1-[0-9a-f]{64}$" }
11
+ },
12
+ "required": ["input", "revision"],
13
+ "additionalProperties": false
14
+ },
15
+ "italic": { "type": "boolean" },
16
+ "indentCharactersPerLevel": { "type": "integer", "minimum": 0, "maximum": 21474836 },
17
+ "output": { "type": "string", "minLength": 1, "x-tiwater-file-role": "write" },
18
+ "receiptOutput": {
19
+ "type": "string",
20
+ "minLength": 1,
21
+ "x-tiwater-file-role": "write",
22
+ "x-tiwater-file-effect": false
23
+ }
24
+ },
25
+ "required": ["targetDocument", "italic", "indentCharactersPerLevel", "output", "receiptOutput"],
26
+ "additionalProperties": false
27
+ }
@@ -21,7 +21,7 @@
21
21
  "targetRef": {
22
22
  "type": "string",
23
23
  "pattern": "^dox1_[0-9a-f]{64}$",
24
- "description": "Target cell ref whose content is replaced while its cell formatting is retained."
24
+ "description": "Target plain-text paragraph or cell ref whose content is replaced while its container formatting is retained. Paragraph bookmarks are preserved; targets containing fields, drawings, nested tables, controls, links, or other non-text content are rejected."
25
25
  },
26
26
  "sourceDocument": {
27
27
  "type": "object",
@@ -35,7 +35,7 @@
35
35
  "sourceSelections": {
36
36
  "type": "array",
37
37
  "minItems": 1,
38
- "description": "Ordered source content copied into the target cell. Select a whole observed object by ref alone, or select an exact substring by adding range to an observed run or text ref. Multiple selections are copied in this array order.",
38
+ "description": "Ordered source content copied into the target paragraph or cell. Select a whole observed object by ref alone, or select an exact substring by adding range to an observed run or text ref. Multiple selections are copied in this array order.",
39
39
  "items": {
40
40
  "type": "object",
41
41
  "properties": {
@@ -0,0 +1,27 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "type": "object",
4
+ "properties": {
5
+ "input": {
6
+ "type": "string",
7
+ "minLength": 1,
8
+ "description": "Path to the current DOCX document.",
9
+ "x-tiwater-file-role": "read"
10
+ },
11
+ "output": {
12
+ "type": "string",
13
+ "minLength": 1,
14
+ "description": "New DOCX output path. Existing files are never overwritten.",
15
+ "x-tiwater-file-role": "write"
16
+ },
17
+ "receiptOutput": {
18
+ "type": "string",
19
+ "minLength": 1,
20
+ "description": "New JSON receipt path. Existing files are never overwritten.",
21
+ "x-tiwater-file-role": "write",
22
+ "x-tiwater-file-effect": false
23
+ }
24
+ },
25
+ "required": ["input", "output", "receiptOutput"],
26
+ "additionalProperties": false
27
+ }
@@ -0,0 +1,42 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "tiwater.office-mcp-input/docx_set_text",
4
+ "type": "object",
5
+ "properties": {
6
+ "targetDocument": {
7
+ "type": "object",
8
+ "properties": {
9
+ "input": { "type": "string", "minLength": 1, "x-tiwater-file-role": "read" },
10
+ "revision": { "type": "string", "pattern": "^docx-rev-v1-[0-9a-f]{64}$" }
11
+ },
12
+ "required": ["input", "revision"],
13
+ "additionalProperties": false
14
+ },
15
+ "changes": {
16
+ "type": "array",
17
+ "minItems": 1,
18
+ "items": {
19
+ "type": "object",
20
+ "properties": {
21
+ "targetRef": {
22
+ "type": "string",
23
+ "pattern": "^dox1_[0-9a-f]{64}$",
24
+ "description": "Observed plain-text paragraph or cell ref whose whole text content is replaced. Paragraph bookmarks are preserved; targets containing fields, drawings, nested tables, controls, links, or other non-text content are rejected."
25
+ },
26
+ "text": { "type": "string" }
27
+ },
28
+ "required": ["targetRef", "text"],
29
+ "additionalProperties": false
30
+ }
31
+ },
32
+ "output": { "type": "string", "minLength": 1, "x-tiwater-file-role": "write" },
33
+ "receiptOutput": {
34
+ "type": "string",
35
+ "minLength": 1,
36
+ "x-tiwater-file-role": "write",
37
+ "x-tiwater-file-effect": false
38
+ }
39
+ },
40
+ "required": ["targetDocument", "changes", "output", "receiptOutput"],
41
+ "additionalProperties": false
42
+ }
@@ -2,9 +2,31 @@
2
2
  "schema": "tiwater.office-provider-contract-manifest/v1",
3
3
  "provider": {
4
4
  "id": "@tiwater/office-mcp",
5
- "version": "0.16.19"
5
+ "version": "0.17.0"
6
6
  },
7
7
  "tools": [
8
+ {
9
+ "name": "docx_apply_font_policy",
10
+ "providerContract": {
11
+ "source": "packages/docx-cli/contracts/mcp-input/docx_apply_font_policy.schema.json",
12
+ "sha256": "153e50e2f6577b5ea70fd1d3522f8ccf3a74b82b683f1f8fe724f6433a9c72e0"
13
+ },
14
+ "inputContract": {
15
+ "path": "office/contracts/docx_apply_font_policy.schema.json",
16
+ "sha256": "153e50e2f6577b5ea70fd1d3522f8ccf3a74b82b683f1f8fe724f6433a9c72e0"
17
+ }
18
+ },
19
+ {
20
+ "name": "docx_apply_toc_style_policy",
21
+ "providerContract": {
22
+ "source": "packages/docx-cli/contracts/mcp-input/docx_apply_toc_style_policy.schema.json",
23
+ "sha256": "2d4887ab4dc57e2c655f130e67c08886ff1630a889e7258b13519fb6e1529d25"
24
+ },
25
+ "inputContract": {
26
+ "path": "office/contracts/docx_apply_toc_style_policy.schema.json",
27
+ "sha256": "2d4887ab4dc57e2c655f130e67c08886ff1630a889e7258b13519fb6e1529d25"
28
+ }
29
+ },
8
30
  {
9
31
  "name": "docx_compare",
10
32
  "providerContract": {
@@ -20,11 +42,11 @@
20
42
  "name": "docx_copy_content",
21
43
  "providerContract": {
22
44
  "source": "packages/docx-cli/contracts/mcp-input/docx_copy_content.schema.json",
23
- "sha256": "27110c4590087bb38bd08f77ab2dc19a62407a836f58a603d222ebdb184c97b6"
45
+ "sha256": "a988f7c4284c5f99bd3cc28f31813c0a12b999c2486f697776bf6f873c9c49e7"
24
46
  },
25
47
  "inputContract": {
26
48
  "path": "office/contracts/docx_copy_content.schema.json",
27
- "sha256": "27110c4590087bb38bd08f77ab2dc19a62407a836f58a603d222ebdb184c97b6"
49
+ "sha256": "a988f7c4284c5f99bd3cc28f31813c0a12b999c2486f697776bf6f873c9c49e7"
28
50
  }
29
51
  },
30
52
  {
@@ -126,6 +148,17 @@
126
148
  "sha256": "29ba026050f1120219491f918e74c344551224795b1d15e49ec886d4e81e092a"
127
149
  }
128
150
  },
151
+ {
152
+ "name": "docx_refresh_fields",
153
+ "providerContract": {
154
+ "source": "packages/convert-cli/schemas/mcp-input/docx_refresh_fields.schema.json",
155
+ "sha256": "5f2a4f928796752adf7a44098919bca94c6faba8dbc9e5ad36b43e7f33035c7c"
156
+ },
157
+ "inputContract": {
158
+ "path": "office/contracts/docx_refresh_fields.schema.json",
159
+ "sha256": "5f2a4f928796752adf7a44098919bca94c6faba8dbc9e5ad36b43e7f33035c7c"
160
+ }
161
+ },
129
162
  {
130
163
  "name": "docx_replace_style_ids",
131
164
  "providerContract": {
@@ -137,6 +170,17 @@
137
170
  "sha256": "aa8fc12a350a391fadf32546847f29a816319efcab01866a1f406dc8313ea1ed"
138
171
  }
139
172
  },
173
+ {
174
+ "name": "docx_set_text",
175
+ "providerContract": {
176
+ "source": "packages/docx-cli/contracts/mcp-input/docx_set_text.schema.json",
177
+ "sha256": "945a5af0d9390c21f380cc9d255429353d6f743264b19a9e85111e75b3c0344b"
178
+ },
179
+ "inputContract": {
180
+ "path": "office/contracts/docx_set_text.schema.json",
181
+ "sha256": "945a5af0d9390c21f380cc9d255429353d6f743264b19a9e85111e75b3c0344b"
182
+ }
183
+ },
140
184
  {
141
185
  "name": "docx_split_cells",
142
186
  "providerContract": {
package/office/index.mjs CHANGED
@@ -100,6 +100,31 @@ const nativeRenderOutput = z.object({
100
100
  }).strict(),
101
101
  }).strict();
102
102
 
103
+ const docxFieldRefreshReceipt = z.object({
104
+ schema: z.literal('tiwater.convert-refresh-docx-fields/v1'),
105
+ status: z.literal('ok'),
106
+ input: z.string(),
107
+ input_sha256: z.string().regex(/^[a-f0-9]{64}$/),
108
+ output: z.string(),
109
+ output_sha256: z.string().regex(/^[a-f0-9]{64}$/),
110
+ source_format: z.literal('docx'),
111
+ target_format: z.literal('docx'),
112
+ version: z.string(),
113
+ backend: z.literal('wps'),
114
+ refresh_scope: z.array(z.enum(['table-of-contents', 'table-of-figures'])).min(1),
115
+ }).strict();
116
+
117
+ const docxFieldRefreshOutput = z.object({
118
+ tool: z.literal('docx_refresh_fields'),
119
+ runtime: runtimeIdentity,
120
+ output: artifact,
121
+ receipt: artifact,
122
+ summary: z.object({
123
+ backend: z.literal('wps'),
124
+ refreshScope: z.array(z.enum(['table-of-contents', 'table-of-figures'])).min(1),
125
+ }).strict(),
126
+ }).strict();
127
+
103
128
  const xlsxFixedTools = [
104
129
  {"name":"xlsx_set_cell_value","description":"Set current workbook cell values."},
105
130
  {"name":"xlsx_set_cell_number_format","description":"Set current workbook cell number formats."},
@@ -200,7 +225,7 @@ const tools = [
200
225
  },
201
226
  {
202
227
  name: 'docx_read_object',
203
- description: 'Read one selected native DOCX object as an ordered native hierarchy written to the requested output artifact. The tool response only identifies that artifact and the selected root object; read the artifact for descendant refs and content. For a table, request row and cell kinds once; each row contains its ordered cells with text, grid span, and vertical merge state. Also request paragraph when paragraph boundaries determine what a later copy operation must retain.',
228
+ description: 'Read one selected native DOCX object as an ordered native hierarchy written to the requested output artifact. The tool response only identifies that artifact and the selected root object; read the artifact for descendant refs and content. For a table, request row and cell once. Add paragraph for whole-paragraph choices; add run and text for exact content selections.',
204
229
  inputSchema: inputContract('docx_read_object'),
205
230
  outputSchema: docxReadObjectOutput,
206
231
  annotations: { readOnlyHint: true, idempotentHint: true },
@@ -208,14 +233,21 @@ const tools = [
208
233
  },
209
234
  {
210
235
  name: 'docx_copy_content',
211
- description: 'Replace content in existing target cells while retaining target cell formatting and source inline meaning. Use this directly or after docx_copy_table_rows when a target cell needs an exact observed subset of source content. A source selection copies a whole object by ref, or an exact substring when range is attached to a run or text ref.',
236
+ description: 'Replace content in existing plain-text target paragraphs or cells while retaining target container formatting and source inline meaning. Targets containing non-text objects are rejected. Batch cells that need exact observed subsets after docx_copy_table_rows. A selection copies a whole object by ref, or an exact substring when range is attached to a run or text ref.',
212
237
  inputSchema: inputContract('docx_copy_content'),
213
238
  outputSchema: fixedEditOutput('docx_copy_content'),
214
239
  handler: args => fixedEdit('docx_copy_content', args),
215
240
  },
241
+ {
242
+ name: 'docx_set_text',
243
+ description: 'Replace the whole text content of observed plain-text paragraph or cell objects while retaining their target formatting. Targets containing non-text objects are rejected. This sets already-derived text; it does not insert objects, copy source formatting, or decide business wording.',
244
+ inputSchema: inputContract('docx_set_text'),
245
+ outputSchema: fixedEditOutput('docx_set_text'),
246
+ handler: args => fixedEdit('docx_set_text', args),
247
+ },
216
248
  {
217
249
  name: 'docx_copy_table_rows',
218
- description: 'Populate existing target tables by replacing selected data-row ranges with selected source rows. Use this whenever the target table already exists; explicit header-cell mappings preserve target presentation and native source grouping even when source and target grid spans differ. Each column must explicitly copy all source-cell paragraphs or only the first; inspect paragraph children before choosing.',
250
+ description: 'Populate existing target tables by replacing selected data-row ranges with selected source rows. Explicit header-cell mappings preserve target presentation and source grouping. A column content mode applies to every copied cell in that column; when cells need different subsets, copy the row structure first and batch those cells with docx_copy_content.',
219
251
  inputSchema: inputContract('docx_copy_table_rows'),
220
252
  outputSchema: fixedEditOutput('docx_copy_table_rows'),
221
253
  handler: args => fixedEdit('docx_copy_table_rows', args),
@@ -277,6 +309,13 @@ const tools = [
277
309
  annotations: { readOnlyHint: true, idempotentHint: true },
278
310
  handler: docxValidateFontPolicy,
279
311
  },
312
+ {
313
+ name: 'docx_apply_font_policy',
314
+ description: 'Apply one explicit font family and size policy to current main-document body and table text. It does not derive a policy or alter other run semantics.',
315
+ inputSchema: inputContract('docx_apply_font_policy'),
316
+ outputSchema: fixedEditOutput('docx_apply_font_policy'),
317
+ handler: args => fixedEdit('docx_apply_font_policy', args),
318
+ },
280
319
  {
281
320
  name: 'docx_validate_toc_style_policy',
282
321
  description: 'Validate current DOCX table-of-contents paragraph styles against an explicit policy.',
@@ -284,6 +323,20 @@ const tools = [
284
323
  annotations: { readOnlyHint: true, idempotentHint: true },
285
324
  handler: docxValidateTocStylePolicy,
286
325
  },
326
+ {
327
+ name: 'docx_apply_toc_style_policy',
328
+ description: 'Apply explicit italic and per-level indentation values to current built-in table-of-contents paragraph styles. It does not change heading text or refresh fields.',
329
+ inputSchema: inputContract('docx_apply_toc_style_policy'),
330
+ outputSchema: fixedEditOutput('docx_apply_toc_style_policy'),
331
+ handler: args => fixedEdit('docx_apply_toc_style_policy', args),
332
+ },
333
+ {
334
+ name: 'docx_refresh_fields',
335
+ description: 'Refresh table-of-contents and table-of-figures field results in a current DOCX through native WPS Writer. It does not change headings, captions, or field definitions.',
336
+ inputSchema: inputContract('docx_refresh_fields'),
337
+ outputSchema: docxFieldRefreshOutput,
338
+ handler: docxRefreshFields,
339
+ },
287
340
  {
288
341
  name: 'docx_strip_direct_formatting',
289
342
  description: 'Remove direct paragraph and run formatting while preserving styles.',
@@ -492,6 +545,42 @@ async function docxReplaceStyleIds(args) {
492
545
  return withTempJsonFile(args.styleMap, styleMapPath => copyTransform('docx_replace_style_ids', docxCandidates, ['replace-style-ids'], args, [styleMapPath]));
493
546
  }
494
547
 
548
+ async function docxRefreshFields(args) {
549
+ const input = path.resolve(requireString(args.input, 'input'));
550
+ const output = path.resolve(requireString(args.output, 'output'));
551
+ const receiptOutput = path.resolve(requireString(args.receiptOutput, 'receiptOutput'));
552
+ if (path.extname(input).toLowerCase() !== '.docx' || path.extname(output).toLowerCase() !== '.docx') {
553
+ throw Object.assign(new Error('DOCX field refresh requires .docx input and output'), { code: -32602 });
554
+ }
555
+ await requireNewFile(output, 'output');
556
+ await requireNewFile(receiptOutput, 'receiptOutput');
557
+ const inputArtifact = await fileArtifact(input);
558
+ try {
559
+ const result = await runJsonCandidateChain(convertCandidates, ['refresh-docx-fields', input, output]);
560
+ const providerReceipt = docxFieldRefreshReceipt.parse(result.json);
561
+ const outputArtifact = await fileArtifact(output);
562
+ if (path.resolve(providerReceipt.input) !== input
563
+ || path.resolve(providerReceipt.output) !== output
564
+ || providerReceipt.input_sha256 !== inputArtifact.sha256
565
+ || providerReceipt.output_sha256 !== outputArtifact.sha256) {
566
+ throw new Error('DOCX field refresh receipt is not bound to the current input and output');
567
+ }
568
+ return {
569
+ tool: 'docx_refresh_fields',
570
+ runtime: commandRuntime(result),
571
+ output: outputArtifact,
572
+ receipt: await writeJsonArtifact(receiptOutput, providerReceipt),
573
+ summary: {
574
+ backend: providerReceipt.backend,
575
+ refreshScope: providerReceipt.refresh_scope,
576
+ },
577
+ };
578
+ } catch (error) {
579
+ await rm(output, { force: true });
580
+ throw error;
581
+ }
582
+ }
583
+
495
584
  async function copyTransform(tool, candidates, command, args, suffix = []) {
496
585
  const input = path.resolve(requireString(args.input, 'input'));
497
586
  const output = path.resolve(requireString(args.output, 'output'));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tiwater/office-mcp",
3
- "version": "0.16.19",
3
+ "version": "0.17.0",
4
4
  "description": "Published MCP server for Tiwater Office document capabilities",
5
5
  "type": "module",
6
6
  "license": "MIT",