mcp-word-bridge 4.1.2 → 4.1.4
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/README.md +2 -1
- package/dist/server.js +186 -61
- package/dist/server.js.map +2 -2
- package/dist/taskpane-app.js +38 -7
- package/dist/taskpane-app.js.map +2 -2
- package/manifest.xml +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -60,7 +60,7 @@ MCP Client ←stdio→ Server ←WebSocket→ Taskpane (Office Add-in) ←→ Wo
|
|
|
60
60
|
|
|
61
61
|
Single process. The MCP client spawns the server, which starts both the HTTPS bridge (for the add-in) and the MCP protocol handler (on stdio). Everything starts and stops together.
|
|
62
62
|
|
|
63
|
-
## Tools (
|
|
63
|
+
## Tools (91)
|
|
64
64
|
|
|
65
65
|
### Document
|
|
66
66
|
| Tool | Description |
|
|
@@ -300,6 +300,7 @@ Platform constraints in the Word JavaScript API that cannot be resolved in this
|
|
|
300
300
|
| Highlight Colors | `highlightColor` only supports 17 named colors (Yellow, Green, Cyan, Magenta, Blue, Red, DarkBlue, DarkCyan, DarkGreen, DarkMagenta, DarkRed, DarkYellow, Gray25, Gray50, Black, White, NoHighlight). The Word API documentation claims `#RRGGBB` is accepted, but Desktop silently maps hex values to the nearest named color. This tool rejects hex to prevent silent mismatch — use `color` for arbitrary RGB. | [office-js#4638](https://github.com/OfficeDev/office-js/issues/4638) |
|
|
301
301
|
| Paragraph Style | TOC field entries and certain table paragraphs return `style: ""` (empty string) instead of the actual style name. Paragraphs are flagged with `isTocEntry: true` when detected as TOC entries. Use this flag rather than the style field for identification. | [office-js#5934](https://github.com/OfficeDev/office-js/issues/5934) |
|
|
302
302
|
| Mixed Formatting | `word_get_paragraph_by_index` returns `null` for font properties (`bold`, `italic`, `size`, etc.) when the paragraph contains mixed formatting (e.g. partially bold text). This is the Word API's way of indicating "no single value" — treat `null` as "mixed". | [Word.Font docs](https://learn.microsoft.com/en-us/javascript/api/word/word.font?view=word-js-preview) |
|
|
303
|
+
| TOC Search | `body.search()` matches text inside TOC field entries as well as body content. Heading text appears in both locations, so search results return TOC matches first. Use `occurrence` to skip past TOC entries and target the body instance. | |
|
|
303
304
|
| Page Info | `word_get_page_info` requires WordApiDesktop 1.2+ (Word for Windows/Mac desktop). Not available on Word for the web. | [WordApiDesktop 1.2](https://learn.microsoft.com/en-us/javascript/api/requirement-sets/word/word-api-desktop-1-2-requirement-set) |
|
|
304
305
|
| Undo | The Word JavaScript API does not expose a programmatic `undo()` method. Changes made by the add-in appear in Word's undo stack (Ctrl+Z works for the user), but there is no way to trigger undo from code. | [Stack Overflow](https://stackoverflow.com/questions/58440921/accessing-the-undo-stack-from-word-javascript-api) |
|
|
305
306
|
|
package/dist/server.js
CHANGED
|
@@ -18646,6 +18646,7 @@ var HEAVY_OPERATIONS = /* @__PURE__ */ new Set([
|
|
|
18646
18646
|
"batchExecute"
|
|
18647
18647
|
]);
|
|
18648
18648
|
var MAX_PAYLOAD = 10 * 1024 * 1024;
|
|
18649
|
+
var HIGHLIGHT_COLORS = ["Yellow", "Green", "Cyan", "Magenta", "Blue", "Red", "DarkBlue", "DarkCyan", "DarkGreen", "DarkMagenta", "DarkRed", "DarkYellow", "Gray25", "Gray50", "Black", "White", "NoHighlight"];
|
|
18649
18650
|
|
|
18650
18651
|
// src/server/bridge.ts
|
|
18651
18652
|
var Bridge = class {
|
|
@@ -18722,7 +18723,7 @@ var Bridge = class {
|
|
|
18722
18723
|
|
|
18723
18724
|
// src/server/mcp.ts
|
|
18724
18725
|
var import_server = require("@modelcontextprotocol/sdk/server/index.js");
|
|
18725
|
-
var
|
|
18726
|
+
var import_types10 = require("@modelcontextprotocol/sdk/types.js");
|
|
18726
18727
|
|
|
18727
18728
|
// src/server/types.ts
|
|
18728
18729
|
var ToolError = class extends Error {
|
|
@@ -18742,6 +18743,7 @@ function forwardTool(name, description, schema, action, validate) {
|
|
|
18742
18743
|
description,
|
|
18743
18744
|
schema,
|
|
18744
18745
|
bridgeAction: action,
|
|
18746
|
+
validate,
|
|
18745
18747
|
async handler(args, bridge2) {
|
|
18746
18748
|
if (validate) validate(args);
|
|
18747
18749
|
const result = await bridge2.send(action, args);
|
|
@@ -18779,7 +18781,15 @@ var setDocumentProperties = forwardTool(
|
|
|
18779
18781
|
format: { type: "string" }
|
|
18780
18782
|
}
|
|
18781
18783
|
},
|
|
18782
|
-
"setDocumentProperties"
|
|
18784
|
+
"setDocumentProperties",
|
|
18785
|
+
(args) => {
|
|
18786
|
+
const hasProperty = args.title !== void 0 || args.subject !== void 0 || args.author !== void 0 || args.keywords !== void 0 || args.comments !== void 0 || args.category !== void 0 || args.company !== void 0 || args.manager !== void 0 || args.format !== void 0;
|
|
18787
|
+
if (!hasProperty) {
|
|
18788
|
+
throw new ToolError(
|
|
18789
|
+
"At least one document property must be provided (title, subject, author, keywords, comments, category, company, manager, format)."
|
|
18790
|
+
);
|
|
18791
|
+
}
|
|
18792
|
+
}
|
|
18783
18793
|
);
|
|
18784
18794
|
var save = forwardTool(
|
|
18785
18795
|
"word_save",
|
|
@@ -18884,18 +18894,6 @@ function checkBounds(index, count, name) {
|
|
|
18884
18894
|
);
|
|
18885
18895
|
}
|
|
18886
18896
|
}
|
|
18887
|
-
function checkOccurrence(occurrence, count) {
|
|
18888
|
-
const idx = occurrence ?? 0;
|
|
18889
|
-
if (idx < 0) {
|
|
18890
|
-
throw new ToolError("occurrence must be non-negative (0-indexed).");
|
|
18891
|
-
}
|
|
18892
|
-
if (idx >= count) {
|
|
18893
|
-
throw new ToolError(
|
|
18894
|
-
`Occurrence ${idx} not found (only ${count} match${count === 1 ? "" : "es"}).`
|
|
18895
|
-
);
|
|
18896
|
-
}
|
|
18897
|
-
return idx;
|
|
18898
|
-
}
|
|
18899
18897
|
var MAX_SPACING_POINTS = 1584;
|
|
18900
18898
|
var MAX_CUSTOM_PROPERTY_KEY_LENGTH = 255;
|
|
18901
18899
|
function checkSpacingBounds(value, name) {
|
|
@@ -18935,6 +18933,14 @@ function checkHexColor(color, name) {
|
|
|
18935
18933
|
throw new ToolError(`${name} must be a valid hex color (e.g. #FF0000).`);
|
|
18936
18934
|
}
|
|
18937
18935
|
}
|
|
18936
|
+
function checkUrl(url) {
|
|
18937
|
+
if (!/^https?:\/\/.+/i.test(url)) {
|
|
18938
|
+
throw new ToolError("URL must be a valid HTTP or HTTPS URL (e.g. https://example.com).");
|
|
18939
|
+
}
|
|
18940
|
+
if (/[<>"{}|\\^`]/.test(url)) {
|
|
18941
|
+
throw new ToolError(`Malformed URL: "${url}". URL contains invalid characters that must be percent-encoded.`);
|
|
18942
|
+
}
|
|
18943
|
+
}
|
|
18938
18944
|
|
|
18939
18945
|
// src/server/tools/paragraphs.ts
|
|
18940
18946
|
var getParagraphs = forwardTool(
|
|
@@ -19022,7 +19028,12 @@ var setParagraphStyle = forwardTool(
|
|
|
19022
19028
|
},
|
|
19023
19029
|
required: ["index"]
|
|
19024
19030
|
},
|
|
19025
|
-
"setParagraphStyle"
|
|
19031
|
+
"setParagraphStyle",
|
|
19032
|
+
(args) => {
|
|
19033
|
+
if (args.style === void 0 && args.alignment === void 0) {
|
|
19034
|
+
throw new ToolError('At least one of "style" or "alignment" must be provided.');
|
|
19035
|
+
}
|
|
19036
|
+
}
|
|
19026
19037
|
);
|
|
19027
19038
|
var setParagraphSpacing = {
|
|
19028
19039
|
name: "word_set_paragraph_spacing",
|
|
@@ -19123,10 +19134,8 @@ var moveParagraph = {
|
|
|
19123
19134
|
}
|
|
19124
19135
|
}
|
|
19125
19136
|
const adjustedTo = fromIndex < toIndex ? toIndex - count : toIndex;
|
|
19126
|
-
|
|
19127
|
-
|
|
19128
|
-
}
|
|
19129
|
-
if (adjustedTo === fromIndex && location === "After") {
|
|
19137
|
+
const effectiveInsertPos = location === "Before" ? adjustedTo : adjustedTo + 1;
|
|
19138
|
+
if (effectiveInsertPos === fromIndex) {
|
|
19130
19139
|
return jsonResult({ success: true, warning: "No move performed \u2014 destination is equivalent to source position.", moved: null });
|
|
19131
19140
|
}
|
|
19132
19141
|
const ooxmlResult = await bridge2.send("getParaOoxml", { index: fromIndex, count });
|
|
@@ -19221,7 +19230,10 @@ var search = forwardTool(
|
|
|
19221
19230
|
},
|
|
19222
19231
|
required: ["query"]
|
|
19223
19232
|
},
|
|
19224
|
-
"search"
|
|
19233
|
+
"search",
|
|
19234
|
+
(args) => {
|
|
19235
|
+
checkNonEmpty(args.query, "query");
|
|
19236
|
+
}
|
|
19225
19237
|
);
|
|
19226
19238
|
var searchAndReplace = {
|
|
19227
19239
|
name: "word_search_and_replace",
|
|
@@ -19268,7 +19280,10 @@ var insertTextAtMatch = forwardTool(
|
|
|
19268
19280
|
},
|
|
19269
19281
|
required: ["text"]
|
|
19270
19282
|
},
|
|
19271
|
-
"insertText"
|
|
19283
|
+
"insertText",
|
|
19284
|
+
(args) => {
|
|
19285
|
+
checkNonEmpty(args.text, "text");
|
|
19286
|
+
}
|
|
19272
19287
|
);
|
|
19273
19288
|
var getSelectionInfo = forwardTool(
|
|
19274
19289
|
"word_get_selection_info",
|
|
@@ -19300,7 +19315,10 @@ var insertLineBreak = forwardTool(
|
|
|
19300
19315
|
},
|
|
19301
19316
|
required: ["anchorText"]
|
|
19302
19317
|
},
|
|
19303
|
-
"insertLineBreak"
|
|
19318
|
+
"insertLineBreak",
|
|
19319
|
+
(args) => {
|
|
19320
|
+
checkNonEmpty(args.anchorText, "anchorText");
|
|
19321
|
+
}
|
|
19304
19322
|
);
|
|
19305
19323
|
var searchTools = [
|
|
19306
19324
|
search,
|
|
@@ -19312,7 +19330,6 @@ var searchTools = [
|
|
|
19312
19330
|
];
|
|
19313
19331
|
|
|
19314
19332
|
// src/server/tools/formatting.ts
|
|
19315
|
-
var HIGHLIGHT_COLORS = ["Yellow", "Green", "Cyan", "Magenta", "Blue", "Red", "DarkBlue", "DarkCyan", "DarkGreen", "DarkMagenta", "DarkRed", "DarkYellow", "Gray25", "Gray50", "Black", "White", "NoHighlight"];
|
|
19316
19333
|
function validateFormatText(args) {
|
|
19317
19334
|
checkNonEmpty(args.text, "text");
|
|
19318
19335
|
const hasFormatting = args.bold !== void 0 || args.italic !== void 0 || args.underline !== void 0 || args.strikeThrough !== void 0 || args.color !== void 0 || args.highlightColor !== void 0 || args.size !== void 0 || args.name !== void 0;
|
|
@@ -19373,7 +19390,10 @@ var clearFormatting = forwardTool(
|
|
|
19373
19390
|
},
|
|
19374
19391
|
required: ["text"]
|
|
19375
19392
|
},
|
|
19376
|
-
"clearFormatting"
|
|
19393
|
+
"clearFormatting",
|
|
19394
|
+
(args) => {
|
|
19395
|
+
checkNonEmpty(args.text, "text");
|
|
19396
|
+
}
|
|
19377
19397
|
);
|
|
19378
19398
|
var getFontInfo = forwardTool(
|
|
19379
19399
|
"word_get_font_info",
|
|
@@ -19386,7 +19406,10 @@ var getFontInfo = forwardTool(
|
|
|
19386
19406
|
},
|
|
19387
19407
|
required: ["text"]
|
|
19388
19408
|
},
|
|
19389
|
-
"getFontInfo"
|
|
19409
|
+
"getFontInfo",
|
|
19410
|
+
(args) => {
|
|
19411
|
+
checkNonEmpty(args.text, "text");
|
|
19412
|
+
}
|
|
19390
19413
|
);
|
|
19391
19414
|
var formattingTools = [
|
|
19392
19415
|
formatText,
|
|
@@ -19409,7 +19432,24 @@ var insertTable = forwardTool(
|
|
|
19409
19432
|
},
|
|
19410
19433
|
required: ["rows", "cols"]
|
|
19411
19434
|
},
|
|
19412
|
-
"insertTable"
|
|
19435
|
+
"insertTable",
|
|
19436
|
+
(args) => {
|
|
19437
|
+
const rows = args.rows;
|
|
19438
|
+
const cols = args.cols;
|
|
19439
|
+
if (typeof rows !== "number" || !Number.isInteger(rows) || rows <= 0) throw new ToolError("rows must be a positive integer (minimum 1).");
|
|
19440
|
+
if (typeof cols !== "number" || !Number.isInteger(cols) || cols <= 0) throw new ToolError("cols must be a positive integer (minimum 1).");
|
|
19441
|
+
if (cols > 63) throw new ToolError("cols must not exceed 63 (Word maximum column limit).");
|
|
19442
|
+
if (rows > 500) throw new ToolError("rows must not exceed 500 (practical limit for performance).");
|
|
19443
|
+
if (args.data !== void 0) {
|
|
19444
|
+
const data = args.data;
|
|
19445
|
+
if (!Array.isArray(data)) throw new ToolError("data must be an array of arrays.");
|
|
19446
|
+
if (data.length !== rows) throw new ToolError(`Data rows (${data.length}) do not match specified rows (${rows}). Provide exactly ${rows} row(s) in the data array.`);
|
|
19447
|
+
for (let i = 0; i < data.length; i++) {
|
|
19448
|
+
if (!Array.isArray(data[i])) throw new ToolError(`data[${i}] must be an array.`);
|
|
19449
|
+
if (data[i].length !== cols) throw new ToolError(`Data row ${i} has ${data[i].length} columns but expected ${cols}.`);
|
|
19450
|
+
}
|
|
19451
|
+
}
|
|
19452
|
+
}
|
|
19413
19453
|
);
|
|
19414
19454
|
var listTables = forwardTool(
|
|
19415
19455
|
"word_list_tables",
|
|
@@ -19440,7 +19480,12 @@ var setTableCell = forwardTool(
|
|
|
19440
19480
|
},
|
|
19441
19481
|
required: ["tableIndex", "row", "col", "text"]
|
|
19442
19482
|
},
|
|
19443
|
-
"setTableCell"
|
|
19483
|
+
"setTableCell",
|
|
19484
|
+
(args) => {
|
|
19485
|
+
checkNonNegative(args.tableIndex, "tableIndex");
|
|
19486
|
+
checkNonNegative(args.row, "row");
|
|
19487
|
+
checkNonNegative(args.col, "col");
|
|
19488
|
+
}
|
|
19444
19489
|
);
|
|
19445
19490
|
var addTableRow = forwardTool(
|
|
19446
19491
|
"word_add_table_row",
|
|
@@ -19465,7 +19510,11 @@ var deleteTableRow = forwardTool(
|
|
|
19465
19510
|
},
|
|
19466
19511
|
required: ["tableIndex", "rowIndex"]
|
|
19467
19512
|
},
|
|
19468
|
-
"deleteTableRow"
|
|
19513
|
+
"deleteTableRow",
|
|
19514
|
+
(args) => {
|
|
19515
|
+
checkNonNegative(args.tableIndex, "tableIndex");
|
|
19516
|
+
checkNonNegative(args.rowIndex, "rowIndex");
|
|
19517
|
+
}
|
|
19469
19518
|
);
|
|
19470
19519
|
var mergeTableCells = forwardTool(
|
|
19471
19520
|
"word_merge_table_cells",
|
|
@@ -19480,7 +19529,17 @@ var mergeTableCells = forwardTool(
|
|
|
19480
19529
|
},
|
|
19481
19530
|
required: ["tableIndex", "topRow", "firstCell", "bottomRow", "lastCell"]
|
|
19482
19531
|
},
|
|
19483
|
-
"mergeTableCells"
|
|
19532
|
+
"mergeTableCells",
|
|
19533
|
+
(args) => {
|
|
19534
|
+
checkNonNegative(args.tableIndex, "tableIndex");
|
|
19535
|
+
checkNonNegative(args.topRow, "topRow");
|
|
19536
|
+
checkNonNegative(args.firstCell, "firstCell");
|
|
19537
|
+
checkNonNegative(args.bottomRow, "bottomRow");
|
|
19538
|
+
checkNonNegative(args.lastCell, "lastCell");
|
|
19539
|
+
if (args.topRow > args.bottomRow) throw new ToolError(`topRow (${args.topRow}) must be less than or equal to bottomRow (${args.bottomRow}).`);
|
|
19540
|
+
if (args.firstCell > args.lastCell) throw new ToolError(`firstCell (${args.firstCell}) must be less than or equal to lastCell (${args.lastCell}).`);
|
|
19541
|
+
if (args.topRow === args.bottomRow && args.firstCell === args.lastCell) throw new ToolError("Cannot merge a single cell with itself. Provide a range spanning at least 2 cells.");
|
|
19542
|
+
}
|
|
19484
19543
|
);
|
|
19485
19544
|
var splitTableCell = forwardTool(
|
|
19486
19545
|
"word_split_table_cell",
|
|
@@ -19495,7 +19554,14 @@ var splitTableCell = forwardTool(
|
|
|
19495
19554
|
},
|
|
19496
19555
|
required: ["tableIndex", "row", "col"]
|
|
19497
19556
|
},
|
|
19498
|
-
"splitTableCell"
|
|
19557
|
+
"splitTableCell",
|
|
19558
|
+
(args) => {
|
|
19559
|
+
checkNonNegative(args.tableIndex, "tableIndex");
|
|
19560
|
+
checkNonNegative(args.row, "row");
|
|
19561
|
+
checkNonNegative(args.col, "col");
|
|
19562
|
+
if (args.rowCount !== void 0 && (typeof args.rowCount !== "number" || args.rowCount <= 0)) throw new ToolError("rowCount must be a positive integer.");
|
|
19563
|
+
if (args.colCount !== void 0 && (typeof args.colCount !== "number" || args.colCount <= 0)) throw new ToolError("colCount must be a positive integer.");
|
|
19564
|
+
}
|
|
19499
19565
|
);
|
|
19500
19566
|
var setTableStyle = forwardTool(
|
|
19501
19567
|
"word_set_table_style",
|
|
@@ -19521,7 +19587,13 @@ var setTableCellShading = forwardTool(
|
|
|
19521
19587
|
},
|
|
19522
19588
|
required: ["tableIndex", "row", "col", "color"]
|
|
19523
19589
|
},
|
|
19524
|
-
"setTableCellShading"
|
|
19590
|
+
"setTableCellShading",
|
|
19591
|
+
(args) => {
|
|
19592
|
+
checkNonNegative(args.tableIndex, "tableIndex");
|
|
19593
|
+
checkNonNegative(args.row, "row");
|
|
19594
|
+
checkNonNegative(args.col, "col");
|
|
19595
|
+
checkHexColor(args.color, "color");
|
|
19596
|
+
}
|
|
19525
19597
|
);
|
|
19526
19598
|
var tableTools = [
|
|
19527
19599
|
insertTable,
|
|
@@ -19674,7 +19746,11 @@ var insertFootnote = forwardTool(
|
|
|
19674
19746
|
},
|
|
19675
19747
|
required: ["anchorText", "text"]
|
|
19676
19748
|
},
|
|
19677
|
-
"insertFootnote"
|
|
19749
|
+
"insertFootnote",
|
|
19750
|
+
(args) => {
|
|
19751
|
+
checkNonEmpty(args.anchorText, "anchorText");
|
|
19752
|
+
checkNonEmpty(args.text, "text");
|
|
19753
|
+
}
|
|
19678
19754
|
);
|
|
19679
19755
|
var insertFootnoteAtIndex = forwardTool(
|
|
19680
19756
|
"word_insert_footnote_at_index",
|
|
@@ -19686,7 +19762,10 @@ var insertFootnoteAtIndex = forwardTool(
|
|
|
19686
19762
|
},
|
|
19687
19763
|
required: ["paragraphIndex", "text"]
|
|
19688
19764
|
},
|
|
19689
|
-
"insertFootnoteAtIndex"
|
|
19765
|
+
"insertFootnoteAtIndex",
|
|
19766
|
+
(args) => {
|
|
19767
|
+
checkNonEmpty(args.text, "text");
|
|
19768
|
+
}
|
|
19690
19769
|
);
|
|
19691
19770
|
var insertEndnote = forwardTool(
|
|
19692
19771
|
"word_insert_endnote",
|
|
@@ -19700,7 +19779,11 @@ var insertEndnote = forwardTool(
|
|
|
19700
19779
|
},
|
|
19701
19780
|
required: ["anchorText", "text"]
|
|
19702
19781
|
},
|
|
19703
|
-
"insertEndnote"
|
|
19782
|
+
"insertEndnote",
|
|
19783
|
+
(args) => {
|
|
19784
|
+
checkNonEmpty(args.anchorText, "anchorText");
|
|
19785
|
+
checkNonEmpty(args.text, "text");
|
|
19786
|
+
}
|
|
19704
19787
|
);
|
|
19705
19788
|
var getFootnotes = forwardTool(
|
|
19706
19789
|
"word_get_footnotes",
|
|
@@ -19765,7 +19848,11 @@ var insertBookmark = forwardTool(
|
|
|
19765
19848
|
},
|
|
19766
19849
|
required: ["name", "anchorText"]
|
|
19767
19850
|
},
|
|
19768
|
-
"insertBookmark"
|
|
19851
|
+
"insertBookmark",
|
|
19852
|
+
(args) => {
|
|
19853
|
+
checkNonEmpty(args.name, "name");
|
|
19854
|
+
checkNonEmpty(args.anchorText, "anchorText");
|
|
19855
|
+
}
|
|
19769
19856
|
);
|
|
19770
19857
|
var deleteBookmark = forwardTool(
|
|
19771
19858
|
"word_delete_bookmark",
|
|
@@ -19776,7 +19863,10 @@ var deleteBookmark = forwardTool(
|
|
|
19776
19863
|
},
|
|
19777
19864
|
required: ["name"]
|
|
19778
19865
|
},
|
|
19779
|
-
"deleteBookmark"
|
|
19866
|
+
"deleteBookmark",
|
|
19867
|
+
(args) => {
|
|
19868
|
+
checkNonEmpty(args.name, "name");
|
|
19869
|
+
}
|
|
19780
19870
|
);
|
|
19781
19871
|
var goToBookmark = forwardTool(
|
|
19782
19872
|
"word_go_to_bookmark",
|
|
@@ -19787,7 +19877,10 @@ var goToBookmark = forwardTool(
|
|
|
19787
19877
|
},
|
|
19788
19878
|
required: ["name"]
|
|
19789
19879
|
},
|
|
19790
|
-
"goToBookmark"
|
|
19880
|
+
"goToBookmark",
|
|
19881
|
+
(args) => {
|
|
19882
|
+
checkNonEmpty(args.name, "name");
|
|
19883
|
+
}
|
|
19791
19884
|
);
|
|
19792
19885
|
var getBookmarkText = forwardTool(
|
|
19793
19886
|
"word_get_bookmark_text",
|
|
@@ -19798,7 +19891,10 @@ var getBookmarkText = forwardTool(
|
|
|
19798
19891
|
},
|
|
19799
19892
|
required: ["name"]
|
|
19800
19893
|
},
|
|
19801
|
-
"getBookmarkText"
|
|
19894
|
+
"getBookmarkText",
|
|
19895
|
+
(args) => {
|
|
19896
|
+
checkNonEmpty(args.name, "name");
|
|
19897
|
+
}
|
|
19802
19898
|
);
|
|
19803
19899
|
var bookmarkTools = [
|
|
19804
19900
|
getBookmarks,
|
|
@@ -19821,7 +19917,12 @@ var insertHyperlink = forwardTool(
|
|
|
19821
19917
|
},
|
|
19822
19918
|
required: ["anchorText", "url"]
|
|
19823
19919
|
},
|
|
19824
|
-
"insertHyperlink"
|
|
19920
|
+
"insertHyperlink",
|
|
19921
|
+
(args) => {
|
|
19922
|
+
checkNonEmpty(args.anchorText, "anchorText");
|
|
19923
|
+
checkNonEmpty(args.url, "url");
|
|
19924
|
+
checkUrl(args.url);
|
|
19925
|
+
}
|
|
19825
19926
|
);
|
|
19826
19927
|
var getHyperlinks = forwardTool(
|
|
19827
19928
|
"word_get_hyperlinks",
|
|
@@ -19840,7 +19941,10 @@ var removeHyperlink = forwardTool(
|
|
|
19840
19941
|
},
|
|
19841
19942
|
required: ["anchorText"]
|
|
19842
19943
|
},
|
|
19843
|
-
"removeHyperlink"
|
|
19944
|
+
"removeHyperlink",
|
|
19945
|
+
(args) => {
|
|
19946
|
+
checkNonEmpty(args.anchorText, "anchorText");
|
|
19947
|
+
}
|
|
19844
19948
|
);
|
|
19845
19949
|
var hyperlinkTools = [
|
|
19846
19950
|
insertHyperlink,
|
|
@@ -19869,7 +19973,10 @@ var insertContentControl = forwardTool(
|
|
|
19869
19973
|
matchCase: { type: "boolean", description: "Default: false" }
|
|
19870
19974
|
}
|
|
19871
19975
|
},
|
|
19872
|
-
"insertContentControl"
|
|
19976
|
+
"insertContentControl",
|
|
19977
|
+
(args) => {
|
|
19978
|
+
checkNonEmpty(args.anchorText, "anchorText");
|
|
19979
|
+
}
|
|
19873
19980
|
);
|
|
19874
19981
|
var setContentControlText = {
|
|
19875
19982
|
name: "word_set_content_control_text",
|
|
@@ -20007,7 +20114,15 @@ var setPageLayout = forwardTool(
|
|
|
20007
20114
|
paperSize: { type: "string", description: "Letter, A4, etc." }
|
|
20008
20115
|
}
|
|
20009
20116
|
},
|
|
20010
|
-
"setPageLayout"
|
|
20117
|
+
"setPageLayout",
|
|
20118
|
+
(args) => {
|
|
20119
|
+
const hasProperty = args.orientation !== void 0 || args.topMargin !== void 0 || args.bottomMargin !== void 0 || args.leftMargin !== void 0 || args.rightMargin !== void 0 || args.paperSize !== void 0;
|
|
20120
|
+
if (!hasProperty) {
|
|
20121
|
+
throw new ToolError(
|
|
20122
|
+
"At least one layout property must be provided (orientation, topMargin, bottomMargin, leftMargin, rightMargin, paperSize)."
|
|
20123
|
+
);
|
|
20124
|
+
}
|
|
20125
|
+
}
|
|
20011
20126
|
);
|
|
20012
20127
|
var getSections = forwardTool(
|
|
20013
20128
|
"word_get_sections",
|
|
@@ -20145,7 +20260,10 @@ var deleteCustomProperty = forwardTool(
|
|
|
20145
20260
|
},
|
|
20146
20261
|
required: ["key"]
|
|
20147
20262
|
},
|
|
20148
|
-
"deleteCustomProperty"
|
|
20263
|
+
"deleteCustomProperty",
|
|
20264
|
+
(args) => {
|
|
20265
|
+
checkNonEmpty(args.key, "key");
|
|
20266
|
+
}
|
|
20149
20267
|
);
|
|
20150
20268
|
var propertyTools = [
|
|
20151
20269
|
getCustomProperties,
|
|
@@ -20205,7 +20323,6 @@ async function loadEquationLib() {
|
|
|
20205
20323
|
buildEquationOoxml2 = lib.buildEquationOoxml;
|
|
20206
20324
|
}
|
|
20207
20325
|
}
|
|
20208
|
-
var MARKER = "\u200B\uFEFF\u200B";
|
|
20209
20326
|
var insertEquation = {
|
|
20210
20327
|
name: "word_insert_equation",
|
|
20211
20328
|
description: "[Equations] Insert a LaTeX math equation as a native editable Word equation. Display mode (default) inserts a centered block. Inline mode inserts after a search match (provide anchorText) or at cursor.",
|
|
@@ -20224,6 +20341,7 @@ var insertEquation = {
|
|
|
20224
20341
|
await loadEquationLib();
|
|
20225
20342
|
const { mml2omml: mml2omml2 } = await Promise.resolve().then(() => (init_dist(), dist_exports));
|
|
20226
20343
|
const latex = args.latex;
|
|
20344
|
+
checkNonEmpty(latex, "latex");
|
|
20227
20345
|
const displayMode = args.displayMode !== false;
|
|
20228
20346
|
let result;
|
|
20229
20347
|
try {
|
|
@@ -20239,15 +20357,8 @@ var insertEquation = {
|
|
|
20239
20357
|
} else if (args.anchorText) {
|
|
20240
20358
|
const anchorText = args.anchorText;
|
|
20241
20359
|
const matchCase = args.matchCase || false;
|
|
20242
|
-
const
|
|
20243
|
-
|
|
20244
|
-
const occurrence = checkOccurrence(args.occurrence, searchResult.count);
|
|
20245
|
-
await bridge2.send("insertText", { text: " " + MARKER, after: anchorText, occurrence, matchCase });
|
|
20246
|
-
try {
|
|
20247
|
-
await bridge2.send("insertOoxmlAtSelection", { ooxml });
|
|
20248
|
-
} finally {
|
|
20249
|
-
await bridge2.send("searchAndReplace", { find: MARKER, replace: "" });
|
|
20250
|
-
}
|
|
20360
|
+
const occurrence = args.occurrence ?? 0;
|
|
20361
|
+
await bridge2.send("insertOoxmlAfterMatch", { ooxml, anchorText, occurrence, matchCase });
|
|
20251
20362
|
} else {
|
|
20252
20363
|
await bridge2.send("insertOoxmlAtSelection", { ooxml });
|
|
20253
20364
|
}
|
|
@@ -20259,7 +20370,7 @@ var equationTools = [
|
|
|
20259
20370
|
];
|
|
20260
20371
|
|
|
20261
20372
|
// src/server/tools/batch.ts
|
|
20262
|
-
function createBatchTool(registry, actionMap) {
|
|
20373
|
+
function createBatchTool(registry, actionMap, validators) {
|
|
20263
20374
|
return {
|
|
20264
20375
|
name: "word_batch",
|
|
20265
20376
|
description: "[Batch] Execute multiple operations in a single call. Operations execute sequentially \u2014 if one fails, subsequent are skipped. Note: paragraph indices are NOT auto-adjusted between operations. Multiple inserts at the same index will produce reversed order (last inserted appears first).",
|
|
@@ -20328,6 +20439,16 @@ function createBatchTool(registry, actionMap) {
|
|
|
20328
20439
|
break;
|
|
20329
20440
|
}
|
|
20330
20441
|
if (actionMap.has(op.tool)) {
|
|
20442
|
+
const validate = validators.get(op.tool);
|
|
20443
|
+
if (validate) {
|
|
20444
|
+
try {
|
|
20445
|
+
validate(op.args || {});
|
|
20446
|
+
} catch (e) {
|
|
20447
|
+
results.push({ index: i, tool: op.tool, success: false, error: e.message });
|
|
20448
|
+
stopped = true;
|
|
20449
|
+
break;
|
|
20450
|
+
}
|
|
20451
|
+
}
|
|
20331
20452
|
nativeBuf.push({ tool: op.tool, args: op.args || {}, originalIndex: i });
|
|
20332
20453
|
} else {
|
|
20333
20454
|
const ok = await flushNative();
|
|
@@ -20387,13 +20508,17 @@ function buildToolRegistry() {
|
|
|
20387
20508
|
];
|
|
20388
20509
|
const handlers = /* @__PURE__ */ new Map();
|
|
20389
20510
|
const actionMap = /* @__PURE__ */ new Map();
|
|
20511
|
+
const validators = /* @__PURE__ */ new Map();
|
|
20390
20512
|
for (const tool of allTools) {
|
|
20391
20513
|
handlers.set(tool.name, tool.handler);
|
|
20392
20514
|
if ("bridgeAction" in tool && typeof tool.bridgeAction === "string") {
|
|
20393
20515
|
actionMap.set(tool.name, tool.bridgeAction);
|
|
20394
20516
|
}
|
|
20517
|
+
if ("validate" in tool && typeof tool.validate === "function") {
|
|
20518
|
+
validators.set(tool.name, tool.validate);
|
|
20519
|
+
}
|
|
20395
20520
|
}
|
|
20396
|
-
const batchTool = createBatchTool(handlers, actionMap);
|
|
20521
|
+
const batchTool = createBatchTool(handlers, actionMap, validators);
|
|
20397
20522
|
allTools.push(batchTool);
|
|
20398
20523
|
handlers.set(batchTool.name, batchTool.handler);
|
|
20399
20524
|
return { tools: allTools, handlers };
|
|
@@ -20534,7 +20659,7 @@ Output always uses canonical form: "Left", "Center", "Right", "Justified".
|
|
|
20534
20659
|
// package.json
|
|
20535
20660
|
var package_default = {
|
|
20536
20661
|
name: "mcp-word-bridge",
|
|
20537
|
-
version: "4.1.
|
|
20662
|
+
version: "4.1.4",
|
|
20538
20663
|
description: "MCP server for live Word document editing via Office Add-in",
|
|
20539
20664
|
main: "dist/server.js",
|
|
20540
20665
|
bin: {
|
|
@@ -20599,7 +20724,7 @@ function createMcpServer(bridge2) {
|
|
|
20599
20724
|
);
|
|
20600
20725
|
const { tools, handlers } = buildToolRegistry();
|
|
20601
20726
|
const toolMutex = createMutex();
|
|
20602
|
-
server.setRequestHandler(
|
|
20727
|
+
server.setRequestHandler(import_types10.ListToolsRequestSchema, async () => ({
|
|
20603
20728
|
tools: tools.map((t) => ({
|
|
20604
20729
|
name: t.name,
|
|
20605
20730
|
description: t.description,
|
|
@@ -20610,7 +20735,7 @@ function createMcpServer(bridge2) {
|
|
|
20610
20735
|
}
|
|
20611
20736
|
}))
|
|
20612
20737
|
}));
|
|
20613
|
-
server.setRequestHandler(
|
|
20738
|
+
server.setRequestHandler(import_types10.CallToolRequestSchema, async (request) => {
|
|
20614
20739
|
return toolMutex.run(async () => {
|
|
20615
20740
|
const { name, arguments: args } = request.params;
|
|
20616
20741
|
const handler = handlers.get(name);
|
|
@@ -20626,7 +20751,7 @@ function createMcpServer(bridge2) {
|
|
|
20626
20751
|
}
|
|
20627
20752
|
});
|
|
20628
20753
|
});
|
|
20629
|
-
server.setRequestHandler(
|
|
20754
|
+
server.setRequestHandler(import_types10.ListResourcesRequestSchema, async () => ({
|
|
20630
20755
|
resources: [{
|
|
20631
20756
|
uri: "word-bridge://usage-guide",
|
|
20632
20757
|
name: "Word Bridge Usage Guide",
|
|
@@ -20634,7 +20759,7 @@ function createMcpServer(bridge2) {
|
|
|
20634
20759
|
mimeType: "text/markdown"
|
|
20635
20760
|
}]
|
|
20636
20761
|
}));
|
|
20637
|
-
server.setRequestHandler(
|
|
20762
|
+
server.setRequestHandler(import_types10.ReadResourceRequestSchema, async (request) => {
|
|
20638
20763
|
if (request.params.uri === "word-bridge://usage-guide") {
|
|
20639
20764
|
return { contents: [{ uri: request.params.uri, mimeType: "text/markdown", text: usageGuide }] };
|
|
20640
20765
|
}
|
|
@@ -20705,7 +20830,7 @@ function createHttpsServer() {
|
|
|
20705
20830
|
};
|
|
20706
20831
|
const rootDir = import_path.default.join(__dirname, "..");
|
|
20707
20832
|
return import_https.default.createServer(options, (req, res) => {
|
|
20708
|
-
|
|
20833
|
+
const urlPath = (req.url || "/").split("?")[0];
|
|
20709
20834
|
let filePath = urlPath === "/" ? "/taskpane.html" : urlPath;
|
|
20710
20835
|
filePath = import_path.default.resolve(rootDir, "." + filePath);
|
|
20711
20836
|
if (!filePath.startsWith(rootDir + import_path.default.sep) && filePath !== rootDir) {
|