Blog

MCP | 10 min read | 2026-04-25 | Updated 2026-04-26 | By Variant Team

Connect Claude Code to an MCP Presentation Editor

Set up Claude Code with an MCP presentation editor, choose OAuth or bearer-token auth, test slide tools, troubleshoot the connection, and export a deck.

Author: Variant Team. Variant is built by a small team working on HTML-native presentation tools, MCP workflows, and agent-editable decks.

Short answer: add Variant as an MCP server in Claude Code, authenticate with OAuth or a scoped bearer token, restart Claude Code, and ask it to list your decks. If that works, Claude can create slides, edit them, render previews, and export files from the same conversation.

The setup is small. The details are where people lose time: which auth mode to use, how to confirm the tools loaded, what a good first test looks like, and how to debug a server that appears connected but cannot touch a deck.

This guide keeps the example concrete. We'll connect Claude Code to Variant, run a tiny end-to-end test, and use this exported sample as the target shape: download the MCP presentation editor demo deck.

#Quick answer

  • Add the MCP presentation editor to Claude Code's MCP config.
  • Use OAuth when you want normal interactive login.
  • Use a scoped bearer token when you need a headless or controlled setup.
  • Restart Claude Code after changing the config.
  • Test the connection with a small deck: list decks, create one slide, preview it, edit one element, then export.

#What you're actually connecting

MCP is the Model Context Protocol. It's a standard way for an agent like Claude Code to talk to a tool server: list available tools, call them with arguments, and get structured results back. When Claude Code is connected to an MCP presentation editor, every tool the editor exposes shows up as something Claude can call directly. No glue code, no copy-paste between tabs.

For a presentation editor, the tools are the obvious things you'd want: list decks, create a deck, get a slide, replace a slide, batch update several slides, preview a slide as an image, export the deck. Variant exposes those as decks.list, deck.create, deck.get, deck.update, deck.replaceAllSlides, deck.listSlides, deck.versions.list, deck.version.restore, deck.export, slide.get, slide.duplicate, slide.move, slide.replace, slide.edit, slides.batchUpdate, slide.preview, selection.get, and asset.upload. Each one is a single MCP tool call.

That last detail matters. When Claude wants to fix a typo on slide 4, it calls slide.edit with a targeted patch. It does not regenerate the whole deck, and it does not ask you to paste a slide back into the chat. The agent is editing your actual deck, in place, and the canvas updates while it works.

Claude Code applies a slide.edit call and the Variant canvas updates
Claude Code applies a slide.edit call and the Variant canvas updates

#Pick your auth: OAuth or bearer token

You have two ways to authenticate Claude Code against Variant. They produce identical capabilities. The difference is in how the credential is stored and rotated.

OAuth is the friendlier default for most humans. You click through a browser login once, Claude Code holds the token, and it refreshes on its own. Good for laptops, good for people who don't want to think about secrets management.

Bearer tokens are scoped, revocable strings you paste into the config. They're better for headless setups: a CI runner, a remote dev container, a teammate's machine where you don't want to bind credentials to your personal account. You generate one in Variant's settings, give it a scope, and treat it like any other API key.

Here's the OAuth version of the config. Open ~/.claude.json (or whichever Claude Code config file you're using) and add:

{
  "mcpServers": {
    "variant": {
      "transport": "http",
      "url": "https://app.variant.art/mcp",
      "auth": {
        "type": "oauth",
        "authorization_server": "https://app.variant.art/oauth"
      }
    }
  }
}

Restart Claude Code. The first time you ask it to do anything Variant-shaped ("list my decks"), it'll pop a browser window, you log in, and the token gets saved.

The bearer-token version looks like this:

{
  "mcpServers": {
    "variant": {
      "transport": "http",
      "url": "https://app.variant.art/mcp",
      "headers": {
        "Authorization": "Bearer ss_..."
      }
    }
  }
}

