Skip to main content
Glama

Update a Zotero item

zotero_update_item
DestructiveIdempotent

Partially update one item (HTTP PATCH — only the fields you supply change; omitted fields are preserved). Provide item_key and a patch object of the fields to change (e.g.

Instructions

Partially update one item (HTTP PATCH — only the fields you supply change; omitted fields are preserved). Provide item_key and a patch object of the fields to change (e.g. {"title":"New","extra":"note"} or {"tags":[{"tag":"reviewed"}]}). All field values are plain JSON strings/numbers/booleans/arrays — never wrapped in nested objects (e.g. "title": "New", NOT "title": {"title": "New"}). Optimistic concurrency is handled for you: if you pass the item's version it is used; otherwise the current version is fetched first. If the item changed on the server in the meantime (412), the update is automatically re-fetched and retried once. Writes to your personal library go to the running Zotero desktop app (Zotero 10+) when it is up, otherwise to the cloud Web API; the version is read from the same place the write goes. Set dry_run:true to preview the field-level before→after diff without writing (arrays like tags/collections are replaced wholesale by PATCH, not merged; a dry_run call performs no write).

Tool call template

Replace each placeholder with a value matching the input schema. Only required parameters are included; add optional parameters as needed.

{
  "id": 1,
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "arguments": {
      "item_key": "<item_key>",
      "patch": "<patch>"
    },
    "name": "zotero_update_item"
  }
}

Input Schema

NameRequiredDescriptionDefault
patchYesObject of fields to change (PATCH semantics), e.g. {"title": "New title", "date": "2024-02-01", "tags": [{"tag": "reviewed"}], "collections": ["ABCD1234"]}. Structured fields (creators, tags, collections, relations) must be real JSON arrays/objects, not JSON-encoded strings. Values are plain, never wrapped in nested objects.
dry_runNoPreview the field-level before→after diff without writing.
versionNoKnown current version; fetched automatically if omitted.
item_keyYesThe 8-character item key.
library_idNoNumeric id of the library to address, e.g. 5234875 for a group (zotero_groups lists the ids you can reach). Omit to use the configured default library; an id given without library_type is read as a group id.
library_typeNoWhich library to address: "user" (a personal library) or "group" (a shared group library). Omit to use the library this server is configured for. "group" on its own is refused: pass library_id with it.

Output Schema

