Connect your ideas to MDSlides.

Create, edit and share presentations from your app, or ask your assistant to do it. The API and MCP server work on your private library and can return a public, read-only link.

1. Connect an assistant without a key (OAuth)

Claude.ai, the Claude desktop and mobile apps, ChatGPT and other MCP clients that support OAuth can connect directly. Add a custom connector with this URL:

https://mdslides.milab.es/mcp

The client opens an MDSlides page in your browser. Sign in with your emailed code if needed, review the requested permissions and approve. The page shows the address you will return to: continue only if you recognise it. You can untick write or AI access before approving; read access is always included. Revoke a connection at any time in Settings → API and MCP → Connected applications.

2. Get an API key

For the REST API and for assistants that accept a Bearer header (Claude Code, Codex, Cursor, VS Code). Sign in and open Settings → API and MCP → API keys (Spanish interface: Ajustes → API y MCP → Claves de API). Name the connection, choose its permissions and expiry, and copy the key: it is shown only once. Settings also offers ready-to-copy configuration for each client with your key filled in.

PermissionAllows
readList and read presentations, themes, collections and images. Always included.
writeCreate, edit, share and delete presentations.
aiTopic generation and image generation with the account's OpenAI (or Draw) key. Incurs charges on that account.

Keys expire after 30 days, 90 days or 1 year. Rotate issues a new secret with the same name and permissions and disables the old one immediately; Revoke deletes it. Each account can hold 10 keys. Store the key as MDSLIDES_API_KEY in a secret store or server environment, never in public frontend code. Recent activity in Settings lists the last operations made with each key or connected application.

3. REST API

Base URL: https://mdslides.milab.es/api/v1. Send Authorization: Bearer YOUR_KEY; request bodies are JSON. A machine-readable description is published at /api/v1/openapi.json (OpenAPI 3.1, no key needed): import it into Postman or a client generator.

Method and pathPurposeScope
GET /meCurrent credential, scopes and rate limitany
GET /format?section=Markdown referenceany
POST /validateCheck Markdown without savingany
GET /themesTheme IDs with light/dark mode, colours and fontsread
GET /collectionsCollections (lists) and their deck countsread
GET /presentations?q=&collection_id=&limit=&offset=List decks, newest change firstread
POST /presentationsCreate from md or topicwrite (+ai for topic)
GET /presentations/{id}Read one deck including its Markdownread
PATCH /presentations/{id}Change title, Markdown, theme or collectionwrite
DELETE /presentations/{id}Delete permanentlywrite
GET /presentations/{id}/pdfDownload the deck as a PDF fileread
GET /presentations/{id}/pdf-linkSigned PDF download link, valid one hourread
POST|DELETE /presentations/{id}/shareEnable or revoke the public linkwrite
GET /images?q=&presentation_id=&offset=Library images with ready-to-insert fencesread
POST /presentations/{id}/imagesGenerate an image for a deckwrite + ai

List your themes

curl https://mdslides.milab.es/api/v1/themes \
  -H "Authorization: Bearer $MDSLIDES_API_KEY"

Each theme has an id, name, kind, mode (light or dark), main colors and fonts. Built-in IDs include builtin:default, builtin:tokyo and builtin:new-york; personal themes use a UUID. Always send the ID, never the display name.

Discover and validate Markdown

Read the public format reference or fetch the same rules through the API. section is one of basics, text, slides, appearance, content, charts or themes.

curl 'https://mdslides.milab.es/api/v1/format?section=appearance' \
  -H "Authorization: Bearer $MDSLIDES_API_KEY"

curl https://mdslides.milab.es/api/v1/validate \
  -H "Authorization: Bearer $MDSLIDES_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"md":"## Results\nFirst sentence.\nSecond sentence."}'

Validation returns format_version, valid, slide counts and English errors/warnings with codes and one-based line and slide numbers. Syntax problems return HTTP 200 with valid: false. It checks common syntax issues, not visual fit or factual accuracy.

