DocsSlima MCP › Structured editing tools (update_*)

Structured editing tools (update_*)

Last updated September 9, 2026 · 10 min read

In one line: how the update_* tools let an outside AI tool change a beat board, a timeline, a screenplay, a relationship map or a world map without dropping the parts it never saw.

What this solves

A prose file can be rewritten whole. The AI read all of the .md, so it can send all of it back, and the worst case is bad writing you roll back from version history.

Structured files have no such safety net. A .beats file holds acts, beats, and the real chapters the author dragged onto it. A .map holds nodes, relationships, group boxes, and where each node sits on the canvas. Asking an AI to send back the whole JSON is asking it to send back the parts it was never shown. It will try, and the failure is silent: the file still opens, it just has less of the author's work in it.

So the 4.0 server closed whole-file writes on these five extensions. write_file, edit_file and append_to_file are refused, and one field-level tool per type takes their place.

Extension Tool Operations
.beats beat board update_beat_board add_act / update_act / remove_act / add_beat / update_beat / remove_beat / move_beat
.timeline timeline update_timeline add_entry / update_entry / remove_entry / set_config
.script screenplay update_script add_scene / update_scene_heading / remove_scene / add_element / update_element / remove_element
.map relationship map update_relationship_map add_node / update_node / move_node / remove_node / add_edge / update_edge / remove_edge / add_group / update_group / remove_group / set_meta
.geomap world map update_world_map add_place / update_place / add_label / update_label / remove_element / add_river / add_border / paint_region / set_meta

Don't memorise that table, and don't treat it as the authority. get_capabilities returns what this server actually accepts right now — see Guides and writing skills.

Rules that apply to all of them

Read the file first. Every id you send has to come from that read. Never retype one from memory, never invent one. An unknown id is refused with the list of real ones, so a mistake costs a round trip instead of the author's data.

One operation per change. Each operation takes only its own arguments. A field belonging to a different operation is refused rather than quietly ignored.

op_ref chains inside one batch. Label what an operation creates with op_ref: "A2", and a later operation in the same batch can point at it as "@A2". Backward references only, and only within that batch — the next call needs the real id, which came back in applied.

The batch is all-or-nothing. If one operation fails, nothing is written, so you never have to work out how far it got. One call carries at most 200 operations; more than that is refused with a note to split them.

A complete example

update_relationship_map({
  "book_token": "bk_...",
  "path": "Worldbuilding/Relationship Map.map",
  "intent": "Put Wen Yun next to Pei Zhao and mark them as colleagues",
  "operations": [
    { "op": "add_node", "label": "Wen Yun", "op_ref": "N1",
      "position": { "near_id": "n-peizhao", "direction": "right" } },
    { "op": "add_edge", "source_id": "n-peizhao", "target_id": "@N1", "label": "colleagues" }
  ]
})

intent is not a comment. It becomes the name of the commit, which is the line the author reads in version history weeks later. Say what this batch did. "Batch update" is not that, and an over-long paragraph is refused before anything is written.

The reply carries three things: the real ids of whatever you created, anything that happened as a side effect (removing a node also removes its edges), and the commit token. Pass the middle one on to the author — those are changes they will see and did not ask for.

There is no review panel here

Inside the app, when the AI Coach changes a structured file, the change first appears as a dashed card the author accepts or skips (see Review AI edits).

MCP has no such step. A batch sent from an outside tool is a commit, and it is in version history immediately. So say what you are about to do, then say what you did — do not send it and then ask "is this okay?" Undo is version history, the same as for a paragraph you wrote yourself. And nothing in version history marks a commit as having come from outside: a row shows the message, when it happened and a word count, and that is all. Your intent line is the only trace, which is the whole reason it has to say something.

Creating a structured file

create_file does work on these five extensions, but the content you send is ignored: the server writes an empty skeleton, and the filename becomes the document's name inside the file. The reply says plainly that your content was replaced.

So it is two steps: create_file to get an empty one, then update_* batches to fill it.

Who can do this

Writing these five types — and deleting them — belongs to Slima's subscription plans. A free account gets a 403 with the code SUBSCRIPTION_REQUIRED, and the message spells out that reading is not restricted: read the file, describe the change you recommend in words, and the author can make it in the app, or subscribe and let the AI make it directly.

This is a different refusal from the other one. .character, .location, .json and .yaml return AI_READONLY_FILE_TYPE, which no upgrade unlocks — those types have no field-level route at all. The two codes are deliberately separate, because the right next step is completely different.

Per-type notes worth knowing

.map relationship map. Position is content, not layout. update_node moves nothing; moving is move_node, so that "I put her next to him" is its own reviewable change. Prefer {near_id, direction} over computing coordinates. Existing nodes never get pushed aside, and the final coordinates come back in the reply. Group boxes are computed from member_ids, so never send x/y/width/height.

.geomap world map. Coordinates are grid cells, not pixels: x 0–519, y 0–363. read_file hands back the map with its three terrain grids replaced by a note — they are machine-encoded and you do not need them. paint_region works in cells. Terrain has no undo, so paint over it instead. remove_element takes any element id (pl_ place, lb_ label, rv_ river, bd_ border). Move a place with update_place, never by removing and re-adding it.

.timeline timeline. Attaching an entry to a chapter is not done here; the link fields are refused with an explanation.

.beats beat board. Removing an act does not remove the beats in it. They become unassigned, and the reply tells you how many.

.script screenplay. One episode per file. Scene headings (interior/exterior, location, time of day) go through update_scene_heading; action, character, dialogue, parenthetical, transition and shot go through add_element / update_element.

Related

Try it in Slima

Open the app and do this with your own book. Free to start, no credit card.

Open Slima
Was this helpful?