numbersmcp 0.2.0 → 0.3.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
@@ -26,6 +26,11 @@ import { mergeCells } from "./tools/mergeCells.js";
26
26
  import { unmergeCells } from "./tools/unmergeCells.js";
27
27
  import { renameTable } from "./tools/renameTable.js";
28
28
  import { setCellStyle } from "./tools/setCellStyle.js";
29
+ import { clearRange } from "./tools/clearRange.js";
30
+ import { transposeTable } from "./tools/transposeTable.js";
31
+ import { createDocument } from "./tools/createDocument.js";
32
+ import { getActiveSheet } from "./tools/getActiveSheet.js";
33
+ import { resizeRowColumn } from "./tools/resizeRowColumn.js";
29
34
  const server = new McpServer({
30
35
  name: "numbersmcp",
31
36
  version: "0.1.0",
@@ -242,5 +247,46 @@ server.tool("set-cell-style", "Set visual styling properties on a cell (font, co
242
247
  const result = await setCellStyle(document, cell, sheet, table, fontName, fontSize, textColor, backgroundColor, bold, italic, alignment);
243
248
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
244
249
  });
250
+ server.tool("clear-range", "Clear all values in a range of cells in a Numbers table", {
251
+ document: z.string().describe("Name of the open Numbers document"),
252
+ range: z.string().describe("Cell range to clear in A1 notation, e.g. 'A1:C10'"),
253
+ sheet: z.string().optional().describe("Sheet name (defaults to first sheet)"),
254
+ table: z.string().optional().describe("Table name (defaults to first table)"),
255
+ }, async ({ document, range, sheet, table }) => {
256
+ const result = await clearRange(document, range, sheet, table);
257
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
258
+ });
259
+ server.tool("transpose-table", "Transpose rows and columns of a Numbers table", {
260
+ document: z.string().describe("Name of the open Numbers document"),
261
+ sheet: z.string().optional().describe("Sheet name (defaults to first sheet)"),
262
+ table: z.string().optional().describe("Table name (defaults to first table)"),
263
+ }, async ({ document, sheet, table }) => {
264
+ const result = await transposeTable(document, sheet, table);
265
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
266
+ });
267
+ server.tool("create-document", "Create a new Numbers document, optionally saving it with a given name", {
268
+ name: z.string().optional().describe("Name for the new document (without extension). If provided, the document is saved to ~/Documents/<name>.numbers"),
269
+ }, async ({ name }) => {
270
+ const result = await createDocument(name);
271
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
272
+ });
273
+ server.tool("get-active-sheet", "Get the name of the currently active sheet in a Numbers document", {
274
+ document: z.string().describe("Name of the open Numbers document"),
275
+ }, async ({ document }) => {
276
+ const result = await getActiveSheet(document);
277
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
278
+ });
279
+ server.tool("resize-row-column", "Resize the height of a row or the width of a column in a Numbers table. At least one of row (with height) or column (with width) must be provided.", {
280
+ document: z.string().describe("Name of the open Numbers document"),
281
+ sheet: z.string().optional().describe("Sheet name (defaults to first sheet)"),
282
+ table: z.string().optional().describe("Table name (defaults to first table)"),
283
+ row: z.number().int().positive().optional().describe("Row number to resize (1-based)"),
284
+ column: z.string().optional().describe("Column letter to resize, e.g. 'B'"),
285
+ height: z.number().positive().optional().describe("New row height in points"),
286
+ width: z.number().positive().optional().describe("New column width in points"),
287
+ }, async ({ document, sheet, table, row, column, height, width }) => {
288
+ const result = await resizeRowColumn(document, sheet, table, row, column, height, width);
289
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
290
+ });
245
291
  const transport = new StdioServerTransport();
246
292
  await server.connect(transport);
@@ -0,0 +1,4 @@
1
+ export declare function clearRange(document: string, range: string, sheet?: string, table?: string): Promise<{
2
+ success: boolean;
3
+ range: string;
4
+ }>;
@@ -0,0 +1,15 @@
1
+ import { runAppleScript, escapeForAppleScript } from "@mailappmcp/shared";
2
+ export async function clearRange(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
+ clear range "${rangeEsc}"
11
+ end tell
12
+ end tell`;
13
+ await runAppleScript(script);
14
+ return { success: true, range };
15
+ }
@@ -0,0 +1,3 @@
1
+ export declare function createDocument(name?: string): Promise<{
2
+ name: string;
3
+ }>;
@@ -0,0 +1,26 @@
1
+ import { runAppleScript, escapeForAppleScript } from "@mailappmcp/shared";
2
+ import * as os from "os";
3
+ import * as path from "path";
4
+ export async function createDocument(name) {
5
+ let script;
6
+ if (name) {
7
+ const nameEsc = escapeForAppleScript(name);
8
+ const savePath = path.join(os.homedir(), "Documents", `${name}.numbers`);
9
+ const savePathEsc = escapeForAppleScript(savePath);
10
+ script = `
11
+ tell application "Numbers"
12
+ set newDoc to make new document
13
+ save newDoc in POSIX file "${savePathEsc}"
14
+ return name of newDoc
15
+ end tell`;
16
+ }
17
+ else {
18
+ script = `
19
+ tell application "Numbers"
20
+ set newDoc to make new document
21
+ return name of newDoc
22
+ end tell`;
23
+ }
24
+ const result = await runAppleScript(script);
25
+ return { name: result.trim() };
26
+ }
@@ -0,0 +1,3 @@
1
+ export declare function getActiveSheet(document: string): Promise<{
2
+ name: string;
3
+ }>;
@@ -0,0 +1,13 @@
1
+ import { runAppleScript, escapeForAppleScript } from "@mailappmcp/shared";
2
+ export async function getActiveSheet(document) {
3
+ const docEsc = escapeForAppleScript(document);
4
+ const script = `
5
+ tell application "Numbers"
6
+ tell document "${docEsc}"
7
+ set s to active sheet
8
+ return name of s
9
+ end tell
10
+ end tell`;
11
+ const result = await runAppleScript(script);
12
+ return { name: result.trim() };
13
+ }
@@ -0,0 +1,8 @@
1
+ export declare function resizeRowColumn(document: string, sheet?: string, table?: string, row?: number, column?: string, height?: number, width?: number): Promise<{
2
+ success: boolean;
3
+ changes: {
4
+ type: string;
5
+ index: number | string;
6
+ size: number;
7
+ }[];
8
+ }>;
@@ -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 resizeRowColumn(document, sheet, table, row, column, height, width) {
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 changes = [];
14
+ const lines = [];
15
+ if (row !== undefined && height !== undefined) {
16
+ lines.push(` set height of row ${row} to ${height}`);
17
+ changes.push({ type: "row", index: row, size: height });
18
+ }
19
+ if (column !== undefined && width !== undefined) {
20
+ const colNum = colLetterToNum(column);
21
+ lines.push(` set width of column ${colNum} to ${width}`);
22
+ changes.push({ type: "column", index: column, size: width });
23
+ }
24
+ const script = `
25
+ tell application "Numbers"
26
+ tell ${tableRef} of ${sheetRef} of document "${docEsc}"
27
+ ${lines.join("\n")}
28
+ end tell
29
+ end tell`;
30
+ await runAppleScript(script);
31
+ return { success: true, changes };
32
+ }
@@ -0,0 +1,6 @@
1
+ export declare function transposeTable(document: string, sheet?: string, table?: string): Promise<{
2
+ success: boolean;
3
+ document: string;
4
+ sheet: string | undefined;
5
+ table: string | undefined;
6
+ }>;
@@ -0,0 +1,14 @@
1
+ import { runAppleScript, escapeForAppleScript } from "@mailappmcp/shared";
2
+ export async function transposeTable(document, 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 script = `
7
+ tell application "Numbers"
8
+ tell ${tableRef} of ${sheetRef} of document "${docEsc}"
9
+ transpose
10
+ end tell
11
+ end tell`;
12
+ await runAppleScript(script);
13
+ return { success: true, document, sheet, table };
14
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "numbersmcp",
3
- "version": "0.2.0",
3
+ "version": "0.3.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",