Skip to main content
Glama
malinoto

tracepass-mcp-server

by malinoto

TracePass passports

tracepass_passports
Destructive

Create, read, and manage EU Digital Product Passports, including compliance checks, registry readiness, QR codes, lifecycle actions, and battery measurement history.

Instructions

Manage Digital Product Passports — create, read, and run lifecycle actions.

IMPORTANT: create makes a DRAFT passport. A draft takes no plan DPP slot and is never billed; the slot, and any per-DPP overage past the plan cap, is taken when the passport is published, which happens in the TracePass dashboard, not through this tool. Each create counts against the daily write budget. archive is IRREVERSIBLE (the public QR permanently 404s); prefer suspend when a change might be undone.

IDENTIFIER SCHEMES (EN 18219): passports are identified by one of five schemes. Battery passports (Battery Regulation Art. 77(3)) accept ONLY gs1 and iso15459. • gs1 — { scheme:"gs1", gtin, serialNumber } — GS1 GTIN + serial; gtin is 8/12/13/14 digits, stored as GTIN-14. • iso15459 — { scheme:"iso15459", issuingAgencyCode, primaryId, serial? } — ISO/IEC 15459; the server derives raw (IAC + primaryId + serial). • iec61406 — { scheme:"iec61406", uri } — IEC 61406 Identification Link (https URI). Not valid for batteries. • did — { scheme:"did", did, method } — W3C DID Core. Not valid for batteries. • doi — { scheme:"doi", doi, granularity:"model"|"batch"|"item" } — ISO 26324 DOI, stored as bare 10./ (any https://doi.org/ or doi: prefix stripped on input; resolves as https://doi.org/); granularity REQUIRED per EN 18219 §5.6.2(b). Not valid for batteries. The legacy top-level gtin + serialNumber pair is still accepted as a deprecated alias for scheme:"gs1".

Actions (pass via action, with args):

  • list — args: { page?, limit? (≤100), productId?, status?, search? }. status ∈ draft|in_review|approved|published|suspended|expired|archived. Read-only.

  • get — args: { id, format? (summary|full), lang? }. Read-only. Response includes identifier, identifierKey, and (for GS1 passports) gs1.

  • get_by_serial — args: { serial, format?, lang?, gtin? }. Read-only. Addresses the passport by your own serial. A serial is unique only WITHIN a GTIN — if the same serial exists under two GTINs in your account the call returns 409 ambiguous_serial; pass gtin (or use the by-id action) to resolve exactly.

  • compliance — args: { id }. Read-only. Returns a three-tier compliance verdict (compliant | compliant_with_warnings | incomplete) with regulation-cited findings — use to gap-check a passport against the rules for its category, fix the cited fields/parties, then re-check. Also returns byRegulation[]: the same findings grouped per regulation, worst first, so you can tell WHICH regime is failing instead of reading one incomplete as everything being wrong. A regulation absent from that array raised no finding — that is not the same as it having passed.

  • registry_readiness — args: { id }. Read-only. Returns { ready, findings[] } — whether the passport would pass the EU DPP Registry's FORMAL submission gate (mandatory fields present, correct formatting, a resolvable public link, item-level granularity via a serial number, and a well-formed commodity code where the category carries one, and, for EV, LMT and industrial (over 2 kWh) batteries, conformance to the Commission's battery data model that the Registry validates against (REG-READY-SEMANTIC)). This is the registry's mechanical pre-submission check, NOT the substantive compliance verdict; a passport can be registry-ready yet not substantively compliant. Battery passports only.

  • place_on_market — args: { id }. WRITE, battery passports only, published only. Places the passport on the market: registers it in the EU DPP registry under the account's own registry access (the upload Battery Regulation Art. 77(10) requires of the operator placing the battery on the market). A legal act for the economic operator — confirm with the user first. ASYNCHRONOUS: answers 202 { passport, passportId, status: "placing", dppId } and the registry call follows in the background; read the passport (get) to follow placeOnMarketStatus: placing → placed (placedOnMarketAt, registrationId) or rejected (registrationRejectionReason). To retry a rejected passport, fix the cause and call place_on_market again. Refusals are 409 with a code: not_a_battery | not_published | already_placed (placing or placed) | operator_id_missing (no economic-operator identifier on the account) | registry_not_configured (an admin sets registry access in the dashboard) | registry_not_ready (findings[] lists what stands in the way — run registry_readiness for the structured findings; an empty list means the configured registry is not open to submissions from TracePass yet). After placement the passport's party operatorIdentifier / facilityIdentifier are locked (409 operator_locked on a change). Counts 1 write.

  • create — args: { productId, identifier?, gtin?, serialNumber?, lineage? }. Creates a draft (not billed). Provide identifier (preferred) or legacy gtin + serialNumber. Battery passports accept only gs1 and iso15459 schemes — other schemes return 400. A duplicate identifier returns 409. lineage (battery only) — a repurposed, remanufactured or reused battery needs a NEW passport linked to the original(s) (Battery Regulation Art. 77(7)): { predecessors: [ { internalPassportId? | identifier?, trigger: preparation_for_reuse|preparation_for_repurposing|repurposing|remanufacturing } ] (≤10), noPredecessorReason? (only with an empty list, e.g. placed on the market before 18 Feb 2027) }. The server derives batteryStatus from the triggers and links your own predecessor passports back. Immutable after create. Rule violations return 422 with the rule code (duplicate_predecessor, predecessor_not_found, status_trigger_mismatch, …).

  • suspend — args: { id }. Reversible — public QR shows 'suspended'.

  • suspend_by_serial — args: { serial, gtin? }. Same as suspend, addressed by your serial. 409 ambiguous_serial if the serial isn't unique in your account — pass gtin.

  • archive — args: { id, reason? (recycled|never_placed|duplicate_or_error) }. IRREVERSIBLE and destructive — confirm with the user first. reason is REQUIRED for battery passports (400 reason_required / invalid_reason without a valid one): recycled, never_placed (never placed on the market or put into service), or duplicate_or_error (a duplicate or erroneous record); for other categories it is optional. A passport marked for deletion cannot be archived (409).

  • archive_by_serial — args: { serial, gtin?, reason? }. IRREVERSIBLE and destructive, addressed by your serial — confirm first. Same reason rule as archive. 409 ambiguous_serial if the serial isn't unique — pass gtin.

  • get_qr — args: { id, format? (svg|png), symbology? (qr|datamatrix) }. Read-only. symbology=datamatrix renders an ISO/IEC 16022 Data Matrix instead of a QR (EN 18220 permits both; same passport URL).

  • get_qr_by_serial — args: { serial, format? (svg|png), symbology? (qr|datamatrix), gtin? }. Read-only. Same as get_qr, addressed by your own serial. A serial is unique only WITHIN a GTIN — if the same serial exists under two GTINs in your account the call returns 409 ambiguous_serial; pass gtin (or use get_qr by id) to resolve exactly.

  • list_snapshots — args: { id, page?, limit? (≤100), at? (ISO 8601) }. Read-only. Returns a paginated list of snapshots for the passport (newest first). A snapshot is written on publish and after every change to a non-draft passport (EN 18221 change archive); each carries id, version, reason (e.g. published|field_edit|status_change|baseline), actor (who caused it, when known), snapshotAt, contentHash, hashValid (re-verified on every read), restorable, fieldCount. With at, returns instead the single snapshot valid at that instant (full record plus validFrom/validUntil) — answers "what did this passport say on date D"; 404 before the first snapshot. Counts 1 against the daily read budget.

  • get_snapshot — args: { id, snapshotId }. Read-only. Returns the full archival record of one snapshot: the complete JSON-LD the passport asserted at that time, plus hash and hashValid. Counts 1 against the daily read budget.

  • get_condition_flags — args: { id }. Read-only. Returns the resolved condition profile Record<flagKey,{value,status,source}>. Condition flags are reviewer-approved yes/no facts gating conditional legal duties. Battery flags: hasBMS, rechargeable, externalStorageOnly, isStationaryBess. An approved flag makes specific fields required — a missing gated field is a hard publish block (conditional_missing). Counts 1 against the daily read budget.

  • get_condition_flags_by_serial — args: { serial, gtin? }. Read-only. Same as get_condition_flags, addressed by your own serial. 409 ambiguous_serial if serial not unique — pass gtin.

  • set_condition_flags — args: { id, flags: Record<flagKey, boolean|null> }. WRITE. Set or clear condition flags (null clears). Keys must be registered for the passport category (battery: hasBMS, rechargeable, externalStorageOnly, isStationaryBess). WARNING: approving a flag can make fields required and block publishing if those fields are empty — fix any gated fields before or immediately after setting the flag. Writes are approved + audited. Idempotency-Key supported. Counts 1 write.

  • set_condition_flags_by_serial — args: { serial, gtin?, flags }. WRITE. Same as set_condition_flags, addressed by your own serial. 409 ambiguous_serial if serial not unique — pass gtin.

  • capture_measurements — args: { id, measurements: [ { fieldKey, value, measuredAt (ISO 8601), externalId?, unit? } ] (≤500) }. WRITE, battery passports only, published only. Pushes over-life measurements from the customer's own equipment (e.g. a BMS reporting stateOfHealth, numberOfFullEquivalentChargingCycles; the Annex XIII point 4 use-data keys). Every measurement is stored; the newest per field becomes the passport's current value and sets dynamicDataAsOf. externalId makes a measurement idempotent. A value may be at most 16 KB serialised. batteryStatus is NOT a measurement (400 invalid_field_key). A key the Regulation keeps off this battery category returns 422 field_not_applicable (e.g. stateOfCertifiedEnergy on an LMT battery). Metered against the plan's monthly measurement allowance, not the daily write budget: paid plans keep counting past it at no charge; Free stops at its allowance. Reading a passport is never metered.

  • capture_measurements_by_serial — args: { serial, gtin?, measurements }. Same, addressed by your own serial.

  • list_measurements — args: { id, fieldKey?, from?, to? (ISO 8601), limit? (≤200), cursor? }. Read-only. Measurement history, newest first; page with the returned nextCursor.

  • list_measurements_by_serial — args: { serial, gtin?, fieldKey?, from?, to?, limit?, cursor? }. Read-only.

  • latest_measurements — args: { id }. Read-only. The newest measurement per accepted key (null where none yet).

  • latest_measurements_by_serial — args: { serial, gtin? }. Read-only.

