Timeline, sheets, maps & media
23 MCP tools. Each applies to the one project the server was launched with; every mutating call is one undo step and saves immediately.
add_media
Imports an on-disk file into the project's assets/ folder and creates a media asset (portrait, map base image, reference art, gallery image). Optionally attaches it to an entity's gallery. The kind is inferred from the file extension when omitted.
| Parameter | Type | Required | Description |
|---|---|---|---|
caption | string | no | Optional caption (defaults to the source file's base name). |
entity | string | no | Optional entity (name or alias) to attach the media to; it is appended to the entity's gallery and becomes the cover when the gallery was empty. |
kind | string | no | Optional: one of image, audio, video, pdf, or other; inferred from the extension when omitted. |
path | string | yes | Absolute path, or a path relative to the project folder, of the file to import. |
Example call
{
"name": "add_media",
"arguments": {
"path": "<path>"
}
}
create_chart
Creates a chart of tabular data. "kind" is bar (default), line, area, or pie; "categories" are the shared x-axis labels; "series" is an array of {name, values:[numbers]} (a pie uses the first series). Charts embed in prose by title with ![[Chart Title]].
| Parameter | Type | Required | Description |
|---|---|---|---|
categories | array | no | The shared x-axis category labels. |
category_axis_title | string | no | Optional x-axis title (ignored by a pie). |
kind | string | no | bar (default), line, area, or pie. |
series | array | no | Data series: {name, values:[numbers]} objects. |
title | string | yes | The chart title. |
value_axis_title | string | no | Optional y-axis title (ignored by a pie). |
Example call
{
"name": "create_chart",
"arguments": {
"title": "<title>"
}
}
create_continuity_rule
Adds a continuity rule the validator checks: entity E's field F, compared against a value V. "comparison" is equals (default), not_equals, contains / not_contains (case-insensitive substring -- good for prose so a wording tweak does not false-alarm), less_than / less_or_equal / greater_than / greater_or_equal (numeric), is_empty / is_non_empty (no value needed), or one_of (V is a set: pass "values" or a '|'-joined "value"). With "when" (a project-calendar date) the field is checked as of that story moment (state-over-time); without it, the base value. get_conflicts reports any violation. "applies_to" scopes the rule to a whole set -- every Item, everything tagged act-one -- so "every Item has a price" is written once rather than per entity, and the reply says how many objects it reaches. For anything one field against one value cannot say, pass "expression" instead of "field"/"comparison"/"value".
| Parameter | Type | Required | Description |
|---|---|---|---|
applies_to | string | no | Apply the rule to a SET instead of one entity: "project", "tag:act-one", "category:Item" for that category exactly, or "under:Item" for it and everything beneath. Written once, it stays true for objects created later. |
comparison | string | no | equals (default), not_equals, contains, not_contains, less_than, less_or_equal, greater_than, greater_or_equal, is_empty, is_non_empty, or one_of. |
entity | string | no | The entity to constrain (name or alias). Give this OR "applies_to". |
expression | string | no | Assert an EXPRESSION instead of one field against one value: "price >= 0 AND price <= 10000", "deathDate > birthDate", "COUNT(members) >= 3". Names are the object's fields, and a dot crosses a reference ("owner.name") or enters a block ("traits.height"); AND, OR and NOT join tests; the functions are SUM, COUNT, DISTINCT, MIN, MAX, AVERAGE, LEN/LENGTH, WORDCOUNT, ISEMPTY, MATCHES (regular expression), IF, CONCAT, LEFT, RIGHT, MID, UPPER, LOWER, TRIM, ABS, INT, ROUND, MOD, POWER and SQRT. The rule holds when it is true. Refused if it cannot be read. |
field | string | no | The field's label or key, e.g. "Title". |
name | string | yes | A name for the rule, e.g. "King after the coronation". |
value | string | no | The value to compare against (a number for the numeric comparisons; omit for is_empty/is_non_empty). |
values | array | no | For one_of: the set of allowed values. |
when | string | no | Optional story date to check as of; omit to check the base value. |
Example call
{
"name": "create_continuity_rule",
"arguments": {
"name": "<name>"
}
}
create_map
Creates a map. Optionally imports a "base_image" file (an absolute path or one relative to the project folder) into assets/ as the backdrop, sets the measurement scale ("width_distance" spanning the image in "distance_unit" units, plus "travel_speed" per hour for the timeline's journey checks), and overlays a battle "grid" (none/square/hex, "grid_columns" wide). get_map/update_map then operate on it (add pins, tokens, reveal regions).
| Parameter | Type | Required | Description |
|---|---|---|---|
base_image | string | no | Optional backdrop image: an absolute path or one relative to the project folder, copied into assets/. |
distance_unit | string | no | Optional distance-unit label (default "km"). |
grid | string | no | Optional battle grid: none (default), square, or hex. |
grid_columns | number | no | Optional grid cells across the image width (at least 1; used when a grid is set. |
title | string | yes | The map's title (unique among maps). |
travel_speed | number | no | Optional overland travel speed in distance units per hour (used to check journey times). |
width_distance | number | no | Optional real-world distance spanning the image width, giving the map a measurement scale. |
Example call
{
"name": "create_map",
"arguments": {
"title": "<title>"
}
}
create_spreadsheet
Creates a spreadsheet, optionally pre-filled with a header row and data rows. Cell values may be formulas ("=SUM(B2:B9)").
| Parameter | Type | Required | Description |
|---|---|---|---|
headers | array | no | Optional header-row labels. |
rows | array | no | Optional data rows, each an array of cell values (a string, number, or "=formula"); e.g. [["Alice", 3], ["Bob", 5]]. |
title | string | yes | The sheet title. |
Example call
{
"name": "create_spreadsheet",
"arguments": {
"title": "<title>"
}
}
create_timeline_event
Creates a timeline event dated in the project calendar. Participants and the location are entity names (or aliases); an unknown name fails rather than being dropped -- unless "create_missing_entities" is true, which creates an uncategorized stub entity for any name that matches nothing (so an out-of-order build need not create every character first). An ambiguous or AI-excluded name still fails. "timeline" picks (or creates) a named timeline; omitted, the project's first timeline is used.
| Parameter | Type | Required | Description |
|---|---|---|---|
create_missing_entities | boolean | no | Create a stub entity for any participant/location name that does not exist yet (default false). |
description | string | no | Optional free-form description. |
location | string | no | The entity where it happens. |
participants | array | no | Entity names taking part. |
timeline | string | no | The timeline to place the event on. |
title | string | yes | What happens. |
until | string | no | Optional end date for a duration event. |
when | string | yes | The start date in the project calendar (e.g. "25 Harvestmoon 1250"). |
Example call
{
"name": "create_timeline_event",
"arguments": {
"title": "<title>",
"when": "<when>"
}
}
delete_continuity_rule
Removes a continuity rule from the project by its name.
| Parameter | Type | Required | Description |
|---|---|---|---|
rule | string | yes | The rule's name. |
Example call
{
"name": "delete_continuity_rule",
"arguments": {
"rule": "<rule>"
}
}
get_calendar
Reads the project's calendar: its months (with lengths), weekday names, era label, and any named eras (a multi-reckoning epoch like Before/After Fall) -- the reckoning every timeline date is written in.
No parameters.
Example call
{
"name": "get_calendar",
"arguments": {}
}
get_chart
Reads a chart's data: its kind (bar/line/area/pie), category labels, each named data series' values, and axis titles.
| Parameter | Type | Required | Description |
|---|---|---|---|
chart | string | yes | The chart's title. |
Example call
{
"name": "get_chart",
"arguments": {
"chart": "<chart>"
}
}
get_conflicts
Runs the validating timeline and the user-authored continuity rules and reports every conflict found: an entity in two places at once, events outside a lifespan, impossible travel, dangling references, broken relative constraints, and violated continuity assertions.
No parameters.
Example call
{
"name": "get_conflicts",
"arguments": {}
}
get_map
Reads a map: its regions (with layers, reveal state, linked entities, and sub-maps), pins, tokens, travel routes, scale, and grid.
| Parameter | Type | Required | Description |
|---|---|---|---|
map | string | yes | The map's title. |
Example call
{
"name": "get_map",
"arguments": {
"map": "<map>"
}
}
get_spreadsheet
Reads a spreadsheet as a Markdown table of evaluated values (formula cells show the formula beside the value). Very large sheets are capped honestly.
| Parameter | Type | Required | Description |
|---|---|---|---|
spreadsheet | string | yes | The spreadsheet's title. |
Example call
{
"name": "get_spreadsheet",
"arguments": {
"spreadsheet": "<spreadsheet>"
}
}
get_timeline
Reads the project's timeline(s): every event with its date(s) in the project calendar, participants and location by name, plus the named eras. Pass "timeline" to read one timeline; omit it for all.
| Parameter | Type | Required | Description |
|---|---|---|---|
timeline | string | no | A timeline's title (omit for all timelines). |
Example call
{
"name": "get_timeline",
"arguments": {
"timeline": "<timeline>"
}
}
list_continuity_rules
Lists the writer-authored continuity rules the validator checks: for each, what it applies to, and either the field, whether it must or must not equal a value, and when (a story date or at any time), or the expression it asserts.
No parameters.
Example call
{
"name": "list_continuity_rules",
"arguments": {}
}
list_media
Lists the project's media assets: caption, kind (image/audio/video/pdf/other), and asset path.
No parameters.
Example call
{
"name": "list_media",
"arguments": {}
}
manage_eras
Adds, removes, or renames a named era (the labelled background bands of story time). "add" needs "start" and "end" dates in the project calendar; "rename" needs "new_name".
| Parameter | Type | Required | Description |
|---|---|---|---|
action | string | yes | One of add, remove, or rename. |
color | string | no | Optional #RRGGBB band colour (add only). |
end | string | no | When the era ends (add only). |
name | string | yes | The era's name. |
new_name | string | no | The new name (rename only). |
start | string | no | When the era begins (add only). |
Example call
{
"name": "manage_eras",
"arguments": {
"action": "<action>",
"name": "<name>"
}
}
set_media_caption
Recaptions a media asset, addressed by its current caption.
| Parameter | Type | Required | Description |
|---|---|---|---|
media | string | yes | The media item's current caption. |
new_caption | string | yes | The caption to set. |
Example call
{
"name": "set_media_caption",
"arguments": {
"media": "<media>",
"new_caption": "<new_caption>"
}
}
update_calendar
Updates the project calendar. Sparse: only the provided keys change. Note that story time is stored as absolute instants, so changing month lengths re-reads every existing date under the new calendar.
| Parameter | Type | Required | Description |
|---|---|---|---|
era_name | string | no | The single era label appended to years (e.g. "Third Age"); used only when no named "eras" are defined. |
eras | array | no | The full replacement list of named eras for a multi-reckoning epoch (BCE/CE style): objects with "name", "start_year" (the absolute year the era begins; year 1 is the epoch), and optional "counts_down" (true for a before-epoch era that counts down toward the next era's start, so the year just before the switch is 1). Pass [] to clear them and revert to the single era label. Stored instants never change -- only how a year is rendered. |
months | array | no | The full replacement month list: objects with "name" and "days". |
weekdays | array | no | The full replacement weekday cycle. |
Example call
{
"name": "update_calendar",
"arguments": {
"era_name": "<era_name>",
"eras": []
}
}
update_chart
Sparse update of a chart: only the provided keys change. "new_title" renames it; "kind", "categories", "series", "value_axis_title", and "category_axis_title" replace those parts. One undo step.
| Parameter | Type | Required | Description |
|---|---|---|---|
categories | array | no | Replacement x-axis category labels. |
category_axis_title | string | no | Replacement x-axis title. |
chart | string | yes | The chart's title. |
kind | string | no | bar, line, area, or pie. |
new_title | string | no | Rename the chart to this. |
series | array | no | Replacement series: {name, values:[numbers]} objects. |
value_axis_title | string | no | Replacement y-axis title. |
Example call
{
"name": "update_chart",
"arguments": {
"chart": "<chart>"
}
}
update_map
Edits a map with one action: add_pin (label, x, y, optional note), move_pin (pin, x, y), add_token (label, x, y, optional color and entity), reveal_region (region, optional revealed=false to hide), or rename (new_title). Coordinates are normalized [0, 1] relative to the base image.
| Parameter | Type | Required | Description |
|---|---|---|---|
action | string | yes | One of add_pin, move_pin, add_token, reveal_region, or rename. |
color | string | no | Optional #RRGGBB token colour. |
entity | string | no | Optional entity the token represents. |
label | string | no | The new pin/token label. |
map | string | yes | The map's title. |
new_title | string | no | rename only: the map's new title. |
note | string | no | Optional free-text pin note. |
pin | string | no | The pin to move (its label). |
region | string | no | The region to reveal/hide (its label). |
revealed | boolean | no | reveal_region only: false hides. |
x | number | no | Normalized x (0..1). |
y | number | no | Normalized y (0..1). |
Example call
{
"name": "update_map",
"arguments": {
"map": "<map>",
"action": "<action>"
}
}
update_spreadsheet
Renames a spreadsheet ("new_title") and/or sets individual cells by A1 address. "cells" maps addresses to raw text -- a literal, a formula starting with '=' (evaluated by the real engine; the result is reported back), or "" to clear the cell. Provide at least one of new_title / cells.
| Parameter | Type | Required | Description |
|---|---|---|---|
cells | object | no | A1 address -> new cell text (e.g. {"B2": "=SUM(B3:B9)"}). |
new_title | string | no | Rename the spreadsheet to this. |
spreadsheet | string | yes | The spreadsheet's current title. |
Example call
{
"name": "update_spreadsheet",
"arguments": {
"spreadsheet": "<spreadsheet>"
}
}
update_timeline
Renames a timeline container. (Add or edit its events with create/update_timeline_event; remove a whole timeline with delete_object.)
| Parameter | Type | Required | Description |
|---|---|---|---|
new_title | string | yes | The new title. |
timeline | string | yes | The timeline's current title. |
Example call
{
"name": "update_timeline",
"arguments": {
"timeline": "<timeline>",
"new_title": "<new_title>"
}
}
update_timeline_event
Updates an existing timeline event, addressed by its title. Sparse: only the keys you provide change (new_title, when, until, description, participants, location); an empty "until"/"location"/"description" clears that field.
| Parameter | Type | Required | Description |
|---|---|---|---|
create_missing_entities | boolean | no | Create a stub entity for any participant/location name that does not exist yet (default false). |
description | string | no | A new description; empty clears it. |
event | string | yes | The event's current title. |
location | string | no | A new location entity; empty clears it. |
new_title | string | no | A new title. |
participants | array | no | The full replacement participant list. |
until | string | no | A new end date; empty makes the event instantaneous. |
when | string | no | A new start date in the project calendar. |
Example call
{
"name": "update_timeline_event",
"arguments": {
"event": "<event>"
}
}