Replace ss_... with the token you generated. No browser flow, no restart loop. Claude Code will start using it immediately.

A practical tip: if your team is working on the same project, do not share a single bearer token. Generate one per person, or use OAuth. It makes revocation actually possible if a laptop walks off.

#Scopes you should think about

Variant tokens are scoped. Pick the smallest set you can live with.

  • Read-only: decks.list, deck.get, deck.listSlides, slide.get, slide.preview, selection.get, deck.versions.list. Useful when you want Claude to summarize decks or grab content for a doc but never touch them.
  • Edit: adds deck.update, slide.edit, slide.replace, slide.duplicate, slide.move, slides.batchUpdate, asset.upload. This is the workhorse scope for daily work.
  • Create + destructive: adds deck.create, deck.replaceAllSlides, deck.version.restore, deck.export. You probably want this on your main token but not on a CI token that just generates exports.

If you're connecting from a CI job that only needs to export a deck to PDF on every commit, give it a scope with deck.get and deck.export and nothing else. Tokens cost nothing.

#What to test after connecting

Don't skip this part. A connected MCP server is not the same as a working one. Run through these in order, and stop at the first failing step.

1. List your decks. Ask Claude Code: "List my Variant decks." You should get back a small set of titles and IDs. If you get an auth error here, your token or OAuth flow is wrong. If you get an empty list and you have decks, your token is scoped to the wrong workspace.

2. Read a slide. "Open the third slide of deck X and show me the HTML." This exercises slide.get. If the slide comes back as a blob of HTML and CSS, you're talking to the editor. If you get a "tool not available" error, your scope is too narrow.

3. Edit a slide in place. "Change the title on slide 1 to 'Q3 review'." This is the test that actually matters. Claude should call slide.edit, the canvas should update, and you should not see the rest of the slide regenerate. If the slide gets rewritten end to end, something is off in how the agent is approaching the task; nudge it with "edit only the title element, don't replace the slide."

4. Preview a slide. "Show me a preview of slide 2." slide.preview returns an image. Claude Code should render it inline. If the preview is blank, the slide may have an asset that isn't uploaded yet, or your render service is rate-limited.

5. Export. "Export this deck as a single-file HTML." You should get back a self-contained HTML file with everything inlined: fonts, images, scripts, the lot. PPTX and PDF should also work. If the HTML export errors, check that your deck doesn't reference an asset whose upload is mid-flight.

Single-file HTML export returned from the MCP presentation editor
Single-file HTML export returned from the MCP presentation editor

If all five pass, you're set. The rest is just using it.

#A real workflow that uses the connection

Here's how I actually work with this setup. Cover slide on a Monday morning, fast.

I start in Claude Code with a one-liner: "Make me a 6-slide deck about our Q3 launch. Use the brand we've been using on the marketing site. Save it to my Variant workspace." Claude reads our marketing repo for color and font cues, calls deck.create with a sensible title, then calls slides.batchUpdate once with all six slides at once. That's faster than generating six slides one by one because it's one MCP round trip instead of six.

Then I open the Variant canvas to look. The canvas and the underlying HTML stay in sync, so I can drag a heading down, switch to the code tab, see what changed, tweak a CSS variable, and the visual updates. If something needs deeper rework, I switch back to Claude Code and say: "On slide 3, replace the bar chart with a line chart, same data." Claude calls slide.edit and the chart on the canvas changes while I'm watching. I don't have to refresh.

Variant canvas and source code shown side by side
Variant canvas and source code shown side by side

When the deck is ready, I ask for deck.export as PPTX for the people who want PowerPoint, and as a single-file HTML to drop into a Notion page. Both come from the same source. No conversion drift, no fonts going sideways.

The moment this clicks for most people is the third or fourth edit, when they realize the agent is editing their actual deck and not producing a new copy each time.

#Common setup mistakes

