We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/Kiran1689/storyblok-mcp-server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server
import json
from typing import Optional, Dict, Any, Literal, List
from httpx import AsyncClient
from mcp.server.fastmcp import FastMCP
from utils.api import (
build_management_url,
get_management_headers,
_handle_response,
create_pagination_params,
add_optional_params,
APIError,
)
from datetime import datetime
def register_assets(mcp: FastMCP, client: AsyncClient) -> None:
@mcp.tool()
async def fetch_assets(
page: Optional[int] = 1,
per_page: Optional[int] = 25,
search: Optional[str] = None,
folder_id: Optional[int] = None,
sort_by: Optional[Literal[
"created_at:asc", "created_at:desc",
"updated_at:asc", "updated_at:desc",
"short_filename:asc", "short_filename:desc"
]] = None,
is_private: Optional[bool] = None,
by_alt: Optional[str] = None,
by_title: Optional[str] = None,
by_copyright: Optional[str] = None,
with_tags: Optional[str] = None
) -> Any:
"""
Retrieve multiple assets from Storyblok Management API.
"""
try:
params = create_pagination_params(page, per_page)
add_optional_params(params, {
"search": search,
"in_folder": folder_id,
"sort_by": sort_by,
"is_private": "1" if is_private else None,
"by_alt": by_alt,
"by_title": by_title,
"by_copyright": by_copyright,
"with_tags": with_tags,
})
url = build_management_url("/assets")
resp = await client.get(url, params=params, headers=get_management_headers())
return _handle_response(resp, url)
except APIError as e:
return {"isError": True, "content": [{"type": "text", "text": str(e)}]}
@mcp.tool()
async def get_asset(id: str) -> Any:
"""Gets a specific asset by ID."""
try:
url = build_management_url(f"/assets/{id}")
resp = await client.get(url, headers=get_management_headers())
return _handle_response(resp, url)
except APIError as e:
return {"isError": True, "content": [{"type": "text", "text": str(e)}]}
@mcp.tool()
async def delete_asset(id: str) -> Any:
"""Deletes an asset from Storyblok."""
try:
url = build_management_url(f"/assets/{id}")
resp = await client.delete(url, headers=get_management_headers())
_handle_response(resp, url)
return {"content": [{"type": "text", "text": f"Asset {id} has been successfully deleted."}]}
except APIError as e:
return {"isError": True, "content": [{"type": "text", "text": str(e)}]}
@mcp.tool()
async def update_asset(
asset_id: int,
asset_folder_id: Optional[int] = None,
internal_tag_ids: Optional[List[int]] = None,
locked: Optional[bool] = None,
is_private: Optional[bool] = None,
publish_at: Optional[datetime] = None,
expire_at: Optional[datetime] = None,
focus: Optional[str] = None,
alt: Optional[str] = None,
title: Optional[str] = None,
source: Optional[str] = None,
copyright: Optional[str] = None,
meta_data: Optional[Dict[str, Any]] = None
) -> Any:
"""
Update an existing asset’s metadata or settings.
"""
try:
payload: Dict[str, Any] = {}
# Core fields
for field, value in [
("asset_folder_id", asset_folder_id),
("internal_tag_ids", internal_tag_ids),
("locked", locked),
("is_private", is_private),
("publish_at", publish_at.isoformat() if publish_at else None),
("expire_at", expire_at.isoformat() if expire_at else None),
("focus", focus),
]:
if value is not None:
payload[field] = value
# Metadata fields
md: Dict[str, Any] = meta_data or {}
for field, value in [
("alt", alt),
("title", title),
("source", source),
("copyright", copyright),
]:
if value is not None and field not in md:
md[field] = value
if md:
payload["meta_data"] = md
url = build_management_url(f"/assets/{asset_id}")
resp = await client.put(url, json=payload, headers=get_management_headers())
return _handle_response(resp, url)
except APIError as e:
return {"isError": True, "content": [{"type": "text", "text": str(e)}]}
@mcp.tool()
async def delete_multiple_assets(
ids: List[int]
) -> Any:
"""
Deletes multiple assets by numeric IDs using the Storyblok Management API.
"""
if not ids:
return {"isError": True, "content": [{"type": "text", "text": "ids list cannot be empty"}]}
try:
payload = {"ids": ids}
url = build_management_url("/assets/bulk_destroy")
resp = await client.post(url, json=payload, headers=get_management_headers())
return _handle_response(resp, url)
except APIError as e:
return {"isError": True, "content": [{"type": "text", "text": str(e)}]}
@mcp.tool()
async def bulk_move_assets(
ids: List[int],
asset_folder_id: int
) -> Any:
"""
Move multiple assets to a specified folder.
"""
if not ids:
return {"isError": True, "content": [{"type": "text", "text": "ids list cannot be empty"}]}
if not isinstance(asset_folder_id, int):
return {"isError": True, "content": [{"type": "text", "text": "asset_folder_id must be an integer"}]}
try:
payload = {
"ids": ids,
"asset_folder_id": asset_folder_id
}
url = build_management_url("/assets/bulk_update")
resp = await client.post(url, json=payload, headers=get_management_headers())
return _handle_response(resp, url)
except APIError as e:
return {"isError": True, "content": [{"type": "text", "text": str(e)}]}
@mcp.tool()
async def bulk_restore_assets(
ids: List[int]
) -> Any:
"""
Restores multiple previously deleted assets
"""
if not ids:
return {"isError": True, "content": [{"type": "text", "text": "ids list cannot be empty"}]}
try:
payload = {"ids": ids}
url = build_management_url("/assets/bulk_restore")
resp = await client.post(url, json=payload, headers=get_management_headers())
return _handle_response(resp, url)
except APIError as e:
return {"isError": True, "content": [{"type": "text", "text": str(e)}]}
@mcp.tool()
async def init_asset_upload(filename: str, size: int, content_type: str) -> Any:
"""Initializes asset upload and returns signed S3 upload URL."""
try:
url = build_management_url("/assets")
payload = {"filename": filename, "size": size, "content_type": content_type}
resp = await client.post(url, json=payload, headers=get_management_headers())
return _handle_response(resp, url)
except APIError as e:
return {"isError": True, "content": [{"type": "text", "text": str(e)}]}
@mcp.tool()
async def complete_asset_upload(asset_id: str) -> Any:
"""Completes the asset upload process after S3 upload."""
try:
url = build_management_url(f"/assets/{asset_id}/finish_upload")
resp = await client.post(url, headers=get_management_headers())
return _handle_response(resp, url)
except APIError as e:
return {"isError": True, "content": [{"type": "text", "text": str(e)}]}