# SlideForge (remote · api.slideforge.dev)

Deterministic, fully editable PowerPoint from typed slide intents. 150+ layouts, brand templates.

- Trust score: 74/100 (medium)
- Change this week: +11
- Registry status: active
- Liveness: live
- Owner verified: no
- Last scored: 2026-08-03

## Components

- remote · `api.slideforge.dev`: 74/100 (this document), [markdown](https://verifymcp.io/servers/dev-slideforge-slideforge/api.md), [page](https://verifymcp.io/servers/dev-slideforge-slideforge/api)
- pypi · `slideforge-mcp`: 13/100, [markdown](https://verifymcp.io/servers/dev-slideforge-slideforge/slideforge-mcp.md), [page](https://verifymcp.io/servers/dev-slideforge-slideforge/slideforge-mcp)

## Channel facts

- Endpoint: `https://api.slideforge.dev/mcp/`
- Transports: `streamable-http`
- Auth: `none`
- Version: `5.5.1`

## Trust breakdown

How this component scores in each security and reliability category. Every signal is checked automatically against the live server, and we only credit what we can confirm. Scores are 0–100 per category. Scoring method: https://verifymcp.io/docs/scoring (what has changed: https://verifymcp.io/docs/scoring/changelog)

Scored 2026-08-03.

- **Endpoint Security**: 92/100
  - The endpoint's TLS certificate is valid, in date, and uses a strong key.
  - Authorisation is enforced on tool calls, advertised via RFC 9728 protected-resource metadata. Discovery is public, which costs nothing: no tool can be invoked without a token.
  - HTTPS is enforced; there's no plaintext access path.
  - HSTS check failed: the Strict-Transport-Security header is absent.
  - DNSSEC check failed: this domain isn't protected by DNSSEC.
  - The authorisation server supports Client ID Metadata Documents, the current MCP client-registration mechanism.
- **Transport & Reachability**: 100/100
  - Verified streamable-http transport via a live MCP handshake.
- **Schema Quality & AI Usability**: 53/100
  - 100% of prompts and resources have a non-trivial description (not blank, and not just the item's name).
  - AI-judged instruction clarity (fair).
  - Context-footprint check failed: tool/resource definitions use about 5300 tokens (~588/item across 9 items; 7 tools + 2 resources), over budget; trim descriptions and params.
  - Usage-examples check failed: none of the tools include examples.
- **Stability & Change Management**: 27/100
  - Stability observed for 8 of 30 days with no destabilising changes; credit accrues until the full window elapses.
- **Tool Coverage**: 97/100
  - 100% of tools have a non-trivial description (not blank, and not just the tool's name).
  - 91% of tool parameters carry a description.
- **Capabilities**: 60/100
  - Spec-recency check failed: implements MCP spec 2025-03-26; the latest is 2026-07-28.
  - Supports UI / widget rendering.

## Install

### Claude

```bash
claude mcp add --transport http dev-slideforge-slideforge https://api.slideforge.dev/mcp/
```

### Codex

```toml
[mcp_servers.dev-slideforge-slideforge]
url = "https://api.slideforge.dev/mcp/"
```

### opencode

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "dev-slideforge-slideforge": {
      "type": "remote",
      "url": "https://api.slideforge.dev/mcp/",
      "enabled": true
    }
  }
}
```

### OpenClaw

```bash
openclaw mcp add dev-slideforge-slideforge --url https://api.slideforge.dev/mcp/ --transport streamable-http
```

### Hermes

```yaml
mcp_servers:
  dev-slideforge-slideforge:
    url: "https://api.slideforge.dev/mcp/"
```

### Other

```json
{
  "mcpServers": {
    "dev-slideforge-slideforge": {
      "type": "http",
      "url": "https://api.slideforge.dev/mcp/"
    }
  }
}
```

The mcpServers block is a cross-client convention. Remote transports vary, so check your client's docs.

## Changelog

Every change recorded for this component, newest first. Days that predate change tracking, or that we cannot explain, say so: "we were watching and nothing happened" and "we were not watching" are different claims.

### 2026-08-03 (score 74, +1)

- [security] Resource “SlideForge Result Card” now points somewhere else: ui://slideforge/result-card/v19 → ui://slideforge/result-card/skybridge/v19
- [security] Tool “create_slide” rewrote its description, which is the text the model reads
- [functional] Schema quality: poor → fair
- [cosmetic] “create_slide” reworded the description of “imagery_tag”

### 2026-08-02 (score 73, +1)

- [security] Resource “SlideForge Result Card” now points somewhere else: ui://slideforge/result-card/v19 → ui://slideforge/result-card/skybridge/v19
- [security] Tool “create_deck” rewrote its description, which is the text the model reads
- [security] Tool “create_slide” rewrote its description, which is the text the model reads
- [cosmetic] “manage_account” added an optional parameter “severity”
- [cosmetic] “manage_account” reworded the description of “action”
- [cosmetic] “manage_account” reworded the description of “category”
- [cosmetic] “manage_account” reworded the description of “message”

### 2026-07-31 (score 72, +7)

- [functional] We updated how we score, so this day's move reflects our rubric, not a change to the server

### 2026-07-30 (score 65, +1)

No change was recorded against any check on this day. Stability & Change Management went from 10 to 13. That category is still filling its 30-day observation window: 3 days of observed history at the previous scan, 4 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-07-28 (score 64, +1)

No change was recorded against any check on this day. Stability & Change Management went from 3 to 7. That category is still filling its 30-day observation window: 1 days of observed history at the previous scan, 2 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-07-27 (score 63, +1)

- [functional] We updated how we score, so this day's move reflects our rubric, not a change to the server

### 2026-07-26 (score 62)

First indexed and scored.

## MCP tools (7)

### `browse_catalog` (~495 tokens)

Browse SlideForge's Catalog (Unified Discovery)

Browse the SSG catalog progressively. No args -> form overview (when-to-use, bound fields, variant counts). family=<form> -> variant one-liners. q=<text> -> ranked search. variant=/prior_id= -> example payload. type=schema + family -> a compact family-level variant chooser (not a sendable contract); type=schema + family + variant -> that variant's exact payload contract (JSON Schema, capacity, field mapping, examples). Free. Code path: type=widgets = the add_widget() catalog (name=<widget> for its contract + thumbnail); type=helpers = python-pptx helper signatures. type=themes + an uploaded theme_id -> that template's branded FURNITURE layouts (its own cover/agenda/divider/closing slides + fill schemas + previews) — render via create_slide(form=template_layout, theme_id, data={layout, fills}).

Input parameters:

- `family` (string)
- `limit` (integer): Max results (with q= or family=).
- `name` (string): Widget name (with type=widgets): returns the full contract + worked example + a rendered thumbnail.
- `offset` (integer): Pagination offset (with q= or family=).
- `prior_id` (string)
- `q` (string): Semantic search across all variants; returns ranked form/variant matches with scores.
- `source` (string): Theme source filter (with type=themes). Default all (built-in + your saved).
- `theme_id` (string): With type=themes: an uploaded theme's id -> its branded furniture layouts + fill schemas (render via create_slide(form=template_layout)).
- `top` (integer): Max results (with type=themes).
- `type` (string): Omit for the form overview (or family=/q= to drill in). schema (+family, optionally +variant=) = schema-first discovery: family only returns a compact variant chooser; family+variant returns that var…
- `variant` (string)

### `plan_slide` (~272 tokens)

Plan a Slide - Form + Variant Candidates

Plan before rendering: send a short brief, get ranked candidates + a separated verdict — route (which slide: selected|needs_confirmation|ambiguous), input (can it render: ready|extractable_from_brief|needs_structured_data) and next_action. Free (one embedding). Then call create_slide with the chosen form(+variant). route.confidence: calibrated = measured P(route correct) with label high/medium/low cut on it; retrieval_score/retrieval_margin = the raw family-aggregated classifier values (not probabilities; margin can be negative when families contest); source = classifier | structural_router (LLM-rescued). candidate_margin on the top candidate = literal gap between the two shown scores.

Input parameters:

- `brief` (string, required)
- `escalate` (boolean): Default true: on a low-confidence route the plan runs the SAME LLM rescue create_slide would (small COGS on that tail only), so plan and create always agree. Set false for a classifier-only, fully fr…
- `top` (integer)
- `variant_policy` (string): production_safe: if the top routed variant is draft/beta, the family's demo-safe sibling leads and route reports both best_semantic and best_production_safe.

### `create_slide` (~2508 tokens)

Create or Inspect a Slide

Create ONE slide from a structured intent in ONE call: pick a `form` from the menu and put your content in the typed fields (placed on the slide as given), or pass a `brief` and let the server route it. Fields tagged (per-form) bind only where the form has that slot — ignored-with-warning elsewhere; see each form's `binds` in browse_catalog.

BLOCKED ($0)? If an error has `can_autofix:true`, merge its `patch` into the args at `patch_target`. Unchanged retries repeat the block. New form: browse_catalog(type=schema) first.


FORM MENU:
  agenda_list: an ordered list of sections/topics to walk through
  bar_rank_chart: bars comparing magnitudes across categories
  calendar_grid: events on a real calendar - week planner (day x hour) or month grid with event chips (data.events)
  card_grid: several equal, unordered peer blocks (features, options, pillars)
  case_story: one named story told as evidence: challenge, action, measured result
  comparison_matrix: options x criteria grid: data.columns x data.rows
  cycle_flow: a closed loop of ordered stages where the last feeds the first (recurring process)
  data_table: a plain factual table of records by fields
  editorial_split: two side-by-side halves in contrast (before/after, problem/solution)
  funnel: a quantity narrowing through ordered stages
  gantt_plan: tasks as bars across named periods on a schedule grid
  gauge_score: one score on a dial against a scale
  hero_statement: a statement slide: covers (typographic/image-led/exec), from->to / thesis-quote transitions, contact or next-steps closings
  hub_spoke: one central element with several elements connected around it
  image_story: a picture shown WHOLE (uncropped) beside/above narrative text - photo story, narrative
  kpi_metrics: a board of headline metric cards; data.sections (Highlights/Risks/Asks) makes it an exec summary / QBR snapshot
  layer_stack: stacked layers where higher sits on, and depends on, lower
  linear_flow: ordered process stages read left…

Input parameters:

- `allow_fabrication` (boolean): Brief mode only: by default a bare brief on a DATA form (kpi/funnel/comparison/…) returns status=would_fabricate at cost:0 rather than INVENT the numbers/entities. Supply the data as typed fields to…
- `allow_low_confidence` (boolean): Brief routing only: by default a brief that doesn't match a form clearly returns status=needs_confirmation + candidates at cost:0 (no guessed render). Set true to render the top guess and bill it. De…
- `allow_truncation` (boolean): By default, supplying MORE items than a form holds is a blocking error (it would drop your data) — the response names the dropped count + a suggested_split. Set true to render the capacity subset any…
- `allow_variant_fallback` (boolean): If the pinned variant is unknown, render the form's default variant (with a warning) instead of rejecting. Default false.
- `blocks` (array): list: [{"label","sub","detail":[str],"emphasis","icon":lucide-name,"metric":{value,label}}]
- `brief` (string): prose fallback / extra context for fills
- `caution` (string): one-line risk / caveat callout (per-form).
- `code` (string): Python code defining build(prs). Canvas 13.33×7.5", coords in inches. Pre-imported: Presentation, Inches, Pt, Emu, RGBColor, MSO_ANCHOR, PP_ALIGN. Helpers: add_text_box(slide, left, top, w, h, text,…
- `context` (string): one-line subtitle/standfirst
- `data` (object): family-specific payload — see the documented shapes
- `date` (string): date callout (per-form).
- `detail` (string): Response verbosity. Default `compact`: status, form/variant, fidelity (verbatim|mixed|ai_completed), warnings[]/errors[] (only when present), urls, cost. `full` adds a debug object (engine internals,…
- `dry_run` (boolean): Free pre-commit check (intent or mode=code), cost:0, no PPTX: status + warnings/errors, plus fidelity_forecast (verbatim|mixed|ai_completed|would_reject) and which fields bind vs get authored. Fix er…
- `force_render` (boolean): On completed_with_errors, pptx_url is null (broken slide). Set true to get it anyway. No cost/status effect.
- `form` (string): the form menu pick (see description) — the routing field
- `form_description` (string)
- `headline` (string): the assertion-style slide title
- `highlight` (string): one-line emphasis callout (per-form).
- `image_prompt` (string): generate an image when no image_src (+$0.05)
- `image_src` (string): https URL | asset:<id> for image-bearing forms
- `imagery` (string): Cover/section-divider imagery: photo (default — curated stock photo, half-bleed), wash (abstract color wash), off (typographic only). Content slides are never photo-decorated.
- `imagery_tag` (string): Industry bucket for cover/section photos. Omit = general; `education` for classrooms.
- `include_preview` (string): Inline-preview PAYLOAD only (not execution). Default: default (768px). none omits the inline image and returns just the URLs — it does NOT change sync/async. Use `wait` to control execution.
- `job_id` (string): Previous job ID (for mode=status, or mode=code patching)
- `language` (string): Target language (default: en)
- `logo_id` (string): Optional brand logo (from upload_asset purpose=logo) drawn as chrome on content slides; covers/section breaks stay clean.
- `metric` (object)
- `min_font_pt` (number): Binding type floor for prose (exhibit furniture has its own). Type grows to meet it; content that can't fit is a $0 min_font_not_met naming the size needed — allow_truncation renders the fitting subs…
- `mode` (string): Default: structured intent / brief. safe = validate-then-render in ONE call (renders + bills only if faithful; else $0 invalid report with the fix — recommended, no dry_run round-trip). code = python…
- `name` (string)
- `quality_profile` (string): Thresholds layout.presentation_ready is judged against (executive strictest). Measurement only — never blocks a render or changes cost.
- `replacements` (array): String replacements on loaded code [{old, new}] (for mode=code with job_id)
- `source_note` (string): source / footnote line (per-form).
- `styling` (string): Subject-informed palette + designed cover on default themes (on by default; the design note names the choice). clean = neutral look. Pinned themes never take it.
- `subject` (string): central entity for forms that have one — hub label, org root, section #, fork origin, media label (per-form).
- `takeaway` (string): optional verdict band (per-form). Put the so-what in the headline; add only for a verdict the title can't carry — not every slide.
- `theme_id` (string): Optional theme id from browse_catalog(type=themes). Omit for Default (slideforge_standard).
- `variant` (string): pin a specific variant within the form (list them via browse_catalog). Unknown variant -> rejected ($0) with the valid list; set allow_variant_fallback to render the family default instead.
- `variant_policy` (string): Routed-variant maturity policy: production_safe = if the ROUTED variant is draft/beta, render the family's demo-safe sibling instead (warning names both). Never overrides an explicit variant=. Defaul…
- `verify` (string): mode=code tier. Default `lint`: static geometry linter (overlap/off-canvas/zero-size) + composer content validators — no LLM. `lint+vlm` adds a VLM second-look (~+3s) and makes a blank/contentless re…
- `wait` (string): AI-image slides block ~10-15s; `false` returns a job_id to poll, not block (mode=brief).

### `create_deck` (~613 tokens)

Create Multi-Slide Deck

Create a WHOLE deck in one call: `slides` is a list of create_slide intents (same form menu + data shapes — see create_slide). Slides fill in parallel and merge into one themed PPTX with page numbers. Include furniture: a hero_statement cover, section_divider breaks, and a closing (hero_statement variant=contact_closing via blocks-free slots).

BLOCKED ($0)? If an error has `can_autofix:true`, merge its `patch` into the args at `patch_target`. Unchanged retries repeat the block. New form: browse_catalog(type=schema) first.



Also: mode=assemble merges existing slide job_ids as-rendered (free; theme_id does NOT re-theme them — render with create_deck(slides=[…], theme_id=…) for a unified theme); mode=fork clones a deck (free).
Polling: deck_id == job_id — manage_account(action=job, job_id=<deck_id>).

Input parameters:

- `allow_partial` (boolean): Non-regret default: if any slide fails, the deck is NOT billed (cost:0) and pptx withheld — the response carries repair_actions (assemble the completed children, free). Set true to render + bill the…
- `deck_id` (string): Existing deck ID (for mode=fork, or mode=render to update)
- `dry_run` (boolean): Deck-level free pre-flight (cost:0, NO render/PPTX): returns a per-slide validation manifest [{i, form, fidelity_forecast, status, errors}] so you can fix bad slides before spending. A deck is one ar…
- `force_render` (boolean): If any slide is completed_with_errors, deck pptx_url is null. Set true to get it anyway; complete slides stay downloadable via their per-slide job_id either way. No cost/status effect.
- `job_ids` (array): Slide job IDs to merge (for mode=assemble)
- `language` (string): Target language
- `logo_id` (string): Optional brand logo (from upload_asset purpose=logo) applied as chrome to every content slide in the deck.
- `mode` (string): Default render. assemble/fork are free deck plumbing.
- `name` (string)
- `slides` (array): each item is a create_slide intent (same form menu, typed fields, and data shapes as create_slide).
- `strict_policy` (object): Optional CI-style gate for automated report pipelines. dry_run returns policy_result; render returns rejected/cost:0 if the policy fails.
- `styling` (string): Deck-level topical-design switch, inherited by every slide (a slide-level styling wins). See create_slide.styling.
- `theme_id` (string)
- `title` (string): Deck title (PowerPoint metadata)

### `translate_deck` (~222 tokens)

Translate PPTX

Translate a PPTX deck preserving all formatting. $0.02/slide. Supports 32 languages (Latin, Cyrillic, Greek scripts). Provide job_id (from a previous create_slide/create_deck), pptx_url, or pptx_base64.

Input parameters:

- `concise_mode` (boolean): Prefer shorter translations for tight text boxes
- `include_notes` (boolean): Translate speaker notes (default false)
- `include_preview` (string): Wait+embed preview (default=wait)
- `include_tables` (boolean): Translate table cells (default true)
- `job_id` (string): Source: previous slide/deck job ID (preferred — no file transfer needed)
- `name` (string): Job name
- `pptx_base64` (string): Source: Base64-encoded .pptx (max ~10 MB)
- `pptx_url` (string): Source: HTTPS URL to .pptx
- `source_language` (string): Source language or 'auto' (default auto)
- `target_language` (string, required): Target language (required)

### `upload_asset` (~413 tokens)

Upload or Generate Asset

Upload a logo, theme PPTX, image, or document — or AI-generate an image.

Purposes:
• logo — company logo for chrome (PNG/JPG/SVG, max 5MB) → logo_id
• image — image for the Image component (max 10MB) → asset_id
• theme — company template PPTX → theme_id; slides with it render NATIVELY on the template (masters/layouts/chrome)
• generate_image — AI-generate via `prompt` → asset_id ($0.05)
• translate — PPTX to translate → deck job_id ($0.02/slide; requires `target_language`)
• pdf — PDF → editable slides; pass `target_language` to also translate

For files >3MB on purpose=pdf, purpose=translate, or purpose=theme, omit `data` — a drop-zone appears in the result card and bytes never pass through the agent.

Input parameters:

- `data` (string): Base64-encoded file content. Required for logo/image/theme/translate. Optional for pdf — omit to get a drop-zone (recommended for files >3MB).
- `filename` (string): Original filename (for type detection)
- `model` (string): Explicit gateway model ID. Overrides `quality`.
- `position` (string): Logo position: top-left / top-right / bottom-left / bottom-right
- `prompt` (string): Image description (required when purpose=generate_image)
- `purpose` (string, required): Asset type (required)
- `quality` (string): draft = Flux Schnell. balanced (default) = Gemini Flash Image. premium = Imagen 4 Fast. Overridden by `model`.
- `size` (string): Image dimensions for generate_image (default 1024×1024)
- `target_language` (string): Required for purpose=translate. Optional for purpose=pdf — chains pdf→pptx→translate in one call.
- `theme_name` (string): Name for extracted theme (purpose=theme)

### `manage_account` (~685 tokens)

Account & History

Account info, billing, job history, feedback, and data controls. All free.
Actions: status (balance+plan), usage (spend breakdown), jobs (history), job (single job detail — slide jobs include `quality_warnings[]`; deck jobs add `slides_completed/slides_failed/failed_slides[]`), feedback (submit), onboarding (capabilities overview), webhooks/webhook_add/webhook_remove/webhook_test (register a push endpoint so you don't poll async jobs to terminal), download_url (mint a fresh short-TTL single-use PPTX download link for an owned job — use when a result carries no inline URL), security_status (retention + access-model + deletion posture), delete_job (irreversibly delete a job + all versions + their files)
Action delete_asset irreversibly deletes a user-owned uploaded/generated image asset.

Input parameters:

- `action` (string, required): Operation (required). feedback → report a defect or request against a render; pass job_id so it is actionable, and ask the user before filing. reports → list report types; webhook_add registers a pus…
- `asset_id` (string): Image asset ID (for action=delete_asset). Logos are content-addressed/shared and are not deleted by this action.
- `category` (string): Feedback category (for action=feedback). The first nine are slide-quality categories — pair them with job_id.
- `days` (integer): Lookback period (for action=usage, default 30)
- `detail` (boolean): For action=status only: default false masks identity fields; true returns full email/user_id diagnostics for the authenticated user.
- `events` (array): Event types to subscribe to (for action=webhook_add; default all): job.completed, job.failed, deck.completed, deck.partial, deck.failed.
- `include_children` (boolean): For action=jobs: include deck child slides (each carries parent_deck_id) so a deck's slides are discoverable by listing. Default false (parents only). Deck rows roll child cost up to the deck.
- `include_preview` (string): Preview (for action=job)
- `job_id` (string): Job ID (for action=job, action=download_url and action=delete_job)
- `limit` (integer): Max jobs (for action=jobs, default 10)
- `message` (string): What went wrong or what you want, in the user's own words (for action=feedback).
- `severity` (string): For action=feedback: `bug` = it is broken, `quality` = it rendered but reads poorly, `suggestion` = a request. Defaults to suggestion, so file real defects explicitly or they are triaged as wishes.
- `slug` (string): Report slug (for action=reports — returns one report's full metadata; omit to list all).
- `status` (string): Filter (for action=jobs): queued/generating/complete/failed
- `url` (string): HTTPS endpoint to receive events (for action=webhook_add). Must be public HTTPS (private/loopback rejected).
- `webhook_id` (string): Webhook subscription id (for action=webhook_remove / webhook_test).

## Diagnostics

Captured diagnostic sections: TLS, DNSSEC, Authorisation, Transports. The full working is on the page: https://verifymcp.io/servers/dev-slideforge-slideforge/api#diagnostics

## Score history

- 2026-08-03: 74
- 2026-08-02: 73
- 2026-08-01: 72
- 2026-07-31: 72
- 2026-07-30: 65
- 2026-07-29: 64
- 2026-07-28: 64
- 2026-07-27: 63
- 2026-07-26: 62

## Links

- Remote endpoint: https://api.slideforge.dev/mcp/
- Repository: https://github.com/smartdatabrokers/slideforge-mcp
- Changelog RSS feed: https://verifymcp.io/servers/dev-slideforge-slideforge/api/changelog.xml
- Changelog JSON feed: https://verifymcp.io/servers/dev-slideforge-slideforge/api/changelog.json
- HTML version of this page: https://verifymcp.io/servers/dev-slideforge-slideforge/api
