batch_annotate
Create multiple PDF annotations in one batch operation to minimize calls. Provide an item ID or file path and a list of annotations with page index and coordinates.
Instructions
一次性创建多条 PDF 标注(减少调用次数)。
每条标注需包含 page_index 和 rects,可选 color/text/comment/type。 写操作需要关闭 Zotero 桌面应用。
Args: item_id: Zotero PDF 附件的 itemID(数字),或 PDF 文件的绝对路径 annotations: 标注列表,每项为: {"page_index": int, "rects": [[x0,y0,x1,y1],...], "color": str, "text": str, "comment": str, "type": str}
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| item_id | Yes | ||
| annotations | Yes |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| result | Yes |
Implementation Reference
- annota/server.py:263-318 (handler)The batch_annotate handler function: iterates over a list of annotation dicts, caches page_heights via pdf_tools.extract_page_text, and calls zotero_db.create_annotation for each. Returns JSON with count and results.
@mcp.tool() def batch_annotate( item_id: str, annotations: list[dict], ) -> str: """一次性创建多条 PDF 标注(减少调用次数)。 每条标注需包含 page_index 和 rects,可选 color/text/comment/type。 写操作需要关闭 Zotero 桌面应用。 Args: item_id: Zotero PDF 附件的 itemID(数字),或 PDF 文件的绝对路径 annotations: 标注列表,每项为: {"page_index": int, "rects": [[x0,y0,x1,y1],...], "color": str, "text": str, "comment": str, "type": str} """ try: attachment_id = _resolve_item_id(item_id) pdf_path = _resolve_pdf_path(item_id) # 缓存每页的 page_height,避免重复解析 page_heights: dict[int, float] = {} results = [] for ann in annotations: page_idx = ann["page_index"] rects = ann["rects"] if page_idx not in page_heights: page_data = pdf_tools.extract_page_text(pdf_path, page_idx) page_heights[page_idx] = page_data["page_height"] result = zotero_db.create_annotation( parent_attachment_id=attachment_id, page_index=page_idx, rects=rects, page_height=page_heights[page_idx], color=ann.get("color", "#ffd400"), comment=ann.get("comment", ""), text=ann.get("text", ""), ann_type=ann.get("type", "highlight"), ) results.append(result) return json.dumps({ "created": len(results), "annotations": results, "message": f"已创建 {len(results)} 条标注。请重启 Zotero 或按 Ctrl+Shift+R 刷新查看。", }, ensure_ascii=False) except sqlite3.OperationalError as e: if "locked" in str(e).lower(): return json.dumps({ "error": "database_locked", "message": "Zotero 数据库被锁定,请先关闭 Zotero 桌面应用再重试。", }, ensure_ascii=False) raise - annota/server.py:264-278 (schema)Function signature and docstring defining input schema: item_id (str) and annotations (list[dict] with page_index, rects, and optional color/text/comment/type).
def batch_annotate( item_id: str, annotations: list[dict], ) -> str: """一次性创建多条 PDF 标注(减少调用次数)。 每条标注需包含 page_index 和 rects,可选 color/text/comment/type。 写操作需要关闭 Zotero 桌面应用。 Args: item_id: Zotero PDF 附件的 itemID(数字),或 PDF 文件的绝对路径 annotations: 标注列表,每项为: {"page_index": int, "rects": [[x0,y0,x1,y1],...], "color": str, "text": str, "comment": str, "type": str} """ - annota/server.py:263-263 (registration)Registration via @mcp.tool() decorator on the batch_annotate function (line 263).
@mcp.tool() - annota/server.py:327-347 (helper)Helper _resolve_pdf_path: resolves item_id to a PDF file path (used indirectly by batch_annotate).
def _resolve_pdf_path(item_id: str) -> Path: """将 item_id 解析为 PDF 文件路径。 如果是纯数字,按 Zotero itemID 查找; 如果包含路径分隔符,按文件路径处理。 """ if "/" in item_id or "\\" in item_id or ":" in item_id: p = Path(item_id) if not p.exists(): raise FileNotFoundError(f"PDF 文件不存在: {item_id}") return p attachment_id = int(item_id) pdf_path = zotero_db.get_pdf_path(attachment_id) if pdf_path is None: raise FileNotFoundError( f"在 Zotero 数据库中未找到 itemID={attachment_id} 对应的 PDF 文件" ) if not pdf_path.exists(): raise FileNotFoundError(f"PDF 文件在磁盘上不存在: {pdf_path}") return pdf_path