Skip to main content
Glama

update_document

Destructive

Modifies an existing document — title, content, language, attachment or archiving. For the content, contentMarkdown (GFM Markdown, RECOMMENDED PATH) or content (raw ProseMirror tree): either one REPLACES the whole tree, not a partial patch. appendMarkdown ADDS at the END without re-sending the document (exclusive with the two others). Each field PROVIDED is written, the others stay intact. cellId: null detaches the document; cellId omitted does not touch the attachment — same semantics as update_task.cellId. expectedVersion (required) is the version read via get_document before writing: if it has diverged (someone else modified the document in the meantime), the call fails naming the current version rather than silently overwriting their work; reading the document again gives the up-to-date version. ⚠️ HISTORY: a content write does NOT always create a revision — if the last revision of the document is by the SAME author, written through the same kind of writer (human or agent), and less than 10 minutes old, the previous version is OVERWRITTEN without being kept (list_document_revisions will never show it); a change of writer (a person, then their own agent, or the reverse) does create one. When this happens, the response carries revisionSkipped ({ reason, windowMinutes, lastRevisionAt }: the last kept version); field ABSENT = a revision was created (or the document has no history, like an HTML document), which does not mean "nothing was lost". warnings (ABSENT when nothing is altered) names what the Markdown conversion could not carry; raw HTML, checkboxes and nesting beyond 100 levels are REFUSED with their reason. A request blocked by the network firewall (a bare HTTP 403 "Forbidden") answers before the application runs, so it carries NO application message; a document body that is read as an attack pattern (for instance a path traversal such as ../../, or a URL whose host is an IPv4 address) can trigger it. The response carries url: the DIRECT LINK of the document (opens the project on this document), which the human follows with one click, unlike the title.

Input Schema

