Skip to content

feat: add group library support and inject_citations tool#83

Open
mlenburg wants to merge 1 commit into
cookjohn:mainfrom
mlenburg:feature/group-libraries-and-citation-injection
Open

feat: add group library support and inject_citations tool#83
mlenburg wants to merge 1 commit into
cookjohn:mainfrom
mlenburg:feature/group-libraries-and-citation-injection

Conversation

@mlenburg

@mlenburg mlenburg commented Jun 7, 2026

Copy link
Copy Markdown

Summary

This PR adds two new capabilities to zotero-mcp:

New tools

  • list_libraries — lists all Zotero libraries (personal + group) with their numeric IDs
  • inject_citations — replaces <zcite key="ITEMKEY"/> placeholder tags in a Word .docx file with native Zotero OOXML field codes (ADDIN ZOTERO_ITEM CSL_CITATION), identical to what the Zotero Word Plugin produces. Supports APA, Chicago, Harvard, IEEE, and Vancouver styles. Appends a bibliography field. The output .docx can be opened in Word with Zotero running and refreshed/reformatted normally.

Extended tools

All search and collection tools now accept an optional libraryID parameter:
search_library, get_collections, search_collections, get_collection_details, get_collection_items, get_subcollections

New file

  • src/modules/citationInjector.ts — core citation injection logic. Uses IOUtils (Gecko API, compatible with Zotero 7 / Firefox 102+) and fflate for zip read/write inside the Zotero runtime.

Usage

# 1. Find item keys
search_library(q="Spira lung cancer", libraryID="2")
# 2. Write placeholders into your .docx (Python helper script available separately)
# 3. Inject
inject_citations(docxPath="/path/to/paper_placeholders.docx", style="apa", libraryID="2")
# 4. Open output _cited.docx in Word with Zotero → click Refresh
---

New tools:
- list_libraries: lists all Zotero libraries (personal + group) with their IDs
- inject_citations: replaces <zcite> placeholder tags in a Word .docx with
  native Zotero OOXML field codes (ADDIN ZOTERO_ITEM CSL_CITATION), compatible
  with the Zotero Word Plugin. Supports APA, Chicago, Harvard, IEEE, Vancouver.
  Appends a bibliography field. Uses IOUtils (Gecko API) and bundled fflate for
  zip read/write inside the Zotero/Firefox runtime.

Extended tools:
- search_library, get_collections, search_collections, get_collection_details,
  get_collection_items, get_subcollections: all now accept an optional libraryID
  parameter to target personal or group libraries

Adds fflate as a dependency for zip manipulation inside the Zotero plugin runtime.
@cookjohn

Copy link
Copy Markdown
Owner

Thank you @mlenburg — there's a lot of value in here, and inject_citations in particular is a genuinely novel capability. To get it merged we need to restructure, because the group-library half of this PR has been superseded: PR #50 was just merged into main, and it threads an optional libraryID through ~16 read and write tools with centralized validation — a superset of the schema additions here. A test merge of the two branches conflicts in streamableMCPServer.ts and silently produces duplicate libraryID schema keys with incompatible types (number from #50 vs string here).

Requested changes:

  1. Rebase onto current main and drop the parts Add optional libraryID support across MCP operations #50 now covers: the libraryID schema additions, list_libraries (main now has get_libraries/search_libraries; its groupID field is worth folding into get_libraries as a small separate PR if you'd like), and the callGetCollectionDetails forwarding fix (already on main).

  2. Resubmit inject_citations as a standalone PR — it's a 487-line module with a new runtime dependency (fflate) and deserves its own review. Issues found that need addressing before it can merge:

    • Invalid-OOXML fallback: the run-matching regexes require attribute-less <w:r> elements; Word-authored documents routinely carry w:rsidR attributes, so real files hit the plain-text fallback, which nests <w:r><w:fldChar/>... inside an existing <w:t> — schema-invalid WordprocessingML that Word may report as corrupt. The run matching needs to tolerate attributes, and the fallback should fail loudly rather than emit invalid XML.
    • File-system safety: docxPath is only checked for a .docx suffix and the output silently overwrites any existing *_cited.docx. Given the plugin's HTTP server is unauthenticated and can be configured to bind non-loopback, a remote MCP client could direct Zotero to read/write arbitrary user files. Please validate/normalize the path, refuse to overwrite without an explicit flag, and gate the tool behind an opt-in preference.
    • Smaller items: empty uris: [] means injected citations behave as unlinked/embedded on Zotero refresh (document this or populate them); sequential cit1, cit2... citation IDs can collide with existing fields (randomize); the entity-unescape order in parseZciteTag double-unescapes &amp;quot;; zipSync/unzipSync run synchronously on the main thread (consider chunking or a worker for large documents).

Happy to review the split PRs quickly once they're up. Issue #63 (group libraries) is closed by #50, so this PR's remaining scope is purely the citation feature.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants