AgentStack
SKILL unreviewed MIT Self-run

Configuring Powerpoint Mcp

skill-peterkalmstrom-claudepowerpointskill-claudepowerpointskill · by PeterKalmstrom

Build production-quality PowerPoint decks on Windows via the powerpoint-mcp server — COM safety patterns, idempotent build scripts, anchor-type word budgets, plus Remotion / Nanobanana / Veo media integration. Load when creating or editing a .pptx, embedding video / AI-generated images or video, or troubleshooting missing PowerPoint tools.

No reviews yet
0 installs
0 views
view→install

Install

$ agentstack add skill-peterkalmstrom-claudepowerpointskill-claudepowerpointskill

Open-source listing — not yet scanned by AgentStack. Follow the source repository for install instructions.

Security review

⚠ Flagged

1 finding(s); flagged for manual review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures
  • high Dangerous shell/eval execution.

What it can access

  • Network access No
  • Filesystem access Used
  • Shell / process execution Used
  • Environment & secrets Used
  • 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.

Are you the author of Configuring Powerpoint Mcp? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

PowerPoint MCP — Setup & Rich Media Workflow

Installs powerpoint-mcp so Claude Code can open, read, edit, and create PowerPoint presentations via COM automation on Windows. Also covers integrating Remotion (programmatic animated video), Nanobanana (AI image generation), and Veo 3.1 (AI video generation from text prompts) for professional-quality slide media.

Contents

  • Prerequisites
  • Installation
  • Troubleshooting
  • COM patterns & safety
  • Workflow
  • Available Tools
  • Quick Verification
  • Nanobanana Integration (AI Images)
  • Remotion Integration (Animated Video)
  • Veo Integration (AI Video Generation)
  • Embedding Media in Slides
  • Combined Workflow Patterns
  • Speaker notes — load them up
  • Showcase-first for multi-slide sections
  • Common defects to self-check
  • Anti-patterns (recurring COM / build traps)

Prerequisites

  • Windows — the server uses PowerPoint COM automation; it does not work on macOS or Linux.
  • Microsoft PowerPoint — must be installed (desktop version, not web-only).
  • uv (Python package runner) — provides the uvx command used to launch the server.

Install uv

Open a PowerShell terminal (not bash):

irm https://astral.sh/uv/install.ps1 | iex

This installs uv.exe and uvx.exe to C:\Users\\.local\bin\.

> Note: Replace ` with the actual Windows username throughout this guide (e.g., C:\Users\alice\.local\bin\uvx.exe`).

Verify:

C:\Users\\.local\bin\uvx.exe --version

Installation

Step 1 — Add the MCP server at user scope with the full path to uvx

claude mcp add --scope user powerpoint -- "C:\Users\\.local\bin\uvx.exe" powerpoint-mcp

Critical details:

  • Use --scope user, not the default project scope. Project-scoped MCP servers are nested inside a project key in .claude.json and the VS Code extension may not load them.
  • Use the full absolute path to uvx.exe, not just uvx. Claude Code's shell environment does not reliably include ~/.local/bin in PATH, so a bare uvx command will fail silently — the server won't start and no tools will appear.

The command writes to the top-level mcpServers block in C:\Users\\.claude.json:

{
  "mcpServers": {
    "powerpoint": {
      "type": "stdio",
      "command": "C:\\Users\\\\.local\\bin\\uvx.exe",
      "args": ["powerpoint-mcp"],
      "env": {}
    }
  }
}

Step 1b — Pre-download the package

The first launch downloads ~45 packages. Run this once to cache them so the MCP server starts instantly on first real use:

"C:\Users\\.local\bin\uvx.exe" powerpoint-mcp --help

Step 1c — Alternative: edit .claude.json directly

If the claude CLI is not available (e.g., running inside the VS Code extension), add the MCP server by editing C:\Users\\.claude.json directly. Add the mcpServers block at the top level of the JSON (not nested inside projects):

