An MCP server that lets AI assistants edit open PowerPoint presentations on macOS and the web
翻译准备中
AI 摘要 · README
插件TypeScript · ShellGitHub @kzarzycki自行安装运营者未确认
试用过了吗? 点一下就好,无需登录。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
安装型项目无需部署域名也可验证。个人仓库可通过 GitHub 登录验证,组织仓库可使用上方的仓库验证文件。
正在加载完整 README。 以下为已保存的摘录。
An MCP server that lets AI assistants manipulate live, open PowerPoint presentations on macOS and PowerPoint Web via Office.js APIs.
Unlike file-based tools (python-pptx), PowerPoint MCP works with presentations that are already open — changes appear instantly, and you keep full access to PowerPoint's UI, animations, and formatting.
This repository includes Codex plugin metadata in .codex-plugin/ and Codex repo instructions in AGENTS.md.
The Codex plugin MCP config in .mcp.json uses the shared HTTP MCP endpoint:查看完整 README ↗An MCP server that lets AI assistants manipulate live, open PowerPoint presentations on macOS and PowerPoint Web via Office.js APIs.
Unlike file-based tools (python-pptx), PowerPoint MCP works with presentations that are already open — changes appear instantly, and you keep full access to PowerPoint's UI, animations, and formatting.
This repository includes Codex plugin metadata in .codex-plugin/ and Codex repo instructions in AGENTS.md.
For local development:
git clone https://github.com/kzarzycki/powerpoint-mcp.git
cd powerpoint-mcp
npm install
npm run build
The Codex plugin MCP config in .mcp.json uses the shared HTTP MCP endpoint:
{
"mcpServers": {
"powerpoint-mcp": {
"type": "http",
"url": "http://localhost:3001/mcp"
}
}
}
The Codex plugin ships a SessionStart hook in hooks/hooks.json. On session start it runs scripts/start-http-bridge.sh, which starts the built bridge with node ./dist/index.cjs --http --bridge if the HTTP MCP server or add-in bridge is not already healthy.
Then restart PowerPoint, open a presentation, and click the bridge add-in in the ribbon. For manual local development, start the TypeScript source directly with node --experimental-strip-types ./server/index.ts --http --bridge.
Zero-config install from the marketplace. MCP auto-starts, add-in auto-sideloads, skill included.
/plugin marketplace add kzarzycki/powerpoint-mcp
/plugin install powerpoint-mcp@powerpoint-mcp
Then restart PowerPoint, open a presentation, and click the bridge add-in in the ribbon.
Build and install as a one-click .mcpb extension (from source):
git clone https://github.com/kzarzycki/powerpoint-mcp.git
cd powerpoint-mcp
npm install && npm run build:mcpb
open powerpoint-mcp-*.mcpb # opens Claude Desktop installer
The extension auto-starts the bridge and auto-sideloads the add-in. Restart PowerPoint after first install.
Known limitations:
git clone https://github.com/kzarzycki/powerpoint-mcp.git
cd powerpoint-mcp
npm install
npm run sideload # copies manifest to PowerPoint's add-in folder
npm start -- --http --bridge # starts the MCP HTTP transport (:3001/mcp) + add-in bridge (:8080)
Then point your MCP client at the HTTP transport. Create or merge into the project's .mcp.json:
{
"mcpServers": {
"powerpoint-mcp": {
"type": "http",
"url": "http://localhost:3001/mcp"
}
}
}
Restart PowerPoint, open a presentation, and click the bridge add-in in the ribbon. For STDIO mode and other standalone options, see skills/powerpoint-mcp/references/setup.md.
This project was inspired by the Claude in PowerPoint add-in. The first time I tried it, I was amazed — it edits live, open decks via Office.js, and the results are far better than file-based pptx tools. But it only works inside the add-in, which means no access to CLAUDE.md, skills, or any other Claude Code features. PowerPoint MCP brings those same Office.js capabilities to Claude Code (and any MCP client) so you get live editing with the full power of your coding environment.
The project was originally named powerpoint-bridge and renamed to powerpoint-mcp in v0.5.0. The "bridge server" component keeps its name — it bridges MCP and the Office.js add-in over WebSocket.
AI Assistant <--MCP STDIO/HTTP--> Bridge Server (Node.js) <--WS/WSS--> PowerPoint Add-in (Office.js)
| |
STDIO (default) Desktop: WKWebView sandbox
or HTTP (:3001/mcp) Web: browser iframe
localhost:8080 (HTTP) Office.js API 1.1-1.8
or :8443 (HTTPS) executes commands on
serves add-in files + WS live presentation
Two MCP transports are supported:
--stdio flag; the MCP client spawns the server process directly127.0.0.1:3001/mcp; enabled by the --http flag (e.g. node server/index.ts --http --bridge for development with .mcp.json)Three components in one repo:
addin/ — Office.js taskpane add-in that loads inside PowerPoint and connects as a WebSocket clientserver/ — Node.js bridge server: HTTP + WS + MCP transport (HTTPS/WSS opt-in via BRIDGE_TLS=1)skills/powerpoint-mcp/ — Claude Code skill with tool docs, code patterns, and setup guide (auto-installed with plugin)certs/ — Optional local TLS certificates for HTTPS mode (generated, gitignored)brew install node
| Tool | Description |
|---|---|
list_presentations | Lists all connected presentations with their IDs and status |
inspect_deck | Deck overview: slide dimensions, theme (colors + fonts), and all slides with layout and shape count |
inspect_layouts | Slide layouts with names, types, placeholders, and positions. Supports field selection |
inspect_slide | Returns detailed shape info for a slide (text, positions, sizes, fills) |
scan_slide | Lightweight shape scanner: IDs, types, and positions |
screenshot_slide | Captures a visual screenshot of a slide as PNG (requires PowerPoint 16.96+) |
preview_deck | Returns thumbnails + text for all/selected slides in one call (efficient full-deck review) |
copy_slides | Copies slides between two open presentations (data stays server-side, never in Claude context) |
insert_image | Inserts an image from a file path, URL, or base64 data onto a slide |
get_local_copy | Returns a local file path for the presentation (passthrough for local, exports cloud files to temp .pptx) |
search_fluent_icons | Search Microsoft Fluent UI icons by keyword and insert as SVG |
execute_officejs | Runs arbitrary Office.js code inside the live presentation |
add_slide | Add a new slide from a named layout at a specific position, with placeholder text pre-filled |
duplicate_slide | Duplicate a slide within the same presentation; data stays server-side |
read_deck_text | Lightweight text extractor: slide titles and body text as plain strings (~20x smaller than inspect_slide) |
read_shape_paragraphs | Read raw OOXML <a:p> paragraphs from a shape's text body, preserving all formatting |
edit_shape_paragraphs | Replace paragraph content of a shape with raw OOXML <a:p> XML |
read_slide_xml |
When multiple presentations are open, pass presentationId (from list_presentations) to target a specific one.
insert_image tool), not shape API; positioning works but no shape-level manipulation after insertionedit_slide_chart), not via Office.js chart APIPowerPoint MCP assumes a single-user, locally-trusted machine. Both network servers bind to the loopback interface only:
127.0.0.1:8080 (or 127.0.0.1:8443 with BRIDGE_TLS=1)127.0.0.1:3001; the default STDIO transport opens no network portHost header is not 127.0.0.1:3001 / localhost:3001)/mcp request bodies to 16 MiB (16,777,216 bytes), enforced while the body streams in rather than after it is fully buffered. The ceiling covers the largest supported request — a base64-encoded image via insert_image — with headroom: base64 inflates raw bytes by ~4/3, so 16 MiB admits a ~12 MB source image plus the surrounding JSON-RPC envelope. An oversized or over-length chunked upload gets a 413 response (Request body too large) instead of being buffered into memory; the connection remains usable for the next request.GET https://registry.npmjs.org/powerpoint-mcp/latest to check for a newer version. Nothing is sent beyond the request itself; no presentation data, telemetry, or identifiers. Disable it with BRIDGE_NO_UPDATE_CHECK=1 or the --no-update-check flag.Local file and URL access. The insert_image tool reads arbitrary local file paths (sourceType: 'file') and fetches arbitrary URLs (sourceType: 'url') with the full privileges of the server process. A URL fetch can reach internal/loopback addresses (SSRF), and a file read can pull in any file the user can read. Only run the bridge on a trusted, single-user machine.
Local-trust posture. The add-in executes whatever JavaScript the bridge sends it over the local WebSocket. The bridge WebSocket enforces an Origin allowlist: it only accepts the upgrade when the request's Origin header exactly matches the bridge's own currently-serving origin (http://localhost:PORT, or https://localhost:PORT with BRIDGE_TLS=1) — the origin the add-in's own served page always connects from, on both PowerPoint for Mac and PowerPoint Web (the WAC host frame at officeapps.live.com never opens this socket itself; the taskpane iframe it hosts navigates directly to the bridge origin first). A missing, malformed, or foreign Origin is rejected before the socket can register or answer any pending request — a real browser/webview always sends Origin on a WebSocket handshake, so no legitimate client is excluded. This is an origin policy, not authentication: it stops a foreign page's script from driving the bridge, but any local process that can reach the loopback port and mimic that Origin header still can. Do not run PowerPoint MCP on a shared or multi-user host.
execute_officejs runs arbitrary code inside PowerPoint's Office.js runtime. This is by design — it gives the AI full access to the Office.js API. Only use this with MCP clients you trust.
Planned hardening. Before binding to any non-loopback interface or shipping a remote-MCP deployment, the bridge needs a per-session handshake token and an authenticated transport.
Add-in not appearing in PowerPoint
npm run sideload and restart PowerPoint~/Library/Containers/com.microsoft.Powerpoint/Data/Documents/wef/manifest.xmlAdd-in shows "Disconnected"
Make sure the bridge server is running. In plugin mode the server auto-starts with Claude Code — call any tool to verify. For standalone installs, run npm start -- --bridge and verify with curl http://127.0.0.1:8080/health. The add-in auto-reconnects with exponential backoff.
Using HTTPS mode (required for PowerPoint Web) HTTPS is required for PowerPoint Web and optional for desktop. To enable:
brew install mkcert && mkcert -install (one-time, trusts the CA in browsers)npm run setup-certs to generate localhost certificatesnpm run sideload:https and restart PowerPointaddin/manifest-https.xmlBRIDGE_TLS=1 npm start -- --bridge| Platform | Status |
|---|---|
| macOS | Supported (primary) |
| PowerPoint Web | Supported — requires HTTPS mode, sideload via browser (all tools work) |
| Windows | Untested — different sideloading path |
| Linux | Not supported (no PowerPoint for Linux) |
The add-in uses Office.AutoShowTaskpaneWithDocument to minimize manual activation:
| Platform | Behavior |
|---|---|
| macOS desktop | Taskpane auto-opens when the add-in is sideloaded. Closing the pane keeps the WebSocket connection alive (shared runtime with lifetime="long"). |
| PowerPoint Web | One ribbon click per document per browser session to activate. After activation, the pane auto-reopens on page reload. Closing the pane keeps the connection alive within the session. |
| New file from template | OOXML template embedding can pre-activate the add-in (see below) |
Requires SharedRuntime 1.1 (PowerPoint 16.46+ on Mac, 2102+ on Windows). Centralized Deployment via Microsoft 365 admin center can eliminate the manual click for organizational use.
External tools can embed the add-in reference directly into .pptx templates so the add-in activates on first open without prior installation. This requires injecting two OOXML parts into the .pptx zip:
ppt/webextensions/webextension1.xml — add-in reference with Office.AutoShowTaskpaneWithDocument propertyppt/webextensions/taskpane.xml — taskpane configuration (dock state, visibility, width)Plus the corresponding entries in [Content_Types].xml and relationship files.
Set visibility="0" if the add-in must already be sideloaded; set visibility="1" to prompt users to install it on first open.
For a complete working example, see Office-OOXML-EmbedAddin. The add-in ID to reference is AE89909C-2813-4B08-9E1B-49E7379BD0E6 with storeType="Registry" and store="developer" for sideloaded installations.
See CONTRIBUTING.md for development setup and guidelines.
| Read the full raw OOXML of a slide, or filter to a specific shape |
edit_slide_xml | Edit slide XML and reimport (xml mode or JS code mode for DOM manipulation) |
read_slide_zip | Read multiple files from the exported slide zip (slide XML, rels, chart XMLs, Content_Types) |
edit_slide_zip | Update multiple files in the slide zip and reimport in a single operation |
edit_slide_chart | Create a chart on a slide from structured data (column, bar, line, pie, doughnut, area) via OOXML |
read_speaker_notes | Read speaker notes from slides as plain text |
edit_speaker_notes | Set speaker notes on one or more slides; accepts markdown text |
format_shapes | Apply fill color and font formatting to multiple shapes on a slide in one call |
search_text | Search for text across all slides — like grep for slides; supports regex |
verify_slides | Run programmatic checks on a slide (overlaps, out-of-bounds, empty text, unused placeholders) |