Create a presentation

curl https://mdslides.milab.es/api/v1/presentations \
  -H "Authorization: Bearer $MDSLIDES_API_KEY" \
  -H 'Content-Type: application/json' \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"title":"My presentation","md":"# Hello\n\n---\n\n## Next steps\n\n- Review\n- Publish","theme_id":"builtin:tokyo","share":true}'

A successful request returns 201:

{
  "id": "PRESENTATION_UUID",
  "title": "My presentation",
  "revision": 1,
  "theme_id": "builtin:tokyo",
  "collection_id": null,
  "created_at": "2026-10-10T12:00:00.000Z",
  "share_url": "https://mdslides.milab.es/view/SHARE_TOKEN",
  "edit_url": "https://mdslides.milab.es/presentations/PRESENTATION_UUID",
  "validation": { "valid": true, "errors": [], "warnings": [] }
}

Every creation runs the validator and returns its report in validation; the deck is saved even when it has warnings or syntax errors, so check the report and fix with PATCH if needed. edit_url opens the deck in the editor.

Retry safely with Idempotency-Key

Send a unique Idempotency-Key header (up to 200 visible ASCII characters, such as a UUID) when creating. Repeating the same request with the same key within 24 hours returns the original response with Idempotent-Replayed: true and creates nothing, including no second AI charge. Reusing a key with a different body returns 422 idempotency_key_reused; a repeat while the first request is still running returns 409 idempotency_in_progress. A failed request releases its key so you can retry it.

Generate a presentation from an idea

curl https://mdslides.milab.es/api/v1/presentations \
  -H "Authorization: Bearer $MDSLIDES_API_KEY" \
  -H 'Content-Type: application/json' \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"topic":"An introduction to teamwork","count":6,"language":"English","style":"Practical, with short examples"}'

Requires the ai permission and an OpenAI key saved in MDSlides Settings. It uses your selected model, incurs charges on your OpenAI account and adds model and usage to the response.

Request fields for creation

FieldMeaning
titleOptional, up to 160 characters. Otherwise inferred from the Markdown or generated.
mdMDSlides Markdown, up to 400,000 characters, with at least one visible slide.
topicAI generation instructions, up to 6,000 characters. Send exactly one of md or topic.
theme_idOptional. Defaults to builtin:default. The theme CSS is copied into the deck.
collection_idOptional collection UUID from GET /collections.
shareOptional boolean. Defaults to false.
count, language, styleAI only: 1–40 slides (default 8), slide language (default Spanish) and tone.

List, read, edit and delete

# Find decks by title
curl 'https://mdslides.milab.es/api/v1/presentations?q=teamwork&limit=20' \
  -H "Authorization: Bearer $MDSLIDES_API_KEY"

# Read one deck, including its Markdown and current revision
curl https://mdslides.milab.es/api/v1/presentations/PRESENTATION_UUID \
  -H "Authorization: Bearer $MDSLIDES_API_KEY"

# Edit: send the revision you read
curl -X PATCH https://mdslides.milab.es/api/v1/presentations/PRESENTATION_UUID \
  -H "Authorization: Bearer $MDSLIDES_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"revision":3,"title":"Teamwork, revised","theme_id":"builtin:new-york"}'

# Delete permanently
curl -X DELETE https://mdslides.milab.es/api/v1/presentations/PRESENTATION_UUID \
  -H "Authorization: Bearer $MDSLIDES_API_KEY"

Lists return presentations, has_more and next_offset; pass offset to fetch the next page (limit 1–100, default 50). PATCH accepts title, md (replaces the whole deck), theme_id (copies the new theme CSS) and collection_id (null removes it from its collection), plus the required revision. If the deck changed since you read it, for example in the editor, the response is 409 revision_conflict: read it again and reapply your change. Changing md also returns a validation report.

Images

