Package com.eqixiac.equinix.mcp.server.broker


package com.eqixiac.equinix.mcp.server.broker
The Safe Mutation Broker - the embedded MCP server's only route to a mutation, enforced by the server rather than by prompt discipline: agents propose, dry-run diffs decide, humans confirm.

The broker is a two-phase protocol over two tools in the opt-in mutate toolset (never served unless the operator names it in the toolset selection):

  1. fabric_propose_change - takes a typed create specification (ChangeType: connection, network, or service-token create; there are no update or delete change types) and executes the real, spec-documented dry run through the SDK's fluent creators (dryRun=true on the actual Fabric v4 endpoint). The Equinix API validates the exact payload that a confirm would send, but provisions nothing. The tool returns the validated entity, a rate-card price context where estimable (honest unpriced otherwise), the compiled request, and a single-use confirm token bound to the SHA-256 of that compiled request (the change type plus the canonical JSON body sent on the wire).
  2. fabric_confirm_change - takes only the confirm token, recompiles the stored spec and requires it to produce the bound request, asks the MCP client to obtain the user's approval, re-checks the TTL when the answer arrives, and on approval sends that request without dryRun, creating billable resources. The agent cannot alter the spec between phases: a different spec is a different proposal with a different token, and any drift between what the dry run validated and what would be sent stops the create.

Tokens live in the in-memory, single-process ProposalStore for 10 minutes and are consumed on the first confirm attempt, successful or not. At most 20 proposals are pending; proposing beyond that evicts the oldest and the propose result lists it under evicted_proposals. Expired, evicted, unknown and replayed tokens each fail with a message telling the agent to re-propose. Every confirm result and every token error carries the redemption predicates as confirm_checks: proposal_exists, not_evicted, not_expired, not_previously_used, request_matches_binding.

A client notifications/cancelled stops fabric_confirm_change before the create is sent (the token is not consumed when the call is cancelled before it starts); once the create has been sent the result reports that it executed.

Human confirmation

A tool argument cannot prove a person approved a mutation, because the calling model writes every argument. The MCP client can: it is the party that renders an elicitation to the user. fabric_confirm_change therefore sends a form elicitation (change type, target, price context, proposal age, request SHA-256 and every field of the compiled request) after consuming the token and before executing.

fabric_confirm_change by client capability and answer
ClientAnswerhuman_confirmation.statusExecuted
declared form elicitationaccept with confirm = true acceptedyes
declared form elicitationdecline, or accept without confirm = true declinedno
declared form elicitationcancelcancelledno
declared form elicitationnone within EQUINIX_MCP_ELICIT_TIMEOUT_MS (default 300000 ms)timed_outno
declared form elicitationthe round trip failedfailedno
declared form elicitationthe client cancelled the tool call call_cancelledno
declared form elicitationaccept, but after the proposal's TTL accepted (not_expired = false)no
did not declare itnot askedunsupported_by_client no, unless the operator set EQUINIX_MCP_ALLOW_UNCONFIRMED_MUTATIONS=true

The token stays consumed in every row. Limits: an accepted status proves the client reported an acceptance, not that a person read the prompt; and with the opt-in above, a client without elicitation support gets no server-side check at all. Beta: the prompt is modelled on the "Confused Deputy Resolution" requirement of the Connection Coordinator specification (connection-coordinator/docs/Protocols.md, marked work in progress there) and is an analogy to it, not an implementation of it.

Vocabulary

The chg- confirm token is a lookup key into one process's proposal store. It is not an activation key. Activation keys are issued by a cloud provider when a customer creates a native multicloud link and are entered at the other provider; the broker neither mints nor accepts them.

Policy, matching the read-only catalog's rules: no delete tools of any kind, and no mutation outside this broker.

  • Class
    Description
    The Safe Mutation Broker's two tools - fabric_propose_change and fabric_confirm_change - registered through the exact same ToolRegistration seam as the read-only catalog, in the opt-in Toolset.MUTATE toolset.
    The mutations the Safe Mutation Broker can carry - deliberately the smallest honest set: three creates, each backed by a spec-documented Fabric v4 dry run the propose phase exercises for real.
    One dry-run-validated proposal awaiting confirmation: the single-use confirm token, the change type, the exact canonicalized spec the dry run validated (the confirm phase recompiles this stored spec - never a re-supplied one), the SHA-256 of the compiled request the token is bound to, the mint and expiry instants, and the price context the proposal reported.
    In-memory, TTL-bounded, single-use store for the Safe Mutation Broker's pending proposals, keyed by confirm token.
    The result of one consume attempt.
    How a ProposalStore.consume(String) attempt resolved.