{
  "mcpServers": {
    "powerpoint": {
      "type": "stdio",
      "command": "C:\\Users\\\\.local\\bin\\uvx.exe",
      "args": ["powerpoint-mcp"],
      "env": {}
    }
  }
}

Step 2 — Restart Claude Code

The MCP server is only discovered at session startup. Close and reopen Claude Code (or the VS Code window) after adding the server.

Step 3 — Verify connection

After restarting, run:

claude mcp list

Expected output:

powerpoint: C:\Users\\.local\bin\uvx.exe powerpoint-mcp - ✓ Connected

If you see ✓ Connected, the PowerPoint tools are available in the session.


Troubleshooting

Tools don't appear after restart

  1. Check claude mcp list — if the server isn't listed at all, the config wasn't saved. Re-run the claude mcp add command.
  2. Server listed but not connected — run uvx.exe manually to check for errors:

``bash "C:\Users\\.local\bin\uvx.exe" powerpoint-mcp `` The first run downloads ~45 packages; subsequent runs are instant.

  1. Server connected in CLI but tools missing in VS Code — the server was likely added at project scope instead of user scope. Check .claude.json:
  • Wrong: mcpServers nested inside "projects""""mcpServers"
  • Right: mcpServers at the top level of the JSON file

Fix: remove the project-scoped entry and re-add with --scope user.

uvx not found

The uv installer wasn't run, or PATH wasn't updated. Use the full path C:\Users\\.local\bin\uvx.exe in the MCP config instead of relying on PATH.

PowerPoint COM errors

  • Ensure PowerPoint is installed (not just Office web apps).
  • Close any "PowerPoint has stopped working" dialogs.
  • If PowerPoint is open with a modal dialog (e.g., save prompt), the COM connection may hang.

Images get swallowed by content placeholders

When adding a picture with AddPicture to a slide that uses a layout with a content placeholder (e.g., "Title and Content"), PowerPoint may absorb the image into the placeholder instead of creating a standalone Picture shape. Deleting the placeholder doesn't help — the layout regenerates it.

Fix: Change the slide layout to "Title Only" before adding the image:

# In evaluate tool:
title_only = presentation.SlideMaster.CustomLayouts(6)  # "Title Only"
slide.CustomLayout = title_only
# Now AddPicture creates a real Picture shape (type=13)
slide.Shapes.AddPicture(path, False, True, left, top, w, h)

This prevents the layout from regenerating content placeholders. The title placeholder is preserved. Use this whenever you need standalone images on slides that originally had content placeholders.

Safe destructive operations — snapshot first

Rule: Before any destructive change to a deck the user cares about (deleting shapes, replacing backgrounds, mass-editing slides, layout changes), write a timestamped side copy with SaveCopyAs. PowerPoint's built-in undo covers the current session but cannot rescue you after a save, across sessions, or when COM operations fail silently.

Why:

  • ExecuteMso("Undo") works for most shape edits but does NOT cover media inserts, layout changes, or some COM-driven modifications
  • Once you call presentation.Save(), the on-disk file is already overwritten — session undo can restore in-memory state but the file has moved
  • Closing PowerPoint clears the undo stack forever
  • Undo is strictly linear: you cannot undo one change and keep later ones

How:

# In evaluate tool — before any risky operation:
import time
src = presentation.FullName
backup = src.replace(".pptx", f".backup-{int(time.time())}.pptx")
presentation.SaveCopyAs(backup)
# Now do the risky thing. If it goes wrong, the backup is on disk.

SaveCopyAs writes a side copy without affecting the open document — you keep working in the original. If something goes wrong, close the original without saving and reopen the backup.

When to use:

  • Deleting shapes you cannot easily recreate (AI-generated images, complex diagrams)
  • Replacing a slide's layout
  • Bulk operations across many slides
  • Any time the user says "my big deck" or "the real one" — assume it's irreplaceable
  • Before the first destructive operation in a new session on a user's working deck

When session undo is enough:

  • Text edits on placeholders
  • Moving or resizing shapes
  • Adding new content (if wrong, just delete it)
  • Any reversible tweak within the current session

Pattern: Think of SaveCopyAs as a git commit and ExecuteMso("Undo") as editor undo. Use both.


COM patterns & safety

Foundational rules for any COM script targeting PowerPoint. These are not "things to do when something breaks" — they are constraints to design around from the first line of code. Read this section before writing any non-trivial COM patch or build script.

Snapshot before any risky bulk edit

Rule: Before running any script that touches more than a handful of shapes — bulk font bumps, layout reflows, multi-slide rebuilds — copy the deck to a timestamped backup. COM operations succeed without raising errors when they corrupt the wrong shapes; the backup is your only undo.

The cheapest pattern is a file-copy (no COM), so the user's open PowerPoint session is undisturbed:

import shutil, datetime, pathlib
src = pathlib.Path(r"C:/path/to/deck.pptx")
ts = datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
dst = src.with_name(f"{src.stem}.{ts}.pre-bulk-fontbump{src.suffix}")
shutil.copy2(src, dst)

Save in PowerPoint first if there are unwritten changes — the file-copy reads disk, not in-memory state.

When to snapshot:

  • Before any bulk script that walks all slides
  • Before a deep-rebuild of a large slide (5+ shapes)
  • Before final pre-talk edits (label pre-rehearsal)
  • After a known-good iteration — gives you a "last clean version" rollback

Multi-presentation safety — never trust ActivePresentation

Rule: When more than one presentation is open in PowerPoint, app.ActivePresentation and the MCP tools that depend on it (slide_snapshot, add_speaker_notes, etc.) can silently target the wrong file. Other windows (a separate deck, a template, a reviewer's copy) can grab focus and flip the active selection without warning.

Why this happens:

  • The MCP server resolves the active presentation at the moment each call is made.
  • A user clicking another PowerPoint window — or even the OS focus changing — can move the active selection.
  • COM operations on the wrong presentation will succeed (no error) and corrupt the wrong deck.

How to apply: Always select the target presentation by name match in COM scripts:

import win32com.client
app = win32com.client.GetActiveObject('PowerPoint.Application')
target = next((p for p in app.Presentations if "MyDeck" in p.Name), None)
if not target:
    raise RuntimeError("Target presentation not open")
slide = target.Slides(34)        # use `target`, never `app.ActivePresentation`
target.Save()

When using MCP tools (which target ActivePresentation), close all other PowerPoint windows first, or activate the right window with target.Windows(1).Activate() before the call. Verify with slide_snapshot after activation.

Multiple matching presentations open. next((p for p in app.Presentations if "MyDeck" in p.Name), None) returns the first match. If both MyDeck.pptx and MyDeck-conflict-...pptx (or MyDeck2.pptx) are open and either could match the substring, prefer exact name first, then fall back to substring:

target = next((p for p in app.Presentations if p.Name == "MyDeck.pptx"), None)
if target is None:
    target = next((p for p in app.Presentations if "MyDeck" in p.Name), None)

A for ... if ...: target = p loop without break is worse than next(...) — it walks the entire list and ends up on the last match, which is whichever order PowerPoint enumerates the open windows (effectively random).

Force UTF-8 stdout in any script that prints Unicode

Rule: On Windows, Python's stdout defaults to the legacy cp1252 codec. Any print() containing , , , non-ASCII diacritics, etc. crashes with UnicodeEncodeErrorafter the COM work has already succeeded and (often) saved the deck. The result is a confusing "the script printed something but also raised, did it actually run?" state, and a partial second run if you retry.

# Put at the top of every COM script that has print() with non-ASCII content:
import sys, io
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8")

Why this matters: the COM call to target.Save() happens before the crashing print(), so the deck state is correct, but the operator can't tell from the stack trace. They'll re-run, and an append-style script (e.g. notes_*.py) may double-apply. Cheaper to add three lines upfront than to debug duplicated state.

Idempotent build scripts

Pattern: For every non-trivial slide, write a build_slide_NN.py script that clears all shapes and rebuilds from scratch. Save these scripts alongside the deck. They make iteration cheap.

def clear_and_bg(slide, img):
    slide.CustomLayout = pres.Designs(1).SlideMaster.CustomLayouts(6)
    for sh in list(slide.Shapes):
        try:
            sh.Delete()
        except:
            pass
    slide.Shapes.AddPicture(img, 0, -1, 0, 0, 960, 540).Name = "BgImage"

Each run produces the same result. To tweak typography or layout, edit the script and re-run — no manual element-by-element fixing in PowerPoint.

Strongly prefer rebuild over patch. Once a slide has 5+ shapes and you need a layout change touching more than two elements, rebuild from scratch is almost always cheaper and safer than a patch script. Patches drift — backing rectangles get left in old positions while text moves, shape Z-order silently shifts, conditional filters miss shapes. A rebuild is a single source of truth.

**Sentinel for "already built?" must only exist after the build.** A common bug in idempotent expansion/build scripts: the "skip duplication" check searches for a phrase that also exists in the pre-build content. The script thinks the work is done, skips the structural step (e.g. Duplicate()), then proceeds to rewrite text into the wrong slides — usually destroying adjacent unrelated slides.

# BAD — "We have the solutions" appears on the original opener slide already.
# First run does Duplicate() + rebuild. Second run sees the phrase on the
# pre-build slide, skips Duplicate(), but still rewrites — overwriting the
# NEXT slide with content meant for the duplicate.
if slide_has(target.Slides(start_n), "We have the solutions"):
    skip_duplication = True

# GOOD — sentinel is something the build itself adds and the pre-build slide
# cannot contain. The motto is set by this script; nothing else writes
# "We are lying." into a slide of this section.
if slide_motto(target.Slides(start_n + 1)) == "We are lying.":
    skip_duplication = True

Rule: the sentinel should be a post-condition of the build, not a phrase from the source content. If the same string could plausibly exist before the script runs, it's not a sentinel — it's a coincidence waiting to happen.

Filtering shapes — HasTextFrame is NOT "is this a text shape"

Rule: Don't use if not sh.HasTextFrame to mean "this is a rectangle / image / decorative shape". AutoShape rectangles return HasTextFrame == True even when they hold no text — they have a text frame, it's just empty. A filter like:

for sh in slide.Shapes:
    if not sh.HasTextFrame:
        # delete or resize the rectangle

…will silently skip every AutoShape rectangle on the slide. Layout patches that depend on this filter fail silently.

Reliable filters:

# By emptiness — true rectangles vs text shapes
if sh.HasTextFrame and not sh.TextFrame.HasText:
    # AutoShape with no text — likely a backing rect
    ...

# By shape type
# 1 = msoAutoShape, 13 = msoPicture, 17 = msoTextBox, 14 = msoPlaceholder
if sh.Type == 1:
    # AutoShape (rectangle, oval, etc.)
    ...
elif sh.Type == 17:
    # TextBox
    ...

# By name (most reliable when you control the build script)
if sh.Name == "HeroBacking":
    ...

Pattern: when building a slide programmatically, name every shape you might need to find later. slide.Shapes.AddShape(...).Name = "HeroBacking". Then patches use sh.Name == "HeroBacking" — survives shape additions, doesn't depend on position or order.

Move text and its backing together

Rule: TextBox and its backing AutoShape are independent shapes in COM. Repositioning one does not move the other. Patches that shift text without shifting the backing leave text floating outside its container — sometimes even off-slide.

Bad:

# Shift text right; backing stays put → text floats outside its card
for sh in slide.Shapes:
    if sh.HasTextFrame and "intro" in sh.TextFrame

…

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [PeterKalmstrom](https://github.com/PeterKalmstrom)
- **Source:** [PeterKalmstrom/ClaudePowerPointSkill](https://github.com/PeterKalmstrom/ClaudePowerPointSkill)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.