google-slides — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited google-slides (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
This skill explains the canonical way to drive the google-slides-mcp server. Tools are exposed as mcp__google-slides__<tool> (shown below by bare name).
The Slides API has no cross-presentation slide copy, and recreating elements by hand loses styling fidelity. So the high-fidelity pattern is always:
copy_presentation) — this clones masters,layouts, theme and color scheme, and brings every example slide along as a reusable palette.
duplicate_slide) within that copy.set_element_text, replace_all_text).prune_parked_slides).Editing the copy this way is functionally identical to hand-editing the showcase.
Never rebuild a slide by reading its elements and recreating them in a different deck — that drops theme/master/placeholder styling and will not be pixel-perfect. Always start from copy_presentation.login (google-slides-mcp-auth). If a tool returns "No cached Google credentials…", tell the user to run that command; do not try to work around it.
https://docs.google.com/presentation/d/<ID>/edit). Ask the user for it if you don't have it.
copy_presentation(source_id="<showcase_id>", title="Q3 Review")
→ { presentationId: "<deck>", url: ... } # the working deck
catalog_slides(presentation_id="<deck>")
→ [ { index, objectId, layoutObjectId, elementTypes, placeholders, title, isSkipped } ]
park_slides(presentation_id="<deck>", slide_ids=[<every example objectId>])
→ hides the palette so it doesn't clutter the in-progress deckcatalog_slides is how you choose which example slide fits each section (look at placeholders, elementTypes, and title). Keep the catalog — you'll reuse the example objectIds on later turns.
You do not have to do everything at once. Each call is independent, so "now add another three-column slide that says X" is just another pass:
duplicate_slide(presentation_id="<deck>", page_id="<3col_example_id>", insertion_index=2)
→ { newSlideId: "<slide>" }
get_page(presentation_id="<deck>", page_id="<slide>")
→ find the element objectIds you need to fill
set_element_text(presentation_id="<deck>", element_id="<col1>", text="…")
set_element_text(presentation_id="<deck>", element_id="<col2>", text="…")Filling strategy:
{{title}}, preferreplace_all_text(presentation_id, mappings={"{{title}}": "Results"}, page_ids=["<slide>"]) — scope it to the new slide so you don't rewrite the whole deck.
set_element_text per element (replaces all of that element'stext in one call; safe on empty elements).
set_element_box(presentation_id, element_id, x_pt, y_pt, width_pt?, height_pt?).
reorder_slides(presentation_id, slide_ids, insertion_index).set_z_order, group_elements, ungroup_elements.batch_update(presentation_id, requests=[...]) (see below).
render_page(presentation_id="<deck>", page_id="<slide>", size="MEDIUM") → PNG to inspect
diff_pages(presentation_id="<deck>", page_a="<slide>", page_b="<example_id>")
→ mismatch ratio (0.0 = pixel-perfect) + a visual diff imageRender after meaningful edits and confirm the slide looks correct before moving on.
prune_parked_slides(presentation_id="<deck>") → deletes ALL parked slidesThis removes the hidden palette. Always do this last. If you need a layout you never instantiated, do it before pruning — once pruned, that example is gone (no cross-deck copy to bring it back).
batch_updatebatch_update takes a list of raw Slides API request objects and applies them atomically (one write quota unit no matter how many sub-requests). Use it for operations without a dedicated tool, e.g. styling:
batch_update(presentation_id="<deck>", requests=[
{ "updateTextStyle": {
"objectId": "<el>", "textRange": {"type": "ALL"},
"style": {"bold": true, "foregroundColor": {"opaqueColor": {"themeColor": "ACCENT1"}}},
"fields": "bold,foregroundColor" } }
])updateShapeProperties, updateTextStyle, and updateSlideProperties require a `fields` mask — the tool warns if it's missing. Reference for request shapes: https://developers.google.com/workspace/slides/api/reference/rest/v1/presentations/request
Every tool makes a bounded number of API calls and returns trimmed output. To keep a session cheap and predictable:
list_slides / catalog_slides to find IDs; only get_page(..., raw=True)or get_presentation(..., raw=True) when you genuinely need full detail.
batch_update rather than many small calls.render_page / diff_pages hit the expensive thumbnail quota (300/min perproject, 60/min per user). Render specific pages you changed — never loop over a whole deck. Prefer MEDIUM size unless you need fine detail.
google-slides-mcp-auth.drive scope; user should re-run auth after enabling it on the consent screen.
re-run the auth command (or publish the consent screen).
example (full fidelity), not rebuilt it from scratch; render and diff_pages against the original example to see the delta.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.