Input Schema

NameRequiredDescriptionDefault
argsNoArguments for the chosen action; required fields depend on `action` (see each action above).
actionYesWhich passport operation to run. Reads: list | get | get_by_serial | compliance | registry_readiness | get_condition_flags | get_condition_flags_by_serial | get_qr | get_qr_by_serial | list_snapshots | get_snapshot | list_measurements(_by_serial) | latest_measurements(_by_serial). Writes: set_condition_flags | set_condition_flags_by_serial | capture_measurements(_by_serial) | create (a draft, not billed). Lifecycle: place_on_market (battery, published; async EU registry entry — confirm first) | suspend (reversible) | archive (IRREVERSIBLE; battery passports need `reason`), the last two each with a _by_serial variant.

Output Schema

NameRequiredDescriptionDefault
idNoThe resource's TracePass id, when the response is a single entity.
pageNoCurrent page number (list actions).
errorNoMachine-readable error code, when the API rejected the request.
itemsNoThe page of results, when the action is a list.
limitNoPage size (list actions).
totalNoTotal matching records across all pages (list actions).
resultNoWraps a non-object response body (e.g. a QR code string).
messageNoHuman-readable error or status detail, when present.
totalPagesNoTotal number of pages (list actions).

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed6 schema fields changedv1.23.2
    • removedInput schema / properties / args / properties / flags / additionalProperties / anyOf
      Removed value: -[
      -  {
      -    "type": "boolean"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • addedInput schema / properties / args / properties / flags / additionalProperties / type
      Added value: +[
      +  "boolean",
      +  "null"
      +]
    • removedOutput schema / properties / error / anyOf
      Removed value: -[
      -  {
      -    "type": "string"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • addedOutput schema / properties / error / type
      Added value: +[
      +  "string",
      +  "null"
      +]
    • removedOutput schema / properties / message / anyOf
      Removed value: -[
      -  {
      -    "type": "string"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • addedOutput schema / properties / message / type
      Added value: +[
      +  "string",
      +  "null"
      +]
  2. Changed3 schema fields changedv1.23.1
    • changedInput schema / properties / action / description
      Previous value: -"Which passport operation to run. Reads: list | get | get_by_serial | compliance | registry_readiness | get_condition_flags | get_condition_flags_by_serial | get_qr | get_qr_by_serial | list_snapshots | get_snapshot | list_measurements(_by_serial) | latest_measurements(_by_serial). Writes: set_condition_flags | set_condition_flags_by_serial | capture_measurements(_by_serial) | create (a draft, not billed). Lifecycle: suspend (reversible) | archive (IRREVERSIBLE; battery passports need `reason`), each with a _by_serial variant."New value: +"Which passport operation to run. Reads: list | get | get_by_serial | compliance | registry_readiness | get_condition_flags | get_condition_flags_by_serial | get_qr | get_qr_by_serial | list_snapshots | get_snapshot | list_measurements(_by_serial) | latest_measurements(_by_serial). Writes: set_condition_flags | set_condition_flags_by_serial | capture_measurements(_by_serial) | create (a draft, not billed). Lifecycle: place_on_market (battery, published; async EU registry entry — confirm first) | suspend (reversible) | archive (IRREVERSIBLE; battery passports need `reason`), the last two each with a _by_serial variant."
    • changedInput schema / properties / action / enum
      Previous value: -[
      -  "list",
      -  "get",
      -  "get_by_serial",
      -  "compliance",
      -  "registry_readiness",
      -  "get_condition_flags",
      -  "get_condition_flags_by_serial",
      -  "set_condition_flags",
      -  "set_condition_flags_by_serial",
      -  "capture_measurements",
      -  "capture_measurements_by_serial",
      -  "list_measurements",
      -  "list_measurements_by_serial",
      -  "latest_measurements",
      -  "latest_measurements_by_serial",
      -  "create",
      -  "suspend",
      -  "suspend_by_serial",
      -  "archive",
      -  "archive_by_serial",
      -  "get_qr",
      -  "get_qr_by_serial",
      -  "list_snapshots",
      -  "get_snapshot"
      -]New value: +[
      +  "list",
      +  "get",
      +  "get_by_serial",
      +  "compliance",
      +  "registry_readiness",
      +  "place_on_market",
      +  "get_condition_flags",
      +  "get_condition_flags_by_serial",
      +  "set_condition_flags",
      +  "set_condition_flags_by_serial",
      +  "capture_measurements",
      +  "capture_measurements_by_serial",
      +  "list_measurements",
      +  "list_measurements_by_serial",
      +  "latest_measurements",
      +  "latest_measurements_by_serial",
      +  "create",
      +  "suspend",
      +  "suspend_by_serial",
      +  "archive",
      +  "archive_by_serial",
      +  "get_qr",
      +  "get_qr_by_serial",
      +  "list_snapshots",
      +  "get_snapshot"
      +]
    • changedInput schema / properties / args / properties / id / description
      Previous value: -"Passport id. Required for get/compliance/suspend/archive/get_qr (the by-id actions)."New value: +"Passport id. Required for get/compliance/place_on_market/suspend/archive/get_qr (the by-id actions)."
  3. Changed3 schema fields changedv1.22.0
    • changedInput schema / properties / action / description
      Previous value: -"Which passport operation to run. Reads: list | get | get_by_serial | compliance | registry_readiness | get_condition_flags | get_condition_flags_by_serial | get_qr | get_qr_by_serial | list_snapshots | get_snapshot | list_measurements(_by_serial) | latest_measurements(_by_serial). Writes: set_condition_flags | set_condition_flags_by_serial | capture_measurements(_by_serial) | create (BILLABLE). Lifecycle: suspend (reversible) | archive (IRREVERSIBLE), each with a _by_serial variant."New value: +"Which passport operation to run. Reads: list | get | get_by_serial | compliance | registry_readiness | get_condition_flags | get_condition_flags_by_serial | get_qr | get_qr_by_serial | list_snapshots | get_snapshot | list_measurements(_by_serial) | latest_measurements(_by_serial). Writes: set_condition_flags | set_condition_flags_by_serial | capture_measurements(_by_serial) | create (a draft, not billed). Lifecycle: suspend (reversible) | archive (IRREVERSIBLE; battery passports need `reason`), each with a _by_serial variant."
    • removedInput schema / properties / args / properties / confirmOverage
      Removed value: -{
      -  "description": "Set true to accept per-passport overage charges when over the plan quota (402). Applies to create.",
      -  "type": "boolean"
      -}
    • addedInput schema / properties / args / properties / reason
      Added value: +{
      +  "description": "archive / archive_by_serial: Required for battery passports: why the passport ends. A battery passport ends only when the battery has been recycled, so the choices are recycled, never placed on the market or put into service, or a duplicate or erroneous record.",
      +  "enum": [
      +    "recycled",
      +    "never_placed",
      +    "duplicate_or_error"
      +  ],
      +  "type": "string"
      +}
  4. Changed4 schema fields changedv1.19.1
    • addedOutput schema / properties / error / anyOf
      Added value: +[
      +  {
      +    "type": "string"
      +  },
      +  {
      +    "type": "null"
      +  }
      +]
    • removedOutput schema / properties / error / type
      Removed value: -"string"
    • addedOutput schema / properties / message / anyOf
      Added value: +[
      +  {
      +    "type": "string"
      +  },
      +  {
      +    "type": "null"
      +  }
      +]
    • removedOutput schema / properties / message / type
      Removed value: -"string"
  5. Changed8 schema fields changedv1.16.2
    • changedInput schema / properties / action / description
      Previous value: -"Which passport operation to run. Reads: list | get | get_by_serial | compliance | registry_readiness | get_condition_flags | get_condition_flags_by_serial | get_qr | get_qr_by_serial | list_snapshots | get_snapshot. Writes: set_condition_flags | set_condition_flags_by_serial | create (BILLABLE). Lifecycle: suspend (reversible) | archive (IRREVERSIBLE), each with a _by_serial variant."New value: +"Which passport operation to run. Reads: list | get | get_by_serial | compliance | registry_readiness | get_condition_flags | get_condition_flags_by_serial | get_qr | get_qr_by_serial | list_snapshots | get_snapshot | list_measurements(_by_serial) | latest_measurements(_by_serial). Writes: set_condition_flags | set_condition_flags_by_serial | capture_measurements(_by_serial) | create (BILLABLE). Lifecycle: suspend (reversible) | archive (IRREVERSIBLE), each with a _by_serial variant."
    • changedInput schema / properties / action / enum
      Previous value: -[
      -  "list",
      -  "get",
      -  "get_by_serial",
      -  "compliance",
      -  "registry_readiness",
      -  "get_condition_flags",
      -  "get_condition_flags_by_serial",
      -  "set_condition_flags",
      -  "set_condition_flags_by_serial",
      -  "create",
      -  "suspend",
      -  "suspend_by_serial",
      -  "archive",
      -  "archive_by_serial",
      -  "get_qr",
      -  "get_qr_by_serial",
      -  "list_snapshots",
      -  "get_snapshot"
      -]New value: +[
      +  "list",
      +  "get",
      +  "get_by_serial",
      +  "compliance",
      +  "registry_readiness",
      +  "get_condition_flags",
      +  "get_condition_flags_by_serial",
      +  "set_condition_flags",
      +  "set_condition_flags_by_serial",
      +  "capture_measurements",
      +  "capture_measurements_by_serial",
      +  "list_measurements",
      +  "list_measurements_by_serial",
      +  "latest_measurements",
      +  "latest_measurements_by_serial",
      +  "create",
      +  "suspend",
      +  "suspend_by_serial",
      +  "archive",
      +  "archive_by_serial",
      +  "get_qr",
      +  "get_qr_by_serial",
      +  "list_snapshots",
      +  "get_snapshot"
      +]
    • addedInput schema / properties / args / properties / cursor
      Added value: +{
      +  "description": "list_measurements(_by_serial): nextCursor from the previous page.",
      +  "type": "string"
      +}
    • addedInput schema / properties / args / properties / fieldKey
      Added value: +{
      +  "description": "list_measurements(_by_serial): only this field key.",
      +  "type": "string"
      +}
    • addedInput schema / properties / args / properties / from
      Added value: +{
      +  "description": "list_measurements(_by_serial): measuredAt from (ISO 8601).",
      +  "type": "string"
      +}
    • addedInput schema / properties / args / properties / lineage
      Added value: +{
      +  "description": "create, battery only: link a second-life battery's new passport to the original passport(s) (Art. 77(7)). See the create action.",
      +  "properties": {
      +    "noPredecessorReason": {
      +      "maxLength": 500,
      +      "type": "string"
      +    },
      +    "predecessors": {
      +      "items": {
      +        "properties": {
      +          "identifier": {
      +            "maxLength": 2000,
      +            "type": "string"
      +          },
      +          "internalPassportId": {
      +            "type": "string"
      +          },
      +          "trigger": {
      +            "enum": [
      +              "preparation_for_reuse",
      +              "preparation_for_repurposing",
      +              "repurposing",
      +              "remanufacturing"
      +            ],
      +            "type": "string"
      +          }
      +        },
      +        "required": [
      +          "trigger"
      +        ],
      +        "type": "object"
      +      },
      +      "maxItems": 10,
      +      "type": "array"
      +    }
      +  },
      +  "required": [
      +    "predecessors"
      +  ],
      +  "type": "object"
      +}
    • addedInput schema / properties / args / properties / measurements
      Added value: +{
      +  "description": "capture_measurements(_by_serial): [{ fieldKey, value, measuredAt, externalId?, unit? }], max 500.",
      +  "items": {
      +    "properties": {
      +      "externalId": {
      +        "type": "string"
      +      },
      +      "fieldKey": {
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "measuredAt": {
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "unit": {
      +        "type": "string"
      +      },
      +      "value": {}
      +    },
      +    "required": [
      +      "fieldKey",
      +      "value",
      +      "measuredAt"
      +    ],
      +    "type": "object"
      +  },
      +  "type": "array"
      +}
    • addedInput schema / properties / args / properties / to
      Added value: +{
      +  "description": "list_measurements(_by_serial): measuredAt to (ISO 8601).",
      +  "type": "string"
      +}
  6. Changed11 schema fields changedv1.14.1
    • changedInput schema / properties / action / description
      Previous value: -"Which passport operation to run. Reads: list | get | get_by_serial | compliance | registry_readiness | get_qr | get_qr_by_serial. Lifecycle: create (BILLABLE) | suspend (reversible) | archive (IRREVERSIBLE), each with a _by_serial variant."New value: +"Which passport operation to run. Reads: list | get | get_by_serial | compliance | registry_readiness | get_condition_flags | get_condition_flags_by_serial | get_qr | get_qr_by_serial | list_snapshots | get_snapshot. Writes: set_condition_flags | set_condition_flags_by_serial | create (BILLABLE). Lifecycle: suspend (reversible) | archive (IRREVERSIBLE), each with a _by_serial variant."
    • changedInput schema / properties / action / enum
      Previous value: -[
      -  "list",
      -  "get",
      -  "get_by_serial",
      -  "compliance",
      -  "registry_readiness",
      -  "create",
      -  "suspend",
      -  "suspend_by_serial",
      -  "archive",
      -  "archive_by_serial",
      -  "get_qr",
      -  "get_qr_by_serial"
      -]New value: +[
      +  "list",
      +  "get",
      +  "get_by_serial",
      +  "compliance",
      +  "registry_readiness",
      +  "get_condition_flags",
      +  "get_condition_flags_by_serial",
      +  "set_condition_flags",
      +  "set_condition_flags_by_serial",
      +  "create",
      +  "suspend",
      +  "suspend_by_serial",
      +  "archive",
      +  "archive_by_serial",
      +  "get_qr",
      +  "get_qr_by_serial",
      +  "list_snapshots",
      +  "get_snapshot"
      +]
    • addedInput schema / properties / args / properties / at
      Added value: +{
      +  "description": "list_snapshots: ISO 8601 instant — return the snapshot valid then instead of the list.",
      +  "type": "string"
      +}
    • changedInput schema / properties / args / properties / confirmOverage / description
      Previous value: -"Set true to accept a per-passport overage charge when create is over the plan quota (402)."New value: +"Set true to accept per-passport overage charges when over the plan quota (402). Applies to create."
    • addedInput schema / properties / args / properties / flags
      Added value: +{
      +  "additionalProperties": {
      +    "anyOf": [
      +      {
      +        "type": "boolean"
      +      },
      +      {
      +        "type": "null"
      +      }
      +    ]
      +  },
      +  "description": "For set_condition_flags / set_condition_flags_by_serial: Record<flagKey, boolean|null>. null clears the flag.",
      +  "propertyNames": {
      +    "type": "string"
      +  },
      +  "type": "object"
      +}
    • changedInput schema / properties / args / properties / gtin / description
      Previous value: -"GTIN disambiguator for *_by_serial actions when a serial isn't unique across GTINs (else 409 ambiguous_serial)."New value: +"For create (legacy): GS1 GTIN. Also used as a disambiguator for *_by_serial actions when a serial isn't unique (else 409 ambiguous_serial)."
    • changedInput schema / properties / args / properties / id / description
      Previous value: -"Passport id. Required for get/compliance/create-result/suspend/archive/get_qr (the by-id actions)."New value: +"Passport id. Required for get/compliance/suspend/archive/get_qr (the by-id actions)."
    • addedInput schema / properties / args / properties / identifier
      Added value: +{
      +  "additionalProperties": {},
      +  "description": "EN 18219 scheme-tagged identifier for create. Must have `scheme` plus scheme-specific fields. Schemes: gs1 {gtin, serialNumber} | iso15459 {issuingAgencyCode, primaryId, serial?} | iec61406 {uri} | did {did, method} | doi {doi, granularity} (granularity: \"model\"|\"batch\"|\"item\" REQUIRED per EN 18219 §5.6.2(b)). Battery passports: gs1 and iso15459 only.",
      +  "propertyNames": {
      +    "type": "string"
      +  },
      +  "type": "object"
      +}
    • changedInput schema / properties / args / properties / serialNumber / description
      Previous value: -"Serial for the new passport. Required for create."New value: +"Serial for the new passport (create, legacy gs1 path)."
    • addedInput schema / properties / args / properties / snapshotId
      Added value: +{
      +  "description": "Snapshot id. Required for get_snapshot.",
      +  "type": "string"
      +}
    • addedInput schema / properties / args / properties / symbology
      Added value: +{
      +  "description": "get_qr/get_qr_by_serial: qr (default) | datamatrix.",
      +  "type": "string"
      +}
  7. Changed7 schema fields changedv1.7.3
    • addedInput schema / properties / action / description
      Added value: +"Which passport operation to run. Reads: list | get | get_by_serial | compliance | registry_readiness | get_qr | get_qr_by_serial. Lifecycle: create (BILLABLE) | suspend (reversible) | archive (IRREVERSIBLE), each with a _by_serial variant."
    • changedInput schema / properties / action / enum
      Previous value: -[
      -  "list",
      -  "get",
      -  "get_by_serial",
      -  "create",
      -  "suspend",
      -  "archive",
      -  "get_qr"
      -]New value: +[
      +  "list",
      +  "get",
      +  "get_by_serial",
      +  "compliance",
      +  "registry_readiness",
      +  "create",
      +  "suspend",
      +  "suspend_by_serial",
      +  "archive",
      +  "archive_by_serial",
      +  "get_qr",
      +  "get_qr_by_serial"
      +]
    • removedInput schema / properties / args / additionalProperties
      Removed value: -{}
    • changedInput schema / properties / args / description
      Previous value: -"Action-specific arguments — see the description for each action's shape."New value: +"Arguments for the chosen action; required fields depend on `action` (see each action above)."
    • addedInput schema / properties / args / properties
      Added value: +{
      +  "confirmOverage": {
      +    "description": "Set true to accept a per-passport overage charge when create is over the plan quota (402).",
      +    "type": "boolean"
      +  },
      +  "format": {
      +    "description": "get/get_by_serial: summary|full. get_qr/get_qr_by_serial: svg|png.",
      +    "type": "string"
      +  },
      +  "gtin": {
      +    "description": "GTIN disambiguator for *_by_serial actions when a serial isn't unique across GTINs (else 409 ambiguous_serial).",
      +    "type": "string"
      +  },
      +  "id": {
      +    "description": "Passport id. Required for get/compliance/create-result/suspend/archive/get_qr (the by-id actions).",
      +    "type": "string"
      +  },
      +  "lang": {
      +    "description": "Resolve field values to one of the 24 EU locales server-side (get/get_by_serial).",
      +    "type": "string"
      +  },
      +  "limit": {
      +    "description": "Page size for list, max 100.",
      +    "type": "number"
      +  },
      +  "page": {
      +    "description": "Page number for list (1-based).",
      +    "type": "number"
      +  },
      +  "productId": {
      +    "description": "Parent product id. Required for create.",
      +    "type": "string"
      +  },
      +  "search": {
      +    "description": "Filter list by a search term.",
      +    "type": "string"
      +  },
      +  "serial": {
      +    "description": "Your own serial number. Required for the *_by_serial actions.",
      +    "type": "string"
      +  },
      +  "serialNumber": {
      +    "description": "Serial for the new passport. Required for create.",
      +    "type": "string"
      +  },
      +  "status": {
      +    "description": "Filter list by status: draft|in_review|approved|published|suspended|expired|archived.",
      +    "type": "string"
      +  }
      +}
    • removedInput schema / properties / args / propertyNames
      Removed value: -{
      -  "type": "string"
      -}
    • changedOutput schema / (root)
      Previous value: -nullNew value: +{
      +  "$schema": "http://json-schema.org/draft-07/schema#",
      +  "additionalProperties": false,
      +  "properties": {
      +    "error": {
      +      "description": "Machine-readable error code, when the API rejected the request.",
      +      "type": "string"
      +    },
      +    "id": {
      +      "description": "The resource's TracePass id, when the response is a single entity.",
      +      "type": "string"
      +    },
      +    "items": {
      +      "description": "The page of results, when the action is a list.",
      +      "items": {},
      +      "type": "array"
      +    },
      +    "limit": {
      +      "description": "Page size (list actions).",
      +      "type": "number"
      +    },
      +    "message": {
      +      "description": "Human-readable error or status detail, when present.",
      +      "type": "string"
      +    },
      +    "page": {
      +      "description": "Current page number (list actions).",
      +      "type": "number"
      +    },
      +    "result": {
      +      "description": "Wraps a non-object response body (e.g. a QR code string)."
      +    },
      +    "total": {
      +      "description": "Total matching records across all pages (list actions).",
      +      "type": "number"
      +    },
      +    "totalPages": {
      +      "description": "Total number of pages (list actions).",
      +      "type": "number"
      +    }
      +  },
      +  "type": "object"
      +}
  8. First observedv1.1.4

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Adds substantial context the coarse annotations (destructiveHint=true covers 25 heterogeneous actions) cannot convey: drafts take no slot and are never billed, the slot is consumed on publish in the dashboard, archive permanently 404s the public QR, place_on_market is async (202 → placing/placed/rejected) and locks operator identifiers, and measurements are metered against a separate allowance. Deducting one point only because the per-action read/write labels are scattered across a very long body rather than summarized up front, making the destructive surface easy to miss.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loading is good — the draft/billing and archive-irreversibility warnings come before anything else, and headers plus bullets make a 25-action surface navigable. However the body is very long and duplicates structured data it does not need to restate (the archive reason enum, the measurements array shape, the action enum), so a meaningful share of sentences do not earn their place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, yet the description still explains return shapes (compliance's three-tier verdict and byRegulation[], registry_readiness { ready, findings[] }, snapshot fields) — helpful but partly redundant. For a 25-action dispatcher with nested args, the coverage of error codes, limits, and preconditions is thorough enough that an agent could call any action correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description genuinely adds meaning: GTIN stored as GTIN-14, DOI prefixes stripped on input, granularity required per EN 18219 §5.6.2(b), battery passports restricted to gs1/iso15459, lineage capped at 10 predecessors and immutable after create, and reason required only for battery passports. It does repeat several schema facts (the reason enum, measurements shape), which keeps it from a 5.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb+resource statement ("Manage Digital Product Passports — create, read, and run lifecycle actions") and then enumerates all 25 actions with concrete semantics, so an agent knows exactly what domain this covers. The only gap at the 5 level is that it never distinguishes itself from the siblings (tracepass_passport_fields, tracepass_passport_parties, tracepass_epcis), so an agent must infer that field/party edits live elsewhere.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Intra-tool routing is unusually explicit: suspend vs archive ("prefer `suspend` when a change might be undone"), compliance vs registry_readiness ("mechanical pre-submission check, NOT the substantive compliance verdict"), by-id vs by-serial (409 ambiguous_serial, pass `gtin`), and confirm-before-place_on_market. What is missing is cross-tool guidance — nothing says when to reach for this tool rather than a sibling.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.