pptx-viewer-mcp 2.4.1 → 2.5.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/CHANGELOG.md +6 -0
- package/dist/codec/index.d.ts +7 -7
- package/dist/codec/index.d.ts.map +1 -1
- package/dist/index.d.ts +174 -79
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +129 -0
- package/dist/index.mjs +125 -2
- package/dist/mcp/index.js +250 -0
- package/dist/mcp/index.mjs +251 -1
- package/dist/schemas/index.d.ts +115 -73
- package/dist/schemas/index.d.ts.map +1 -1
- package/dist/schemas/index.js +49 -0
- package/dist/schemas/index.mjs +44 -1
- package/package.json +8 -7
package/dist/mcp/index.mjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
3
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
4
4
|
import { z } from 'zod';
|
|
5
|
-
import { validatePptx, repairPptx, PptxHandler, hasTextProperties, resolveThemeColorRef, cloneElement as cloneElement$1, isTemplateElementId, makeStoreAwareId, reassignDescendantIds, groupElements as groupElements$1, ungroupElements as ungroupElements$1, TABLE_STYLE_PART_SEQUENCE, normalizeTableStyleGuid, createTableStyleEntry, addTableStyleToMap, deleteTableStyleFromMap, PptxMarkdownConverter, ThemePresets, getThemePreset, setChartType, setChartTitle, setChartGrouping, setChartLegend, setChartDataLabels, setChartAxis, setChartCategories, addChartSeries, removeChartSeries, updateChartSeriesValues, ChartBuilder, setChartDataPointStyle, setChartDataPointExplosion, setChartDataPointMarker, setChartDataPointLabel, setChartSeriesMarker, setChartSeriesTrendline, setChartSeriesErrorBars, setChartHelperLine, setChartColorMapOverride, listChartUserShapes, addChartUserShape, updateChartUserShape, removeChartUserShape, decomposeSmartArt, demoteSmartArtNode, promoteSmartArtNode, reorderSmartArtNode, updateSmartArtNodeText, removeSmartArtNode, addSmartArtNode, findPlaceholders, applyTemplate, getSectionForSlide, moveSlidesToSection, reorderSections, removeSection, addSection, SvgExporter, buildPptxJsonDocument, deserializePptxFromJson, applyImportedPptxData, replaceWithCustomGeometry, replaceShapeGeometry, setElementLocked, findLayoutByName, findLayoutByType, resolveDisplayedChartTypeName } from 'pptx-viewer-core';
|
|
5
|
+
import { validatePptx, repairPptx, PptxHandler, hasTextProperties, resolveThemeColorRef, cloneElement as cloneElement$1, isTemplateElementId, makeStoreAwareId, reassignDescendantIds, groupElements as groupElements$1, ungroupElements as ungroupElements$1, TABLE_STYLE_PART_SEQUENCE, normalizeTableStyleGuid, createTableStyleEntry, addTableStyleToMap, deleteTableStyleFromMap, PptxMarkdownConverter, ThemePresets, getThemePreset, setChartType, setChartTitle, setChartGrouping, setChartLegend, setChartDataLabels, setChartAxis, setChartCategories, addChartSeries, removeChartSeries, updateChartSeriesValues, ChartBuilder, setChartDataPointStyle, setChartDataPointExplosion, setChartDataPointMarker, setChartDataPointLabel, setChartSeriesMarker, setChartSeriesTrendline, setChartSeriesErrorBars, setChartHelperLine, setChartColorMapOverride, listChartUserShapes, addChartUserShape, updateChartUserShape, removeChartUserShape, decomposeSmartArt, demoteSmartArtNode, promoteSmartArtNode, reorderSmartArtNode, updateSmartArtNodeText, removeSmartArtNode, addSmartArtNode, findPlaceholders, applyTemplate, getSectionForSlide, moveSlidesToSection, reorderSections, removeSection, addSection, SvgExporter, buildPptxJsonDocument, deserializePptxFromJson, applyImportedPptxData, replaceWithCustomGeometry, replaceShapeGeometry, setElementLocked, findLayoutByName, findLayoutByType, resolveOleEditorKindFromPayload, getOleNestedDeckDetail, getOleDocumentParagraphs, getOleSheetGrid, applyOleSheetCellEdit, applyOleDocumentParagraphEdit, applyOleNestedDeckElementTextEdit, parseDataUrlToBytes, replaceOleFile, setOleObjectName, resolveDisplayedChartTypeName } from 'pptx-viewer-core';
|
|
6
6
|
import { writeFile, readFile } from 'fs/promises';
|
|
7
7
|
import { resolve, isAbsolute, sep } from 'path';
|
|
8
8
|
|
|
@@ -879,6 +879,49 @@ var ApplyLayoutSchema = z.object({
|
|
|
879
879
|
layoutName: z.string().optional().describe("Layout name to apply"),
|
|
880
880
|
layoutType: z.string().optional().describe("Layout type to apply (alternative to name)")
|
|
881
881
|
});
|
|
882
|
+
var GetOleContentSchema = z.object({
|
|
883
|
+
filePath: z.string().describe("Path to the PPTX file"),
|
|
884
|
+
slideIndex: z.number().int().min(0).describe("Zero-based slide index"),
|
|
885
|
+
elementId: z.string().describe("OLE element ID")
|
|
886
|
+
});
|
|
887
|
+
var SetOleSheetCellSchema = z.object({
|
|
888
|
+
filePath: z.string().describe("Path to the PPTX file"),
|
|
889
|
+
slideIndex: z.number().int().min(0).describe("Zero-based slide index"),
|
|
890
|
+
elementId: z.string().describe("OLE element ID (Excel payload: .xlsx or .xls)"),
|
|
891
|
+
row: z.number().int().min(0).describe("Zero-based row index on the first worksheet"),
|
|
892
|
+
col: z.number().int().min(0).describe("Zero-based column index on the first worksheet"),
|
|
893
|
+
value: z.string().describe("New cell value")
|
|
894
|
+
});
|
|
895
|
+
var SetOleDocumentParagraphSchema = z.object({
|
|
896
|
+
filePath: z.string().describe("Path to the PPTX file"),
|
|
897
|
+
slideIndex: z.number().int().min(0).describe("Zero-based slide index"),
|
|
898
|
+
elementId: z.string().describe("OLE element ID (Word payload: .docx)"),
|
|
899
|
+
paragraphIndex: z.number().int().min(0).describe("Zero-based paragraph index"),
|
|
900
|
+
text: z.string().describe("New paragraph text")
|
|
901
|
+
});
|
|
902
|
+
var SetOleDeckSlideTitleSchema = z.object({
|
|
903
|
+
filePath: z.string().describe("Path to the PPTX file"),
|
|
904
|
+
slideIndex: z.number().int().min(0).describe("Zero-based slide index"),
|
|
905
|
+
elementId: z.string().describe("OLE element ID (nested-deck payload: .pptx)"),
|
|
906
|
+
deckSlideIndex: z.number().int().min(0).describe("Zero-based slide index within the nested deck"),
|
|
907
|
+
deckElementId: z.string().describe(
|
|
908
|
+
"ID of the text-bearing shape to edit within the nested slide, from ole_get_content's deckSlides[n].elements[i].elementId"
|
|
909
|
+
),
|
|
910
|
+
title: z.string().describe("New text for the chosen shape")
|
|
911
|
+
});
|
|
912
|
+
var ReplaceOleFileSchema = z.object({
|
|
913
|
+
filePath: z.string().describe("Path to the PPTX file"),
|
|
914
|
+
slideIndex: z.number().int().min(0).describe("Zero-based slide index"),
|
|
915
|
+
elementId: z.string().describe("OLE element ID"),
|
|
916
|
+
fileData: z.string().describe('New payload as a base64 data URL (e.g. "data:application/pdf;base64,...")'),
|
|
917
|
+
fileName: z.string().optional().describe("Optional new file name (also updates the resolved MIME type)")
|
|
918
|
+
});
|
|
919
|
+
var SetOleObjectNameSchema = z.object({
|
|
920
|
+
filePath: z.string().describe("Path to the PPTX file"),
|
|
921
|
+
slideIndex: z.number().int().min(0).describe("Zero-based slide index"),
|
|
922
|
+
elementId: z.string().describe("OLE element ID"),
|
|
923
|
+
name: z.string().describe("New Object Name (p:oleObj/@name); blank/whitespace clears it")
|
|
924
|
+
});
|
|
882
925
|
function generateElementId() {
|
|
883
926
|
return `el-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
884
927
|
}
|
|
@@ -2847,6 +2890,129 @@ function updateMetadata(ctx, params) {
|
|
|
2847
2890
|
result: { updated }
|
|
2848
2891
|
};
|
|
2849
2892
|
}
|
|
2893
|
+
function resolveOleElement(ctx, slideIndex, elementId) {
|
|
2894
|
+
const err = validateSlideIndex(slideIndex, ctx.pptxData.slides.length);
|
|
2895
|
+
if (err) {
|
|
2896
|
+
throw new Error(err);
|
|
2897
|
+
}
|
|
2898
|
+
const slide = ctx.pptxData.slides[slideIndex];
|
|
2899
|
+
const index = slide.elements.findIndex((e) => e.id === elementId);
|
|
2900
|
+
if (index === -1) {
|
|
2901
|
+
throw new Error(`Element '${elementId}' not found on slide ${slideIndex}.`);
|
|
2902
|
+
}
|
|
2903
|
+
const element = slide.elements[index];
|
|
2904
|
+
if (element.type !== "ole") {
|
|
2905
|
+
throw new Error(`Element '${elementId}' is not an OLE object.`);
|
|
2906
|
+
}
|
|
2907
|
+
return { slide, element, index };
|
|
2908
|
+
}
|
|
2909
|
+
function commitOleElement(slide, index, updated) {
|
|
2910
|
+
slide.elements.splice(index, 1, updated);
|
|
2911
|
+
slide.isDirty = true;
|
|
2912
|
+
}
|
|
2913
|
+
async function getOleContent(ctx, params) {
|
|
2914
|
+
const { element } = resolveOleElement(ctx, params.slideIndex, params.elementId);
|
|
2915
|
+
const kind = await resolveOleEditorKindFromPayload(element);
|
|
2916
|
+
const base = { pptxData: ctx.pptxData, dirty: false };
|
|
2917
|
+
switch (kind) {
|
|
2918
|
+
case "sheet-xlsx":
|
|
2919
|
+
case "sheet-xls": {
|
|
2920
|
+
const sheet = await getOleSheetGrid(element);
|
|
2921
|
+
return { ...base, result: { elementId: element.id, kind, editable: true, sheet } };
|
|
2922
|
+
}
|
|
2923
|
+
case "document-docx":
|
|
2924
|
+
case "document-doc": {
|
|
2925
|
+
const paragraphs = await getOleDocumentParagraphs(element);
|
|
2926
|
+
return { ...base, result: { elementId: element.id, kind, editable: true, paragraphs } };
|
|
2927
|
+
}
|
|
2928
|
+
case "deck-pptx": {
|
|
2929
|
+
const deckSlides = await getOleNestedDeckDetail(element);
|
|
2930
|
+
return { ...base, result: { elementId: element.id, kind, editable: true, deckSlides } };
|
|
2931
|
+
}
|
|
2932
|
+
default:
|
|
2933
|
+
return {
|
|
2934
|
+
...base,
|
|
2935
|
+
result: {
|
|
2936
|
+
elementId: element.id,
|
|
2937
|
+
kind,
|
|
2938
|
+
editable: false,
|
|
2939
|
+
message: `This OLE object's content (${kind}) is not directly editable; use ole_replace_file to replace it wholesale.`
|
|
2940
|
+
}
|
|
2941
|
+
};
|
|
2942
|
+
}
|
|
2943
|
+
}
|
|
2944
|
+
async function setOleSheetCell(ctx, params) {
|
|
2945
|
+
const { slide, element, index } = resolveOleElement(ctx, params.slideIndex, params.elementId);
|
|
2946
|
+
const updated = await applyOleSheetCellEdit(element, {
|
|
2947
|
+
row: params.row,
|
|
2948
|
+
col: params.col,
|
|
2949
|
+
value: params.value
|
|
2950
|
+
});
|
|
2951
|
+
const changed = updated !== element;
|
|
2952
|
+
if (changed) {
|
|
2953
|
+
commitOleElement(slide, index, updated);
|
|
2954
|
+
}
|
|
2955
|
+
return {
|
|
2956
|
+
pptxData: ctx.pptxData,
|
|
2957
|
+
dirty: changed,
|
|
2958
|
+
result: { elementId: params.elementId, changed }
|
|
2959
|
+
};
|
|
2960
|
+
}
|
|
2961
|
+
async function setOleDocumentParagraph(ctx, params) {
|
|
2962
|
+
const { slide, element, index } = resolveOleElement(ctx, params.slideIndex, params.elementId);
|
|
2963
|
+
const updated = await applyOleDocumentParagraphEdit(element, params.paragraphIndex, params.text);
|
|
2964
|
+
const changed = updated !== element;
|
|
2965
|
+
if (changed) {
|
|
2966
|
+
commitOleElement(slide, index, updated);
|
|
2967
|
+
}
|
|
2968
|
+
return {
|
|
2969
|
+
pptxData: ctx.pptxData,
|
|
2970
|
+
dirty: changed,
|
|
2971
|
+
result: { elementId: params.elementId, changed }
|
|
2972
|
+
};
|
|
2973
|
+
}
|
|
2974
|
+
async function setOleDeckSlideTitle(ctx, params) {
|
|
2975
|
+
const { slide, element, index } = resolveOleElement(ctx, params.slideIndex, params.elementId);
|
|
2976
|
+
const updated = await applyOleNestedDeckElementTextEdit(
|
|
2977
|
+
element,
|
|
2978
|
+
params.deckSlideIndex,
|
|
2979
|
+
params.deckElementId,
|
|
2980
|
+
params.title
|
|
2981
|
+
);
|
|
2982
|
+
const changed = updated !== element;
|
|
2983
|
+
if (changed) {
|
|
2984
|
+
commitOleElement(slide, index, updated);
|
|
2985
|
+
}
|
|
2986
|
+
return {
|
|
2987
|
+
pptxData: ctx.pptxData,
|
|
2988
|
+
dirty: changed,
|
|
2989
|
+
result: { elementId: params.elementId, changed }
|
|
2990
|
+
};
|
|
2991
|
+
}
|
|
2992
|
+
async function setOleObjectNameT(ctx, params) {
|
|
2993
|
+
const { slide, element, index } = resolveOleElement(ctx, params.slideIndex, params.elementId);
|
|
2994
|
+
const updated = await setOleObjectName(element, params.name);
|
|
2995
|
+
commitOleElement(slide, index, updated);
|
|
2996
|
+
return {
|
|
2997
|
+
pptxData: ctx.pptxData,
|
|
2998
|
+
dirty: true,
|
|
2999
|
+
result: { elementId: params.elementId, changed: true }
|
|
3000
|
+
};
|
|
3001
|
+
}
|
|
3002
|
+
async function replaceOleFileT(ctx, params) {
|
|
3003
|
+
const { slide, element, index } = resolveOleElement(ctx, params.slideIndex, params.elementId);
|
|
3004
|
+
const parsed = parseDataUrlToBytes(params.fileData);
|
|
3005
|
+
if (!parsed) {
|
|
3006
|
+
throw new Error('fileData must be a base64 data URL, e.g. "data:<mime-type>;base64,<...>".');
|
|
3007
|
+
}
|
|
3008
|
+
const updated = await replaceOleFile(element, parsed.bytes, params.fileName);
|
|
3009
|
+
commitOleElement(slide, index, updated);
|
|
3010
|
+
return {
|
|
3011
|
+
pptxData: ctx.pptxData,
|
|
3012
|
+
dirty: true,
|
|
3013
|
+
result: { elementId: params.elementId, changed: true }
|
|
3014
|
+
};
|
|
3015
|
+
}
|
|
2850
3016
|
|
|
2851
3017
|
// src/tools/presentation-tools.ts
|
|
2852
3018
|
function getPresentationProperties(ctx) {
|
|
@@ -4960,6 +5126,90 @@ function createServer() {
|
|
|
4960
5126
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
4961
5127
|
}
|
|
4962
5128
|
);
|
|
5129
|
+
server2.registerTool(
|
|
5130
|
+
"ole_get_content",
|
|
5131
|
+
{
|
|
5132
|
+
description: "Inspect an embedded OLE object's editable content: resolved kind, plus the sheet grid, paragraph list, or nested-deck slide summaries, whichever applies",
|
|
5133
|
+
inputSchema: GetOleContentSchema.shape
|
|
5134
|
+
},
|
|
5135
|
+
async (params) => {
|
|
5136
|
+
const result = await runMcpTool(
|
|
5137
|
+
params.filePath,
|
|
5138
|
+
(ctx) => getOleContent(ctx, params)
|
|
5139
|
+
);
|
|
5140
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5141
|
+
}
|
|
5142
|
+
);
|
|
5143
|
+
server2.registerTool(
|
|
5144
|
+
"ole_set_sheet_cell",
|
|
5145
|
+
{
|
|
5146
|
+
description: "Edit one cell of an embedded Excel OLE object's first worksheet",
|
|
5147
|
+
inputSchema: SetOleSheetCellSchema.shape
|
|
5148
|
+
},
|
|
5149
|
+
async (params) => {
|
|
5150
|
+
const result = await runMcpTool(
|
|
5151
|
+
params.filePath,
|
|
5152
|
+
(ctx) => setOleSheetCell(ctx, params)
|
|
5153
|
+
);
|
|
5154
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5155
|
+
}
|
|
5156
|
+
);
|
|
5157
|
+
server2.registerTool(
|
|
5158
|
+
"ole_set_document_paragraph",
|
|
5159
|
+
{
|
|
5160
|
+
description: "Replace one paragraph's text in an embedded Word (.docx or legacy .doc) OLE object",
|
|
5161
|
+
inputSchema: SetOleDocumentParagraphSchema.shape
|
|
5162
|
+
},
|
|
5163
|
+
async (params) => {
|
|
5164
|
+
const result = await runMcpTool(
|
|
5165
|
+
params.filePath,
|
|
5166
|
+
(ctx) => setOleDocumentParagraph(ctx, params)
|
|
5167
|
+
);
|
|
5168
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5169
|
+
}
|
|
5170
|
+
);
|
|
5171
|
+
server2.registerTool(
|
|
5172
|
+
"ole_set_deck_slide_title",
|
|
5173
|
+
{
|
|
5174
|
+
description: "Edit one text-bearing shape on one slide of an embedded nested-deck (PowerPoint) OLE object, via a full load/save round-trip through the nested deck (call ole_get_content first to discover each slide's elementIds)",
|
|
5175
|
+
inputSchema: SetOleDeckSlideTitleSchema.shape
|
|
5176
|
+
},
|
|
5177
|
+
async (params) => {
|
|
5178
|
+
const result = await runMcpTool(
|
|
5179
|
+
params.filePath,
|
|
5180
|
+
(ctx) => setOleDeckSlideTitle(ctx, params)
|
|
5181
|
+
);
|
|
5182
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5183
|
+
}
|
|
5184
|
+
);
|
|
5185
|
+
server2.registerTool(
|
|
5186
|
+
"ole_replace_file",
|
|
5187
|
+
{
|
|
5188
|
+
description: `Replace an embedded OLE object's payload wholesale with an arbitrary file; works for any OLE kind, including a generic "Package" object or an unsupported format`,
|
|
5189
|
+
inputSchema: ReplaceOleFileSchema.shape
|
|
5190
|
+
},
|
|
5191
|
+
async (params) => {
|
|
5192
|
+
const result = await runMcpTool(
|
|
5193
|
+
params.filePath,
|
|
5194
|
+
(ctx) => replaceOleFileT(ctx, params)
|
|
5195
|
+
);
|
|
5196
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5197
|
+
}
|
|
5198
|
+
);
|
|
5199
|
+
server2.registerTool(
|
|
5200
|
+
"ole_set_object_name",
|
|
5201
|
+
{
|
|
5202
|
+
description: "Rename an OLE object's Object Name (p:oleObj/@name); regenerates the baked-in icon caption too when the object is displayed as an icon",
|
|
5203
|
+
inputSchema: SetOleObjectNameSchema.shape
|
|
5204
|
+
},
|
|
5205
|
+
async (params) => {
|
|
5206
|
+
const result = await runMcpTool(
|
|
5207
|
+
params.filePath,
|
|
5208
|
+
(ctx) => setOleObjectNameT(ctx, params)
|
|
5209
|
+
);
|
|
5210
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
5211
|
+
}
|
|
5212
|
+
);
|
|
4963
5213
|
return server2;
|
|
4964
5214
|
}
|
|
4965
5215
|
|