Conversation
Wire the existing document-api blocks.delete / blocks.deleteRange ops into the MCP tool surface as superdoc_edit actions delete_block and delete_block_range, so clients can remove an entire block node, not just its text content. Deleting a heading/paragraph's text previously left an empty container behind, still rendering as block spacing. Regenerates the MCP catalog and intent-dispatch (Node, browser, Python) and adds end-to-end protocol tests proving physical block removal (block-count decrement + nodeId absence). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
4c75ffe to
b36f627
Compare
|
Thanks for the contribution, Jacob! We reproduced the block-deletion gap in the released MCP package. The newer core path handles selected paragraph deletion on main, but it hasn’t shipped, and we haven’t established equivalent range support. We’re keeping this PR open while we work through those remaining gaps. |
|
I have read the CLA Document and I hereby sign the CLA Jacob Jove seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account. |
Summary
Wires the existing
document-apiblocks.delete/blocks.deleteRangeops into the MCP tool surface as two newsuperdoc_editactions —delete_blockanddelete_block_range— so an MCP client can remove an entire block node, not just its text. Closes the gap where deleting a heading/paragraph's text leaves an empty container that still renders as block spacing.Proposed in #3586 (surface options A/B/C discussed there). This PR implements option A.
What changed
packages/document-api/src/contract/operation-definitions.ts):intentGroup:'edit'+intentAction:'delete_block'onblocks.delete;intentGroup:'edit'+intentAction:'delete_block_range'onblocks.deleteRange; one disambiguation sentence and oneinputExampleinINTENT_GROUP_META.edit.pnpm run generate:all:apps/mcp/src/generated/{catalog,intent-dispatch.generated}.ts,packages/sdk/langs/browser/src/intent-dispatch.ts,packages/sdk/tools/intent_dispatch_generated.py.apps/mcp/src/__tests__/protocol.test.ts): action-enum assertion plus three end-to-end cases asserting physical block removal (block-count decrement + nodeId absence) — one demonstrating the text-delete-leaves-empty-container bug vsdelete_blockremoving it, and one assertingdelete_block_rangeremoves a contiguous top-level span (deletedCount+ spanned nodeIds absent, with a neighbor outside the range surviving so the delete is proven bounded).Addressing
delete(existing) takes a textref;delete_blocktakestarget:{kind:'block',nodeType,nodeId};delete_block_rangetakesstart/end(each a{kind:'block',nodeType,nodeId}top-level block, inclusive). Thedelete_blockname is forced by the existingdeletecollision in theeditgroup.Verification
apps/mcp41 pass (4 new) ·document-api1480 pass (blocks + contract-parity) · conformance 1198 pass · codegen incl. cross-lang-parity (Node↔Python) 57 pass · typecheck 0 new errors vs baseline.Limitations
supportsTrackedMode: false, so block-node removal isn't recordable as a tracked change (cf. feat(track-changes): block-level structural tracked changes for tables #3343 for tables).superdoc_mutationsblock.deletestep (option C); a sound follow-up.blocks.deleteoverlapstables.delete/lists.deleteas the type-agnostic primitive; the type-specific tools remain.delete_block_rangecontract entry carries the disambiguation sentence but not its owninputExample(theeditgroup example coversdelete_block); deferred until the maintainer surface decision in MCP: expose block-node deletion (blocks.delete / blocks.deleteRange) via superdoc_edit #3586 (option A vs a dedicatedsuperdoc_blockstool vs asuperdoc_mutationsblock.deletestep) is settled, to avoid regenerating prose that a surface change would rewrite.