Install
$ agentstack add mcp-sweetrb-apple-numbers-mcp ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ● Shell / process execution Used
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
Apple Numbers MCP Server
A Model Context Protocol (MCP) server that enables AI assistants like Claude to read, write, search, and modify Apple Numbers (.numbers) spreadsheet files. Backed by the numbers-parser Python library.
[](https://www.npmjs.com/package/apple-numbers-mcp) [](https://www.npmjs.com/package/apple-numbers-mcp) [](https://www.npmjs.com/package/apple-numbers-mcp) [](https://github.com/sweetrb/apple-numbers-mcp/actions/workflows/ci.yml) [](https://scorecard.dev/viewer/?uri=github.com/sweetrb/apple-numbers-mcp) [](https://www.apple.com/macos/) [](https://opensource.org/licenses/MIT) [](https://modelcontextprotocol.io)
What is This?
This server acts as a bridge between AI assistants and Apple Numbers spreadsheets. Once configured, you can ask Claude (or any MCP-compatible AI) to:
- "What's in this spreadsheet?" — inspect sheets, tables, dimensions
- "Find every row where the customer is Acme Corp"
- "Export the Q3 Results table to CSV"
- "Set cell B5 to =SUM(B2:B4)"
- "Append these three rows to the Inventory table"
- "Bold and center the header row"
- "Import this CSV into a new spreadsheet"
The AI assistant communicates with this server, which uses numbers-parser to read and write .numbers files directly (no Numbers.app required for most operations). All data stays local on your machine.
Quick Start
Using Claude Code (Easiest)
If you're using Claude Code (in Terminal or VS Code), just ask Claude to install it:
Install the sweetrb/apple-numbers-mcp MCP server so you can help me work with my Numbers spreadsheets
Claude will handle the installation and configuration automatically. After install, you'll need to install numbers-parser (Python) — see [Requirements](#requirements) below.
Using the Plugin Marketplace
Install as a Claude Code plugin for automatic configuration and enhanced AI behavior:
/plugin marketplace add sweetrb/apple-numbers-mcp
/plugin install apple-numbers
This method also installs a skill that teaches Claude when and how to use Apple Numbers effectively.
Using the Codex Marketplace
Install the same public marketplace in Codex:
codex plugin marketplace add sweetrb/apple-numbers-mcp
codex plugin add apple-numbers@apple-numbers-mcp
The Codex package registers the apple-numbers MCP server through npx -y apple-numbers-mcp — the same published-package invocation documented for Claude Desktop below — and bundles the Apple Numbers skill guidance. As with every install path, the numbers-parser Python sidecar must be available (pip3 install numbers-parser); see [Requirements](#requirements).
Other Hosts (Hermes, Antigravity)
Configuration for two more hosts is included — each registers the same apple-numbers MCP server (npx -y apple-numbers-mcp). All paths still need the numbers-parser Python sidecar available; see [Requirements](#requirements).
- Hermes Agent (NousResearch) — Hermes has no plugin/marketplace drop-in. Add the server with
hermes mcp add apple-numbers --command npx --args -y apple-numbers-mcp, or merge [.hermes-plugin/config.yaml](.hermes-plugin/config.yaml) into~/.hermes/config.yaml. Details: [.hermes-plugin/README.md](.hermes-plugin/README.md). - Antigravity (Google) — add the server entry from [
.antigravity-plugin/mcp_config.json](.antigravity-plugin/mcpconfig.json) to~/.gemini/config/mcp_config.json(or via Antigravity's MCP settings).
Manual Installation
1. Install the server:
npm install -g github:sweetrb/apple-numbers-mcp
2. Install numbers-parser (the Python library this server depends on):
pip3 install numbers-parser
Or, if you cloned the repo, run pnpm run setup to create a project-local Python venv with numbers-parser pre-installed.
3. Add to Claude Desktop (~/Library/Application Support/Claude/claude_desktop_config.json):
{
"mcpServers": {
"apple-numbers": {
"command": "npx",
"args": ["apple-numbers-mcp"]
}
}
}
4. Restart Claude Desktop and start using natural language:
"What sheets are in ~/Documents/budget.numbers?"
Running from a clone in Claude Code (project-scope .mcp.json)
This repo ships a .mcp.json at its root so that, when you run claude from inside a clone, the server is registered automatically as a project-scope server — no manual config needed. Before launching, run both:
pnpm run build # compile TypeScript to build/
pnpm run setup # create the ./venv the Python sidecar needs
pnpm run setup is required because this is a Python-sidecar server: it shells out to ./venv/bin/python3 running numbers-parser. Without the venv, the server starts but every tool call fails. Then launch Claude Code from the repo directory and approve the server when prompted.
The entrypoint is written as:
"args": ["${CLAUDE_PROJECT_DIR:-.}/build/index.js"]
CLAUDE_PROJECT_DIR is the variable Claude Code injects into a project/user-scoped server's environment, and it resolves to the repo root. You must launch claude from inside the repo for this to work — the bare . fallback is only a last resort and is not reliable, because it resolves against the launching process's working directory, not the repo.
> Why not ${CLAUDE_PLUGIN_ROOT}? CLAUDE_PLUGIN_ROOT is set only for marketplace plugin installs, never for a project-scope clone, so it can't drive the clone workflow. Conversely, a plugin install can't use CLAUDE_PROJECT_DIR (in a plugin, that points at the user's project, not the plugin's own directory). Claude Code does not support nested defaults like ${CLAUDE_PLUGIN_ROOT:-${CLAUDE_PROJECT_DIR:-.}}, so a single entrypoint string cannot serve both contexts. The two distribution paths are therefore decoupled: the plugin carries its own MCP config in .claude-plugin/plugin.json (using ${CLAUDE_PLUGIN_ROOT}), while the root .mcp.json is dedicated to the clone workflow (using ${CLAUDE_PROJECT_DIR:-.}). Because plugin.json declares its own mcpServers, the plugin does not also auto-load the root .mcp.json, so there is no double-registration.
> Heads-up on scope precedence: project-scope (.mcp.json) outranks user-scope. If you also have an apple-numbers entry registered at user scope (e.g. an absolute path in ~/.claude.json), the project-scope entry wins and the user-scope one is ignored entirely. Pick one — for local development on this repo, the project-scope .mcp.json is the intended source. To pin a specific local build instead, register it at local scope (claude mcp add apple-numbers -s local -- node /abs/path/build/index.js), which outranks project scope.
Requirements
- macOS or Linux —
numbers-parserreads the file format directly, so most tools work anywhere. Formatting and formula tools require macOS with Numbers.app. - Node.js 20+ — Required for the MCP server
- Python 3.11+ — the
numbers-parserlibrary installs automatically into a project-local venv on first use (or pre-warm withpnpm run setup). numbers-parser requires Python ≥ 3.10; macOS ships 3.9, so install a newer Python first (e.g.brew install python@3.12). - Automation permission (writes only) — Reads and exports need no special permission, but write/format tools drive Numbers.app via AppleScript and require the host app to have Automation permission for Numbers, granted on first use. See the [Automation Permission guide](docs/AUTOMATION-PERMISSION.md). Run the
doctortool to verify your setup.
Features
Read
| Feature | Description | |---------|-------------| | File Inspection | List sheets, tables, dimensions, and header rows | | Table Read | Read data with optional row range and column filtering | | Cell Read | Single cells by 0-based index, with optional formula/format/merge metadata | | Search | Case-insensitive text search across every cell, optionally scoped to one sheet | | Export | Export a table to CSV, TSV, or JSON |
Write
| Feature | Description | |---------|-------------| | Create Spreadsheet | New .numbers file with headers and optional initial rows | | Set Cell | Write a value to a single cell, with optional type coercion | | Set Cells Batch | Write many cells in one operation (more efficient than multiple set-cell calls) | | Add / Update / Delete Rows | Append, replace, or remove rows by index | | Sheets and Tables | Add new sheets or tables to an existing file; rename either |
Formulas (requires Numbers.app)
| Feature | Description | |---------|-------------| | Set Formula | Write a formula like =SUM(B2:B10) to a cell | | Set Formulas Batch | Write many formulas at once |
Formatting (requires Numbers.app)
| Feature | Description | |---------|-------------| | Cell Styles | Font, size, colors, number format, alignment | | Cell Styles Batch | Style many cells at once | | Column Width / Row Height | Set dimensions in pixels | | Merge / Unmerge | Merge a range of cells, or undo a merge |
Import / Diagnostics
| Feature | Description | |---------|-------------| | Import CSV/TSV/JSON | Convert a tabular file into a new .numbers spreadsheet | | Health Check | Verify Python 3 and numbers-parser are installed | | Doctor | Richer setup diagnostic — read sidecar, Numbers.app, and Automation permission, each reported ok / warn / fail with actionable advice |
All tools also return structured JSON (structuredContent) alongside the human-readable text, so agents can consume results without parsing prose.
MCP resources & prompts
Resources expose read-only context the client can attach without a tool call: the numbers://file/{path} template (file structure — sheets, tables, dimensions, headers) and the numbers://table/{path} template (the default table's data). Both are templated by a URL-encoded .numbers file path. Prompts package common workflows: analyze-spreadsheet, bulk-edit, import-csv-guide.
Tool Reference
This section documents all available tools. AI agents should use these tool names and parameters exactly as specified.
Read
health-check
Verify Python 3 and numbers-parser are installed and reachable from the server.
Parameters: None Returns: numbers-parser version, or an error explaining how to install.
doctor
Run a full setup diagnostic with three separate checks: numbers_parser (the read sidecar — required for all reads/exports), numbers_app (Numbers.app present — required for write/format tools), and automation_permission (an informational reminder that write tools need Automation permission for Numbers.app). Each is reported as ok / warn / fail with actionable advice. This is the richer counterpart to health-check; reach for it first when a tool returns a permission or setup error.
Parameters: None
Returns: A per-check report. The structuredContent carries the raw { healthy, checks[] }, where each check has name, status (ok/warn/fail), and detail. Reads don't need Automation permission, but writes do — see [docs/AUTOMATION-PERMISSION.md](docs/AUTOMATION-PERMISSION.md).
get-file-info
Get the structure of a .numbers file: sheets, tables, dimensions, header rows.
| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | path | string | Yes | Absolute or ~-relative path to the .numbers file |
Returns: Default sheet name, plus each sheet with its tables (name, dimensions, header row).
read-table
Read data from a table. Returns headers and rows. Defaults to the first sheet and first table if not specified.
| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | path | string | Yes | Path to the .numbers file | | sheet | string | No | Sheet name (default: first sheet) | | table | string | No | Table name (default: first table) | | startRow | number | No | 0-based start row, inclusive (default: 1, after header) | | endRow | number | No | 0-based end row, inclusive (default: last row) | | columns | (string \| number)[] | No | Column filter: header names or 0-based indices |
get-cell
Read a single cell value by row and column index (0-based).
| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | path | string | Yes | Path to the .numbers file | | sheet | string | Yes | Sheet name | | table | string | Yes | Table name | | row | number | Yes | Row index (0-based) | | col | number | Yes | Column index (0-based) | | verbose | boolean | No | Include formula, formatted value, and merge info |
search
Case-insensitive partial match across every cell in a .numbers file.
| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | path | string | Yes | Path to the .numbers file | | query | string | Yes | Text to search for | | sheet | string | No | Limit search to one sheet |
Returns: Each match with sheet, table, row, column header, and value.
export-table
Export a table to CSV, TSV, or JSON.
| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | path | string | Yes | Path to the .numbers file | | format | "csv" \| "tsv" \| "json" | Yes | Output format | | outputPath | string | Yes | Path for the output file | | sheet | string | No | Sheet name (default: first sheet) | | table | string | No | Table name (default: first table) |
Write
create-spreadsheet
Create a new .numbers file with one sheet and table.
⚠️ Safety: Overwrites the file at path if it already exists — confirm the destination first.
| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | path | string | Yes | Path for the new file | | headers | string[] | Yes | Column header names | | rows | (string \| number \| boolean \| null)[][] | No | Initial data rows | | sheetName | string | No | Default: "Sheet 1" | | tableName | string | No | Default: "Table 1" |
set-cell
Write a value to a single cell.
⚠️ Safety: Overwrites the existing cell value in place in the .numbers file.
| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | path | string | Yes | Path to the .numbers file | | row | number | Yes | Row index (0-based) | | col | number | Yes | Column index (0-based) | | value | string \| number \| boolean \| null | Yes | Value to write | | sheet | string | No | Sheet name (default: first sheet) | | table | string | No | Table name (default: first table) | | type | "string" \| "number" \| "boolean" \| "date" | No | Force value type (default: auto-detect) |
set-cells-batch
Write multiple cells in a single operation. Much more efficient than multiple set-cell calls.
⚠️ Safety: Overwrites the existing cell values in place in the .numbers file.
| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | path | string | Yes | Path to the .numbers file | | updates | array | Yes | Array of {row, col, value, type?} objects | | sheet | string | No | Sheet name | | table | string | No | Table name |
add-rows
Append rows of data after the last existing row.
| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | path | string | Yes | Path to the .numbers file | | rows | array[] | Yes | Rows to a
…
Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: sweetrb
- Source: sweetrb/apple-numbers-mcp
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.