Using the Storyblok MCP Server: A Practical Guide
Storyblok is the first headless CMS that works for developers & marketers alike.
The Storyblok MCP server uses a discovery-first approach instead of wrapping every API endpoint. The core tools (search, describe, and three execute tools) plus a specialized asset flow give you access to the Management API. This guide shows you how to use them.
New to the Storyblok MCP? Start with the setup documentation. For the architectural deep-dive on the benefits of the discovery approach works, read The Hidden Cost of Flat MCP Tool Lists.
The tools at a glance
Every Storyblok operation follows the same flow: search β describe β execute. Here's what each tool does:
Tool | What it does | When your agent calls it |
|---|---|---|
| Finds operations by keyword | When you describe what you want to do |
| Returns the schema for an operation | Before executing (cached after first call) |
| Runs read operations | Listing, fetching, querying |
| Runs write operations | Creating, updating, publishing |
| Runs delete operations | Deleting, purging (requires confirmation) |
Plus a two-step asset upload flow (upload_asset and upload_asset_finish) that keeps file bytes out of the MCP transport.
Step 1: Search for operations
Your agent calls search automatically when you describe what you want to do. You never call it directly.
Example:
You: "Add a blog post titled 'Launch week' to my Storyblok space [spaceID]." The agent searches the API catalog for operations matching "add blog post" or "create story". It gets back candidate operations (like createStory or createApproval) and picks the one that matches your intent.
What this means for you: Describe outcomes, not endpoints. You don't need to know that creating a story uses POST /v2/spaces/{space_id}/stories. Just say what you want.
Step 2: Describe the operation
After finding an operation, your agent calls describe to get its schema. This happens automatically (guardrails enforce it), and the schema gets cached in context for repeat use.
Continuing the example:
You: "Add a blog post titled 'Launch week' to my Storyblok space [spaceId]."
Agent: *...searches for relevant operation...*
[*calls* describe(operationId, "createStory")]
Here's the createStory operation:
Execute with: execute_mutating
Parameters:
- space_id (path, required) β integer
- publish (query) β boolean; if true, story is published on creation
- release_id (query) β integer; attach to a release
- disable_fe_editor (query) β boolean; disables visual editor for this story
- preset_id (query) β integer
- use_default_preset (query) β boolean
Request body (required): UpdateStoryRequest
Typical body shape for a story:
{
"story": {
"name": "Launch weeks",
"slug": "launch-weeks",
"parent_id": 0,
"content": { "component": "article" },
"tag_list": [],
"is_folder": false
}
}
Notes:
- content.component must be a valid root content type in the space (e.g. article, page).
- slug must be unique within its parent folder.
- parent_id places the story in a folder (omit or 0 for root).
- For publishing on create, add ?publish=1 via the publish param. The agent learned from describe that:
nameandslugare requiredpublishis optional (defaults tofalsefor drafts)- This routes to
execute_mutating(it's a write operation)
Watch for region-based operations: If describe shows no space_id parameter, the operation routes by region (eu, us, cn, ap, ca). Your agent should ask which region to use.
Step 3a: Execute read operations
Read operations (listing, fetching, querying) route through execute_readonly.
Example: List stories with specific fields
You: "Show me the 10 most recently updated stories. I only need their name, slug, and publish status."
Agent:
execute_readonly(operation: "listStories", parameters:
{"space_id":572524126162802,"sort_by":"updated_at:desc","per_page":10,"page":1}, fields:
["stories.name","stories.slug","stories.published","stories.unpublished_changes"]) // [Calls getStories with fields=name,slug,published and per_page=10]
Agent: Here are the 10 most recent stories:
βββββββ¬βββββββββββββββββββ¬βββββββββββββββββββ¬ββββββββββββ
β # β Name β Slug β Status β
βββββββΌβββββββββββββββββββΌβββββββββββββββββββΌββββββββββββ€
β 1 β Launch week 21 β launch-week-21 β Published β
βββββββΌβββββββββββββββββββΌβββββββββββββββββββΌββββββββββββ€
β 2 β Launch week 2026 β launch-week-2026 β Published β
βββββββΌβββββββββββββββββββΌβββββββββββββββββββΌββββββββββββ€
... Tips:
- Be specific about fields: "Give me the names and slugs" lets the agent pass a tighter
fieldsfilter and skip unnecessary fields - Set limits: "Show me 10 stories" is clearer than "list stories" for paginated operations
- Not all operations support pagination: check
pagination.total_pagesin responses
Step 3b: Execute write operations
Write operations (create, update, publish) route through execute_mutating. These are recoverable changes.
Example: Create a story
You: "Create a blog post titled 'Launch week', slug 'launch-week'. Leave it as a draft."
Agent:
Storyblok - execute_mutating(operation: "createStory", parameters:
{"space_id":123,"story":{"name":"Launch
week","slug":"launch-week","content":{"component":"article"}}}) (MCP)
Execute a mutating Storyblok API operation (behavior: 'idempotent' or unset).
Do you want me to proceed?
You: "Yes"
Agent: Created "Launch week" as a draft in My Project US.
- ID: 12345678910
- Slug: launch-week
- Status: draft Tip: Make sure your agent reads the plan back before executing. If it tries to skip confirmation and run immediately, ask it to slow down. Mutating operations can have unintended side effects (publishing early, wrong folder, schema overwrites).
Step 3c: Execute destructive operations
Destructive operations (deletes, purges) route through execute_destructive. These are irreversible and require explicit confirmation.
Example: Delete a story
You: "Delete the story titled 'Launch week'."
Agent: *...searches for relevant operation...*
[*calls* describe(operationId: "deleteStory")]
Agent:
Storyblok - execute_destructive(operation: "deleteStory", parameters:
{"space_id":123,"id":12345678910}) (MCP)
Execute a destructive Storyblok API operation (behavior: 'destructive').
Data may be permanently lost.
Do you want to proceed?
You: "Yes"
Agent: Deleted "Launch day" (ID 12345678910) from [Space Name]. Always verify before confirming: Re-read the story name and ID the agent quotes back. Make sure it matches what you intended to delete. The MCP won't stop you from deleting the wrong story.
Uploading assets: a two-step flow
Assets use a specialized two-step flow (upload_asset + upload_asset_finish) that keeps file bytes out of the MCP transport.
Example: Upload an image
You: "Upload sunset.jpg to Storyblok with alt text "Image of Sunset""
Agent:
Storyblok - upload_asset(space_id: 123, filename: "sunset.jpg", alt:
"Image of Sunset") (MCP)
Create an asset record in Storyblok and get a signed S3 upload URL.
Returns a ready-to-use curl command for environments with shell access
(Claude Code, Cursor), or a Storyblok asset manager link for manual upload.
After the file is uploaded to S3, call `upload_asset_finish` to finalize the
asset.
Do you want to proceed?
β― 1. Yes
Agent:
Bash command
curl -s -o /dev/null -w "%{http_code}\\n" -X POST
"<https://s3.amazonaws.com/a-us.storyblok.com>" \\
*...A whole bunch of other stuff...*
-F "file=@/Users/danielmendoza/sunset.jpg"
Upload sunset.jpg to the Storyblok S3 bucket
This command requires approval
Do you want to proceed?
β― 1. Yes
Agent:
Tool use
Storyblok - upload_asset_finish(space_id: 123, asset_id: 168411926216117)
(MP)
Finalize an asset upload after the file has been uploaded to S3 externally.
Call this after using a signed S3 URL (from `upload_asset`) to complete the
upload via curl or manual upload.
Do you want to proceed?
β― 1. Yes
Agent: Uploaded sunset.jpg to [Space Name].
- Asset ID: 168411926216117
- URL: <https://s3.amazonaws.com/a-us.storyblok.com/f/123/456/sunset.jpg>
- Alt text: Image of Sunset
How it works:
upload_assetregisters the file and returns a signed S3 URL + curl command- The agent (or you) uploads directly to S3
upload_asset_finishfinalizes the asset in Storyblok
If your agent has shell access, this is automatic. Otherwise, the agent will show you the curl command to run manually.
For additional information, visit the upload and replace assets documentation.
Full example: create and publish a story
Here's what a complete workflow looks like from a single prompt:
You: "Create a blog post titled 'Launch week', slug 'launch-week' in space [spaceId] and publish it."
Agent:
Tool use
Storyblok - search(query: "create story") (MCP)
Search for available Storyblok API endpoints. Returns the top 3 matching operations with
their operationId, summary, and behavior.
Always use this first when you don't know which operation to call. Then call `describe` with
the operationId to get all parameters, request body schema, and the `executeWith` field that
tells you which execute tool to call.
Do you want to proceed?
β― 1. Yes
Agent:
Tool use
Storyblok - describe(operationId: "createStory") (MCP)
Get full details for a Storyblok API operation. Returns all parameters (path, query) with
descriptions and schemas, the request body schema for write operations, available response
fields, the `executeWith` tool name to call next, and a `requiresRegion` flag when the user's
region must be confirmed before executing.
Always call this after `search` and before executing.
Do you want to proceed?
β― 1. Yes
Agent:
Tool use
Storyblok - execute_mutating(operation: "createStory", parameters:
{"space_id":572524126162802,"publish":true,"story":{"name":"Launch week
21","slug":"launch-week-21","content":{"component":"page","body":[]}}}) (MCP)
Execute a mutating Storyblok API operation (behavior: 'idempotent' or unset).
Do you want to proceed?
β― 1. Yes
Agent: Created and published. Story ID 168414172465922, live at /launch-week. What happened behind the scenes:
- 1Γ
search(find createStory): search(query: "create story") - 1Γ
describe(get schema for operation): describe(operationId: "createStory") - 1Γ
execute_mutating(create and publish)
You described the outcome. The agent handled the discovery and execution.
General tips for working with the Storyblok MCP
Be specific in your prompts
- "Show me the 10 most recent stories with names and slugs" is better than "list stories"
- Explicit field lists help the agent pass tighter filters to Storyblok
Watch for confirmations
- Mutating operations should show you the plan before running
- Destructive operations require explicit confirmation - always verify the ID
Region-based operations
- When needed your agent will ask for a region (
eu,us,cn,ap,ca)
The server is hosted
- New API endpoints appear automatically in search results
- No client updates needed when Storyblok adds new operations
Related Articles
- Read the architectural deep-dive to understand why this approach works