Eonevolve Learning
Unity and DevelopmentUnity and codeAdvanced~7 min

Stable MCP Tool Contracts and Error Semantics

Snapshot

~85 sec

A stable MCP tool contract performs one operation with typed input, bounded output, and distinguishable failure. Safe retry needs real server behavior, such as an operation key plus a precondition and recorded outcome. An idempotency annotation is only a hint. Dry-run, expected diff, and post-change evidence make writes reviewable.

You will learn

  • Design one-operation input and output contracts with bounded results.
  • Separate protocol errors from tool execution results marked isError.
  • Require preconditions and operation-key tracking before treating a write retry as idempotent.

Target outcome

You can review an MCP tool contract for stable semantics, honest retry behavior, and evidence-rich failure handling.

Visual walkthrough

Visual walkthrough

~7 min

  1. Six contract commitments

    • One operation

      The tool name and description declare one stable responsibility.

    • Typed input

      Required fields, allowed values, identifiers, limits, and preconditions are machine-checkable.

    • Bounded output

      Result size, pagination, coverage, and expected fields are explicit.

    • Real idempotency

      The server recognizes an operation key, checks preconditions, and returns the recorded outcome instead of repeating a write.

    • Error layer

      Protocol failure and completed tool execution with isError have different meanings.

    • Untrusted annotation

      Hints help a client present risk, but the client must not treat them as proof of behavior.

  2. Ambiguous mutation versus stable contract

    ApproachOperation scopeRetry behaviorBefore-write evidenceFailure meaning
    fix_sceneA broad tool chooses edits, saves the scene, and returns free-form text.The same input can rename, delete, add, or save unrelated invented objects.A repeated call may apply another mutation because no operation key or precondition is tracked.The caller cannot review an expected diff before authority is granted.A paragraph does not distinguish malformed protocol, rejected input, partial execution, or project validation failure.
    rename_scene_objectOne exact invented object moves from an expected current name to one proposed name.Stable object ID, expectedName, and newName bound one property change.The server records operationKey and outcome; the same key returns that outcome without reapplying.dryRun returns expectedDiff with applied false before a write approval.Unknown tool or invalid protocol stays separate from an executed tool result that reports isError.
  3. Make idempotency server-observable

    A write becomes safely repeatable only when the server can distinguish a new operation from a duplicate and enforce the same precondition and outcome.

    1. Receive request

      Typed target, expected current value, proposed value, operation key, and dry-run mode.

    2. Look up operation key

      Check a durable operation record before touching project state.

    3. Check precondition

      Confirm the exact invented object still has expectedName.

    4. Execute once

      Apply the one approved rename only for a new valid operation.

    5. Record outcome

      Persist operation key, target, resulting state, and evidence before returning.

    6. Return known outcome

      A duplicate key returns the recorded result without a second rename.

    A write becomes safely repeatable only when the server can distinguish a new operation from a duplicate and enforce the same precondition and outcome.

    Reading order

    1. Receive request

      Typed target, expected current value, proposed value, operation key, and dry-run mode.

    2. Look up operation key

      Check a durable operation record before touching project state.

    3. Check precondition

      Confirm the exact invented object still has expectedName.

    4. Execute once

      Apply the one approved rename only for a new valid operation.

    5. Record outcome

      Persist operation key, target, resulting state, and evidence before returning.

    6. Return known outcome

      A duplicate key returns the recorded result without a second rename.

    Connection explanations

    1. Receive request → Look up operation key (first)

      The operation key is checked before any mutation, not used only as a log label afterward.

    2. Look up operation key → Check precondition (if new)

      A new key still needs a current-state precondition so stale writes are rejected.

    3. Check precondition → Execute once (if current)

      Only a matching before state permits the one declared operation.

    4. Execute once → Record outcome (then)

      The server records enough evidence to distinguish completion from an unknown outcome.

    5. Record outcome → Return known outcome (supports retry)

      A retry with the same key receives the known result rather than executing again.

  4. Preview the exact diff before authority

    Invented conceptual request and result. A real server implementation must validate the schema, enforce the operation key and precondition, and produce the result from current project state.

    Languagejson
    {
      "tool": "rename_scene_object",
      "input": {
        "objectId": "target-dummy-01",
        "expectedName": "TargetDummy",
        "newName": "PracticeTarget",
        "operationKey": "rename-2026-07-26-001",
        "dryRun": true
      },
      "result": {
        "status": "preview",
        "expectedDiff": {
          "objectId": "target-dummy-01",
          "name": ["TargetDummy", "PracticeTarget"]
        },
        "applied": false
      }
    }

    Code annotations

    1. Lines 3-5

      Bind target and before state

      Stable object ID and expectedName identify both what may change and the state that must still be true.

      Effect: A stale or substituted target is rejected before mutation.

    2. Lines 6-7

      Request preview under one operation key

      The key identifies the logical operation; dryRun requests evidence without applying it.

      Effect: The caller can review the same bounded operation before changing authority.

    3. Lines 9-16

      Return structured expected diff

      Status, target, before and after values, and applied false are separate fields.

      Effect: Approval can name the exact proposed change rather than rely on prose.

  5. Judge a timed-out write

    An invented rename tool times out after sending a write. Its metadata says idempotent, but the request has no operation key and the server stores no outcome record. Should the client retry automatically?

    Expected reasoning

    No. The annotation is only a hint and the outcome is unknown. A retry could apply another or conflicting mutation. First inspect current target state. Redesign the tool with a stable target, expected before value, operation key, durable outcome lookup, dry-run expected diff, and post-change evidence. Retry the same logical write only when the server can distinguish duplicate from new execution.

Go deeper