numbersmcp 0.1.1 → 0.2.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/dist/index.js CHANGED
@@ -11,6 +11,21 @@ import { addRow } from "./tools/addRow.js";
11
11
  import { readTable } from "./tools/readTable.js";
12
12
  import { getFormula } from "./tools/getFormula.js";
13
13
  import { setFormula } from "./tools/setFormula.js";
14
+ import { addColumn } from "./tools/addColumn.js";
15
+ import { deleteColumn } from "./tools/deleteColumn.js";
16
+ import { deleteRow } from "./tools/deleteRow.js";
17
+ import { addSheet } from "./tools/addSheet.js";
18
+ import { deleteSheet } from "./tools/deleteSheet.js";
19
+ import { renameSheet } from "./tools/renameSheet.js";
20
+ import { addTable } from "./tools/addTable.js";
21
+ import { deleteTable } from "./tools/deleteTable.js";
22
+ import { setCellFormat } from "./tools/setCellFormat.js";
23
+ import { sortTable } from "./tools/sortTable.js";
24
+ import { exportDocument } from "./tools/exportDocument.js";
25
+ import { mergeCells } from "./tools/mergeCells.js";
26
+ import { unmergeCells } from "./tools/unmergeCells.js";
27
+ import { renameTable } from "./tools/renameTable.js";
28
+ import { setCellStyle } from "./tools/setCellStyle.js";
14
29
  const server = new McpServer({
15
30
  name: "numbersmcp",
16
31
  version: "0.1.0",
@@ -91,5 +106,141 @@ server.tool("set-formula", "Set a formula on a specific cell in a Numbers table
91
106
  const result = await setFormula(document, cell, formula, sheet, table);
92
107
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
93
108
  });
109
+ server.tool("add-column", "Add a new column to a Numbers table", {
110
+ document: z.string().describe("Name of the open Numbers document"),
111
+ afterColumn: z.string().optional().describe("Column letter after which to insert (e.g. 'C'). Defaults to last column."),
112
+ sheet: z.string().optional().describe("Sheet name (defaults to first sheet)"),
113
+ table: z.string().optional().describe("Table name (defaults to first table)"),
114
+ }, async ({ document, afterColumn, sheet, table }) => {
115
+ const result = await addColumn(document, afterColumn, sheet, table);
116
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
117
+ });
118
+ server.tool("delete-column", "Delete a column from a Numbers table", {
119
+ document: z.string().describe("Name of the open Numbers document"),
120
+ column: z.string().describe("Column letter to delete (e.g. 'C')"),
121
+ sheet: z.string().optional().describe("Sheet name (defaults to first sheet)"),
122
+ table: z.string().optional().describe("Table name (defaults to first table)"),
123
+ }, async ({ document, column, sheet, table }) => {
124
+ const result = await deleteColumn(document, column, sheet, table);
125
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
126
+ });
127
+ server.tool("delete-row", "Delete a row from a Numbers table", {
128
+ document: z.string().describe("Name of the open Numbers document"),
129
+ row: z.number().int().positive().describe("Row number to delete"),
130
+ sheet: z.string().optional().describe("Sheet name (defaults to first sheet)"),
131
+ table: z.string().optional().describe("Table name (defaults to first table)"),
132
+ }, async ({ document, row, sheet, table }) => {
133
+ const result = await deleteRow(document, row, sheet, table);
134
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
135
+ });
136
+ server.tool("add-sheet", "Add a new sheet to a Numbers document", {
137
+ document: z.string().describe("Name of the open Numbers document"),
138
+ name: z.string().optional().describe("Name for the new sheet"),
139
+ }, async ({ document, name }) => {
140
+ const result = await addSheet(document, name);
141
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
142
+ });
143
+ server.tool("delete-sheet", "Delete a sheet from a Numbers document", {
144
+ document: z.string().describe("Name of the open Numbers document"),
145
+ sheet: z.string().describe("Name of the sheet to delete"),
146
+ }, async ({ document, sheet }) => {
147
+ const result = await deleteSheet(document, sheet);
148
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
149
+ });
150
+ server.tool("rename-sheet", "Rename a sheet in a Numbers document", {
151
+ document: z.string().describe("Name of the open Numbers document"),
152
+ sheet: z.string().describe("Current name of the sheet"),
153
+ newName: z.string().describe("New name for the sheet"),
154
+ }, async ({ document, sheet, newName }) => {
155
+ const result = await renameSheet(document, sheet, newName);
156
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
157
+ });
158
+ server.tool("add-table", "Add a new table to a sheet in a Numbers document", {
159
+ document: z.string().describe("Name of the open Numbers document"),
160
+ sheet: z.string().optional().describe("Sheet name (defaults to first sheet)"),
161
+ name: z.string().optional().describe("Name for the new table"),
162
+ }, async ({ document, sheet, name }) => {
163
+ const result = await addTable(document, sheet, name);
164
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
165
+ });
166
+ server.tool("delete-table", "Delete a table from a sheet in a Numbers document", {
167
+ document: z.string().describe("Name of the open Numbers document"),
168
+ table: z.string().describe("Name of the table to delete"),
169
+ sheet: z.string().optional().describe("Sheet name (defaults to first sheet)"),
170
+ }, async ({ document, table, sheet }) => {
171
+ const result = await deleteTable(document, table, sheet);
172
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
173
+ });
174
+ server.tool("set-cell-format", "Set the format of a cell (number, currency, percentage, date, text, etc.)", {
175
+ document: z.string().describe("Name of the open Numbers document"),
176
+ cell: z.string().describe("Cell reference in A1 notation, e.g. 'B3'"),
177
+ format: z.enum(["automatic", "number", "currency", "percentage", "date", "date-and-time", "duration", "checkbox", "star-rating", "text", "fraction", "scientific", "numeral-system"]).describe("Cell format type"),
178
+ sheet: z.string().optional().describe("Sheet name (defaults to first sheet)"),
179
+ table: z.string().optional().describe("Table name (defaults to first table)"),
180
+ }, async ({ document, cell, format, sheet, table }) => {
181
+ const result = await setCellFormat(document, cell, format, sheet, table);
182
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
183
+ });
184
+ server.tool("sort-table", "Sort a Numbers table by a column", {
185
+ document: z.string().describe("Name of the open Numbers document"),
186
+ column: z.string().describe("Column letter to sort by, e.g. 'B'"),
187
+ direction: z.enum(["ascending", "descending"]).describe("Sort direction"),
188
+ sheet: z.string().optional().describe("Sheet name (defaults to first sheet)"),
189
+ table: z.string().optional().describe("Table name (defaults to first table)"),
190
+ }, async ({ document, column, direction, sheet, table }) => {
191
+ const result = await sortTable(document, column, direction, sheet, table);
192
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
193
+ });
194
+ server.tool("export-document", "Export a Numbers document to PDF, Excel, or CSV format", {
195
+ document: z.string().describe("Name of the open Numbers document"),
196
+ path: z.string().describe("Full output file path, e.g. '/Users/me/output.xlsx'"),
197
+ format: z.enum(["pdf", "excel", "csv"]).describe("Export format"),
198
+ }, async ({ document, path, format }) => {
199
+ const result = await exportDocument(document, path, format);
200
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
201
+ });
202
+ server.tool("merge-cells", "Merge a range of cells in a Numbers table", {
203
+ document: z.string().describe("Name of the open Numbers document"),
204
+ range: z.string().describe("Cell range to merge, e.g. 'A1:C1'"),
205
+ sheet: z.string().optional().describe("Sheet name (defaults to first sheet)"),
206
+ table: z.string().optional().describe("Table name (defaults to first table)"),
207
+ }, async ({ document, range, sheet, table }) => {
208
+ const result = await mergeCells(document, range, sheet, table);
209
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
210
+ });
211
+ server.tool("unmerge-cells", "Unmerge a range of cells in a Numbers table", {
212
+ document: z.string().describe("Name of the open Numbers document"),
213
+ range: z.string().describe("Cell range to unmerge, e.g. 'A1:C1'"),
214
+ sheet: z.string().optional().describe("Sheet name (defaults to first sheet)"),
215
+ table: z.string().optional().describe("Table name (defaults to first table)"),
216
+ }, async ({ document, range, sheet, table }) => {
217
+ const result = await unmergeCells(document, range, sheet, table);
218
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
219
+ });
220
+ server.tool("rename-table", "Rename a table in a Numbers document", {
221
+ document: z.string().describe("Name of the open Numbers document"),
222
+ table: z.string().describe("Current name of the table"),
223
+ newName: z.string().describe("New name for the table"),
224
+ sheet: z.string().optional().describe("Sheet name (defaults to first sheet)"),
225
+ }, async ({ document, table, newName, sheet }) => {
226
+ const result = await renameTable(document, table, newName, sheet);
227
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
228
+ });
229
+ server.tool("set-cell-style", "Set visual styling properties on a cell (font, color, bold, italic, alignment, background)", {
230
+ document: z.string().describe("Name of the open Numbers document"),
231
+ cell: z.string().describe("Cell reference in A1 notation, e.g. 'B3'"),
232
+ sheet: z.string().optional().describe("Sheet name (defaults to first sheet)"),
233
+ table: z.string().optional().describe("Table name (defaults to first table)"),
234
+ fontName: z.string().optional().describe("Font name, e.g. 'Helvetica'"),
235
+ fontSize: z.number().optional().describe("Font size in points"),
236
+ textColor: z.string().optional().describe("Text color as RGB hex, e.g. '#FF0000'"),
237
+ backgroundColor: z.string().optional().describe("Background color as RGB hex, e.g. '#0000FF'"),
238
+ bold: z.boolean().optional().describe("Set bold"),
239
+ italic: z.boolean().optional().describe("Set italic"),
240
+ alignment: z.enum(["left", "center", "right", "justify", "auto"]).optional().describe("Horizontal text alignment"),
241
+ }, async ({ document, cell, sheet, table, fontName, fontSize, textColor, backgroundColor, bold, italic, alignment }) => {
242
+ const result = await setCellStyle(document, cell, sheet, table, fontName, fontSize, textColor, backgroundColor, bold, italic, alignment);
243
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
244
+ });
94
245
  const transport = new StdioServerTransport();
95
246
  await server.connect(transport);
@@ -0,0 +1,7 @@
1
+ export declare function addColumn(document: string, afterColumn?: string, sheet?: string, table?: string): Promise<{
2
+ success: boolean;
3
+ document: string;
4
+ sheet: string;
5
+ table: string;
6
+ afterColumn: string;
7
+ }>;
@@ -0,0 +1,44 @@
1
+ import { runAppleScript, escapeForAppleScript } from "@mailappmcp/shared";
2
+ function colLetterToNum(col) {
3
+ let n = 0;
4
+ for (const ch of col.toUpperCase()) {
5
+ n = n * 26 + (ch.charCodeAt(0) - 64);
6
+ }
7
+ return n;
8
+ }
9
+ export async function addColumn(document, afterColumn, sheet, table) {
10
+ const docEsc = escapeForAppleScript(document);
11
+ const tableRef = table
12
+ ? `table "${escapeForAppleScript(table)}"`
13
+ : "table 1";
14
+ const sheetRef = sheet
15
+ ? `sheet "${escapeForAppleScript(sheet)}"`
16
+ : "sheet 1";
17
+ let script;
18
+ if (afterColumn) {
19
+ const colNum = colLetterToNum(afterColumn);
20
+ script = `
21
+ tell application "Numbers"
22
+ tell ${tableRef} of ${sheetRef} of document "${docEsc}"
23
+ add column after column ${colNum}
24
+ end tell
25
+ end tell`;
26
+ }
27
+ else {
28
+ script = `
29
+ tell application "Numbers"
30
+ tell ${tableRef} of ${sheetRef} of document "${docEsc}"
31
+ set colCount to column count
32
+ add column after column colCount
33
+ end tell
34
+ end tell`;
35
+ }
36
+ await runAppleScript(script);
37
+ return {
38
+ success: true,
39
+ document,
40
+ sheet: sheet ?? "sheet 1",
41
+ table: table ?? "table 1",
42
+ afterColumn: afterColumn ?? "last",
43
+ };
44
+ }
@@ -0,0 +1,5 @@
1
+ export declare function addSheet(document: string, name?: string): Promise<{
2
+ success: boolean;
3
+ document: string;
4
+ name: string | null;
5
+ }>;
@@ -0,0 +1,28 @@
1
+ import { runAppleScript, escapeForAppleScript } from "@mailappmcp/shared";
2
+ export async function addSheet(document, name) {
3
+ const docEsc = escapeForAppleScript(document);
4
+ let script;
5
+ if (name) {
6
+ const nameEsc = escapeForAppleScript(name);
7
+ script = `
8
+ tell application "Numbers"
9
+ tell document "${docEsc}"
10
+ make new sheet with properties {name:"${nameEsc}"}
11
+ end tell
12
+ end tell`;
13
+ }
14
+ else {
15
+ script = `
16
+ tell application "Numbers"
17
+ tell document "${docEsc}"
18
+ make new sheet
19
+ end tell
20
+ end tell`;
21
+ }
22
+ await runAppleScript(script);
23
+ return {
24
+ success: true,
25
+ document,
26
+ name: name ?? null,
27
+ };
28
+ }
@@ -0,0 +1,6 @@
1
+ export declare function addTable(document: string, sheet?: string, name?: string): Promise<{
2
+ success: boolean;
3
+ document: string;
4
+ sheet: string;
5
+ name: string | null;
6
+ }>;
@@ -0,0 +1,32 @@
1
+ import { runAppleScript, escapeForAppleScript } from "@mailappmcp/shared";
2
+ export async function addTable(document, sheet, name) {
3
+ const docEsc = escapeForAppleScript(document);
4
+ const sheetRef = sheet
5
+ ? `sheet "${escapeForAppleScript(sheet)}"`
6
+ : "sheet 1";
7
+ let script;
8
+ if (name) {
9
+ const nameEsc = escapeForAppleScript(name);
10
+ script = `
11
+ tell application "Numbers"
12
+ tell ${sheetRef} of document "${docEsc}"
13
+ make new table with properties {name:"${nameEsc}"}
14
+ end tell
15
+ end tell`;
16
+ }
17
+ else {
18
+ script = `
19
+ tell application "Numbers"
20
+ tell ${sheetRef} of document "${docEsc}"
21
+ make new table
22
+ end tell
23
+ end tell`;
24
+ }
25
+ await runAppleScript(script);
26
+ return {
27
+ success: true,
28
+ document,
29
+ sheet: sheet ?? "sheet 1",
30
+ name: name ?? null,
31
+ };
32
+ }
@@ -0,0 +1,7 @@
1
+ export declare function deleteColumn(document: string, column: string, sheet?: string, table?: string): Promise<{
2
+ success: boolean;
3
+ document: string;
4
+ sheet: string;
5
+ table: string;
6
+ column: string;
7
+ }>;
@@ -0,0 +1,32 @@
1
+ import { runAppleScript, escapeForAppleScript } from "@mailappmcp/shared";
2
+ function colLetterToNum(col) {
3
+ let n = 0;
4
+ for (const ch of col.toUpperCase()) {
5
+ n = n * 26 + (ch.charCodeAt(0) - 64);
6
+ }
7
+ return n;
8
+ }
9
+ export async function deleteColumn(document, column, sheet, table) {
10
+ const docEsc = escapeForAppleScript(document);
11
+ const colNum = colLetterToNum(column);
12
+ const tableRef = table
13
+ ? `table "${escapeForAppleScript(table)}"`
14
+ : "table 1";
15
+ const sheetRef = sheet
16
+ ? `sheet "${escapeForAppleScript(sheet)}"`
17
+ : "sheet 1";
18
+ const script = `
19
+ tell application "Numbers"
20
+ tell ${tableRef} of ${sheetRef} of document "${docEsc}"
21
+ delete column ${colNum}
22
+ end tell
23
+ end tell`;
24
+ await runAppleScript(script);
25
+ return {
26
+ success: true,
27
+ document,
28
+ sheet: sheet ?? "sheet 1",
29
+ table: table ?? "table 1",
30
+ column,
31
+ };
32
+ }
@@ -0,0 +1,7 @@
1
+ export declare function deleteRow(document: string, row: number, sheet?: string, table?: string): Promise<{
2
+ success: boolean;
3
+ document: string;
4
+ sheet: string;
5
+ table: string;
6
+ row: number;
7
+ }>;
@@ -0,0 +1,24 @@
1
+ import { runAppleScript, escapeForAppleScript } from "@mailappmcp/shared";
2
+ export async function deleteRow(document, row, sheet, table) {
3
+ const docEsc = escapeForAppleScript(document);
4
+ const tableRef = table
5
+ ? `table "${escapeForAppleScript(table)}"`
6
+ : "table 1";
7
+ const sheetRef = sheet
8
+ ? `sheet "${escapeForAppleScript(sheet)}"`
9
+ : "sheet 1";
10
+ const script = `
11
+ tell application "Numbers"
12
+ tell ${tableRef} of ${sheetRef} of document "${docEsc}"
13
+ delete row ${row}
14
+ end tell
15
+ end tell`;
16
+ await runAppleScript(script);
17
+ return {
18
+ success: true,
19
+ document,
20
+ sheet: sheet ?? "sheet 1",
21
+ table: table ?? "table 1",
22
+ row,
23
+ };
24
+ }
@@ -0,0 +1,5 @@
1
+ export declare function deleteSheet(document: string, sheet: string): Promise<{
2
+ success: boolean;
3
+ document: string;
4
+ sheet: string;
5
+ }>;
@@ -0,0 +1,17 @@
1
+ import { runAppleScript, escapeForAppleScript } from "@mailappmcp/shared";
2
+ export async function deleteSheet(document, sheet) {
3
+ const docEsc = escapeForAppleScript(document);
4
+ const sheetEsc = escapeForAppleScript(sheet);
5
+ const script = `
6
+ tell application "Numbers"
7
+ tell document "${docEsc}"
8
+ delete sheet "${sheetEsc}"
9
+ end tell
10
+ end tell`;
11
+ await runAppleScript(script);
12
+ return {
13
+ success: true,
14
+ document,
15
+ sheet,
16
+ };
17
+ }
@@ -0,0 +1,6 @@
1
+ export declare function deleteTable(document: string, table: string, sheet?: string): Promise<{
2
+ success: boolean;
3
+ document: string;
4
+ sheet: string;
5
+ table: string;
6
+ }>;
@@ -0,0 +1,21 @@
1
+ import { runAppleScript, escapeForAppleScript } from "@mailappmcp/shared";
2
+ export async function deleteTable(document, table, sheet) {
3
+ const docEsc = escapeForAppleScript(document);
4
+ const tableEsc = escapeForAppleScript(table);
5
+ const sheetRef = sheet
6
+ ? `sheet "${escapeForAppleScript(sheet)}"`
7
+ : "sheet 1";
8
+ const script = `
9
+ tell application "Numbers"
10
+ tell ${sheetRef} of document "${docEsc}"
11
+ delete table "${tableEsc}"
12
+ end tell
13
+ end tell`;
14
+ await runAppleScript(script);
15
+ return {
16
+ success: true,
17
+ document,
18
+ sheet: sheet ?? "sheet 1",
19
+ table,
20
+ };
21
+ }
@@ -0,0 +1,6 @@
1
+ export declare function exportDocument(document: string, path: string, format: "pdf" | "excel" | "csv"): Promise<{
2
+ success: boolean;
3
+ document: string;
4
+ path: string;
5
+ format: "pdf" | "excel" | "csv";
6
+ }>;
@@ -0,0 +1,17 @@
1
+ import { runAppleScript, escapeForAppleScript } from "@mailappmcp/shared";
2
+ const FORMAT_MAP = {
3
+ pdf: "PDF",
4
+ excel: "Microsoft Excel",
5
+ csv: "CSV",
6
+ };
7
+ export async function exportDocument(document, path, format) {
8
+ const docEsc = escapeForAppleScript(document);
9
+ const pathEsc = escapeForAppleScript(path);
10
+ const asFormat = FORMAT_MAP[format];
11
+ const script = `
12
+ tell application "Numbers"
13
+ export document "${docEsc}" to POSIX file "${pathEsc}" as ${asFormat}
14
+ end tell`;
15
+ await runAppleScript(script);
16
+ return { success: true, document, path, format };
17
+ }
@@ -0,0 +1,5 @@
1
+ export declare function mergeCells(document: string, range: string, sheet?: string, table?: string): Promise<{
2
+ success: boolean;
3
+ document: string;
4
+ range: string;
5
+ }>;
@@ -0,0 +1,15 @@
1
+ import { runAppleScript, escapeForAppleScript } from "@mailappmcp/shared";
2
+ export async function mergeCells(document, range, sheet, table) {
3
+ const docEsc = escapeForAppleScript(document);
4
+ const tableRef = table ? `table "${escapeForAppleScript(table)}"` : "table 1";
5
+ const sheetRef = sheet ? `sheet "${escapeForAppleScript(sheet)}"` : "sheet 1";
6
+ const rangeEsc = escapeForAppleScript(range);
7
+ const script = `
8
+ tell application "Numbers"
9
+ tell ${tableRef} of ${sheetRef} of document "${docEsc}"
10
+ merge range "${rangeEsc}"
11
+ end tell
12
+ end tell`;
13
+ await runAppleScript(script);
14
+ return { success: true, document, range };
15
+ }
@@ -0,0 +1,6 @@
1
+ export declare function renameSheet(document: string, sheet: string, newName: string): Promise<{
2
+ success: boolean;
3
+ document: string;
4
+ sheet: string;
5
+ newName: string;
6
+ }>;
@@ -0,0 +1,17 @@
1
+ import { runAppleScript, escapeForAppleScript } from "@mailappmcp/shared";
2
+ export async function renameSheet(document, sheet, newName) {
3
+ const docEsc = escapeForAppleScript(document);
4
+ const sheetEsc = escapeForAppleScript(sheet);
5
+ const newNameEsc = escapeForAppleScript(newName);
6
+ const script = `
7
+ tell application "Numbers"
8
+ set name of sheet "${sheetEsc}" of document "${docEsc}" to "${newNameEsc}"
9
+ end tell`;
10
+ await runAppleScript(script);
11
+ return {
12
+ success: true,
13
+ document,
14
+ sheet,
15
+ newName,
16
+ };
17
+ }
@@ -0,0 +1,6 @@
1
+ export declare function renameTable(document: string, table: string, newName: string, sheet?: string): Promise<{
2
+ success: boolean;
3
+ document: string;
4
+ oldName: string;
5
+ newName: string;
6
+ }>;
@@ -0,0 +1,13 @@
1
+ import { runAppleScript, escapeForAppleScript } from "@mailappmcp/shared";
2
+ export async function renameTable(document, table, newName, sheet) {
3
+ const docEsc = escapeForAppleScript(document);
4
+ const tableEsc = escapeForAppleScript(table);
5
+ const newNameEsc = escapeForAppleScript(newName);
6
+ const sheetRef = sheet ? `sheet "${escapeForAppleScript(sheet)}"` : "sheet 1";
7
+ const script = `
8
+ tell application "Numbers"
9
+ set name of table "${tableEsc}" of ${sheetRef} of document "${docEsc}" to "${newNameEsc}"
10
+ end tell`;
11
+ await runAppleScript(script);
12
+ return { success: true, document, oldName: table, newName };
13
+ }
@@ -0,0 +1,8 @@
1
+ export declare function setCellFormat(document: string, cell: string, format: string, sheet?: string, table?: string): Promise<{
2
+ success: boolean;
3
+ document: string;
4
+ cell: string;
5
+ format: string;
6
+ sheet: string;
7
+ table: string;
8
+ }>;
@@ -0,0 +1,53 @@
1
+ import { runAppleScript, escapeForAppleScript } from "@mailappmcp/shared";
2
+ const FORMAT_MAP = {
3
+ "automatic": "automatic",
4
+ "number": "number",
5
+ "currency": "currency",
6
+ "percentage": "percentage",
7
+ "date": "date and time",
8
+ "date-and-time": "date and time",
9
+ "duration": "duration",
10
+ "checkbox": "checkbox",
11
+ "star-rating": "star rating",
12
+ "text": "text",
13
+ "fraction": "fraction",
14
+ "scientific": "scientific",
15
+ "numeral-system": "numeral system",
16
+ };
17
+ function parseCellRef(ref) {
18
+ const match = ref.match(/^([A-Z]+)(\d+)$/i);
19
+ if (!match)
20
+ throw new Error(`Invalid cell reference: ${ref}`);
21
+ const letters = match[1].toUpperCase();
22
+ let col = 0;
23
+ for (let i = 0; i < letters.length; i++) {
24
+ col = col * 26 + (letters.charCodeAt(i) - 64);
25
+ }
26
+ return { row: parseInt(match[2], 10), col };
27
+ }
28
+ export async function setCellFormat(document, cell, format, sheet, table) {
29
+ const docEsc = escapeForAppleScript(document);
30
+ const tableRef = table
31
+ ? `table "${escapeForAppleScript(table)}"`
32
+ : "table 1";
33
+ const sheetRef = sheet
34
+ ? `sheet "${escapeForAppleScript(sheet)}"`
35
+ : "sheet 1";
36
+ const { row, col } = parseCellRef(cell);
37
+ const resolved = FORMAT_MAP[format.toLowerCase()] ?? format;
38
+ const script = `
39
+ tell application "Numbers"
40
+ tell ${tableRef} of ${sheetRef} of document "${docEsc}"
41
+ set format of cell ${col} of row ${row} to ${resolved}
42
+ end tell
43
+ end tell`;
44
+ await runAppleScript(script);
45
+ return {
46
+ success: true,
47
+ document,
48
+ cell,
49
+ format: resolved,
50
+ sheet: sheet ?? "sheet 1",
51
+ table: table ?? "table 1",
52
+ };
53
+ }
@@ -0,0 +1,5 @@
1
+ export declare function setCellStyle(document: string, cell: string, sheet?: string, table?: string, fontName?: string, fontSize?: number, textColor?: string, backgroundColor?: string, bold?: boolean, italic?: boolean, alignment?: "left" | "center" | "right" | "justify" | "auto"): Promise<{
2
+ success: boolean;
3
+ cell: string;
4
+ appliedStyles: string[];
5
+ }>;
@@ -0,0 +1,64 @@
1
+ import { runAppleScript, escapeForAppleScript } from "@mailappmcp/shared";
2
+ import { parseCellRef } from "./readRange.js";
3
+ function hexToAppleScriptRgb(hex) {
4
+ const h = hex.replace(/^#/, "");
5
+ const r = Math.round((parseInt(h.slice(0, 2), 16) / 255) * 65535);
6
+ const g = Math.round((parseInt(h.slice(2, 4), 16) / 255) * 65535);
7
+ const b = Math.round((parseInt(h.slice(4, 6), 16) / 255) * 65535);
8
+ return `{${r}, ${g}, ${b}}`;
9
+ }
10
+ const ALIGNMENT_MAP = {
11
+ left: "left",
12
+ center: "center",
13
+ right: "right",
14
+ justify: "justify",
15
+ auto: "auto",
16
+ };
17
+ export async function setCellStyle(document, cell, sheet, table, fontName, fontSize, textColor, backgroundColor, bold, italic, alignment) {
18
+ const docEsc = escapeForAppleScript(document);
19
+ const tableRef = table ? `table "${escapeForAppleScript(table)}"` : "table 1";
20
+ const sheetRef = sheet ? `sheet "${escapeForAppleScript(sheet)}"` : "sheet 1";
21
+ const { row, col } = parseCellRef(cell);
22
+ const styleLines = [];
23
+ const appliedStyles = [];
24
+ if (fontName !== undefined) {
25
+ styleLines.push(`set font name of theCell to "${escapeForAppleScript(fontName)}"`);
26
+ appliedStyles.push("fontName");
27
+ }
28
+ if (fontSize !== undefined) {
29
+ styleLines.push(`set font size of theCell to ${fontSize}`);
30
+ appliedStyles.push("fontSize");
31
+ }
32
+ if (textColor !== undefined) {
33
+ styleLines.push(`set text color of theCell to ${hexToAppleScriptRgb(textColor)}`);
34
+ appliedStyles.push("textColor");
35
+ }
36
+ if (backgroundColor !== undefined) {
37
+ styleLines.push(`set background color of theCell to ${hexToAppleScriptRgb(backgroundColor)}`);
38
+ appliedStyles.push("backgroundColor");
39
+ }
40
+ if (bold !== undefined) {
41
+ styleLines.push(`set bold of theCell to ${bold}`);
42
+ appliedStyles.push("bold");
43
+ }
44
+ if (italic !== undefined) {
45
+ styleLines.push(`set italic of theCell to ${italic}`);
46
+ appliedStyles.push("italic");
47
+ }
48
+ if (alignment !== undefined) {
49
+ styleLines.push(`set alignment of theCell to ${ALIGNMENT_MAP[alignment]}`);
50
+ appliedStyles.push("alignment");
51
+ }
52
+ if (styleLines.length === 0) {
53
+ return { success: true, cell, appliedStyles: [] };
54
+ }
55
+ const script = `
56
+ tell application "Numbers"
57
+ tell ${tableRef} of ${sheetRef} of document "${docEsc}"
58
+ set theCell to cell ${col} of row ${row}
59
+ ${styleLines.join("\n ")}
60
+ end tell
61
+ end tell`;
62
+ await runAppleScript(script);
63
+ return { success: true, cell, appliedStyles };
64
+ }
@@ -0,0 +1,6 @@
1
+ export declare function sortTable(document: string, column: string, direction: "ascending" | "descending", sheet?: string, table?: string): Promise<{
2
+ success: boolean;
3
+ document: string;
4
+ column: string;
5
+ direction: "ascending" | "descending";
6
+ }>;
@@ -0,0 +1,22 @@
1
+ import { runAppleScript, escapeForAppleScript } from "@mailappmcp/shared";
2
+ function colLetterToNum(col) {
3
+ let n = 0;
4
+ for (const ch of col.toUpperCase()) {
5
+ n = n * 26 + (ch.charCodeAt(0) - 64);
6
+ }
7
+ return n;
8
+ }
9
+ export async function sortTable(document, column, direction, sheet, table) {
10
+ const docEsc = escapeForAppleScript(document);
11
+ const tableRef = table ? `table "${escapeForAppleScript(table)}"` : "table 1";
12
+ const sheetRef = sheet ? `sheet "${escapeForAppleScript(sheet)}"` : "sheet 1";
13
+ const colNum = colLetterToNum(column);
14
+ const script = `
15
+ tell application "Numbers"
16
+ tell ${tableRef} of ${sheetRef} of document "${docEsc}"
17
+ sort by column ${colNum} direction ${direction}
18
+ end tell
19
+ end tell`;
20
+ await runAppleScript(script);
21
+ return { success: true, document, column, direction };
22
+ }
@@ -0,0 +1,5 @@
1
+ export declare function unmergeCells(document: string, range: string, sheet?: string, table?: string): Promise<{
2
+ success: boolean;
3
+ document: string;
4
+ range: string;
5
+ }>;
@@ -0,0 +1,15 @@
1
+ import { runAppleScript, escapeForAppleScript } from "@mailappmcp/shared";
2
+ export async function unmergeCells(document, range, sheet, table) {
3
+ const docEsc = escapeForAppleScript(document);
4
+ const tableRef = table ? `table "${escapeForAppleScript(table)}"` : "table 1";
5
+ const sheetRef = sheet ? `sheet "${escapeForAppleScript(sheet)}"` : "sheet 1";
6
+ const rangeEsc = escapeForAppleScript(range);
7
+ const script = `
8
+ tell application "Numbers"
9
+ tell ${tableRef} of ${sheetRef} of document "${docEsc}"
10
+ unmerge range "${rangeEsc}"
11
+ end tell
12
+ end tell`;
13
+ await runAppleScript(script);
14
+ return { success: true, document, range };
15
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "numbersmcp",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "description": "MCP server for macOS Numbers.app — spreadsheet access via AppleScript",
5
5
  "mcpName": "io.github.aernouddekker/numbersmcp",
6
6
  "type": "module",