Skip to main content
Glama

Visual stories: create a private story with scenes

create_visual_story

A story explained in scenes ("visa vad som hände"): bubbles, a timeline, before and after, flows, each scene answering one question. Private to them; never publishes. Numbers from a source you have; every claim marked observed, derived or hypothesis. First: use_tool list_story_templates with an id gives a skeleton; dry_run checks it. A table that just animates: create_data_story.

Input Schema

NameRequiredDescriptionDefault
recipeYesschemaVersion 2: get a skeleton with use_tool list_story_templates {id}, then fill it.
dry_runNoCheck it and return the outline and any issues, saving nothing.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed8 schema fields changed
    • removedInput schema / $schema
      Removed value: -"http://json-schema.org/draft-07/schema#"
    • removedInput schema / additionalProperties
      Removed value: -false
    • changedInput schema / properties / dry_run / description
      Previous value: -"Check and return the outline without saving anything."New value: +"Check it and return the outline and any issues, saving nothing."
    • changedInput schema / properties / recipe / additionalProperties
      Previous value: -falseNew value: +{}
    • addedInput schema / properties / recipe / description
      Added value: +"schemaVersion 2: get a skeleton with use_tool list_story_templates {id}, then fill it."
    • removedInput schema / properties / recipe / properties
      Removed value: -{
      -  "datasets": {
      -    "items": {
      -      "additionalProperties": false,
      -      "properties": {
      -        "currency": {
      -          "maxLength": 8,
      -          "type": "string"
      -        },
      -        "derived": {
      -          "additionalProperties": false,
      -          "description": "For a computed dataset: how, and from which datasets.",
      -          "properties": {
      -            "from": {
      -              "items": {
      -                "type": "string"
      -              },
      -              "type": "array"
      -            },
      -            "method": {
      -              "maxLength": 200,
      -              "type": "string"
      -            }
      -          },
      -          "required": [
      -            "method",
      -            "from"
      -          ],
      -          "type": "object"
      -        },
      -        "gapFill": {
      -          "description": "Only set this to fill gaps, and say so in limits.",
      -          "enum": [
      -            "none",
      -            "step",
      -            "linear"
      -          ],
      -          "type": "string"
      -        },
      -        "id": {
      -          "maxLength": 32,
      -          "type": "string"
      -        },
      -        "label": {
      -          "maxLength": 40,
      -          "type": "string"
      -        },
      -        "metric": {
      -          "maxLength": 40,
      -          "type": "string"
      -        },
      -        "ref": {
      -          "additionalProperties": false,
      -          "description": "Instead of x + series: the `ref` fetch_dataset returned. The server reads the rows (and the source, and the entities) itself — nothing to resend on later edits.",
      -          "properties": {
      -            "dataset": {
      -              "type": "string"
      -            },
      -            "from": {
      -              "type": "number"
      -            },
      -            "pick": {
      -              "items": {
      -                "type": "string"
      -              },
      -              "type": "array"
      -            },
      -            "region": {
      -              "type": "string"
      -            },
      -            "to": {
      -              "type": "number"
      -            },
      -            "top": {
      -              "type": "number"
      -            }
      -          },
      -          "required": [
      -            "dataset"
      -          ],
      -          "type": "object"
      -        },
      -        "series": {
      -          "items": {
      -            "additionalProperties": false,
      -            "properties": {
      -              "entity": {
      -                "type": "string"
      -              },
      -              "v": {
      -                "description": "One per period; null = not observed. A null is shown as a gap, never filled.",
      -                "items": {
      -                  "type": [
      -                    "number",
      -                    "null"
      -                  ]
      -                },
      -                "type": "array"
      -              }
      -            },
      -            "required": [
      -              "entity",
      -              "v"
      -            ],
      -            "type": "object"
      -          },
      -          "maxItems": 60,
      -          "type": "array"
      -        },
      -        "source": {
      -          "description": "sources[].id (not needed with `ref`).",
      -          "type": "string"
      -        },
      -        "unit": {
      -          "description": "'%', 'mdr USD', 'personer'. Required: numbers without a unit can't be compared.",
      -          "maxLength": 16,
      -          "type": "string"
      -        },
      -        "x": {
      -          "description": "The periods, rising: numbers (years) OR ISO 8601 dates / timestamps WITH an offset ('2026-10-30T09:30:00-04:00'). Never mix. Hour data stays hours. Leave out when you give `ref`.",
      -          "items": {
      -            "type": [
      -              "number",
      -              "string"
      -            ]
      -          },
      -          "maxItems": 1500,
      -          "type": "array"
      -        }
      -      },
      -      "required": [
      -        "id",
      -        "metric",
      -        "unit"
      -      ],
      -      "type": "object"
      -    },
      -    "maxItems": 8,
      -    "type": "array"
      -  },
      -  "entities": {
      -    "description": "Things that keep their identity from scene to scene.",
      -    "items": {
      -      "additionalProperties": false,
      -      "properties": {
      -        "id": {
      -          "maxLength": 32,
      -          "type": "string"
      -        },
      -        "label": {
      -          "maxLength": 40,
      -          "type": "string"
      -        },
      -        "type": {
      -          "maxLength": 16,
      -          "type": "string"
      -        }
      -      },
      -      "required": [
      -        "id",
      -        "label"
      -      ],
      -      "type": "object"
      -    },
      -    "maxItems": 60,
      -    "type": "array"
      -  },
      -  "events": {
      -    "items": {
      -      "additionalProperties": false,
      -      "properties": {
      -        "at": {
      -          "description": "When it HAPPENED.",
      -          "type": [
      -            "number",
      -            "string"
      -          ]
      -        },
      -        "id": {
      -          "maxLength": 32,
      -          "type": "string"
      -        },
      -        "label": {
      -          "maxLength": 100,
      -          "type": "string"
      -        },
      -        "publishedAt": {
      -          "$ref": "#/properties/recipe/properties/datasets/items/properties/x/items",
      -          "description": "When it was PUBLISHED (news). Different from at."
      -        },
      -        "source": {
      -          "type": "string"
      -        }
      -      },
      -      "required": [
      -        "id",
      -        "at",
      -        "label"
      -      ],
      -      "type": "object"
      -    },
      -    "maxItems": 40,
      -    "type": "array"
      -  },
      -  "flows": {
      -    "items": {
      -      "additionalProperties": false,
      -      "properties": {
      -        "from": {
      -          "type": "string"
      -        },
      -        "kind": {
      -          "enum": [
      -            "measured",
      -            "hypothetical"
      -          ],
      -          "type": "string"
      -        },
      -        "label": {
      -          "maxLength": 60,
      -          "type": "string"
      -        },
      -        "source": {
      -          "description": "Required for measured.",
      -          "type": "string"
      -        },
      -        "to": {
      -          "type": "string"
      -        },
      -        "unit": {
      -          "maxLength": 16,
      -          "type": "string"
      -        },
      -        "value": {
      -          "type": "number"
      -        }
      -      },
      -      "required": [
      -        "from",
      -        "to",
      -        "value",
      -        "unit",
      -        "kind"
      -      ],
      -      "type": "object"
      -    },
      -    "maxItems": 40,
      -    "type": "array"
      -  },
      -  "limits": {
      -    "description": "What is missing or uncertain, in plain words. Shown on the last scene.",
      -    "items": {
      -      "maxLength": 200,
      -      "type": "string"
      -    },
      -    "maxItems": 8,
      -    "type": "array"
      -  },
      -  "locale": {
      -    "description": "'sv-SE', 'en-US' …",
      -    "maxLength": 12,
      -    "type": "string"
      -  },
      -  "paths": {
      -    "description": "Alternative ways through the story, e.g. 'Kort' and 'Djup': the viewer picks one and only those scenes play, in that order.",
      -    "items": {
      -      "additionalProperties": false,
      -      "properties": {
      -        "id": {
      -          "maxLength": 32,
      -          "type": "string"
      -        },
      -        "label": {
      -          "maxLength": 30,
      -          "type": "string"
      -        },
      -        "scenes": {
      -          "items": {
      -            "type": "string"
      -          },
      -          "maxItems": 16,
      -          "minItems": 1,
      -          "type": "array"
      -        }
      -      },
      -      "required": [
      -        "id",
      -        "label",
      -        "scenes"
      -      ],
      -      "type": "object"
      -    },
      -    "maxItems": 6,
      -    "type": "array"
      -  },
      -  "playback": {
      -    "additionalProperties": false,
      -    "properties": {
      -      "allowExploration": {
      -        "type": "boolean"
      -      },
      -      "allowScrubbing": {
      -        "type": "boolean"
      -      },
      -      "autoplay": {
      -        "type": "boolean"
      -      }
      -    },
      -    "type": "object"
      -  },
      -  "relations": {
      -    "description": "For network scenes.",
      -    "items": {
      -      "additionalProperties": false,
      -      "properties": {
      -        "from": {
      -          "type": "string"
      -        },
      -        "kind": {
      -          "enum": [
      -            "observed",
      -            "hypothesis"
      -          ],
      -          "type": "string"
      -        },
      -        "label": {
      -          "maxLength": 40,
      -          "type": "string"
      -        },
      -        "source": {
      -          "description": "Required for observed.",
      -          "type": "string"
      -        },
      -        "to": {
      -          "type": "string"
      -        }
      -      },
      -      "required": [
      -        "from",
      -        "to",
      -        "kind"
      -      ],
      -      "type": "object"
      -    },
      -    "maxItems": 80,
      -    "type": "array"
      -  },
      -  "scenes": {
      -    "items": {
      -      "additionalProperties": false,
      -      "properties": {
      -        "actions": {
      -          "description": "introduce: pop in during this scene; remove: fade out; focus: the rest dims.",
      -          "items": {
      -            "additionalProperties": false,
      -            "properties": {
      -              "targets": {
      -                "items": {
      -                  "type": "string"
      -                },
      -                "maxItems": 60,
      -                "type": "array"
      -              },
      -              "type": {
      -                "enum": [
      -                  "introduce",
      -                  "remove",
      -                  "focus",
      -                  "change"
      -                ],
      -                "type": "string"
      -              }
      -            },
      -            "required": [
      -              "type",
      -              "targets"
      -            ],
      -            "type": "object"
      -          },
      -          "maxItems": 8,
      -          "type": "array"
      -        },
      -        "camera": {
      -          "additionalProperties": false,
      -          "properties": {
      -            "focus": {
      -              "items": {
      -                "type": "string"
      -              },
      -              "maxItems": 8,
      -              "type": "array"
      -            },
      -            "zoom": {
      -              "enum": [
      -                "auto",
      -                "year",
      -                "month",
      -                "day",
      -                "hour",
      -                "minute"
      -              ],
      -              "type": "string"
      -            }
      -          },
      -          "required": [
      -            "focus"
      -          ],
      -          "type": "object"
      -        },
      -        "claims": {
      -          "items": {
      -            "additionalProperties": false,
      -            "properties": {
      -              "evidence": {
      -                "description": "Source ids (sources[].id). Required for observed and derived.",
      -                "items": {
      -                  "type": "string"
      -                },
      -                "maxItems": 6,
      -                "type": "array"
      -              },
      -              "kind": {
      -                "description": "observed = in a source; derived = computed from observed data (say how in the text); hypothesis = an interpretation nobody has established. A cause is always a hypothesis.",
      -                "enum": [
      -                  "observed",
      -                  "derived",
      -                  "hypothesis"
      -                ],
      -                "type": "string"
      -              },
      -              "text": {
      -                "maxLength": 220,
      -                "type": "string"
      -              }
      -            },
      -            "required": [
      -              "kind",
      -              "text"
      -            ],
      -            "type": "object"
      -          },
      -          "maxItems": 5,
      -          "type": "array"
      -        },
      -        "durationMs": {
      -          "maximum": 30000,
      -          "minimum": 2000,
      -          "type": "number"
      -        },
      -        "events": {
      -          "description": "Event ids (recipe.events) marked on a timeline.",
      -          "items": {
      -            "type": "string"
      -          },
      -          "maxItems": 12,
      -          "type": "array"
      -        },
      -        "id": {
      -          "description": "Short and stable: the edit tool names scenes by it.",
      -          "maxLength": 32,
      -          "type": "string"
      -        },
      -        "insight": {
      -          "description": "The one thing the reader learns here, in words. Not the numbers repeated, and not the same as another scene's.",
      -          "maxLength": 200,
      -          "type": "string"
      -        },
      -        "narration": {
      -          "additionalProperties": false,
      -          "properties": {
      -            "body": {
      -              "description": "A couple of sentences at most.",
      -              "maxLength": 320,
      -              "type": "string"
      -            },
      -            "headline": {
      -              "maxLength": 70,
      -              "type": "string"
      -            }
      -          },
      -          "required": [
      -            "headline",
      -            "body"
      -          ],
      -          "type": "object"
      -        },
      -        "purpose": {
      -          "enum": [
      -            "introduce",
      -            "context",
      -            "change",
      -            "relation",
      -            "answer",
      -            "compare",
      -            "conclude"
      -          ],
      -          "type": "string"
      -        },
      -        "question": {
      -          "description": "The question this scene answers.",
      -          "maxLength": 140,
      -          "type": "string"
      -        },
      -        "show": {
      -          "description": "Entity ids shown (default: all in the dataset).",
      -          "items": {
      -            "type": "string"
      -          },
      -          "maxItems": 60,
      -          "type": "array"
      -        },
      -        "time": {
      -          "additionalProperties": false,
      -          "description": "The stretch of the dataset's time this scene plays through.",
      -          "properties": {
      -            "from": {
      -              "$ref": "#/properties/recipe/properties/datasets/items/properties/x/items"
      -            },
      -            "to": {
      -              "$ref": "#/properties/recipe/properties/datasets/items/properties/x/items"
      -            }
      -          },
      -          "required": [
      -            "from",
      -            "to"
      -          ],
      -          "type": "object"
      -        },
      -        "visual": {
      -          "additionalProperties": false,
      -          "properties": {
      -            "dataset": {
      -              "description": "A dataset id. One dataset (one unit) per scene.",
      -              "type": "string"
      -            },
      -            "from": {
      -              "$ref": "#/properties/recipe/properties/datasets/items/properties/x/items"
      -            },
      -            "scale": {
      -              "description": "Leave out or 'area'. Radius scaling is refused.",
      -              "enum": [
      -                "area",
      -                "linear"
      -              ],
      -              "type": "string"
      -            },
      -            "to": {
      -              "$ref": "#/properties/recipe/properties/datasets/items/properties/x/items"
      -            },
      -            "type": {
      -              "description": "bubble: entities as circles, AREA = value. timeline: series over time + dated events. comparison: before → after per entity (set from/to). transform: how one total's value changed (set from/to) — a change of value, NOT money that moved. flow: ONLY measured volumes from recipe.flows (hypothetical ones are drawn dashed). network: entities as nodes and recipe.relations as arrows (observed = solid + needs a source; hypothesis = dashed); dataset is optional and sizes the nodes. On a timeline, scenes on the same dataset with different `time` windows zoom smoothly between them.",
      -              "enum": [
      -                "bubble",
      -                "timeline",
      -                "comparison",
      -                "transform",
      -                "flow",
      -                "network"
      -              ],
      -              "type": "string"
      -            }
      -          },
      -          "required": [
      -            "type",
      -            "dataset"
      -          ],
      -          "type": "object"
      -        }
      -      },
      -      "required": [
      -        "id",
      -        "purpose",
      -        "question",
      -        "insight",
      -        "visual",
      -        "narration",
      -        "claims"
      -      ],
      -      "type": "object"
      -    },
      -    "maxItems": 16,
      -    "minItems": 1,
      -    "type": "array"
      -  },
      -  "schemaVersion": {
      -    "const": 2,
      -    "type": "number"
      -  },
      -  "sources": {
      -    "items": {
      -      "additionalProperties": false,
      -      "properties": {
      -        "id": {
      -          "maxLength": 32,
      -          "type": "string"
      -        },
      -        "name": {
      -          "maxLength": 80,
      -          "type": "string"
      -        },
      -        "publishedAt": {
      -          "type": "string"
      -        },
      -        "retrievedAt": {
      -          "type": "string"
      -        },
      -        "url": {
      -          "maxLength": 300,
      -          "type": "string"
      -        }
      -      },
      -      "required": [
      -        "id",
      -        "name"
      -      ],
      -      "type": "object"
      -    },
      -    "maxItems": 20,
      -    "type": "array"
      -  },
      -  "subtitle": {
      -    "maxLength": 120,
      -    "type": "string"
      -  },
      -  "timeZone": {
      -    "description": "IANA zone times are shown in ('Europe/Stockholm', 'America/New_York').",
      -    "maxLength": 40,
      -    "type": "string"
      -  },
      -  "title": {
      -    "maxLength": 80,
      -    "type": "string"
      -  }
      -}
    • removedInput schema / properties / recipe / required
      Removed value: -[
      -  "title",
      -  "sources",
      -  "datasets",
      -  "entities",
      -  "scenes"
      -]
    • changedOutput schema / (root)
      Previous value: -{
      -  "$schema": "http://json-schema.org/draft-07/schema#",
      -  "additionalProperties": false,
      -  "properties": {
      -    "changed": {
      -      "items": {
      -        "type": "string"
      -      },
      -      "type": "array"
      -    },
      -    "code": {
      -      "type": "string"
      -    },
      -    "current_version": {
      -      "type": "number"
      -    },
      -    "dry_run": {
      -      "type": "boolean"
      -    },
      -    "duration_ms": {
      -      "type": "number"
      -    },
      -    "error": {
      -      "type": "string"
      -    },
      -    "errors": {
      -      "items": {
      -        "type": "string"
      -      },
      -      "type": "array"
      -    },
      -    "imported": {
      -      "type": "boolean"
      -    },
      -    "issues": {
      -      "items": {
      -        "additionalProperties": false,
      -        "properties": {
      -          "level": {
      -            "enum": [
      -              "error",
      -              "warning"
      -            ],
      -            "type": "string"
      -          },
      -          "message": {
      -            "type": "string"
      -          },
      -          "path": {
      -            "type": "string"
      -          }
      -        },
      -        "required": [
      -          "level",
      -          "path",
      -          "message"
      -        ],
      -        "type": "object"
      -      },
      -      "type": "array"
      -    },
      -    "next": {
      -      "type": "string"
      -    },
      -    "note": {
      -      "type": "string"
      -    },
      -    "open": {
      -      "type": "string"
      -    },
      -    "outline": {
      -      "additionalProperties": {},
      -      "type": "object"
      -    },
      -    "private": {
      -      "type": "boolean"
      -    },
      -    "recipe": {
      -      "additionalProperties": {},
      -      "type": "object"
      -    },
      -    "scenes": {
      -      "type": "number"
      -    },
      -    "scenes_in_app": {
      -      "type": "boolean"
      -    },
      -    "skeleton": {
      -      "additionalProperties": {},
      -      "type": "object"
      -    },
      -    "sourced": {
      -      "type": "boolean"
      -    },
      -    "status": {
      -      "type": "string"
      -    },
      -    "story_id": {
      -      "type": "string"
      -    },
      -    "templates": {
      -      "items": {
      -        "additionalProperties": {},
      -        "type": "object"
      -      },
      -      "type": "array"
      -    },
      -    "title": {
      -      "type": "string"
      -    },
      -    "url": {
      -      "type": "string"
      -    },
      -    "valid": {
      -      "type": "boolean"
      -    },
      -    "version": {
      -      "type": "number"
      -    },
      -    "warnings": {
      -      "items": {
      -        "type": "string"
      -      },
      -      "type": "array"
      -    }
      -  },
      -  "type": "object"
      -}New value: +null
  2. Added

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations cover the safety profile (not read-only, not destructive, closed-world), and the description adds value beyond them: it guarantees the story is private and "never publishes," that dry_run saves nothing, and that numeric claims must be tagged observed/derived/hypothesis. It does not say what is returned after a real creation, which is the remaining gap.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Short and front-loaded, with the scene definition first and the workflow and sibling pointer after. The telegraphic fragments ("A table that just animates: create_data_story") and the untranslated Swedish aside read as clipped, but no sentence is filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool taking a free-form nested recipe object with no output schema, the description supplies the workflow, the privacy guarantee, and the content-integrity rules an agent needs to fill the recipe correctly. Only the post-creation outcome (identifier, confirmation, error surface) is left unspecified.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so both parameters are already documented, but the description adds real meaning: recipe is a free-form nested object whose skeleton must come from list_story_templates, and dry_run is a validation-only path. That workflow context goes beyond the schema's one-line field descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource (create a visual story composed of scenes) and immediately concretizes what a scene is: bubbles, timeline, before/after, flows. It explicitly separates itself from the sibling create_data_story ("a table that just animates"), so an agent can pick the right tool without opening either schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives a concrete prerequisite workflow (call use_tool list_story_templates with an id to get a skeleton, then dry_run to check) and names the alternative tool for the data-table case. It does not spell out when *not* to use it beyond that one alternative, so it falls short of a full when/when-not treatment.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.