MCP tutorial

Two sources. One current record.

A CRM says a customer prefers phone contact. Support later records email. Follow both proposals through the same managed database and inspect what changed.

Prepare a demonstration database

Create a fresh Flexible database without starter classes. Connect with Read and write access using the Connection guide. This example explicitly defines its vocabulary and uses the default supersede, deterministic, auto-apply policy. Do not apply the tutorial schema over an existing customer model.

The calls below are MCP tool arguments. Replace uppercase placeholders with values from the previous response. The two example idempotency keys identify this run; use new keys for a new demonstration, and retain the same key and payload when recovering an uncertain request.

1. Inspect and define the vocabulary

ontology_list
{}

Listing classes inspects vocabulary; it does not read customer facts. Confirm that Customer is absent in this fresh database, then preview this definition:

ontology_preview
{
  "class": "Customer",
  "strict": true,
  "defaultPolicy": {
    "updateSemantics": "supersede",
    "conflictHandling": "deterministic",
    "retention": "permanent",
    "privacy": "internal",
    "reviewThreshold": "auto_apply"
  },
  "predicates": [
    {
      "name": "contact_channel",
      "valueType": "string",
      "cardinality": "single",
      "allowedValues": [
        "phone",
        "email"
      ]
    }
  ]
}

Inspect findings. Only errors block the schema proposal. Copy the returned preview.baseRevision into expectedRevision and apply the same definition:

ontology_define
{
  "class": "Customer",
  "strict": true,
  "defaultPolicy": {
    "updateSemantics": "supersede",
    "conflictHandling": "deterministic",
    "retention": "permanent",
    "privacy": "internal",
    "reviewThreshold": "auto_apply"
  },
  "predicates": [
    {
      "name": "contact_channel",
      "valueType": "string",
      "cardinality": "single",
      "allowedValues": [
        "phone",
        "email"
      ]
    }
  ],
  "expectedRevision": "BASE_REVISION_FROM_PREVIEW"
}

Confirm success and call ontology_list again. If the revision is stale, inspect the changed schema and preview again. In a Model-driven Restricted database, an authenticated human editor must administer schema through the console; an agent credential cannot acquire that authority.

2. Propose the CRM value

memory_insert — phone
{
  "entityType": "Customer",
  "entityRef": "crm:1042",
  "data": {
    "contact_channel": "phone"
  },
  "source": "crm",
  "confidence": 0.97,
  "extractionMethod": "structured_import",
  "idempotencyKey": "tutorial-crm-1042-phone-1"
}
Keep the receipt. Save results[0].canonicalId or results[0].entityId. A source reference such as crm:1042 can differ from the stored canonical ID. Use the returned identity for later reads, history, traversal, retraction, and updates to this record.
Write receipt without a profile
FieldInspect
okProcessing completed; this does not mean every proposed value was accepted.
results[].operationDetailsApplied changes. The first accepted observation creates an entity and asserts phone.
results[].skippedDetailsChanges not written and their reasons.
results[].violationDetailsWarnings and refusals. blocking: true identifies a refused change.
results[].pendingReviewsHeld proposals; do not treat these as current facts.
operationThe durable operation ID and completion status.

These examples omit profile. With compact-v1, inspect operations, skipped, violations, and pendingReview instead. summary-v1 summarizes applied operations; memory_operation retrieves full receipts under receipt.results with the compact-v1 fields by default.

3. Propose the support update

Replace the entityRef placeholder with the first receipt’s canonicalId. Continue only after checking the first result.

memory_insert — email
{
  "entityType": "Customer",
  "entityRef": "CANONICAL_ID_FROM_FIRST_RECEIPT",
  "data": {
    "contact_channel": "email"
  },
  "source": "support",
  "confidence": 0.97,
  "extractionMethod": "structured_import",
  "idempotencyKey": "tutorial-crm-1042-email-1"
}

Under this tutorial’s policy, the accepted email value supersedes phone. Both proposals address one customer. Inspect the second receipt before continuing.

4. Read current state and history

memory_get
{
  "entity": "CANONICAL_ID_FROM_FIRST_RECEIPT"
}

Expected: the current contact_channel is email. The earlier phone value is no longer current.

memory_history
{
  "entity": "CANONICAL_ID_FROM_FIRST_RECEIPT",
  "limit": 20
}

Expected: entity creation and channel changes, including the supersession. Provenance distinguishes the crm and support sources, with the actor and recording timestamp assigned by the service. History is not an extra current value.

5. Interpret failures and recover

Write outcomes
SignalNext step
SkippedRead the reason. A skip may be a no-op or a policy decision; do not retry blindly.
ViolationCheck blocking. Advisory warnings can accompany an applied write.
Pending reviewAn authorized reviewer must decide before a held proposal can become current.
NOT_FOUND after writingCheck the returned identity, selected database, and actual write outcome. A raw entityRef mismatch is one possible cause.
Lost responseLook up the operation with the original idempotency key and the same authenticated principal.
memory_operation
{
  "idempotencyKey": "tutorial-crm-1042-phone-1"
}

This retrieves confirmed results; it does not resume execution. Only if the operation is prepared and needs recovery, call:

memory_insert — resume
{
  "operationId": "OPERATION_UUID_FROM_LOOKUP"
}

A batch commits each observation separately. A failure keeps confirmed observations and stops at failedIndex; resuming retries from that observation. Refused proposals are results, not operation failures.

Relation arguments

On insert, an edge uses relationType and targetRef. On memory_get, omit relations for the default behavior, or use false or an object selector; boolean true is invalid. Use the MCP reference for the remaining tools.