mcp-word-bridge 4.0.5 → 4.1.1
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 +13 -0
- package/dist/server.js +118 -52
- package/dist/server.js.map +4 -4
- package/dist/taskpane-app.js +326 -53
- package/dist/taskpane-app.js.map +4 -4
- package/manifest.xml +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -289,6 +289,19 @@ src/
|
|
|
289
289
|
└── equations.ts # LaTeX→OMML conversion pipeline
|
|
290
290
|
```
|
|
291
291
|
|
|
292
|
+
## Known Limitations
|
|
293
|
+
|
|
294
|
+
Platform constraints in the Word JavaScript API that cannot be resolved in this project:
|
|
295
|
+
|
|
296
|
+
| Area | Limitation | Upstream Issue |
|
|
297
|
+
|------|------------|----------------|
|
|
298
|
+
| Tracked Changes | `word_get_tracked_changes` returns empty `text` for deletions. The `Word.TrackedChange.text` property returns `""` when `type` is `"Deleted"`. Only additions and formatting changes include text content. | [office-js#5188](https://github.com/OfficeDev/office-js/issues/5188) |
|
|
299
|
+
| Tracked Changes | `getTrackedChanges()` throws if the document contains "moved" tracked changes (drag-and-drop reorders). These produce paired "moved from"/"moved to" entries that the API cannot handle. | [office-js#5535](https://github.com/OfficeDev/office-js/issues/5535) |
|
|
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
|
+
| 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
|
+
| Page Info | `word_get_page_info` requires WordApiDesktop 1.2+ (Word for Windows/Mac desktop). Not available on Word for the web. | |
|
|
303
|
+
| 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. | |
|
|
304
|
+
|
|
292
305
|
## License
|
|
293
306
|
|
|
294
307
|
MIT
|
package/dist/server.js
CHANGED
|
@@ -18722,7 +18722,15 @@ var Bridge = class {
|
|
|
18722
18722
|
|
|
18723
18723
|
// src/server/mcp.ts
|
|
18724
18724
|
var import_server = require("@modelcontextprotocol/sdk/server/index.js");
|
|
18725
|
-
var
|
|
18725
|
+
var import_types8 = require("@modelcontextprotocol/sdk/types.js");
|
|
18726
|
+
|
|
18727
|
+
// src/server/types.ts
|
|
18728
|
+
var ToolError = class extends Error {
|
|
18729
|
+
constructor(message) {
|
|
18730
|
+
super(message);
|
|
18731
|
+
this.name = "ToolError";
|
|
18732
|
+
}
|
|
18733
|
+
};
|
|
18726
18734
|
|
|
18727
18735
|
// src/server/tools/helpers.ts
|
|
18728
18736
|
function jsonResult(data) {
|
|
@@ -18823,6 +18831,9 @@ var getDocumentOutline = {
|
|
|
18823
18831
|
},
|
|
18824
18832
|
async handler(args, bridge2) {
|
|
18825
18833
|
const maxLevel = args.maxLevel ?? 3;
|
|
18834
|
+
if (typeof args.maxLevel === "number" && (args.maxLevel < 1 || args.maxLevel > 9 || !Number.isInteger(args.maxLevel))) {
|
|
18835
|
+
throw new ToolError("maxLevel must be an integer between 1 and 9.");
|
|
18836
|
+
}
|
|
18826
18837
|
const result = await bridge2.send("getParagraphs", {});
|
|
18827
18838
|
const headings = [];
|
|
18828
18839
|
for (const para of result.paragraphs) {
|
|
@@ -18854,24 +18865,7 @@ var documentTools = [
|
|
|
18854
18865
|
getDocumentOutline
|
|
18855
18866
|
];
|
|
18856
18867
|
|
|
18857
|
-
// src/server/types.ts
|
|
18858
|
-
var ToolError = class extends Error {
|
|
18859
|
-
constructor(message) {
|
|
18860
|
-
super(message);
|
|
18861
|
-
this.name = "ToolError";
|
|
18862
|
-
}
|
|
18863
|
-
};
|
|
18864
|
-
|
|
18865
18868
|
// src/server/validation.ts
|
|
18866
|
-
var WORD_SPECIAL_CODES = /\^(p|w|t|l|m|b|n|s|d|a|e|f|g|v|~|\^|\-|13|11|14|12|07|09|30|31|32|34|36|37|38|39|40|41|42|43|44|45|46|47|92|94|127|129|130|131|132|133|134|135|136|137|138|139|140|141|142|143|144|145|146|147|148|149|150|151|152|153|154|155|156|157|158|159|160|161|162|163|164|165|166|167|168|169|170|171|172|173|174|175|176|177|178|179|180|181|182|183|184|185|186|187|188|189|190|191|192|193|194|195|196|197|198|199|200|201|202|203|204|205|206|207|208|209|210|211|212|213|214|215|216|217|218|219|220|221|222|223|224|225|226|227|228|229|230|231|232|233|234|235|236|237|238|239|240|241|242|243|244|245|246|247|248|249|250|251|252|253|254|255)/;
|
|
18867
|
-
function checkNoSpecialCodes(text2, paramName) {
|
|
18868
|
-
const match = text2.match(WORD_SPECIAL_CODES);
|
|
18869
|
-
if (match) {
|
|
18870
|
-
throw new ToolError(
|
|
18871
|
-
`${paramName} contains Word special code "${match[0]}" which can corrupt document structure. Use literal text only. Common special codes: ^p (paragraph mark), ^t (tab), ^w (whitespace), ^13 (paragraph mark).`
|
|
18872
|
-
);
|
|
18873
|
-
}
|
|
18874
|
-
}
|
|
18875
18869
|
function checkNonEmpty(value, name) {
|
|
18876
18870
|
if (!value || typeof value !== "string" || value.trim() === "") {
|
|
18877
18871
|
throw new ToolError(`${name} must be a non-empty string.`);
|
|
@@ -18910,6 +18904,24 @@ function checkSpacingBounds(value, name) {
|
|
|
18910
18904
|
);
|
|
18911
18905
|
}
|
|
18912
18906
|
}
|
|
18907
|
+
function checkIndentBounds(value, name) {
|
|
18908
|
+
if (name === "firstLineIndent") {
|
|
18909
|
+
if (value < -MAX_SPACING_POINTS || value > MAX_SPACING_POINTS) {
|
|
18910
|
+
throw new ToolError(
|
|
18911
|
+
`${name} value ${value} is out of range. Valid range: -${MAX_SPACING_POINTS} to ${MAX_SPACING_POINTS} points.`
|
|
18912
|
+
);
|
|
18913
|
+
}
|
|
18914
|
+
} else {
|
|
18915
|
+
if (value < 0) {
|
|
18916
|
+
throw new ToolError(`${name} must be non-negative (in points).`);
|
|
18917
|
+
}
|
|
18918
|
+
if (value > MAX_SPACING_POINTS) {
|
|
18919
|
+
throw new ToolError(
|
|
18920
|
+
`${name} value ${value} exceeds maximum (${MAX_SPACING_POINTS} points = 22 inches).`
|
|
18921
|
+
);
|
|
18922
|
+
}
|
|
18923
|
+
}
|
|
18924
|
+
}
|
|
18913
18925
|
function checkPropertyKeyLength(key) {
|
|
18914
18926
|
if (key.length > MAX_CUSTOM_PROPERTY_KEY_LENGTH) {
|
|
18915
18927
|
throw new ToolError(
|
|
@@ -18972,7 +18984,7 @@ var insertParagraphAtIndex = forwardTool(
|
|
|
18972
18984
|
);
|
|
18973
18985
|
var deleteParagraph = forwardTool(
|
|
18974
18986
|
"word_delete_paragraph",
|
|
18975
|
-
"[Paragraphs] Delete a paragraph by its 0-based index.",
|
|
18987
|
+
"[Paragraphs] Delete a paragraph by its 0-based index. For table cells with multiple paragraphs, extra paragraphs can be removed (the last paragraph in a cell cannot be deleted).",
|
|
18976
18988
|
{
|
|
18977
18989
|
properties: {
|
|
18978
18990
|
index: { type: "number", description: "Paragraph index (0-based)" }
|
|
@@ -19027,14 +19039,21 @@ var setParagraphSpacing = {
|
|
|
19027
19039
|
const spacingFields = [
|
|
19028
19040
|
["lineSpacing", args.lineSpacing],
|
|
19029
19041
|
["spaceBefore", args.spaceBefore],
|
|
19030
|
-
["spaceAfter", args.spaceAfter]
|
|
19042
|
+
["spaceAfter", args.spaceAfter]
|
|
19043
|
+
];
|
|
19044
|
+
for (const [name, value] of spacingFields) {
|
|
19045
|
+
if (value !== void 0 && typeof value === "number") {
|
|
19046
|
+
checkSpacingBounds(value, name);
|
|
19047
|
+
}
|
|
19048
|
+
}
|
|
19049
|
+
const indentFields = [
|
|
19031
19050
|
["firstLineIndent", args.firstLineIndent],
|
|
19032
19051
|
["leftIndent", args.leftIndent],
|
|
19033
19052
|
["rightIndent", args.rightIndent]
|
|
19034
19053
|
];
|
|
19035
|
-
for (const [name, value] of
|
|
19054
|
+
for (const [name, value] of indentFields) {
|
|
19036
19055
|
if (value !== void 0 && typeof value === "number") {
|
|
19037
|
-
|
|
19056
|
+
checkIndentBounds(value, name);
|
|
19038
19057
|
}
|
|
19039
19058
|
}
|
|
19040
19059
|
const result = await bridge2.send("setParagraphSpacing", args);
|
|
@@ -19067,7 +19086,7 @@ var moveParagraph = {
|
|
|
19067
19086
|
throw new ToolError(`toIndex (${toIndex}) is inside the source range [${fromIndex}, ${fromIndex + count - 1}]. Move to a position outside the range.`);
|
|
19068
19087
|
}
|
|
19069
19088
|
const paraCount = await bridge2.send("getParagraphs", {});
|
|
19070
|
-
const total = paraCount.
|
|
19089
|
+
const total = paraCount.total;
|
|
19071
19090
|
checkBounds(fromIndex, total, "fromIndex");
|
|
19072
19091
|
if (fromIndex + count - 1 >= total) throw new ToolError(`fromIndex + count (${fromIndex + count}) exceeds paragraph count (${total}).`);
|
|
19073
19092
|
checkBounds(toIndex, total, "toIndex");
|
|
@@ -19076,6 +19095,15 @@ var moveParagraph = {
|
|
|
19076
19095
|
throw new ToolError(`Paragraph ${para.index} is inside a table cell. Use table-specific tools to modify table content.`);
|
|
19077
19096
|
}
|
|
19078
19097
|
}
|
|
19098
|
+
const lastIdx = total - 1;
|
|
19099
|
+
if (fromIndex + count - 1 === lastIdx) {
|
|
19100
|
+
const lastPara = paraCount.paragraphs.find((p) => p.index === lastIdx);
|
|
19101
|
+
if (lastPara && lastPara.text === "") {
|
|
19102
|
+
throw new ToolError(
|
|
19103
|
+
`Cannot move the last paragraph (index ${lastIdx}) \u2014 Word requires at least one paragraph and will auto-create a replacement, resulting in duplication. Use word_copy_paragraph instead, or exclude the trailing paragraph from the range.`
|
|
19104
|
+
);
|
|
19105
|
+
}
|
|
19106
|
+
}
|
|
19079
19107
|
const adjustedTo = fromIndex < toIndex ? toIndex - count : toIndex;
|
|
19080
19108
|
if (toIndex === fromIndex + count && location === "After") {
|
|
19081
19109
|
return jsonResult({ success: true, warning: "No move performed \u2014 destination is equivalent to source position.", moved: null });
|
|
@@ -19123,7 +19151,7 @@ var copyParagraph = {
|
|
|
19123
19151
|
if (!Number.isInteger(count)) throw new ToolError("count must be an integer.");
|
|
19124
19152
|
if (count < 1) throw new ToolError("count must be at least 1");
|
|
19125
19153
|
const paraCount = await bridge2.send("getParagraphs", {});
|
|
19126
|
-
const total = paraCount.
|
|
19154
|
+
const total = paraCount.total;
|
|
19127
19155
|
checkBounds(fromIndex, total, "fromIndex");
|
|
19128
19156
|
if (fromIndex + count - 1 >= total) throw new ToolError(`fromIndex + count (${fromIndex + count}) exceeds paragraph count (${total}).`);
|
|
19129
19157
|
checkBounds(toIndex, total, "toIndex");
|
|
@@ -19155,12 +19183,17 @@ var paragraphTools = [
|
|
|
19155
19183
|
// src/server/tools/search.ts
|
|
19156
19184
|
var search = forwardTool(
|
|
19157
19185
|
"word_search",
|
|
19158
|
-
'[Search] Find text in the document. Returns match count and up to 30 matches. Query must be \u2264255 chars.
|
|
19186
|
+
'[Search] Find text in the document. Returns match count and up to 30 matches. Query must be \u2264255 chars. Supports Word search codes (^p = paragraph mark, ^t = tab, etc.) and wildcard mode (?, *, [], {n,m}). To search for literal "^", use "^^".',
|
|
19159
19187
|
{
|
|
19160
19188
|
properties: {
|
|
19161
19189
|
query: { type: "string" },
|
|
19162
19190
|
matchCase: { type: "boolean", description: "Case-sensitive search. Default: false" },
|
|
19163
|
-
matchWholeWord: { type: "boolean" }
|
|
19191
|
+
matchWholeWord: { type: "boolean", description: "Match whole words only. Default: false" },
|
|
19192
|
+
matchWildcards: { type: "boolean", description: "Enable wildcard/regex search (?, *, [], {n,m}, @). Default: false" },
|
|
19193
|
+
matchPrefix: { type: "boolean", description: "Match words that begin with the search string. Default: false" },
|
|
19194
|
+
matchSuffix: { type: "boolean", description: "Match words that end with the search string. Default: false" },
|
|
19195
|
+
ignorePunct: { type: "boolean", description: "Ignore punctuation between words when matching. Default: false" },
|
|
19196
|
+
ignoreSpace: { type: "boolean", description: "Ignore whitespace between words when matching. Default: false" }
|
|
19164
19197
|
},
|
|
19165
19198
|
required: ["query"]
|
|
19166
19199
|
},
|
|
@@ -19168,38 +19201,46 @@ var search = forwardTool(
|
|
|
19168
19201
|
);
|
|
19169
19202
|
var searchAndReplace = {
|
|
19170
19203
|
name: "word_search_and_replace",
|
|
19171
|
-
description: "[Search] Find and replace ALL occurrences. For single-paragraph edits, prefer word_replace_paragraph_text.",
|
|
19204
|
+
description: "[Search] Find and replace ALL occurrences. Supports Word search codes in both find and replace: ^p (paragraph mark), ^l (line break), ^m (page break), ^n (column break), ^t (tab), ^s (non-breaking space), ^~ (non-breaking hyphen), ^- (optional hyphen), ^+ (em dash), ^= (en dash), ^^ (literal caret). Supports wildcard search in find string. For single-paragraph edits, prefer word_replace_paragraph_text.",
|
|
19172
19205
|
schema: {
|
|
19173
19206
|
properties: {
|
|
19174
19207
|
find: { type: "string" },
|
|
19175
19208
|
replace: { type: "string" },
|
|
19176
19209
|
matchCase: { type: "boolean", description: "Default: false" },
|
|
19177
|
-
matchWholeWord: { type: "boolean" }
|
|
19210
|
+
matchWholeWord: { type: "boolean", description: "Match whole words only. Default: false" },
|
|
19211
|
+
matchWildcards: { type: "boolean", description: "Enable wildcard/regex search in find string (?, *, [], {n,m}, @). Default: false" },
|
|
19212
|
+
matchPrefix: { type: "boolean", description: "Match words that begin with the find string. Default: false" },
|
|
19213
|
+
matchSuffix: { type: "boolean", description: "Match words that end with the find string. Default: false" },
|
|
19214
|
+
ignorePunct: { type: "boolean", description: "Ignore punctuation between words when matching. Default: false" },
|
|
19215
|
+
ignoreSpace: { type: "boolean", description: "Ignore whitespace between words when matching. Default: false" },
|
|
19216
|
+
preserveBookmarks: { type: "boolean", description: "Re-create bookmarks on replacement text after replace. Default: false" }
|
|
19178
19217
|
},
|
|
19179
19218
|
required: ["find", "replace"]
|
|
19180
19219
|
},
|
|
19181
19220
|
async handler(args, bridge2) {
|
|
19182
19221
|
const find = args.find;
|
|
19183
|
-
const replace = args.replace;
|
|
19184
19222
|
if (!find || typeof find !== "string" || find.trim() === "") {
|
|
19185
19223
|
throw new ToolError("find string cannot be empty.");
|
|
19186
19224
|
}
|
|
19187
|
-
checkNoSpecialCodes(find, "find");
|
|
19188
|
-
checkNoSpecialCodes(replace, "replace");
|
|
19189
19225
|
const result = await bridge2.send("searchAndReplace", args);
|
|
19190
19226
|
return jsonResult(result);
|
|
19191
19227
|
}
|
|
19192
19228
|
};
|
|
19193
19229
|
var insertTextAtMatch = forwardTool(
|
|
19194
19230
|
"word_insert_text_at_match",
|
|
19195
|
-
'[Search] Insert text before or after a search match. Provide "after" OR "before" as the anchor text. Use occurrence for Nth match.',
|
|
19231
|
+
'[Search] Insert text before or after a search match. Supports Word search codes in inserted text: ^p (paragraph mark), ^l (line break), ^t (tab), ^s (non-breaking space), ^m (page break), ^n (column break), ^~ (non-breaking hyphen), ^- (optional hyphen), ^+ (em dash), ^= (en dash), ^^ (literal caret). Provide "after" OR "before" as the anchor text. Use occurrence for Nth match.',
|
|
19196
19232
|
{
|
|
19197
19233
|
properties: {
|
|
19198
19234
|
text: { type: "string", description: "Text to insert" },
|
|
19199
19235
|
after: { type: "string", description: "Search for this text and insert AFTER it" },
|
|
19200
19236
|
before: { type: "string", description: "Search for this text and insert BEFORE it" },
|
|
19201
19237
|
occurrence: { type: "number", description: "0=first, 1=second, etc. Default: 0" },
|
|
19202
|
-
matchCase: { type: "boolean", description: "Default: false" }
|
|
19238
|
+
matchCase: { type: "boolean", description: "Default: false" },
|
|
19239
|
+
matchWildcards: { type: "boolean", description: "Enable wildcard/regex search for anchor text. Default: false" },
|
|
19240
|
+
matchPrefix: { type: "boolean", description: "Match words that begin with the anchor text. Default: false" },
|
|
19241
|
+
matchSuffix: { type: "boolean", description: "Match words that end with the anchor text. Default: false" },
|
|
19242
|
+
ignorePunct: { type: "boolean", description: "Ignore punctuation between words when matching. Default: false" },
|
|
19243
|
+
ignoreSpace: { type: "boolean", description: "Ignore whitespace between words when matching. Default: false" }
|
|
19203
19244
|
},
|
|
19204
19245
|
required: ["text"]
|
|
19205
19246
|
},
|
|
@@ -19259,7 +19300,7 @@ var formatText = forwardTool(
|
|
|
19259
19300
|
underline: { type: "boolean" },
|
|
19260
19301
|
strikeThrough: { type: "boolean" },
|
|
19261
19302
|
color: { type: "string", description: "Hex color e.g. #FF0000" },
|
|
19262
|
-
highlightColor: { type: "string", description: "Highlight color name
|
|
19303
|
+
highlightColor: { type: "string", description: "Highlight color name (Yellow, Green, Cyan, Magenta, Blue, Red, DarkBlue, DarkCyan, DarkGreen, DarkMagenta, DarkRed, DarkYellow, Gray25, Gray50, Black, White, NoHighlight)" },
|
|
19263
19304
|
size: { type: "number", description: "Font size in points (1-1638)" },
|
|
19264
19305
|
name: { type: "string", description: "Font name" },
|
|
19265
19306
|
matchCase: { type: "boolean", description: "Default: false" }
|
|
@@ -19311,7 +19352,7 @@ var insertTable = forwardTool(
|
|
|
19311
19352
|
data: { type: "array", items: { type: "array", items: { type: "string" } }, description: "Cell values as array of row arrays" },
|
|
19312
19353
|
location: { type: "string", enum: ["Start", "End"] },
|
|
19313
19354
|
style: { type: "string", description: "Table style name" },
|
|
19314
|
-
headerRowCount: { type: "number" }
|
|
19355
|
+
headerRowCount: { type: "number", description: "Number of header rows (default: 0). Set to 1 to mark the first row as a repeating header." }
|
|
19315
19356
|
},
|
|
19316
19357
|
required: ["rows", "cols"]
|
|
19317
19358
|
},
|
|
@@ -19790,6 +19831,9 @@ var setContentControlText = {
|
|
|
19790
19831
|
if (tag) {
|
|
19791
19832
|
const ccResult = await bridge2.send("getContentControls", {});
|
|
19792
19833
|
const matches = ccResult.controls.filter((c) => c.tag === tag);
|
|
19834
|
+
if (matches.length === 0) {
|
|
19835
|
+
throw new ToolError(`Content control with tag "${tag}" not found. Use word_get_content_controls to list available controls.`);
|
|
19836
|
+
}
|
|
19793
19837
|
if (matches.length > 1) {
|
|
19794
19838
|
throw new ToolError(
|
|
19795
19839
|
`Multiple content controls (${matches.length}) share tag "${tag}". Use "id" instead to target a specific control. Matching IDs: ${matches.map((m) => m.id).join(", ")}.`
|
|
@@ -20177,6 +20221,11 @@ function createBatchTool(registry, actionMap) {
|
|
|
20177
20221
|
if (operations.length > MAX_BATCH_OPERATIONS) {
|
|
20178
20222
|
throw new ToolError(`maximum ${MAX_BATCH_OPERATIONS} operations per batch`);
|
|
20179
20223
|
}
|
|
20224
|
+
for (const op of operations) {
|
|
20225
|
+
if (op.tool === "word_batch") {
|
|
20226
|
+
throw new ToolError("word_batch cannot be nested inside another batch. Flatten your operations into a single batch call.");
|
|
20227
|
+
}
|
|
20228
|
+
}
|
|
20180
20229
|
const results = [];
|
|
20181
20230
|
let nativeBuf = [];
|
|
20182
20231
|
let stopped = false;
|
|
@@ -20290,6 +20339,20 @@ function buildToolRegistry() {
|
|
|
20290
20339
|
return { tools: allTools, handlers };
|
|
20291
20340
|
}
|
|
20292
20341
|
|
|
20342
|
+
// src/server/mutex.ts
|
|
20343
|
+
function createMutex() {
|
|
20344
|
+
let chain = Promise.resolve();
|
|
20345
|
+
return {
|
|
20346
|
+
run(fn) {
|
|
20347
|
+
const next = chain.then(fn, fn);
|
|
20348
|
+
chain = next.then(noop, noop);
|
|
20349
|
+
return next;
|
|
20350
|
+
}
|
|
20351
|
+
};
|
|
20352
|
+
}
|
|
20353
|
+
function noop() {
|
|
20354
|
+
}
|
|
20355
|
+
|
|
20293
20356
|
// src/server/usage-guide.ts
|
|
20294
20357
|
var usageGuide = `# MCP Word Bridge \u2014 Usage Guide
|
|
20295
20358
|
|
|
@@ -20400,7 +20463,7 @@ After inserting a Table of Contents, heading text appears twice (in TOC and body
|
|
|
20400
20463
|
// package.json
|
|
20401
20464
|
var package_default = {
|
|
20402
20465
|
name: "mcp-word-bridge",
|
|
20403
|
-
version: "4.
|
|
20466
|
+
version: "4.1.1",
|
|
20404
20467
|
description: "MCP server for live Word document editing via Office Add-in",
|
|
20405
20468
|
main: "dist/server.js",
|
|
20406
20469
|
bin: {
|
|
@@ -20464,7 +20527,8 @@ function createMcpServer(bridge2) {
|
|
|
20464
20527
|
{ capabilities: { tools: {}, resources: {} } }
|
|
20465
20528
|
);
|
|
20466
20529
|
const { tools, handlers } = buildToolRegistry();
|
|
20467
|
-
|
|
20530
|
+
const toolMutex = createMutex();
|
|
20531
|
+
server.setRequestHandler(import_types8.ListToolsRequestSchema, async () => ({
|
|
20468
20532
|
tools: tools.map((t) => ({
|
|
20469
20533
|
name: t.name,
|
|
20470
20534
|
description: t.description,
|
|
@@ -20475,21 +20539,23 @@ function createMcpServer(bridge2) {
|
|
|
20475
20539
|
}
|
|
20476
20540
|
}))
|
|
20477
20541
|
}));
|
|
20478
|
-
server.setRequestHandler(
|
|
20479
|
-
|
|
20480
|
-
|
|
20481
|
-
|
|
20482
|
-
|
|
20483
|
-
|
|
20484
|
-
|
|
20485
|
-
|
|
20486
|
-
|
|
20487
|
-
|
|
20488
|
-
|
|
20489
|
-
|
|
20490
|
-
|
|
20542
|
+
server.setRequestHandler(import_types8.CallToolRequestSchema, async (request) => {
|
|
20543
|
+
return toolMutex.run(async () => {
|
|
20544
|
+
const { name, arguments: args } = request.params;
|
|
20545
|
+
const handler = handlers.get(name);
|
|
20546
|
+
if (!handler) {
|
|
20547
|
+
return { content: [{ type: "text", text: "Unknown tool: " + name }], isError: true };
|
|
20548
|
+
}
|
|
20549
|
+
try {
|
|
20550
|
+
const result = await handler(args || {}, bridge2);
|
|
20551
|
+
return result;
|
|
20552
|
+
} catch (e) {
|
|
20553
|
+
const msg = e instanceof ToolError ? e.message : "Error: " + e.message;
|
|
20554
|
+
return { content: [{ type: "text", text: msg }], isError: true };
|
|
20555
|
+
}
|
|
20556
|
+
});
|
|
20491
20557
|
});
|
|
20492
|
-
server.setRequestHandler(
|
|
20558
|
+
server.setRequestHandler(import_types8.ListResourcesRequestSchema, async () => ({
|
|
20493
20559
|
resources: [{
|
|
20494
20560
|
uri: "word-bridge://usage-guide",
|
|
20495
20561
|
name: "Word Bridge Usage Guide",
|
|
@@ -20497,7 +20563,7 @@ function createMcpServer(bridge2) {
|
|
|
20497
20563
|
mimeType: "text/markdown"
|
|
20498
20564
|
}]
|
|
20499
20565
|
}));
|
|
20500
|
-
server.setRequestHandler(
|
|
20566
|
+
server.setRequestHandler(import_types8.ReadResourceRequestSchema, async (request) => {
|
|
20501
20567
|
if (request.params.uri === "word-bridge://usage-guide") {
|
|
20502
20568
|
return { contents: [{ uri: request.params.uri, mimeType: "text/markdown", text: usageGuide }] };
|
|
20503
20569
|
}
|