NameRequiredDescriptionDefault
titleNoDocument title (1 to 200 characters).
cellIdNo`null` DETACHES the document from any block. Field omitted: does not touch the attachment. A value REPLACES any existing attachment (pattern `update_task.assignees`).
contentNoReplaces the ENTIRE content — not a partial patch of the tree. Reserved for cases that build the tree programmatically; `contentMarkdown` is the recommended path. Providing both at once is an explicit REFUSAL (ambiguous, so it is not resolved silently).
archivedNoArchives (true) or unarchives (false) the document. Omitted: does not change the state.
documentIdYesIdentifier of the document to modify.
htmlSourceNoREPLACES the ENTIRE source of a `kind: "html"` document — not a partial patch. On a richtext document, this field is REFUSED by naming it (the form is immutable). The document search text is recomputed from the new source. The COMPLETE, SELF-CONTAINED HTML document: markup + `<style>` + `<script>` inline, in a single string (maximum 250000 characters). Meant for what a richtext document cannot carry — an overview page, an interactive report, a visualization, a calculator. Long documentation belongs in an ordinary richtext document (`contentMarkdown`), which stays editable by hand. ⚠️ RISK, STATED TO THE USER WHEN THEY CLICK "▶ Run the document": the sandbox protects the user's SESSION (opaque origin, no cookie or storage) but does NOT guarantee that the document's content stays inside OrgGen — the WebRTC channel is not closed (measured in a browser): anything a document embeds can leave OrgGen. ⚠️ SELF-CONTAINED IN THE STRICT SENSE: the document is served in a sandbox WITHOUT ordinary network access (`fetch`, WebSocket, remote resource). Any REMOTE or RELATIVE resource (`<script src>`, `<link rel=stylesheet>`, `<img src="/x.png">`, a Google font, a CSS `@import`) is REFUSED AT WRITE TIME, naming the offending URL — rather than accepting a document half of which would die silently at display time. Images are embedded as `data:`, CSS and JS are written inline. ⚠️ TWO MANDATORY LINES, whose omission raises NO error — it just yields a document that will look broken. (a) `body` EXPLICITLY declares `background` AND `color`: the document is served in an ISOLATED frame, it inherits nothing from the application theme, so without a declared background it displays in WHITE in the middle of a dark panel. The viewer sets `color-scheme` and `data-og-theme` on `<html>`, but `color-scheme` is a hint to the rendering engine, NOT a stylesheet — it invents no color. (b) a `<meta name="viewport" content="width=device-width, initial-scale=1">`, and content that fits in ~390 px: the panel is readable on a phone. The viewer injects this `<meta>` if it is missing, but this safety net designs nothing — a grid in fixed widths will stay off-screen. ⚠️ NINE COMMON CONSTRUCTIONS ARE DEAD in this sandbox, WITHOUT any error being reported (the write succeeds, the document displays, the button stays inert) — including `alert()`, `window.print()`, `localStorage`, forms, `eval`, and `confirm()`, which returns `false` in every case: the "cancel" branch runs, it is the only one whose result is WRONG instead of inert. The nine, with what works instead, are listed in `get_playbook({topic: "html"})`.
visibilityNo'private' makes the document invisible to EVERYONE EXCEPT ITS CREATOR (including ordinary project editors); 'inherited' (default) makes it visible to whoever has access to the project/block. Settable ONLY by the creator of the document — another caller gets a named error. Omitted: does not touch the visibility.
contentLocaleNo`null` clears the declared language. Field omitted: does not touch the language.
appendMarkdownNoAPPENDS Markdown (GFM, same dialect as contentMarkdown) AFTER the existing content, which is kept node for node — so a long document is never re-sent in full just to add a section. Richtext documents only (an html document is refused: its source is replaced with `htmlSource`). Mutually exclusive with `content` and `contentMarkdown` (providing both is an explicit REFUSAL). Same write as any content change: `expectedVersion` applies, a revision is kept (or reported as `revisionSkipped`). Refusals name the line, counted from the first line of THIS text. There is no partial replace of a section: to rewrite one, send the whole document with `contentMarkdown`.
contentMarkdownNoReplaces the ENTIRE content, as Markdown (GFM) — RECOMMENDED PATH, same dialect as create_document (headings, lists, tables, quotes, code blocks, bold/italic/strikethrough/inline code, links, images, horizontal rules). This is not a partial patch: the new text REPLACES all of the old. An unsupported construct (raw HTML, YAML frontmatter, or a TASK list `- [ ]`/`- [x]`) is REFUSED with the offending node type named — it is not silently omitted from the document.
expectedVersionYesThe document version you believe you are editing (obtained via get_document). If it has diverged since, the call fails with the current version rather than overwriting a concurrent write.
expectedProjectIdNoUUID of the project targeted by THIS call. ACTUALLY targets this project instead of the session project. Refused without changing anything if access is not granted.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed1 schema field changed
    • addedInput schema / properties / appendMarkdown
      Added value: +{
      +  "description": "APPENDS Markdown (GFM, same dialect as contentMarkdown) AFTER the existing content, which is kept node for node — so a long document is never re-sent in full just to add a section. Richtext documents only (an html document is refused: its source is replaced with `htmlSource`). Mutually exclusive with `content` and `contentMarkdown` (providing both is an explicit REFUSAL). Same write as any content change: `expectedVersion` applies, a revision is kept (or reported as `revisionSkipped`). Refusals name the line, counted from the first line of THIS text. There is no partial replace of a section: to rewrite one, send the whole document with `contentMarkdown`.",
      +  "minLength": 1,
      +  "type": "string"
      +}
  2. Changed13 schema fields changed
    • changedInput schema / properties / archived / description
      Previous value: -"Archive (true) ou désarchive (false) le document. Omis : ne change pas l’état."New value: +"Archives (true) or unarchives (false) the document. Omitted: does not change the state."
    • changedInput schema / properties / cellId / anyOf
      Previous value: -[
      -  {
      -    "description": "Identifiant du bloc (cellule) du canevas — voir get_schema_overview pour la liste.",
      -    "maxLength": 200,
      -    "minLength": 1,
      -    "type": "string"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]New value: +[
      +  {
      +    "description": "Identifier of the canvas block (cell) — see get_schema_overview for the list.",
      +    "maxLength": 200,
      +    "minLength": 1,
      +    "type": "string"
      +  },
      +  {
      +    "type": "null"
      +  }
      +]
    • changedInput schema / properties / cellId / description
      Previous value: -"`null` DÉTACHE le document de tout bloc. Champ omis : ne touche pas à l’ancrage. Une valeur REMPLACE toute ancre existante (patron `update_task.assignees`)."New value: +"`null` DETACHES the document from any block. Field omitted: does not touch the attachment. A value REPLACES any existing attachment (pattern `update_task.assignees`)."
    • changedInput schema / properties / content / description
      Previous value: -"Remplace le contenu ENTIER — jamais un patch partiel de l’arbre. Réservé aux cas qui construisent l’arbre programmatiquement ; `contentMarkdown` est le chemin recommandé. Fournir les deux à la fois est un REFUS explicite (ambigu, jamais résolu en silence)."New value: +"Replaces the ENTIRE content — not a partial patch of the tree. Reserved for cases that build the tree programmatically; `contentMarkdown` is the recommended path. Providing both at once is an explicit REFUSAL (ambiguous, so it is not resolved silently)."
    • changedInput schema / properties / contentLocale / anyOf
      Previous value: -[
      -  {
      -    "description": "Langue du contenu (fr/en/de/es).",
      -    "enum": [
      -      "fr",
      -      "en",
      -      "de",
      -      "es"
      -    ],
      -    "type": "string"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]New value: +[
      +  {
      +    "description": "Language of the content (fr/en/de/es).",
      +    "enum": [
      +      "fr",
      +      "en",
      +      "de",
      +      "es"
      +    ],
      +    "type": "string"
      +  },
      +  {
      +    "type": "null"
      +  }
      +]
    • changedInput schema / properties / contentLocale / description
      Previous value: -"`null` efface la langue déclarée. Champ omis : ne touche pas à la langue."New value: +"`null` clears the declared language. Field omitted: does not touch the language."
    • changedInput schema / properties / contentMarkdown / description
      Previous value: -"Remplace le contenu ENTIER, en Markdown (GFM) — CHEMIN RECOMMANDÉ, même dialecte que create_document (titres, listes, tableaux, citations, blocs de code, gras/italique/barré/code en ligne, liens, images, règles horizontales). Jamais un patch partiel : le nouveau texte REMPLACE tout l’ancien. Un construit non supporté (HTML brut, frontmatter YAML, ou une liste de TÂCHES `- [ ]`/`- [x]`) est REFUSÉ avec le type de nœud fautif nommé — jamais silencieusement omis du document."New value: +"Replaces the ENTIRE content, as Markdown (GFM) — RECOMMENDED PATH, same dialect as create_document (headings, lists, tables, quotes, code blocks, bold/italic/strikethrough/inline code, links, images, horizontal rules). This is not a partial patch: the new text REPLACES all of the old. An unsupported construct (raw HTML, YAML frontmatter, or a TASK list `- [ ]`/`- [x]`) is REFUSED with the offending node type named — it is not silently omitted from the document."
    • changedInput schema / properties / documentId / description
      Previous value: -"Identifiant du document à modifier."New value: +"Identifier of the document to modify."
    • changedInput schema / properties / expectedProjectId / description
      Previous value: -"UUID du projet visé par CET appel. Cible RÉELLEMENT ce projet au lieu du projet de session. Refusé sans rien modifier si l'accès n'est pas accordé."New value: +"UUID of the project targeted by THIS call. ACTUALLY targets this project instead of the session project. Refused without changing anything if access is not granted."
    • changedInput schema / properties / expectedVersion / description
      Previous value: -"La version du document que tu crois éditer (obtenue via get_document). Si elle a divergé depuis, l'appel échoue avec la version actuelle plutôt que d'écraser une écriture concurrente."New value: +"The document version you believe you are editing (obtained via get_document). If it has diverged since, the call fails with the current version rather than overwriting a concurrent write."
    • changedInput schema / properties / htmlSource / description
      Previous value: -"REMPLACE la source ENTIÈRE d’un document `kind: \"html\"` — jamais un patch partiel. Sur un document richtext, ce champ est REFUSÉ en le nommant (la forme est immuable). Le texte de recherche du document est recalculé depuis la nouvelle source. Le document HTML COMPLET et AUTO-CONTENU : balisage + `<style>` + `<script>` inline, dans une seule chaîne (maximum 250000 caractères). Sert à ce qu’un document richtext ne peut pas porter — tableau de bord, rapport interactif, visualisation, calculateur. La documentation longue relève d’un document richtext ordinaire (`contentMarkdown`), qui reste éditable à la main.\n⚠️ RISQUE, DIT À L’UTILISATEUR AU CLIC « Exécuter » : le bac à sable protège sa SESSION (origine opaque, ni cookie ni stockage) mais ne garantit PAS que le contenu du document reste dans OrgGen — le canal WebRTC n’est pas fermé (mesuré en navigateur) : tout ce qu’un document embarque peut quitter OrgGen.\n⚠️ AUTO-CONTENU AU SENS STRICT : le document est servi dans un bac à sable SANS accès réseau ordinaire (`fetch`, WebSocket, ressource distante). Toute ressource DISTANTE ou RELATIVE (`<script src>`, `<link rel=stylesheet>`, `<img src=\"/x.png\">`, une police Google, un `@import` CSS) est REFUSÉE À L’ÉCRITURE, en nommant l’URL fautive — plutôt que d’accepter un document dont la moitié mourrait en silence à l’affichage. Les images s’embarquent en `data:`, le CSS et le JS s’écrivent en ligne.\n⚠️ DEUX LIGNES OBLIGATOIRES, dont l’oubli ne lève AUCUNE erreur — il rend juste un document qu’on croira cassé. (a) `body` déclare EXPLICITEMENT `background` ET `color` : le document est servi dans un cadre ISOLÉ, il n’hérite rien du thème de l’application, donc sans fond déclaré il s’affiche en BLANC au milieu d’un panneau sombre. La visionneuse définit `color-scheme` et `data-og-theme` sur `<html>`, mais `color-scheme` est un indice au moteur de rendu, PAS une feuille de style — il n’invente aucune couleur. (b) un `<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">`, et un contenu qui tient à ~390 px : le panneau est lisible sur téléphone. La visionneuse injecte ce `<meta>` s’il manque, mais ce filet ne conçoit aucun design — une grille en largeurs fixes restera hors écran.\n⚠️ NEUF CONSTRUCTIONS COURANTES SONT MORTES dans ce bac à sable, SANS qu’aucune erreur ne soit signalée (l’écriture réussit, le document s’affiche, le bouton reste inerte) — dont `alert()`, `window.print()`, `localStorage`, les formulaires, `eval`, et `confirm()` qui rend TOUJOURS `false` : la branche « annuler » s’exécute, c’est la seule dont le résultat est FAUX au lieu d’inerte. Les neuf, avec ce qui marche à la place, sont listées dans `get_playbook({topic: \"html\"})`."New value: +"REPLACES the ENTIRE source of a `kind: \"html\"` document — not a partial patch. On a richtext document, this field is REFUSED by naming it (the form is immutable). The document search text is recomputed from the new source. The COMPLETE, SELF-CONTAINED HTML document: markup + `<style>` + `<script>` inline, in a single string (maximum 250000 characters). Meant for what a richtext document cannot carry — an overview page, an interactive report, a visualization, a calculator. Long documentation belongs in an ordinary richtext document (`contentMarkdown`), which stays editable by hand.\n⚠️ RISK, STATED TO THE USER WHEN THEY CLICK \"▶ Run the document\": the sandbox protects the user's SESSION (opaque origin, no cookie or storage) but does NOT guarantee that the document's content stays inside OrgGen — the WebRTC channel is not closed (measured in a browser): anything a document embeds can leave OrgGen.\n⚠️ SELF-CONTAINED IN THE STRICT SENSE: the document is served in a sandbox WITHOUT ordinary network access (`fetch`, WebSocket, remote resource). Any REMOTE or RELATIVE resource (`<script src>`, `<link rel=stylesheet>`, `<img src=\"/x.png\">`, a Google font, a CSS `@import`) is REFUSED AT WRITE TIME, naming the offending URL — rather than accepting a document half of which would die silently at display time. Images are embedded as `data:`, CSS and JS are written inline.\n⚠️ TWO MANDATORY LINES, whose omission raises NO error — it just yields a document that will look broken. (a) `body` EXPLICITLY declares `background` AND `color`: the document is served in an ISOLATED frame, it inherits nothing from the application theme, so without a declared background it displays in WHITE in the middle of a dark panel. The viewer sets `color-scheme` and `data-og-theme` on `<html>`, but `color-scheme` is a hint to the rendering engine, NOT a stylesheet — it invents no color. (b) a `<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">`, and content that fits in ~390 px: the panel is readable on a phone. The viewer injects this `<meta>` if it is missing, but this safety net designs nothing — a grid in fixed widths will stay off-screen.\n⚠️ NINE COMMON CONSTRUCTIONS ARE DEAD in this sandbox, WITHOUT any error being reported (the write succeeds, the document displays, the button stays inert) — including `alert()`, `window.print()`, `localStorage`, forms, `eval`, and `confirm()`, which returns `false` in every case: the \"cancel\" branch runs, it is the only one whose result is WRONG instead of inert. The nine, with what works instead, are listed in `get_playbook({topic: \"html\"})`."
    • changedInput schema / properties / title / description
      Previous value: -"Titre du document (1 à 200 caractères)."New value: +"Document title (1 to 200 characters)."
    • changedInput schema / properties / visibility / description
      Previous value: -"'private' rend le document invisible à TOUT LE MONDE SAUF SON CRÉATEUR (y compris les éditeurs projet ordinaires) ; 'inherited' (défaut) le rend visible à qui a accès au projet/bloc. Réglable UNIQUEMENT par le créateur du document — un autre appelant reçoit une erreur nommée. Omis : ne touche pas à la visibilité."New value: +"'private' makes the document invisible to EVERYONE EXCEPT ITS CREATOR (including ordinary project editors); 'inherited' (default) makes it visible to whoever has access to the project/block. Settable ONLY by the creator of the document — another caller gets a named error. Omitted: does not touch the visibility."
  3. Changed2 schema fields changed
    • changedInput schema / properties / content / description
      Previous value: -"Remplace le contenu ENTIER — jamais un patch partiel de l’arbre. Réservé aux cas qui construisent l’arbre programmatiquement ; PRÉFÈRE `contentMarkdown`. Fournir les deux à la fois est un REFUS explicite (ambigu, jamais résolu en silence)."New value: +"Remplace le contenu ENTIER — jamais un patch partiel de l’arbre. Réservé aux cas qui construisent l’arbre programmatiquement ; `contentMarkdown` est le chemin recommandé. Fournir les deux à la fois est un REFUS explicite (ambigu, jamais résolu en silence)."
    • changedInput schema / properties / htmlSource / description
      Previous value: -"REMPLACE la source ENTIÈRE d’un document `kind: \"html\"` — jamais un patch partiel. Sur un document richtext, ce champ est REFUSÉ en le nommant (la forme est immuable). Le texte de recherche du document est recalculé depuis la nouvelle source. Le document HTML COMPLET et AUTO-CONTENU : balisage + `<style>` + `<script>` inline, dans une seule chaîne (maximum 250000 caractères). Sert à ce qu’un document richtext ne peut pas porter — tableau de bord, rapport interactif, visualisation, calculateur. Pour de la documentation longue, garde un document richtext ordinaire (`contentMarkdown`), qui reste éditable à la main.\n⚠️ RISQUE, DIT À L’UTILISATEUR AU CLIC « Exécuter » : le bac à sable protège sa SESSION (origine opaque, ni cookie ni stockage) mais ne garantit PAS que le contenu du document reste dans OrgGen — le canal WebRTC n’est pas fermé (mesuré en navigateur). N’embarque dans un document que ce qui peut quitter OrgGen.\n⚠️ AUTO-CONTENU AU SENS STRICT : le document est servi dans un bac à sable SANS accès réseau ordinaire (`fetch`, WebSocket, ressource distante). Toute ressource DISTANTE ou RELATIVE (`<script src>`, `<link rel=stylesheet>`, `<img src=\"/x.png\">`, une police Google, un `@import` CSS) est REFUSÉE À L’ÉCRITURE, en nommant l’URL fautive — plutôt que d’accepter un document dont la moitié mourrait en silence à l’affichage. Embarque tes images en `data:` et écris ton CSS/JS en ligne.\n⚠️ DEUX LIGNES OBLIGATOIRES, dont l’oubli ne lève AUCUNE erreur — il rend juste un document qu’on croira cassé. (a) `body` déclare EXPLICITEMENT `background` ET `color` : le document est servi dans un cadre ISOLÉ, il n’hérite rien du thème de l’application, donc sans fond déclaré il s’affiche en BLANC au milieu d’un panneau sombre. La visionneuse pose `color-scheme` et `data-og-theme` sur `<html>`, mais `color-scheme` est un indice au moteur de rendu, PAS une feuille de style — il n’invente aucune couleur. (b) un `<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">`, et un contenu qui tient à ~390 px : le panneau est lisible sur téléphone. La visionneuse injecte ce `<meta>` s’il manque, mais ce filet ne devine pas un design — une grille en largeurs fixes restera hors écran.\n⚠️ NEUF CONSTRUCTS COURANTS NE MARCHENT PAS dans ce bac à sable — dont `alert()`, `window.print()`, `localStorage`, les formulaires, `eval`, et `confirm()` qui rend TOUJOURS `false` (donc la branche « annuler » s’exécute). Appelle `get_playbook({topic: \"html\"})` AVANT d’écrire : la liste complète y est, avec ce qui marche à la place."New value: +"REMPLACE la source ENTIÈRE d’un document `kind: \"html\"` — jamais un patch partiel. Sur un document richtext, ce champ est REFUSÉ en le nommant (la forme est immuable). Le texte de recherche du document est recalculé depuis la nouvelle source. Le document HTML COMPLET et AUTO-CONTENU : balisage + `<style>` + `<script>` inline, dans une seule chaîne (maximum 250000 caractères). Sert à ce qu’un document richtext ne peut pas porter — tableau de bord, rapport interactif, visualisation, calculateur. La documentation longue relève d’un document richtext ordinaire (`contentMarkdown`), qui reste éditable à la main.\n⚠️ RISQUE, DIT À L’UTILISATEUR AU CLIC « Exécuter » : le bac à sable protège sa SESSION (origine opaque, ni cookie ni stockage) mais ne garantit PAS que le contenu du document reste dans OrgGen — le canal WebRTC n’est pas fermé (mesuré en navigateur) : tout ce qu’un document embarque peut quitter OrgGen.\n⚠️ AUTO-CONTENU AU SENS STRICT : le document est servi dans un bac à sable SANS accès réseau ordinaire (`fetch`, WebSocket, ressource distante). Toute ressource DISTANTE ou RELATIVE (`<script src>`, `<link rel=stylesheet>`, `<img src=\"/x.png\">`, une police Google, un `@import` CSS) est REFUSÉE À L’ÉCRITURE, en nommant l’URL fautive — plutôt que d’accepter un document dont la moitié mourrait en silence à l’affichage. Les images s’embarquent en `data:`, le CSS et le JS s’écrivent en ligne.\n⚠️ DEUX LIGNES OBLIGATOIRES, dont l’oubli ne lève AUCUNE erreur — il rend juste un document qu’on croira cassé. (a) `body` déclare EXPLICITEMENT `background` ET `color` : le document est servi dans un cadre ISOLÉ, il n’hérite rien du thème de l’application, donc sans fond déclaré il s’affiche en BLANC au milieu d’un panneau sombre. La visionneuse définit `color-scheme` et `data-og-theme` sur `<html>`, mais `color-scheme` est un indice au moteur de rendu, PAS une feuille de style — il n’invente aucune couleur. (b) un `<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">`, et un contenu qui tient à ~390 px : le panneau est lisible sur téléphone. La visionneuse injecte ce `<meta>` s’il manque, mais ce filet ne conçoit aucun design — une grille en largeurs fixes restera hors écran.\n⚠️ NEUF CONSTRUCTIONS COURANTES SONT MORTES dans ce bac à sable, SANS qu’aucune erreur ne soit signalée (l’écriture réussit, le document s’affiche, le bouton reste inerte) — dont `alert()`, `window.print()`, `localStorage`, les formulaires, `eval`, et `confirm()` qui rend TOUJOURS `false` : la branche « annuler » s’exécute, c’est la seule dont le résultat est FAUX au lieu d’inerte. Les neuf, avec ce qui marche à la place, sont listées dans `get_playbook({topic: \"html\"})`."
  4. First observed

TDQS

A4.9/5.0
Behavior5/5

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

Annotations declare destructiveHint=true, and the description goes well beyond that: it discloses the revision-collapsing rule (same author/writer within 10 minutes overwrites history), the revisionSkipped response contract, that warnings name unconvertible Markdown constructs, that raw HTML/checkboxes/deep nesting are refused, and even that a firewall 403 arrives with no application message. This is substantive behavioral context not present in the structured fields.

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?

Front-loads the core purpose and the write-path choice, and every paragraph covers a distinct concern (versioning, history, conversions, firewall, URL). It is, however, very long and dense with ⚠️-heavy emphasis, making it a wall of text an agent must parse carefully; some of the htmlSource risk prose could be compressed or deferred to get_playbook.

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

Completeness5/5

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

With no output schema, the description supplies the return contract itself (revisionSkipped shape, warnings absence semantics, url direct link). For a 12-parameter destructive mutation tool, the coverage of concurrency, history loss, and refusal behavior leaves no material gap for correct invocation.

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

Parameters5/5

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

Although schema coverage is 100%, the description adds cross-parameter semantics the schema cannot express: cellId:null detaches vs omitted leaves attachment untouched, the exclusivity between appendMarkdown and the two content fields, that provided fields are written while others stay intact, and that content/htmlSource are whole replacements rather than patches. It directly mirrors the update_task.cellId convention for consistency.

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?

Opens with a specific verb and resource ('Modifies an existing document') and then enumerates the modifiable facets (title, content, language, attachment, archiving). It clearly distinguishes the write paths (contentMarkdown / content / appendMarkdown / htmlSource) so an agent can tell this apart from create_document and its siblings without opening the schema.

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

Usage Guidelines5/5

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

Gives explicit routing guidance: contentMarkdown is the 'RECOMMENDED PATH', content is 'reserved for cases that build the tree programmatically', appendMarkdown is for adding at the end, htmlSource is only for kind:html, and expectedVersion must be read via get_document first. It also states exclusions (appendMarkdown is exclusive with the two others) and refusal conditions, which is exactly when-to-use/when-not.

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.