Skip to main content
Glama

Manage Zotero collections

zotero_manage_collections
Destructive

List, create, rename, reparent, or delete collections, and move items into or out of a collection. Set action to one of: "list" (collections with key/name/parent, sorted by name; q filters by name over the whole library…

Instructions

List, create, rename, reparent, or delete collections, and move items into or out of a collection. Set action to one of: "list" (collections with key/name/parent, sorted by name; q filters by name over the whole library, start/limit page, totalResults counts them all), "create" (needs name, optional parent_collection key; omit it for top-level), "rename" (needs collection_key + name), "reparent" (needs collection_key; parent_collection key, or omit to move to top level), "delete" (needs collection_key), "add_items" / "remove_items" (need collection_key + item_keys; collection membership lives on each item). Writes to your personal library go to the running Zotero desktop app (Zotero 10+) and otherwise to the cloud Web API; group libraries always write to the cloud. When the server sets a bulk-write threshold (ZOTEUS_CONFIRM_BULK_WRITES, off by default), removing more items than that from a collection in one call also needs confirm: true.

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": {
      "action": "<action>"
    },
    "name": "zotero_manage_collections"
  }
}

Input Schema

NameRequiredDescriptionDefault
qNoOnly collections whose name contains this text (case-insensitive), searched over the whole library, not one page. Use it to find a collection by name.
nameNoCollection name (create/rename).
limitNoCollections to return (default 200, at most 1000).
startNoZero-based offset into the listing, for paging (default 0). Page with start += limit while `totalResults` is larger.
actionYesWhat to do. "list" reads every collection (then `q`, `start`, `limit` apply); "create" needs `name`; "rename" needs `collection_key` + `name`; "reparent" needs `collection_key`; "delete" needs `collection_key`; "add_items"/"remove_items" need `collection_key` + `item_keys`.
confirmNoRequired to remove more items in one call than the server's bulk-write threshold.
item_keysNoItem keys (add_items/remove_items).
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.
collection_keyNoTarget collection key (all actions except list/create).
parent_collectionNoParent collection key; omit for top-level.

Output Schema