curl https://mdslides.milab.es/api/v1/presentations/PRESENTATION_UUID/images \
  -H "Authorization: Bearer $MDSLIDES_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"prompt":"Editorial illustration of a team around a table, soft colours","ratio":"16:9","request_id":"A_UUID"}'

Generation uses the account image engine and its charges. Reuse the same request_id to retry without paying twice. The response includes markdown, an image fence you can insert into a slide with PATCH. GET /images lists existing library images with the same field.

Export as PDF

curl https://mdslides.milab.es/api/v1/presentations/PRESENTATION_UUID/pdf \
  -H "Authorization: Bearer $MDSLIDES_API_KEY" -o presentation.pdf

curl https://mdslides.milab.es/api/v1/presentations/PRESENTATION_UUID/pdf-link \
  -H "Authorization: Bearer $MDSLIDES_API_KEY"

The first call returns the file (application/pdf): one 16:9 page per visible slide with selectable text, the deck theme, images and charts, like Create PDF in the editor. Speaker notes are left out. Rendering takes a few seconds. The second returns download_url, a signed link that anyone can open for one hour to download the PDF without a key, plus expires_at, file_name and slide_count. A deck without visible slides returns 422 no_visible_slides.

Enable or revoke sharing

curl -X POST https://mdslides.milab.es/api/v1/presentations/PRESENTATION_UUID/share \
  -H "Authorization: Bearer $MDSLIDES_API_KEY" \
  -H 'Content-Type: application/json' -d '{}'

curl -X DELETE https://mdslides.milab.es/api/v1/presentations/PRESENTATION_UUID/share \
  -H "Authorization: Bearer $MDSLIDES_API_KEY"

Both return share_url: the active URL, or null after revocation. Revoking a key does not revoke existing public links.

Errors

Errors return English text and a stable code you can branch on:

{ "error": "Theme not found. Use list_themes or GET /api/v1/themes.", "code": "theme_not_found" }

Common codes: missing_token, invalid_token, insufficient_scope (with required_scope), unknown_parameter, invalid_parameter, md_or_topic_required, invalid_markdown, presentation_not_found, no_visible_slides, pdf_render_failed, theme_not_found, collection_not_found, revision_conflict, nothing_to_update, idempotency_key_reused, idempotency_in_progress, account_limit_reached, rate_limited, ai_key_missing, ai_quota_exceeded, upstream_error and service_unavailable. When an error comes from a provider message that has no English translation yet, the original text is kept in detail.

Limits

600 API/MCP requests per hour per key or connected application, 30 creation attempts per hour per account, 10 keys and 200 presentations per account, and 1 MB JSON bodies. Existing AI limits also apply. Every response carries RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset (seconds); a 429 adds Retry-After.

Browser apps (CORS)

The API, MCP endpoint and OAuth token endpoints answer cross-origin requests from any site, without cookies: a key must be sent explicitly in the header. Do not embed a key in a public website; call the API from your server, or use OAuth where available.

4. Connect your assistant with MCP

Endpoint: https://mdslides.milab.es/mcp. Transport: Streamable HTTP (stateless, JSON responses). Authentication: OAuth (see section 1) or Authorization: Bearer YOUR_KEY.

Claude Code

claude mcp add --transport http mdslides \
  https://mdslides.milab.es/mcp \
  --header "Authorization: Bearer $MDSLIDES_API_KEY"

Claude Code may store the header in its local configuration; keep that file private.

Codex

[mcp_servers.mdslides]
url = "https://mdslides.milab.es/mcp"
bearer_token_env_var = "MDSLIDES_API_KEY"

Make MDSLIDES_API_KEY available in the environment that starts Codex and restart it.

Cursor

// ~/.cursor/mcp.json
{
  "mcpServers": {
    "mdslides": {
      "url": "https://mdslides.milab.es/mcp",
      "headers": { "Authorization": "Bearer YOUR_KEY" }
    }
  }
}

VS Code