A short list of things I've watched people trip on, in rough order of how often it happens.

  • Editing the wrong config file. Claude Code reads from a specific path. If you're editing a stale claude_desktop_config.json from an old install, your changes do nothing. Check the docs for the file Claude Code is actually loading.
  • Forgetting to restart. Claude Code reads MCP config at startup. New entries are not picked up live.
  • Trailing comma in JSON. Yes, still. The config file is plain JSON, not JSON5. If your other MCP servers stop working after you add variant, suspect a stray comma.
  • Token scoped to a different workspace. Variant supports multiple workspaces per account. A token is tied to one. If decks.list returns an empty array but you can see decks in the UI, your token is pointing somewhere else.
  • OAuth callback blocked. If you're on a corporate VPN that intercepts localhost callbacks, OAuth will hang. Use a bearer token instead.
  • Mixing transports. transport should be http for the hosted Variant MCP. If you copy a stdio config from another server's docs and adapt it, it won't connect.
  • Asking the agent to "regenerate" instead of "edit". This isn't a config issue, it's a prompt habit. Once you're connected, ask Claude to edit. Saying "regenerate slide 4 with a better headline" gets you a new slide. Saying "fix the headline on slide 4" gets you a one-line patch. The second one is what you want most of the time.

#Limitations and tradeoffs

A few things to know before you commit a workflow to this.

The hosted MCP server has rate limits. If you ask Claude Code to bulk-generate 80 slides in a single request, you'll hit them. slides.batchUpdate is the right answer for big changes; many small slide.edit calls will be slower and noisier.

slide.preview renders the slide on Variant's side. That's usually fast, but a slide with heavy custom JavaScript or a large fill image will take longer than a plain text slide. If you're scripting an export pipeline, prefer deck.export over previewing every slide.

Version restore is real but not unlimited. deck.versions.list shows you a window of recent versions, not the full history forever. If you need a permanent snapshot, export to JSON.

And the obvious one: connecting Claude Code to an editor means Claude can edit. If you point a high-permission token at an agent, expect the agent to use it. Scope tokens, and if you're nervous, start with a read-only scope and graduate.

#Try it

If you want to actually wire this up, use the OAuth flow or generate a scoped token, paste one of the snippets above into your Claude Code config, and run through the five tests. The setup is quick. The useful part is what happens after: Claude can make a deck, preview a slide, fix one element, and export the result without turning the whole thing into a guessing game.

#FAQ

Does Claude Code need to be restarted every time I change the MCP config? Yes. Claude Code reads MCP server entries at startup. After editing the config, fully quit and relaunch. You don't need to reauthenticate if you're using OAuth and the token is still valid.

Can I run Variant's MCP server alongside other MCP servers? Yes. The mcpServers object holds as many entries as you want. Variant doesn't conflict with Linear, GitHub, filesystem, or any other server. Tools from each show up under their own names.

What happens if my OAuth token expires while Claude Code is running? Claude Code will hit a 401 on the next tool call and start a refresh. If the refresh token is also expired, you'll get prompted to log in again. For long-running agents, bearer tokens are simpler because they don't expire on a short cycle.

How do I revoke access if a laptop is lost? Open Variant's settings, find the token, and revoke it. For OAuth sessions, the same screen lists active sessions and lets you sign them out. Once revoked, the next MCP call from that client returns 401.

Can other agents use this MCP server, or is it Claude Code only? Any MCP-capable client can connect: Codex, Cursor, custom agents you've built, anything that speaks MCP over HTTP. The config shape is similar. The tools are the same. Claude Code is just the most common client we see, which is why this post is written around it.

Will the agent overwrite my work if I'm editing the canvas at the same time? Variant tracks deck versions. If the agent makes a destructive change, deck.versions.list and deck.version.restore get you back. In practice, conflicts are rare because edits are scoped to specific slide elements, not whole-deck rewrites. If you're doing heavy concurrent editing, work on different slides or take turns.