iwork-mcp 0.5.0 → 0.5.2
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 +3 -2
- package/dist/tools/numbers.js +136 -13
- package/dist/tools/pages.js +3 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ Ask Claude to build spreadsheets, write documents, and create presentations —
|
|
|
14
14
|
|
|
15
15
|
**Keynote** — Create presentations, add/delete/duplicate/reorder slides, set titles and bullet points, add images and shapes, set transitions and presenter notes, start/stop slideshows, export to PDF/PowerPoint/HTML.
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
73 tools total.
|
|
18
18
|
|
|
19
19
|
## Install
|
|
20
20
|
|
|
@@ -50,7 +50,7 @@ claude mcp add iwork -- npx -y iwork-mcp
|
|
|
50
50
|
|
|
51
51
|
## Tools
|
|
52
52
|
|
|
53
|
-
### Numbers (
|
|
53
|
+
### Numbers (36 tools)
|
|
54
54
|
|
|
55
55
|
| Tool | Description |
|
|
56
56
|
|------|-------------|
|
|
@@ -89,6 +89,7 @@ claude mcp add iwork -- npx -y iwork-mcp
|
|
|
89
89
|
| `numbers_format_cells` | Set font, size, color, bold, italic, alignment, background |
|
|
90
90
|
| `numbers_set_column_width` | Set column width |
|
|
91
91
|
| `numbers_set_row_height` | Set row height |
|
|
92
|
+
| `numbers_create_sheet_with_table` | Create a full sheet with table, data, and formatting in one fast call |
|
|
92
93
|
|
|
93
94
|
### Pages (15 tools)
|
|
94
95
|
|
package/dist/tools/numbers.js
CHANGED
|
@@ -605,9 +605,9 @@ export function registerNumbersTools(server) {
|
|
|
605
605
|
}
|
|
606
606
|
|
|
607
607
|
function hexToRGB(hex) {
|
|
608
|
-
const r = parseInt(hex.slice(1, 3), 16)
|
|
609
|
-
const g = parseInt(hex.slice(3, 5), 16)
|
|
610
|
-
const b = parseInt(hex.slice(5, 7), 16)
|
|
608
|
+
const r = parseInt(hex.slice(1, 3), 16) * 257;
|
|
609
|
+
const g = parseInt(hex.slice(3, 5), 16) * 257;
|
|
610
|
+
const b = parseInt(hex.slice(5, 7), 16) * 257;
|
|
611
611
|
return [r, g, b];
|
|
612
612
|
}
|
|
613
613
|
|
|
@@ -615,12 +615,10 @@ export function registerNumbersTools(server) {
|
|
|
615
615
|
if (fmt.fontSize !== undefined) cell.fontSize = fmt.fontSize;
|
|
616
616
|
if (fmt.fontName !== undefined) cell.fontName = fmt.fontName;
|
|
617
617
|
if (fmt.textColor !== undefined) {
|
|
618
|
-
|
|
619
|
-
cell.textColor = [r, g, b];
|
|
618
|
+
cell.textColor = hexToRGB(fmt.textColor);
|
|
620
619
|
}
|
|
621
620
|
if (fmt.backgroundColor !== undefined) {
|
|
622
|
-
|
|
623
|
-
cell.backgroundColor = [r, g, b];
|
|
621
|
+
cell.backgroundColor = hexToRGB(fmt.backgroundColor);
|
|
624
622
|
}
|
|
625
623
|
if (fmt.alignment !== undefined) {
|
|
626
624
|
cell.alignment = fmt.alignment;
|
|
@@ -631,16 +629,16 @@ export function registerNumbersTools(server) {
|
|
|
631
629
|
if (fmt.textWrap !== undefined) {
|
|
632
630
|
cell.textWrap = fmt.textWrap;
|
|
633
631
|
}
|
|
634
|
-
// Bold/italic: switch font to bold/italic variant
|
|
632
|
+
// Bold/italic: switch font to bold/italic variant (PostScript names)
|
|
635
633
|
if (fmt.bold !== undefined || fmt.italic !== undefined) {
|
|
636
634
|
let fontName = fmt.fontName || cell.fontName();
|
|
637
|
-
const baseName = fontName.replace(/ ?(Bold
|
|
638
|
-
let suffix = "";
|
|
635
|
+
const baseName = fontName.replace(/[- ]?(Bold ?Italic|BoldItalic|Bold|Italic)$/i, "").trim();
|
|
639
636
|
const wantBold = fmt.bold !== undefined ? fmt.bold : /Bold/i.test(fontName);
|
|
640
637
|
const wantItalic = fmt.italic !== undefined ? fmt.italic : /Italic/i.test(fontName);
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
else if (
|
|
638
|
+
let suffix = "";
|
|
639
|
+
if (wantBold && wantItalic) suffix = "-BoldItalic";
|
|
640
|
+
else if (wantBold) suffix = "-Bold";
|
|
641
|
+
else if (wantItalic) suffix = "-Italic";
|
|
644
642
|
cell.fontName = baseName + suffix;
|
|
645
643
|
}
|
|
646
644
|
}
|
|
@@ -684,4 +682,129 @@ export function registerNumbersTools(server) {
|
|
|
684
682
|
table.rows[params.row - 1].height = params.height;
|
|
685
683
|
return JSON.stringify({ row: params.row, height: params.height, set: true });
|
|
686
684
|
`, { documentName, row, height, sheetName: sheetName ?? null, tableName: tableName ?? null })));
|
|
685
|
+
// ── Compound / Batch Tools ──
|
|
686
|
+
server.tool("numbers_create_sheet_with_table", "Create a complete sheet with a named table, data, and formatting in ONE operation. Much faster than calling individual tools. Use this for bulk setup like calendars, reports, dashboards.", {
|
|
687
|
+
documentName: z.string().describe("Name of the open document"),
|
|
688
|
+
sheetName: z.string().describe("Name for the new sheet"),
|
|
689
|
+
tableName: z.string().optional().describe("Name for the table (default: same as sheet name)"),
|
|
690
|
+
data: z.array(z.array(z.union([z.string(), z.number(), z.boolean(), z.null()])))
|
|
691
|
+
.describe("2D array of table data. First row can be headers."),
|
|
692
|
+
headerRowCount: z.number().optional().describe("Number of header rows (default: 0 for no header styling)"),
|
|
693
|
+
columnWidths: z.array(z.number()).optional().describe("Width in points for each column"),
|
|
694
|
+
rowHeights: z.array(z.number()).optional().describe("Height in points for each row"),
|
|
695
|
+
formatting: z.array(z.object({
|
|
696
|
+
cellRange: z.string().describe("Cell or range, e.g. 'A1' or 'A1:G1'"),
|
|
697
|
+
bold: z.boolean().optional(),
|
|
698
|
+
italic: z.boolean().optional(),
|
|
699
|
+
fontSize: z.number().optional(),
|
|
700
|
+
fontName: z.string().optional(),
|
|
701
|
+
textColor: z.string().optional().describe("Hex color, e.g. '#FF0000'"),
|
|
702
|
+
backgroundColor: z.string().optional().describe("Hex color, e.g. '#0000FF'"),
|
|
703
|
+
alignment: z.enum(["left", "center", "right", "auto"]).optional(),
|
|
704
|
+
verticalAlignment: z.enum(["top", "center", "bottom"]).optional(),
|
|
705
|
+
textWrap: z.boolean().optional(),
|
|
706
|
+
})).optional().describe("Array of formatting rules to apply"),
|
|
707
|
+
deleteDefaultTable: z.boolean().optional().describe("Delete the default 'Table 1' that Numbers auto-creates (default: true)"),
|
|
708
|
+
}, async ({ documentName, sheetName, tableName, data, headerRowCount, columnWidths, rowHeights, formatting, deleteDefaultTable }) => handleJXA(() => runJXA(`
|
|
709
|
+
const app = Application("Numbers");
|
|
710
|
+
const doc = app.documents.byName(params.documentName);
|
|
711
|
+
|
|
712
|
+
// Create the sheet
|
|
713
|
+
const sheet = app.Sheet();
|
|
714
|
+
doc.sheets.push(sheet);
|
|
715
|
+
sheet.name = params.sheetName;
|
|
716
|
+
|
|
717
|
+
// Delete the default "Table 1" that Numbers auto-creates
|
|
718
|
+
if (params.deleteDefaultTable !== false) {
|
|
719
|
+
try { app.delete(sheet.tables[0]); } catch(e) {}
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
// Create our table with the right dimensions
|
|
723
|
+
const dataRows = params.data.length;
|
|
724
|
+
const dataCols = Math.max(...params.data.map(r => r.length));
|
|
725
|
+
const table = app.Table({ rowCount: dataRows, columnCount: dataCols });
|
|
726
|
+
sheet.tables.push(table);
|
|
727
|
+
table.name = params.tableName || params.sheetName;
|
|
728
|
+
|
|
729
|
+
// Set header row count (default 0 = no grey header styling)
|
|
730
|
+
table.headerRowCount = (params.headerRowCount !== null && params.headerRowCount !== undefined) ? params.headerRowCount : 0;
|
|
731
|
+
|
|
732
|
+
// Write all data
|
|
733
|
+
const colCount = table.columnCount();
|
|
734
|
+
for (let r = 0; r < dataRows; r++) {
|
|
735
|
+
for (let c = 0; c < params.data[r].length; c++) {
|
|
736
|
+
const val = params.data[r][c];
|
|
737
|
+
if (val !== null) {
|
|
738
|
+
table.cells[r * colCount + c].value = val;
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
// Set column widths
|
|
744
|
+
if (params.columnWidths) {
|
|
745
|
+
for (let i = 0; i < Math.min(params.columnWidths.length, colCount); i++) {
|
|
746
|
+
table.columns[i].width = params.columnWidths[i];
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
// Set row heights
|
|
751
|
+
if (params.rowHeights) {
|
|
752
|
+
for (let i = 0; i < Math.min(params.rowHeights.length, dataRows); i++) {
|
|
753
|
+
table.rows[i].height = params.rowHeights[i];
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
// Apply formatting
|
|
758
|
+
function hexToRGB(hex) {
|
|
759
|
+
return [parseInt(hex.slice(1,3),16)*257, parseInt(hex.slice(3,5),16)*257, parseInt(hex.slice(5,7),16)*257];
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
if (params.formatting) {
|
|
763
|
+
for (const fmt of params.formatting) {
|
|
764
|
+
let cells = [];
|
|
765
|
+
if (fmt.cellRange.includes(":")) {
|
|
766
|
+
cells = table.ranges[fmt.cellRange].cells();
|
|
767
|
+
} else {
|
|
768
|
+
cells = [table.cells[fmt.cellRange]];
|
|
769
|
+
}
|
|
770
|
+
for (const cell of cells) {
|
|
771
|
+
if (fmt.fontSize !== undefined) cell.fontSize = fmt.fontSize;
|
|
772
|
+
if (fmt.fontName !== undefined) cell.fontName = fmt.fontName;
|
|
773
|
+
if (fmt.textColor !== undefined) cell.textColor = hexToRGB(fmt.textColor);
|
|
774
|
+
if (fmt.backgroundColor !== undefined) cell.backgroundColor = hexToRGB(fmt.backgroundColor);
|
|
775
|
+
if (fmt.alignment !== undefined) cell.alignment = fmt.alignment;
|
|
776
|
+
if (fmt.verticalAlignment !== undefined) cell.verticalAlignment = fmt.verticalAlignment;
|
|
777
|
+
if (fmt.textWrap !== undefined) cell.textWrap = fmt.textWrap;
|
|
778
|
+
if (fmt.bold !== undefined || fmt.italic !== undefined) {
|
|
779
|
+
let fontName = fmt.fontName || cell.fontName();
|
|
780
|
+
const baseName = fontName.replace(/[- ]?(Bold ?Italic|BoldItalic|Bold|Italic)$/i, "").trim();
|
|
781
|
+
const wantBold = fmt.bold !== undefined ? fmt.bold : /Bold/i.test(fontName);
|
|
782
|
+
const wantItalic = fmt.italic !== undefined ? fmt.italic : /Italic/i.test(fontName);
|
|
783
|
+
let suffix = "";
|
|
784
|
+
if (wantBold && wantItalic) suffix = "-BoldItalic";
|
|
785
|
+
else if (wantBold) suffix = "-Bold";
|
|
786
|
+
else if (wantItalic) suffix = "-Italic";
|
|
787
|
+
cell.fontName = baseName + suffix;
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
return JSON.stringify({
|
|
794
|
+
sheetName: sheet.name(),
|
|
795
|
+
tableName: table.name(),
|
|
796
|
+
rows: dataRows,
|
|
797
|
+
columns: dataCols,
|
|
798
|
+
headerRowCount: table.headerRowCount(),
|
|
799
|
+
});
|
|
800
|
+
`, {
|
|
801
|
+
documentName, sheetName,
|
|
802
|
+
tableName: tableName ?? null,
|
|
803
|
+
data,
|
|
804
|
+
headerRowCount: headerRowCount ?? null,
|
|
805
|
+
columnWidths: columnWidths ?? null,
|
|
806
|
+
rowHeights: rowHeights ?? null,
|
|
807
|
+
formatting: formatting ?? null,
|
|
808
|
+
deleteDefaultTable: deleteDefaultTable ?? true,
|
|
809
|
+
})));
|
|
687
810
|
}
|
package/dist/tools/pages.js
CHANGED
|
@@ -194,9 +194,9 @@ export function registerPagesTools(server) {
|
|
|
194
194
|
if (fmt.italic !== undefined) paragraph.italic = fmt.italic;
|
|
195
195
|
if (fmt.textColor !== undefined) {
|
|
196
196
|
const hex = fmt.textColor;
|
|
197
|
-
const r = parseInt(hex.slice(1, 3), 16)
|
|
198
|
-
const g = parseInt(hex.slice(3, 5), 16)
|
|
199
|
-
const b = parseInt(hex.slice(5, 7), 16)
|
|
197
|
+
const r = parseInt(hex.slice(1, 3), 16) * 257;
|
|
198
|
+
const g = parseInt(hex.slice(3, 5), 16) * 257;
|
|
199
|
+
const b = parseInt(hex.slice(5, 7), 16) * 257;
|
|
200
200
|
paragraph.color = [r, g, b];
|
|
201
201
|
}
|
|
202
202
|
|