// .vscode/mcp.json
{
  "servers": {
    "mdslides": {
      "type": "http",
      "url": "https://mdslides.milab.es/mcp",
      "headers": { "Authorization": "Bearer ${input:mdslides-key}" }
    }
  },
  "inputs": [
    { "type": "promptString", "id": "mdslides-key", "description": "MDSlides API key", "password": true }
  ]
}

Claude.ai, Claude desktop and mobile, ChatGPT

Use OAuth: add a custom connector with https://mdslides.milab.es/mcp and approve access (section 1). No key is needed.

Tools

Tools appear according to the permissions of the key or connection.

ToolPurposeScope
get_format_referenceEnglish rules and examples; optional sectionany
validate_markdownCheck md before savingany
list_themes, list_collectionsTheme IDs with colours; collectionsread
list_presentations, get_presentationFind decks; read Markdown and revisionread
export_pdfPDF of a deck: a one-hour download_url; include_file also attaches the fileread
list_imagesLibrary images with ready-to-insert fencesread
create_presentationCreate from md or topic; optional idempotency_keywrite (+ai for topic)
update_presentationChange title, Markdown, theme or collection with revisionwrite
delete_presentationDelete permanentlywrite
set_presentation_sharingEnable or revoke a public linkwrite
generate_imageGenerate an image for a deckwrite + ai

Resources and prompts

Resources: mdslides://format (format reference), mdslides://themes and mdslides://presentations/{id} (the Markdown of each deck; the 50 most recent are listed). Prompts: create_deck (topic, slides, theme, language), convert_document (turn pasted text into slides) and improve_deck (review and edit a saved deck).

Try this instruction:

Read the MDSlides format reference and list my themes. Write six slides
about teamwork using Tokyo, with a shared confidentiality footer.
Validate the Markdown, fix errors, then create it and give me the edit link.

Supply actual data for charts and review the presentation before sharing.

5. Simple Markdown examples

Add | Apply all at the end of a formatting directive to apply it across the deck, including new slides. Without it, the directive applies to its own slide. A local setting overrides the deck default. In the editor, select the Apply all checkbox before inserting a format. Content blocks are inserted into all existing slides; shared headings are used on slides without a heading of the same level.

<!-- footer: Confidential | align: left | color: #dc2626 | size: 12 | Apply all -->
<!-- logo: url(https://example.com/logo.png) position(bottom-right) size(50px) | Apply all -->
<!-- title-align: right | Apply all -->
# Project update | Apply all

## First slide
First sentence.
Second sentence.

---
## Second slide
The shared footer, logo and heading also appear here.

Separate slides with --- on its own line. Use # for a cover and ## for a slide heading. A single newline creates a visible line break; an empty line starts a new paragraph. Lists, tables and fenced code blocks are supported. Speaker notes use <!-- notes: … --> and are omitted from public links.

Alignment and a confidentiality footer

<!-- title-align: right -->
<!-- valign: top -->
<!-- footer: Confidential | align: left | color: #dc2626 | size: 12 -->
## Quarterly results

A short explanation.

title-align: left|center|right aligns headings only. align: left|center|right aligns slide text. valign: top|center|bottom positions the heading and body vertically. These directives apply only to their slide. The footer stays near the bottom independently of body alignment. Edit its text, alignment, hex color and size (8–32 pixels). A confidentiality label is visible text; it does not restrict sharing or access.

Multiple lines with point markers

## Monthly results

```chart
type: line
labels: false
points: true

| Month | Sales | Target |
|-------|-------|--------|
| January | 12 | 15 |
| February | 18 | 18 |
| March | 16 | 20 |
```

Each numeric column is a series, up to seven. points: true displays point markers; false hides them. labels controls value labels. Themes set --chart-color-1 through --chart-color-7, --chart-text, --chart-grid and --chart-font. Other chart types are bar, horizontal-bar, pie, donut and waterfall. Use up to 60 data rows, decimal dots and no thousands separators.

Configuration references: Codex MCP documentation · Claude Code MCP documentation · Official MCP SDK · MCP authorization.

Back to MDSlides