Safe Mutation Broker
Two-step creation of Fabric resources through the MCP server: propose with a dry run, then confirm.
Model#
The broker is the only part of the MCP server that can change an account. A create passes through two tool calls.
fabric_propose_changesends the create request to Fabric withdryRun=trueand stores the request when Fabric accepts it. It returns a confirm token only for a stored request.fabric_confirm_changeshows the user every field of the stored request and sends the real create only after the user accepts.
The server has no other code path to a create. The confirm call takes a token and no request body, so the request cannot change after the dry run.
Scope#
| Property | Value |
|---|---|
| Default | Off. The mutate toolset must be named in EQUINIX_MCP_TOOLSETS. |
| Change types | connection_create, network_create, service_token_create |
| Updates | None |
| Deletes | None, by policy |
| Token lifetime | 10 minutes, single use, held in the memory of that server process |
Propose#
fabric_propose_change takes a change type and a spec. The broker compiles the spec into the same typed builder calls a Java program would make, and sends the request with dryRun=true.
The broker rejects a spec before any API call when a known field has the wrong JSON type, when an integer is fractional or out of range, or when a string contains control characters. A field is rejected, never dropped, so the request that Fabric validated is the request that is hashed, displayed and executed.
The result carries:
- the validation result from Fabric
- a price context: for a connection, a monthly and non-recurring estimate with its provenance where a rate card can price it, and an explicit
priced: falseotherwise - a confirm token with the prefix
chg-
The chg- token is a lookup key into the proposal store of that server process. It is unrelated to the cloud provider activation keys described under Cloud-to-cloud, which the broker neither issues nor accepts.
Confirm#
fabric_confirm_change takes the token as its only argument and performs four steps in order.
- It consumes the token. The token cannot be used again, whatever the outcome of the later steps.
- It checks that the proposal exists, has not expired, was not used before, and that the stored spec still matches its hash.
- It sends an MCP form elicitation to the client. The form lists the change type, the target, every field the create will send as escaped JSON literals, the price context, the age of the proposal and the SHA-256 of the spec.
- It executes the stored spec when the user accepts with
confirm = true.
Every result carries confirm_checks (proposal_exists, not_expired, not_previously_used, spec_matches_binding), human_confirmation {status, detail} and token_state.
| Client | User answer | human_confirmation.status | Executed |
|---|---|---|---|
| Declared form elicitation | Accept with confirm = true | accepted | Yes |
| Declared form elicitation | Decline, or accept without confirm = true | declined | No |
| Declared form elicitation | Cancel | cancelled | No |
| Declared form elicitation | No answer within EQUINIX_MCP_ELICIT_TIMEOUT_MS (default 300000 ms) | timed_out | No |
| Declared form elicitation | Round trip failed | failed | No |
| Did not declare it | Not asked | unsupported_by_client | No, unless the operator opted in |
Because the token is consumed in every row, any status other than accepted requires a new fabric_propose_change.
Clients without elicitation#
A client that did not declare form elicitation cannot show the prompt. For such a client, fabric_confirm_change in 4.0 executes nothing, where release 3.0.0 executed the create.
EQUINIX_MCP_ALLOW_UNCONFIRMED_MUTATIONS=true restores execution for a client without elicitation. The server then performs no approval check of its own, and the tool-approval prompt of the MCP host is the only point at which a person sees the change. Set the variable only on a host that shows that prompt for every tool call.
Limits of the guarantee#
- The status
acceptedmeans that the client reported an acceptance. The server cannot tell whether a person read the prompt, and a host that approves elicitations automatically removes the check. - The dry run validates the request at proposal time, and up to 10 minutes can pass before the confirm. If a VLAN or a bandwidth allocation is taken during that time, the create fails with the error the API returns.
- A created connection is billable from the moment it is provisioned. The broker has no delete tool, so removing it is done through the SDK, the portal or another tool.
- The price context is a design-time estimate from the rate cards, see Cost and value.
Example exchange#
fabric_propose_change arguments for a connection:
{
"change_type": "connection_create",
"spec": {
"type": "EVPL_VC",
"name": "dc-port-to-aws",
"bandwidth_mbps": 500,
"notification_emails": ["noc@example.com"],
"a_side": {
"port_uuid": "c1e3a8f0-0000-0000-0000-000000000000",
"link_protocol": {"type": "dot1q", "vlan_tag": 1000}
},
"z_side": {
"service_profile_uuid": "69ee618d-0000-0000-0000-000000000000",
"metro_code": "DC"
}
}
}Each side names exactly one endpoint: port_uuid, service_profile_uuid, cloud_router_uuid, network_uuid, service_token_uuid or virtual_device_uuid. A service-profile Z-side also needs metro_code, and a spec with an unknown field is rejected. The tool's published inputSchema describes the three specs in full, including the provider authentication fields that this example leaves out.
The server answers with the validation, the price context and a token such as chg-7f3a.... The agent calls fabric_confirm_change with that token, the host shows the form, and the result reports human_confirmation.status and, when accepted, the UUID of the created connection.