NameRequiredDescriptionDefault
startNoThe offset this page starts at.
failedNoOne entry per object the write could not land; absent or empty when all of them did.
targetNoWhere the write went: "local" (Zotero desktop local API), "desktop" (connector protocol) or "cloud" (Zotero Web API).
createdNoKey of the collection created (action:"create").
deletedNoKey of the collection deleted.
updatedNoItem keys added to or removed from the collection.
completeNoFalse when the library holds more collections than Zoteus reads in one listing (10,000); the page then comes from those read.
collectionsNoThis page of the collections, sorted by name (action:"list").
totalResultsNoCollections matching in total (every collection when there is no `q`), not just this page. Page with start/limit while it is larger.
collection_keyNoThe collection renamed or reparented.
libraryVersionNoThe library's Last-Modified-Version after this write.

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. Changed8 schema fields changedv1.22.3
    • changedInput schema / properties / action / description
      Previous value: -"What to do. \"list\" reads every collection; \"create\" needs `name`; \"rename\" needs `collection_key` + `name`; \"reparent\" needs `collection_key`; \"delete\" needs `collection_key`; \"add_items\"/\"remove_items\" need `collection_key` + `item_keys`."New value: +"What to do. \"list\" reads every collection (then `q`, `start`, `limit` apply); \"create\" needs `name`; \"rename\" needs `collection_key` + `name`; \"reparent\" needs `collection_key`; \"delete\" needs `collection_key`; \"add_items\"/\"remove_items\" need `collection_key` + `item_keys`."
    • addedInput schema / properties / limit
      Added value: +{
      +  "description": "Collections to return (default 200, at most 1000).",
      +  "maximum": 1000,
      +  "minimum": 1,
      +  "type": "integer"
      +}
    • addedInput schema / properties / q
      Added value: +{
      +  "description": "Only collections whose name contains this text (case-insensitive), searched over the whole library, not one page. Use it to find a collection by name.",
      +  "type": "string"
      +}
    • addedInput schema / properties / start
      Added value: +{
      +  "description": "Zero-based offset into the listing, for paging (default 0). Page with start += limit while `totalResults` is larger.",
      +  "minimum": 0,
      +  "type": "integer"
      +}
    • changedOutput schema / properties / collections / description
      Previous value: -"Every collection in the library (action:\"list\")."New value: +"This page of the collections, sorted by name (action:\"list\")."
    • addedOutput schema / properties / complete
      Added value: +{
      +  "description": "False when the library holds more collections than Zoteus reads in one listing (10,000); the page then comes from those read.",
      +  "type": "boolean"
      +}
    • addedOutput schema / properties / start
      Added value: +{
      +  "description": "The offset this page starts at.",
      +  "type": "number"
      +}
    • addedOutput schema / properties / totalResults
      Added value: +{
      +  "description": "Collections matching in total (every collection when there is no `q`), not just this page. Page with start/limit while it is larger.",
      +  "type": "number"
      +}
  3. Changed1 schema field changedv1.21.0
    • addedInput schema / properties / library_id / exclusiveMinimum
      Added value: +0
  4. 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#"
  5. Changed4 schema fields changedv1.20.0
    • addedInput schema / properties / action / description
      Added value: +"What to do. \"list\" reads every collection; \"create\" needs `name`; \"rename\" needs `collection_key` + `name`; \"reparent\" needs `collection_key`; \"delete\" needs `collection_key`; \"add_items\"/\"remove_items\" need `collection_key` + `item_keys`."
    • 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": {
      +    "collection_key": {
      +      "description": "The collection renamed or reparented.",
      +      "type": "string"
      +    },
      +    "collections": {
      +      "description": "Every collection in the library (action:\"list\").",
      +      "items": {
      +        "additionalProperties": true,
      +        "properties": {
      +          "key": {
      +            "description": "8-character collection key.",
      +            "type": "string"
      +          },
      +          "name": {
      +            "description": "Collection name.",
      +            "type": "string"
      +          },
      +          "numItems": {
      +            "description": "Items directly in the collection, when the backend reports it.",
      +            "type": "number"
      +          },
      +          "parentCollection": {
      +            "description": "Parent collection key, or false for a top-level collection.",
      +            "type": [
      +              "string",
      +              "boolean"
      +            ]
      +          }
      +        },
      +        "type": "object"
      +      },
      +      "type": "array"
      +    },
      +    "created": {
      +      "description": "Key of the collection created (action:\"create\").",
      +      "items": {
      +        "type": "string"
      +      },
      +      "type": "array"
      +    },
      +    "deleted": {
      +      "description": "Key of the collection deleted.",
      +      "type": "string"
      +    },
      +    "failed": {
      +      "description": "One entry per object the write could not land; absent or empty when all of them did.",
      +      "items": {
      +        "additionalProperties": true,
      +        "properties": {
      +          "code": {
      +            "description": "Zotero status for this object, e.g. 400 or 412.",
      +            "type": "number"
      +          },
      +          "index": {
      +            "description": "Position of the failed object in the request.",
      +            "type": "number"
      +          },
      +          "key": {
      +            "description": "Item key, when the failed object named one.",
      +            "type": "string"
      +          },
      +          "message": {
      +            "description": "Why Zotero refused it.",
      +            "type": "string"
      +          }
      +        },
      +        "type": "object"
      +      },
      +      "type": "array"
      +    },
      +    "libraryVersion": {
      +      "description": "The library's Last-Modified-Version after this write.",
      +      "type": "number"
      +    },
      +    "updated": {
      +      "description": "Item keys added to or removed from the collection.",
      +      "items": {
      +        "type": "string"
      +      },
      +      "type": "array"
      +    }
      +  },
      +  "type": "object"
      +}
  6. Changed1 schema field changedv1.17.0
    • addedInput schema / properties / confirm
      Added value: +{
      +  "description": "Required to remove more items in one call than the server's bulk-write threshold.",
      +  "type": "boolean"
      +}
  7. First observedv1.0.4

TDQS

A4.1/5.0
Behavior5/5

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

Goes well beyond the destructiveHint/openWorld hints: it discloses the write-routing rule (personal-library writes go to the running Zotero desktop app on Zotero 10+, otherwise the cloud Web API; group libraries always cloud), the ZOTEUS_CONFIRM_BULK_WRITES threshold and its off-by-default state, and the fact that collection membership is stored on each item. These are exactly the behavioral facts an agent cannot get from annotations.

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?

Front-loaded with the capability statement followed by a compact per-action contract and the write-routing caveat. It is dense but every clause carries information; the only mild duplication is repeating the action-to-parameter mapping already present in the action enum's schema description.

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 an 11-parameter, seven-action tool with an output schema, the description covers the action taxonomy, per-action prerequisites, pagination, library targeting, and the destructive bulk-removal confirmation path. Nothing needed 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 meaning: it maps each action to its required keys, clarifies that omitting parent_collection means top-level, and explains that `q` searches the whole library rather than the current page. This goes beyond restating the schema.

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?

States a precise verb set (list/create/rename/reparent/delete/add_items/remove_items) against a clear resource (Zotero collections), and enumerates each action's required parameters. It never distinguishes itself from the sibling zotero_list_collections, whose territory overlaps the "list" action, so an agent has to infer which tool to reach for.

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?

Gives conditional guidance for the confirm/bulk-write path and per-action parameter prerequisites, which is genuinely useful. However, there is no explicit when-to-use-this-vs-alternatives statement, and the overlap with zotero_list_collections and zotero_manage_tags is left unresolved.

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