outline-mcp demonstrates solid foundational quality with 23 well-organized tools. Tool naming follows verb_noun conventions consistently (node_create, node_update, snapshot_restore, etc.). All tools have descriptions ranging 95 - 260 characters, meeting the 10 - 1024 char baseline. Parameter schemas are visible and typed. However, significant gaps exist: (1) Output schemas are largely undocumented, the code shows tool implementations return CallToolResult but the actual field structure agents should expect is not formally specified in the tool definitions. (2) Many parameters lack explicit constraints (e.g., node_type accepts 'section' or 'content' but this is only mentioned in description text, not as an enum in schema). (3) Error handling descriptions are minimal, tools reference 'map_err(Self::to_mcp_error)' but the error guidance to agents is weak. (4) Some parameter descriptions are thin: e.g., 'Position among siblings (optional)' doesn't specify valid range or default behavior. (5) No idempotency or retry guidance despite several destructive operations (node_move, snapshot_restore, batch_update). The server handles a complex domain well (hierarchical notes, snapshots, diffs) and composition is sound, but lacks LLM-optimization details needed for robust agent planning.
Atomically move multiple nodes to new parents. All succeed or none persist.
Atomically update multiple nodes. All succeed or none persist. Body/placeholder are merged with existing content; supply the full value to replace.
Show recent changes to the book (all nodes, reverse chronological).
Export a section as a Markdown checklist with checkboxes. First run `toc` to find the section ID, then pass it as subtree_root (e.g. '2'). Omit subtree_root for full book export. Book is NOT modified.
Export the current book as Markdown or JSON.
Generate URL routing rules from inject/scope properties in a subtree.
Output schemas are not formally documented. Tools return CallToolResult but agents cannot inspect what fields to expect in responses (e.g., does snapshot_diff return a unified string, line-by-line array, or structured diff object?). This forces agents to rely on trial-and-error or tool-specific prompts.
Enum constraints are mentioned only in descriptions, not declared in JSON Schema. E.g., node_type accepts 'section' or 'content', format accepts 'markdown' or 'json', action accepts 'move' or 'remove', these should be JSON Schema enums so agents can see valid options without parsing text.
Inferred effective spec: <=2025-11-25.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | D | 59 | <=2025-11-25 | v2 |
Import a Markdown or JSON file as the current book's structure.
Create a new book with the given slug and title. Selects it automatically.
Add a new node to the book. Use a parent ID from `toc` output (e.g. '1') to nest under a section, or omit for root-level.
Show changelog for a specific node (create/update/move/delete events).
Move or delete a node (and its descendants). Specify node by ID from `toc` output (e.g. '2-3'). Action 'move' relocates, 'remove' deletes.
Query nodes by property filter. Returns matching nodes with paths.
Edit a node's title, body, type, or placeholder. Specify the node by ID from `toc` output (e.g. '2-3'). Only specified fields are changed.
Select which book (slug) to operate on. Run `shelf` first to list available books.
List all books in the shelf directory with their slugs and node counts.
Create a named snapshot of the current book state for later restore.
Show diff between current book and a snapshot (side-by-side or unified).
Export a snapshot as Markdown or JSON file.
Bulk export all snapshots to a directory.
List all snapshots with timestamps and optional descriptions.
Restore the book to a previous snapshot by tag name.
Rename or update a snapshot's description.
Show table of contents with numbered IDs (e.g. 1, 1-1, 2-3). Run this first — use the returned IDs to specify nodes in `checklist`, `node_create`, and other tools.
Destructive operations (node_move with 'remove', snapshot_restore, batch_update, batch_move) lack confirmation or dry-run support. No guidance on how to handle errors mid-operation (e.g., if batch_move succeeds on 3/5 items, how does the agent undo the partial state?). This violates the confirmation-request pattern for irreversible actions.
Error handling is generic. Code shows 'map_err(Self::to_mcp_error)' but error responses to agents do not indicate: (1) is the error retryable? (2) should the user be asked to intervene? (3) what specific constraint was violated? Without error classification, agents cannot reason about recovery.
Parameter range constraints are underdocumented. E.g., max_depth in init, limit in node_history and book_history, position in node_create lack explicit min/max values. Agents have no guidance on what 'out of range' looks like.
No idempotency guarantees documented. Agents may retry on network failures or ambiguous errors, tools like batch_update and batch_move should explicitly state whether repeated calls with the same input are safe (idempotent_hint=true in annotations) or risk duplicates.
Tool composition dependencies are not explicit. E.g., most tools require a book to be selected first (select_book or init), but this prerequisite is not stated in tool descriptions. Agents may attempt tools without realizing a setup step is needed.
Several parameters accept hierarchical node IDs (e.g., '2-3') but validation rules and error messages for invalid IDs are not documented. If an agent passes '2-99' and no such node exists, what error is returned? How should the agent recover?