feat: Compute write tools - #74
Conversation
…l destroy resources
There was a problem hiding this comment.
Pull request overview
Adds opt-in (scope-gated) Compute Engine write tools to the MCP server while keeping the default experience read-only. This extends the existing scope/confirmation architecture so compute mutations only appear in tools/list when IONOS_MCP_TOOL_SCOPE enables them, and introduces shared preview rendering for two-phase confirmations.
Changes:
- Introduces action-verb classification (
start_,stop_,attach_, etc.) alongside CRUD prefixes for consistent scope gating in both direct registration and the dynamic dispatcher. - Adds product-agnostic preview/confirmation rendering helpers and expands compute write tools (create/update/delete + selected actions) with accompanying tests.
- Updates documentation, changelog, and bumps the compute SDK dependency to
sdk-go-bundle/products/compute/v2 v2.0.7.
Reviewed changes
Copilot reviewed 75 out of 76 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| tools/scope.go | Adds action-verb classification and RegisterActionTool for non-CRUD operations; updates scope/tool annotation logic. |
| tools/scope_test.go | Adds tests for action-verb invariants, classification parity, annotations, and registration gating/panics. |
| tools/preview.go | New shared preview renderer and helper utilities for two-phase confirmation flows. |
| tools/helpers.go | Updates SDK error interface/comments and keeps helper surface for tool results/errors. |
| tools/dynamic/search_test.go | Adds defense-in-depth test ensuring action verbs are classified and scope-guarded in dynamic mode. |
| tools/dynamic/dynamic.go | Improves ionos_call_tool description to document action verbs, scope requirements, and two-phase behavior. |
| tools/confirm.go | Tightens/updates confirmation-store documentation for two-phase flow semantics. |
| tools/compute/volume.go | Migrates compute read tools to scope-gated registration (RegisterTool) and updates signature. |
| tools/compute/volume_actions.go | New volume snapshot create + restore tools with confirmation previews and action-verb classification. |
| tools/compute/template.go | Migrates template read tools to scope-gated registration and updates signature. |
| tools/compute/target_group.go | Migrates target group read tools to scope-gated registration and updates signature. |
| tools/compute/target_group_write.go | New create/update/delete target-group write tools with preview + carry-forward semantics where needed. |
| tools/compute/snapshot.go | Migrates snapshot read tools to scope-gated registration and updates signature. |
| tools/compute/snapshot_write.go | New snapshot update/delete write tools with two-phase delete previews. |
| tools/compute/server.go | Migrates server read tools to scope-gated registration and updates signature. |
| tools/compute/security_group.go | Migrates security-group read tools to scope-gated registration and updates signature. |
| tools/compute/security_group_write.go | New create/update/delete security-group write tools with blast-radius previews for delete. |
| tools/compute/security_group_assign.go | New assign_* action tools (PUT replace semantics) for server/NIC security-group assignment. |
| tools/compute/request.go | Migrates request read tools to scope-gated registration and updates signature. |
| tools/compute/register.go | Wires compute read/write/action registrars together under shared scope and confirm store. |
| tools/compute/private_cross_connect.go | Migrates PCC read tools to scope-gated registration and updates signature. |
| tools/compute/private_cross_connect_write.go | New create/update/delete PCC write tools with peer-aware delete preview and preflight checks. |
| tools/compute/nic.go | Migrates NIC read tools to scope-gated registration and updates signature. |
| tools/compute/nic_write.go | New create/update/delete NIC write tools with carry-forward of non-pointer lan and delete blast radius. |
| tools/compute/network_loadbalancer.go | Migrates NLB read tools to scope-gated registration and updates signature. |
| tools/compute/nat_gateway.go | Migrates NAT gateway read tools to scope-gated registration and updates signature. |
| tools/compute/location.go | Migrates location read tools to scope-gated registration and updates signature. |
| tools/compute/loadbalancer.go | Migrates classic LB read tools to scope-gated registration and updates signature. |
| tools/compute/loadbalancer_write.go | New create/update/delete classic LB tools with delete blast-radius preview. |
| tools/compute/lan.go | Migrates LAN read tools to scope-gated registration and updates signature. |
| tools/compute/lan_write.go | New create/update/delete LAN tools with two-phase create/delete previews and PATCH updates. |
| tools/compute/ip_block.go | Migrates IP block read tools to scope-gated registration and updates signature. |
| tools/compute/ip_block_write.go | New create/delete IP block tools (no update) with consumer-aware delete preview. |
| tools/compute/image.go | Migrates image read tools to scope-gated registration and updates signature. |
| tools/compute/image_write.go | New image update/delete tools with carry-forward for required/non-pointer fields and two-phase delete. |
| tools/compute/firewall_rule.go | Migrates firewall-rule read tools to scope-gated registration and updates signature. |
| tools/compute/datacenter_write.go | Refactors datacenter write previews to use shared preview renderer and token remediation helper. |
| tools/compute/contract.go | Migrates contract read tool to scope-gated registration and updates signature. |
| tools/compute/application_loadbalancer.go | Migrates ALB read tools to scope-gated registration and updates signature. |
| test/setup_test.go | Adds computeOnlyTools helper to isolate compute tool registration in tests. |
| test/compute_write_test.go | Adds exhaustive test ensuring every compute tool is annotated and classification matches tool names. |
| test/compute_snapshot_image_write_test.go | New test suite for snapshot/image write tools: PATCH bodies, two-phase flows, and scope gating. |
| README.md | Updates public docs to describe compute write tools, action verbs, tool counts, and safety warning. |
| handoff.md | New internal handoff doc capturing architecture, research approach, and gotchas for compute write tools. |
| go.sum | Updates dependency checksums for compute SDK bump. |
| go.mod | Bumps compute SDK from v2.0.5 to v2.0.7. |
| docs/compute/volume.md | Expands volume docs to include new write/action tools and confirmation semantics. |
| docs/compute/target-group.md | Updates target group docs for write tools and list-replacement semantics. |
| docs/compute/snapshot.md | Adds snapshot write-tool docs and clarifies absence of create_snapshot. |
| docs/compute/security-group.md | Adds security-group assignment/write tool docs and replacement semantics warnings. |
| docs/compute/private-cross-connect.md | Documents PCC write tools and LAN-side attachment behavior. |
| docs/compute/nic.md | Adds NIC write-tool docs with warnings about LAN IDs and firewall activation. |
| docs/compute/network-loadbalancer.md | Updates NLB docs to include write tools and list-replacement semantics section. |
| docs/compute/nat-gateway.md | Updates NAT gateway docs to include write tools and list-replacement semantics section. |
| docs/compute/loadbalancer.md | Documents classic LB write tools and notes missing balanced-NIC attach/detach tools. |
| docs/compute/lan.md | Adds LAN write-tool docs including two-phase delete and disruptive change warnings. |
| docs/compute/ip-block.md | Adds IP block write-tool docs and explains why update/rename is not offered. |
| docs/compute/image.md | Adds image write-tool docs and clarifies no create_image. |
| docs/compute/firewall-rule.md | Updates firewall-rule docs for write tools and documents clear vs CIDR pitfalls. |
| docs/compute/application-loadbalancer.md | Updates ALB docs to include write tools and list-replacement semantics section. |
| CLAUDE.md | Extends repository guidance on write-tools, SDK serialization hazards, and shared preview utilities. |
| CHANGELOG.md | Updates changelog to describe compute write operations, gating, and confirmation flow. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 75 out of 76 changed files in this pull request and generated no new comments.
Suppressed comments (4)
tools/compute/target_group_write.go:83
- The preview's replay arguments omit required fields (
algorithmandprotocol). If a user follows the preview and callscreate_target_groupagain with onlyname+confirmation_token, the handler will reject the call before it can consume the token. Include the required fields inReplay(and ideally mention thattargetsmust also be repeated if provided).
docs/compute/lan.md:140 - The docs say
update_lancan detach a LAN from a cross connect by passing an empty string forpcc, but the actual input schema explicitly states detaching is not exposed (see tools/inputs.go:327). This should be corrected to avoid suggesting a workflow the tool cannot perform.
| `pcc` | string | No | Attach to this cross connect ID, or pass an empty string to detach. |
tools/compute/private_cross_connect_write.go:73
- This tool description says you can "attach or detach" LANs via
update_lan'spccfield, but UpdateLanInput currently cannot clearpcc(tools/inputs.go:327) and delete_pcc's error text says detaching isn't exposed yet. Please adjust the wording to avoid claiming a detach path that isn't implemented.
tools/compute/target_group_write.go:53 - When token consumption fails, the remediation text says to re-run with only
name, but the tool also requiresalgorithmandprotocolon every call. Updating this guidance makes it possible to follow without immediately hitting the "algorithm is required" validation error.
This issue also appears on line 79 of the same file.
Co-authored-by: Mihaela Mihalescu <mihaela-violeta.mihalescu1@ionos.com>
Opt-in write operations for Compute Engine
69 write tools. Read-only by default — nothing changes unless
IONOS_MCP_TOOL_SCOPEis set.read(default)writecreate_*,update_*,start_/resume_/attach_/assign_destructivedelete_*,stop_/reboot_/suspend_/upgrade_/restore_/detach_19 creates, 19 updates, 20 deletes, 11 actions — data centers, servers, volumes, NICs, LANs,
firewall rules, security groups + rules, IP blocks, classic/network/application load balancers
tools/list. Enforced in all load modes, re-checked in thedynamicdispatcher.stop_serveris a destructivePOST,detach_server_volumea non-destructiveDELETE.token bound to that target and operation. Delete previews list what else is affected.
fields serialize unconditionally — eleven fields across eight models are read and carried
forward. Without that, renaming an NLB forwarding rule would empty its backend pool.
Gaps found
locationin update requests; the SDKmodels
location/sizeas non-pointer fields it always serializes.IpblocksPutis noescape.
sdk-go/v6guards them, which is how Terraform renames a block. → model as pointers.422 [(root).properties] Attribute not allowed in resource reference.Nic.PropertiesandImage.Propertiesare non-pointer;Volumeisn't, which is whyattach_server_volumeworks. Sending the current values doesn't help — presence is the objection. → model these
bodies as id-only.
both resources survive), but
pccis a plain*stringwith no null form. Compounded byPccsDeleterequiring no LANs attached. → modelpccasNullableString.0.0.0.0/0on a firewall rule silently matches nothing — the API stores the bare0.0.0.0, so a rule meant to open a port closes it. Now rejected with the right remedy.Missing tools
Not in this PR. Roughly in order of value.
PUT (full-replace) is not exposed at all — 35 endpoints. Every update here is a
PATCH.21 of those PUTs are on resources this PR already writes (
DatacentersPut,ServersPut,VolumesPut,ServersNicsPut,LansPut,IpblocksPut, both forwarding-rule flavours,TargetgroupsPut,NatgatewaysPut,SecuritygroupsPut,SnapshotsPut,ImagesPut, …).Worth a deliberate decision rather than a blanket add: replace semantics are riskier than
partial update, since an omitted field is cleared rather than kept. But they are also the only
way to express "clear this field" for properties the SDK models without a null form — which is
exactly gap 3, and would unblock the LAN/cross-connect detach without an SDK change.