NameRequiredDescriptionDefault
diffNoField-level before/after for a dry run; only fields the patch would actually change.
dryRunNoTrue when nothing was written.
targetNoWhere the write went: "local" (Zotero desktop local API), "desktop" (connector protocol) or "cloud" (Zotero Web API).
retriedNoTrue when a version conflict (412) was re-fetched and retried once.
versionNoCurrent version on the server (dry run only).
item_keyYesThe item this call addressed.
newVersionNoVersion after the PATCH; absent on a dry run.
arrayReplacementsNoFields in that diff that PATCH replaces wholesale rather than merging, e.g. ["tags"].

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed1 schema field changedv1.23.0
    • addedOutput schema / properties / target
      Added value: +{
      +  "description": "Where the write went: \"local\" (Zotero desktop local API), \"desktop\" (connector protocol) or \"cloud\" (Zotero Web API).",
      +  "type": "string"
      +}
  2. Changed1 schema field changedv1.21.0
    • addedInput schema / properties / library_id / exclusiveMinimum
      Added value: +0
  3. Changed2 schema fields changedv1.20.2
    • removedInput schema / $schema
      Removed value: -"http://json-schema.org/draft-07/schema#"
    • removedOutput schema / $schema
      Removed value: -"http://json-schema.org/draft-07/schema#"
  4. Changed3 schema fields changedv1.20.0
    • addedInput schema / properties / library_id / description
      Added value: +"Numeric id of the library to address, e.g. 5234875 for a group (zotero_groups lists the ids you can reach). Omit to use the configured default library; an id given without library_type is read as a group id."
    • addedInput schema / properties / library_type / description
      Added value: +"Which library to address: \"user\" (a personal library) or \"group\" (a shared group library). Omit to use the library this server is configured for. \"group\" on its own is refused: pass library_id with it."
    • changedOutput schema / (root)
      Previous value: -nullNew value: +{
      +  "$schema": "http://json-schema.org/draft-07/schema#",
      +  "additionalProperties": true,
      +  "properties": {
      +    "arrayReplacements": {
      +      "description": "Fields in that diff that PATCH replaces wholesale rather than merging, e.g. [\"tags\"].",
      +      "items": {
      +        "type": "string"
      +      },
      +      "type": "array"
      +    },
      +    "diff": {
      +      "additionalProperties": {
      +        "additionalProperties": true,
      +        "properties": {
      +          "after": {
      +            "description": "Value the patch would set."
      +          },
      +          "before": {
      +            "description": "Value the item carries now."
      +          }
      +        },
      +        "type": "object"
      +      },
      +      "description": "Field-level before/after for a dry run; only fields the patch would actually change.",
      +      "type": "object"
      +    },
      +    "dryRun": {
      +      "description": "True when nothing was written.",
      +      "type": "boolean"
      +    },
      +    "item_key": {
      +      "description": "The item this call addressed.",
      +      "type": "string"
      +    },
      +    "newVersion": {
      +      "description": "Version after the PATCH; absent on a dry run.",
      +      "type": "number"
      +    },
      +    "retried": {
      +      "description": "True when a version conflict (412) was re-fetched and retried once.",
      +      "type": "boolean"
      +    },
      +    "version": {
      +      "description": "Current version on the server (dry run only).",
      +      "type": [
      +        "number",
      +        "null"
      +      ]
      +    }
      +  },
      +  "required": [
      +    "item_key"
      +  ],
      +  "type": "object"
      +}
  5. Changed2 schema fields changedv1.3.1
    • changedInput schema / properties / patch / description
      Previous value: -"Object of fields to change (PATCH semantics). Structured fields (creators, tags, collections, relations) must be real JSON arrays/objects, not JSON-encoded strings."New value: +"Object of fields to change (PATCH semantics), e.g. {\"title\": \"New title\", \"date\": \"2024-02-01\", \"tags\": [{\"tag\": \"reviewed\"}], \"collections\": [\"ABCD1234\"]}. Structured fields (creators, tags, collections, relations) must be real JSON arrays/objects, not JSON-encoded strings. Values are plain, never wrapped in nested objects."
    • addedInput schema / properties / patch / properties / itemType
      Added value: +{
      +  "description": "The Zotero item type as a plain string, e.g. \"journalArticle\", \"book\", \"preprint\", \"report\", \"thesis\".",
      +  "type": "string"
      +}
  6. First observedv1.0.4

TDQS

A4.1/5.0
Behavior5/5

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

Beyond the annotations (destructiveHint/idempotentHint/openWorldHint), the description discloses a lot of non-obvious behavior: optimistic concurrency with automatic version fetch, a 412 re-fetch-and-retry-once policy, write routing to the desktop app (Zotero 10+) vs the cloud Web API with the version read from the same target, and the fact that array fields like tags/collections are replaced wholesale rather than merged.

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

Conciseness4/5

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

It is a single dense paragraph that is front-loaded with the PATCH semantics before the concurrency and routing details, and every clause carries information. It is somewhat run-on with stacked parentheticals, which slightly hurts scannability but not enough to waste content.

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

Completeness5/5

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

For a mutation tool with an output schema present, the description covers the concurrency model, the write target selection, the retry behavior, the dry-run preview, and the array-replacement semantics. Nothing an agent needs in order to invoke it correctly is missing.

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 adds real semantic value: it warns that field values must be plain JSON and never wrapped in nested objects (with a concrete wrong/right example), shows a valid patch shape, and clarifies that version is used if passed and otherwise fetched. The nested-object pitfall is exactly the kind of gotcha the schema alone underplays.

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?

The description opens with a precise verb+resource and scope: 'Partially update one item (HTTP PATCH — only the fields you supply change; omitted fields are preserved).' That PATCH framing implicitly separates it from zotero_create_items and zotero_merge_items, but no sibling is named explicitly, so the differentiation is left to inference.

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

Usage Guidelines3/5

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

It explains how to call the tool (supply item_key plus a patch object) and how to preview with dry_run:true, so usage is implied. It never states when to prefer this over zotero_create_items or zotero_merge_items, nor any when-not conditions, so routing guidance is missing.

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