Keynote MCP Server
# Keynote MCP Server
A Model Context Protocol (MCP) server that provides full programmatic control over Apple Keynote through AppleScript and JXA (JavaScript for Automation). Designed for use with Claude Desktop and any MCP-compatible client, this server lets you create, edit, present, and export Keynote presentations entirely through natural language.
## Prerequisites
- **macOS** (any recent version with Keynote installed)
- **Apple Keynote** (free from the Mac App Store)
- **Node.js 18+** (check with `node --version`)
- **Accessibility permissions** -- your terminal or IDE must be allowed to control Keynote via System Settings > Privacy & Security > Accessibility
## Installation
```bash
git clone https://github.com/superdwayne/keynoteMP.git keynote-mcp-server
cd keynote-mcp-server
npm install
npm run build
```
Verify the build succeeds and types pass:
```bash
npx tsc --noEmit
```
## Claude Desktop Configuration
Add the following entry to your `claude_desktop_config.json` (typically located at `~/Library/Application Support/Claude/claude_desktop_config.json`):
```json
{
"mcpServers": {
"keynote": {
"command": "node",
"args": ["/absolute/path/to/keynote-mcp-server/dist/index.js"]
}
}
}
```
Replace `/absolute/path/to/keynote-mcp-server` with the actual path on your machine. Restart Claude Desktop after saving the configuration.
## Tool Reference
The server registers **70 tools** across 13 modules. All slide indices are **1-based**.
### Design Engine (8 tools)
The Design Engine automates professional slide composition with a brand-aware system including 23+ layouts, typography scaling, color harmonies, and presentation templates.
| Tool | Parameters | Description |
|------|-----------|-------------|
| `design_slide` | `slideIndex`, `title?`, `subtitle?`, `body?`, `bodyItems?`, `quote?`, `imagePaths?`, `stats?`, `layoutName?`, `primaryColor?`, `style?`, `variationSeed?`, `addAccents?` | Composes a complete slide with automatic layout, typography, and color |
| `design_deck` | `slides[]`, `primaryColor?`, `style?`, `addAccents?` | Composes multiple slides with consistent branding and layout variety |
| `set_brand` | `primaryColor?`, `secondaryColor?`, `accentColor?`, `backgroundColor?`, `fontPrimary?`, `fontSecondary?`, `style?` | Sets brand configuration for subsequent design operations |
| `get_brand` | -- | Extracts brand configuration from the active Keynote theme |
| `list_layouts` | `category?` | Lists all available slide layouts with descriptions and element details |
| `list_templates` | -- | Lists all presentation templates with slide counts |
| `get_template` | `templateName` | Gets full structure of a template with content hints |
| `design_from_template` | `templateName`, `slides?`, `primaryColor?`, `style?`, `startSlideIndex?` | Creates a full presentation from a template |
**Available layouts:** `title-center`, `title-left`, `title-bold`, `section-break`, `section-gradient`, `content-left`, `content-right-image`, `content-left-image`, `two-column`, `three-column`, `full-image`, `image-grid`, `quote`, `statistic`, `comparison`, `closing-cta`, `closing-thankyou`, `blank-canvas`, `timeline`, `before-after`, `team-grid`, `pricing-table`, `roadmap`
**Available templates:** `pitch-deck` (10 slides), `status-update` (5 slides), `workshop` (8 slides), `product-launch` (7 slides)
**Brand styles:** `minimal`, `bold`, `elegant`, `playful`, `corporate`
### Presentation Management (6 tools)
| Tool | Parameters | Description |
|------|-----------|-------------|
| `create_presentation` | `themeName?` (string) | Creates a new blank Keynote presentation, optionally with a named theme |
| `open_presentation` | `filePath` (string) | Opens an existing `.key` file by absolute path |
| `save_presentation` | `filePath?` (string) | Saves the frontmost presentation; provide a path for save-as |
| `close_presentation` | `saving?` (boolean, default: true) | Closes the frontmost presentation |
| `list_presentations` | -- | Lists all open presentations with names and file paths |
| `get_presentation_info` | `name?` (string) | Returns slide count, theme, dimensions, and path for a presentation |
### Slide Management (7 tools)
| Tool | Parameters | Description |
|------|-----------|-------------|
| `add_slide` | `position?` (int), `masterSlideName?` (string) | Adds a new slide at a given position with an optional layout |
| `delete_slide` | `slideIndex` (int) | Removes a slide by index |
| `duplicate_slide` | `slideIndex` (int) | Duplicates a slide at the given index |
| `move_slide` | `fromIndex` (int), `toIndex` (int) | Moves a slide from one position to another |
| `get_slide_count` | -- | Returns total number of slides |
| `list_slides` | -- | Returns all slides with index, title, and layout name |
| `get_slide_layout_names` | -- | Lists available master slide / layout names for the current theme |
### Text Content (7 tools)
| Tool | Parameters | Description |
|------|-----------|-------------|
| `set_slide_title` | `slideIndex` (int), `text` (string) | Sets the title text of a slide |
| `set_slide_body` | `slideIndex` (int), `text` (string) | Sets the body text of a slide |
| `add_text_item` | `slideIndex` (int), `text` (string), `x`, `y`, `width`, `height` (numbers), `role?` (display/heading/subheading/body/caption/quote/overline/bodySmall), `autoPosition?` (boolean) | Adds a text box with optional brand-aware typography via `role` |
| `update_text_item` | `slideIndex` (int), `itemIndex` (int), `text` (string) | Updates text content of an existing text item |
| `delete_text_item` | `slideIndex` (int), `itemIndex` (int) | Removes a text item from a slide |
| `list_text_items` | `slideIndex` (int) | Lists all text items on a slide with content, position, and size |
| `format_text` | `slideIndex` (int), `itemIndex` (int), `fontName?`, `fontSize?`, `bold?`, `italic?`, `color?` (hex), `alignment?` (left/center/right) | Applies formatting to a text item |
### Images & Media (5 tools)
| Tool | Parameters | Description |
|------|-----------|-------------|
| `add_image` | `slideIndex` (int), `filePath` (string), `x?`, `y?`, `width?`, `height?` (numbers), `role?` (hero-image/thumbnail/background-image/icon/inline/avatar) | Adds an image with optional role-based sizing |
| `replace_image` | `slideIndex` (int), `imageIndex` (int), `filePath` (string) | Replaces an existing image with a new file |
| `delete_image` | `slideIndex` (int), `imageIndex` (int) | Removes an image from a slide |
| `list_images` | `slideIndex` (int) | Lists all images on a slide with positions and file names |
| `set_image_position` | `slideIndex` (int), `imageIndex` (int), `x?`, `y?`, `width?`, `height?` (numbers) | Repositions or resizes an existing image |
### Presenter Notes (3 tools)
| Tool | Parameters | Description |
|------|-----------|-------------|
| `set_presenter_notes` | `slideIndex` (int), `notes` (string) | Sets presenter notes for a slide |
| `get_presenter_notes` | `slideIndex` (int) | Retrieves presenter notes for a slide |
| `get_all_presenter_notes` | -- | Returns all slides' presenter notes as an array |
### Themes & Styling (6 tools)
| Tool | Parameters | Description |
|------|-----------|-------------|
| `list_themes` | -- | Lists available Keynote themes (queries Keynote or falls back to a built-in list) |
| `apply_theme` | `themeName` (string) | Applies a theme to the frontmost presentation |
| `set_slide_background_color` | `slideIndex` (int), `color` (hex string) | Sets a solid background color on a slide |
| `set_slide_background_image` | `slideIndex` (int), `filePath` (string) | Sets an image as the slide background |
| `get_slide_master` | `slideIndex` (int) | Returns the master slide / layout name for a slide |
| `change_slide_master` | `slideIndex` (int), `masterName` (string) | Changes a slide's master layout |
### Transitions & Animations (6 tools)
| Tool | Parameters | Description |
|------|-----------|-------------|
| `set_slide_transition` | `slideIndex` (int), `effect` (string), `duration?` (number, default: 1.0) | Sets a transition effect on a slide |
| `get_slide_transition` | `slideIndex` (int) | Returns current transition settings for a slide |
| `list_transition_types` | -- | Lists all 33 available transition effect names |
| `add_build_animation` | `slideIndex` (int), `itemIndex` (int), `type` (appear/dissolve/scale/move_in/fly_in/fade_and_move), `buildType` (in/out), `duration?` (number) | Adds a build-in or build-out animation to an item |
| `remove_build_animation` | `slideIndex` (int), `itemIndex` (int), `buildType` (in/out) | Removes an animation from an item |
| `list_build_animations` | `slideIndex` (int) | Lists all build animations for every item on a slide |
### Tables & Charts (6 tools)
| Tool | Parameters | Description |
|------|-----------|-------------|
| `add_table` | `slideIndex` (int), `rows` (int), `columns` (int), `x?`, `y?`, `width?`, `height?` (numbers) | Adds a table to a slide |
| `set_table_cell` | `slideIndex` (int), `tableIndex` (int), `row` (int), `column` (int), `value` (string) | Sets the value of a specific table cell |
| `set_table_data` | `slideIndex` (int), `tableIndex` (int), `data` (string[][]) | Bulk-sets table data from a 2D array |
| `get_table_data` | `slideIndex` (int), `tableIndex` (int) | Reads all data from a table as a 2D array |
| `delete_table` | `slideIndex` (int), `tableIndex` (int) | Removes a table from a slide |
| `add_chart` | `slideIndex` (int), `chartType` (bar/line/pie/area), `x?`, `y?`, `width?`, `height?`, `data?` (series array) | Adds a chart to a slide (may fall back to a data table due to AppleScript limitations) |
### Live Slideshow Control (6 tools)
| Tool | Parameters | Description |
|------|-----------|-------------|
| `start_slideshow` | `fromSlide?` (int) | Starts the slideshow from the beginning or a specific slide |
| `stop_slideshow` | -- | Stops the currently running slideshow |
| `next_slide` | -- | Advances to the next slide or build |
| `previous_slide` | -- | Goes back to the previous slide or build |
| `go_to_slide` | `slideIndex` (int) | Jumps to a specific slide during the slideshow |
| `get_slideshow_status` | -- | Returns whether a slideshow is playing and the current slide number |
### Export (4 tools)
| Tool | Parameters | Description |
|------|-----------|-------------|
| `export_to_pdf` | `filePath` (string) | Exports the presentation as a PDF |
| `export_to_images` | `directoryPath` (string), `format?` (PNG/JPEG) | Exports all slides as individual image files to a directory |
| `export_to_pptx` | `filePath` (string) | Exports as Microsoft PowerPoint (.pptx) |
| `export_slide_to_image` | `slideIndex` (int), `filePath` (string), `format?` (PNG/JPEG) | Exports a single slide as an image file |
### Content Extraction (2 tools)
| Tool | Parameters | Description |
|------|-----------|-------------|
| `get_slide_content` | `slideIndex` (int) | Returns all content on a slide: title, body, text items, images, shapes, tables, and notes |
| `get_full_presentation_content` | -- | Returns a structured summary of the entire presentation with per-slide details |
### Shapes & Drawing (4 tools)
| Tool | Parameters | Description |
|------|-----------|-------------|
| `add_shape` | `slideIndex` (int), `shapeType` (rectangle/circle/triangle/arrow_right/arrow_left/star/diamond/line), `x`, `y`, `width`, `height` (numbers), `fillColor?` (hex), `role?` (accent-shape/divider/background-shape/highlight/background-panel) | Adds a shape with optional brand-aware color via `role` |
| `delete_shape` | `slideIndex` (int), `shapeIndex` (int) | Removes a shape from a slide |
| `list_shapes` | `slideIndex` (int) | Lists all shapes on a slide with position and size |
| `update_shape` | `slideIndex` (int), `shapeIndex` (int), `x?`, `y?`, `width?`, `height?`, `fillColor?`, `borderColor?`, `borderWidth?` | Modifies a shape's position, size, or styling |
## Usage Examples
### Design a pitch deck from a template
```
"Create a pitch deck for my startup using the pitch-deck template with our brand colors #2563EB and an elegant style."
```
Claude will call `set_brand`, then `design_from_template` with "pitch-deck", generating all 10 slides with coordinated layouts, typography, and transitions.
### Design a single slide with brand-aware styling
```
"Design slide 3 with the title 'Market Opportunity', body text about the TAM, and use the statistic layout."
```
Claude will call `design_slide` with the content and layout name, automatically applying brand colors and typography.
### Create a presentation from scratch
```
"Create a new Keynote presentation with the Gradient theme, add 5 slides, and set titles for each one."
```
Claude will call `create_presentation`, then `add_slide` five times, and `set_slide_title` for each slide.
### Build a data-driven slide
```
"On slide 3, add a table with quarterly revenue data: Q1: $1.2M, Q2: $1.5M, Q3: $1.8M, Q4: $2.1M."
```
Claude will use `add_table`, then `set_table_data` to populate the cells.
### Export for sharing
```
"Export my presentation as a PDF to the Desktop and also save each slide as a PNG image."
```
Claude will call `export_to_pdf` and `export_to_images` with the appropriate paths.
### Add brand-aware text and shapes
```
"Add a heading with role 'display' on slide 1 that says 'Welcome'."
```
Claude will call `add_text_item` with `role: "display"`, which automatically applies brand-aware font, size, and color with WCAG-compliant contrast.
## Architecture
```
keynote-mcp-server/
src/
index.ts # Entry point -- creates MCP server, registers all tool modules
applescript.ts # AppleScript/JXA execution bridge (runAppleScript, runJXA)
tools/
presentation.ts # create, open, save, close, list, info
slides.ts # add, delete, duplicate, move, count, list, layouts
text.ts # title, body, text items, formatting (brand-aware via role)
images.ts # add, replace, delete, list, reposition (role-based sizing)
notes.ts # set, get, get-all presenter notes
theme.ts # themes, backgrounds, master slides
transitions.ts # slide transitions, build animations
tables-charts.ts # tables (CRUD + bulk data), charts
slideshow.ts # start, stop, next, previous, go-to, status
export.ts # PDF, images, PowerPoint, single-slide export
content.ts # read slide content, full presentation summary
shapes.ts # add, delete, list, update shapes (brand-aware via role)
design.ts # design_slide, design_deck, set_brand, get_brand, list_layouts,
# list_templates, get_template, design_from_template
design/
tokens.ts # Design tokens (spacing, margins, canvas sizes)
color.ts # Color math, harmonies, WCAG contrast
typography.ts # Type scale system (8 roles, modular scale)
grid.ts # 12-column, 8-row grid system
layouts.ts # Layout definition schema
layout-library.ts # 23+ pre-built slide layouts
brand.ts # Brand configuration, theme extraction
brand-state.ts # Shared brand state across all tool modules
balance.ts # Visual balance and whitespace utilities
accents.ts # Decorative accent generation
variations.ts # Layout variation engine (mirror, shift, toggle)
composer.ts # Slide/deck composition orchestration
templates.ts # Presentation templates (pitch-deck, status-update, etc.)
progress.ts # Progress indicators for multi-slide decks
dist/ # Compiled JavaScript output (generated by `npm run build`)
package.json
tsconfig.json
```
The server uses **stdio transport** (standard for local MCP servers). Each tool module exports a `register*Tools(server)` function that registers tools with the MCP server instance. All Keynote automation is performed by shelling out to `osascript` via `child_process.execFile`, using either AppleScript or JXA depending on the operation.
## Troubleshooting
### "AppleScript error: Not authorized to send Apple events"
Your terminal or IDE needs Accessibility permissions. Go to **System Settings > Privacy & Security > Accessibility** and add your terminal application (Terminal.app, iTerm2, VS Code, etc.).
You may also need to grant permissions under **Privacy & Security > Automation** to allow your terminal to control Keynote.
### "Keynote got an error: Can't get document 1"
No Keynote presentation is currently open. Use `create_presentation` or `open_presentation` first.
### Build errors
Make sure you have Node.js 18+ installed and run `npm install` before `npm run build`. The project requires TypeScript and the MCP SDK as dependencies.
### Keynote must be installed
This server controls Keynote.app via AppleScript. It will not work without Keynote installed. Keynote is free from the Mac App Store.
### Chart creation limitations
Direct chart creation via AppleScript is limited in some Keynote versions. The `add_chart` tool will attempt to create a chart directly but may fall back to creating a data table with your values. You can then manually convert that table to a chart in Keynote.
### Timeout errors
Each AppleScript command has a 30-second timeout. Operations on very large presentations or complex exports may occasionally time out. If this happens, try the operation again or work with fewer slides at a time.
## License
MIT
TDQS
Scored across 70 tools
Most tools have distinct purposes, but some overlap exists between high-level design tools (design_deck, design_slide, design_from_template) and between get_full_presentation_content and get_presentation_info. Despite 70 tools, boundaries are mostly clear.
Predominantly uses verb_noun pattern (add_slide, delete_image), but inconsistencies exist: 'list' vs 'get' for similar operations (list_slides vs get_slide_count), and 'change_slide_master' vs 'set_slide_background_color'. Minor mix of 'format_text' instead of 'set_text_formatting'.
70 tools is excessive for an MCP server, far beyond the typical 10-20. While comprehensive, many tools (e.g., multiple design functions, separate list/get variants) could be consolidated. The high number risks overwhelming agents and increasing selection errors.
Covers nearly all aspects of Keynote automation: creation, editing, formatting, animations, transitions, exporting, slideshow control, and branding. Minor gaps exist (chart support is limited, no audio/video/hyperlink tools), but the surface is remarkably complete for a presentation tool.