You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The apps/mcp server can delete text (superdoc_edit action:"delete", superdoc_mutations text.delete) but has no way to remove an entire block node. Deleting a heading's or paragraph's text leaves the empty <w:p> container behind — it still renders as block/heading spacing — so an MCP client (e.g. an AI agent running a redline/cleanup pass) can't remove a clause, heading, or stray empty paragraph.
The capability already exists in document-api: blocks.delete and blocks.deleteRange are implemented, tested, and wired through the super-editor adapter (they physically remove the container via deleteBlockNodeById / tr.delete()), merged in #3444. They're just not exposed on the MCP tool surface: their operation-definitions.ts entries carry no intentGroup/intentAction, so codegen skips them.
Proposed solution
Expose both as actions on the existing superdoc_edit tool (intentGroup: 'edit'):
blocks.deleteRange → delete_block_range, input { start, end }
This is the smallest additive change: two field-pairs on the contract plus regenerated catalog/dispatch, no new tool, no plan-engine work. The delete_block name is forced by a collision, since the existing text-delete op already owns intentAction:'delete' in the edit group.
A draft PR implementing exactly this is up (#3587): regenerated MCP catalog plus Node/browser/Python dispatch, and end-to-end apps/mcp protocol tests proving physical block removal (block-count decrement + nodeId absence). Opened as draft to confirm the surface choice before marking ready.
Alternatives considered
Dedicated superdoc_blocks tool (action:"delete" / "delete_range"). Matches the structural-delete precedent (lists.delete→superdoc_list action:"delete", tables.delete→superdoc_table action:"delete") and avoids the delete collision, but blocks.list already lives under superdoc_get_content, so this yields a 2-op tool that can't list; a whole new tool for two ops is heavier.
superdoc_mutationsblock.delete step. Enables atomic batching of block removal within a multi-step redline, but requires extending the plan-engine step framework. A sound follow-up, not v1.
Happy to rework toward either if you'd prefer.
Additional context / limitations
blocks.delete / blocks.deleteRange have supportsTrackedMode: false, so block-node removal can't currently be recorded as a tracked change; the "AI suggests a clause deletion as a redline" workflow isn't covered. Tracked structural deletion is a separate effort (cf. feat(track-changes): block-level structural tracked changes for tables #3343 for tables).
blocks.delete covers a superset of node types (paragraph, heading, listItem, table, sdt), overlapping tables.delete / lists.delete. It's the type-agnostic primitive alongside the type-specific tools.
Environment: superdoc-dev/superdoc @ current main.
What problem does this solve?
The
apps/mcpserver can delete text (superdoc_edit action:"delete",superdoc_mutations text.delete) but has no way to remove an entire block node. Deleting a heading's or paragraph's text leaves the empty<w:p>container behind — it still renders as block/heading spacing — so an MCP client (e.g. an AI agent running a redline/cleanup pass) can't remove a clause, heading, or stray empty paragraph.The capability already exists in
document-api:blocks.deleteandblocks.deleteRangeare implemented, tested, and wired through the super-editor adapter (they physically remove the container viadeleteBlockNodeById/tr.delete()), merged in #3444. They're just not exposed on the MCP tool surface: theiroperation-definitions.tsentries carry nointentGroup/intentAction, so codegen skips them.Proposed solution
Expose both as actions on the existing
superdoc_edittool (intentGroup: 'edit'):blocks.delete→delete_block, input{ target: { kind:'block', nodeType, nodeId } }blocks.deleteRange→delete_block_range, input{ start, end }This is the smallest additive change: two field-pairs on the contract plus regenerated catalog/dispatch, no new tool, no plan-engine work. The
delete_blockname is forced by a collision, since the existing text-delete op already ownsintentAction:'delete'in theeditgroup.A draft PR implementing exactly this is up (#3587): regenerated MCP catalog plus Node/browser/Python dispatch, and end-to-end
apps/mcpprotocol tests proving physical block removal (block-count decrement + nodeId absence). Opened as draft to confirm the surface choice before marking ready.Alternatives considered
superdoc_blockstool (action:"delete"/"delete_range"). Matches the structural-delete precedent (lists.delete→superdoc_list action:"delete",tables.delete→superdoc_table action:"delete") and avoids thedeletecollision, butblocks.listalready lives undersuperdoc_get_content, so this yields a 2-op tool that can't list; a whole new tool for two ops is heavier.superdoc_mutationsblock.deletestep. Enables atomic batching of block removal within a multi-step redline, but requires extending the plan-engine step framework. A sound follow-up, not v1.Happy to rework toward either if you'd prefer.
Additional context / limitations
blocks.delete/blocks.deleteRangehavesupportsTrackedMode: false, so block-node removal can't currently be recorded as a tracked change; the "AI suggests a clause deletion as a redline" workflow isn't covered. Tracked structural deletion is a separate effort (cf. feat(track-changes): block-level structural tracked changes for tables #3343 for tables).blocks.deletecovers a superset of node types (paragraph, heading, listItem, table, sdt), overlappingtables.delete/lists.delete. It's the type-agnostic primitive alongside the type-specific tools.Environment:
superdoc-dev/superdoc@ currentmain.