zotero-fulltext
Provides tools to search, lookup, and read items from a Zotero library, including fulltext retrieval and in-document search.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@zotero-fulltextfind papers on sustainability reporting"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Access your Zotero library with your favorite AI tool.

This MCP server for Zotero 8+ gives Claude and Codex access to your library via search and citekeys. It talks directly to Zotero's local API and aims to keep token usage low. Fulltext is fetched only on demand.
Quick Start
Make sure Zotero 8+ is running with the local API enabled (Settings → Advanced → "Allow other applications on this computer to communicate with Zotero").
Install the Claude Code plugin:
/plugin marketplace add statzhero/zotero-fulltext
/plugin install zotero@zotero-fulltextRun
/mcpto confirm the server is connected, then try a slash command:
/zotero:find sustainability reportingAlso works with Claude Desktop, Codex, and as a standalone MCP server without slash commands.
Related MCP server: zotero-mcp
Commands
The Claude Code plugin provides four slash commands:
Command | What it does |
| Search the whole library |
| Exact citekey metadata lookup |
| Numbered fulltext paragraphs |
| Search inside one paper's fulltext |
find searches the whole library. lookup is lightweight metadata confirmation. read returns the actual paper text. within searches only one item's indexed fulltext.
Without the plugin, all the same functionality is available through the MCP tools directly (see Tools).
Installation
Claude Code (plugin with slash commands)
/plugin marketplace add statzhero/zotero-fulltext
/plugin install zotero@zotero-fulltextThis installs the MCP server and slash commands. Run /mcp to confirm the server is connected.
Claude Desktop
Requires uv (install with brew install uv or curl -LsSf https://astral.sh/uv/install.sh | sh).
Open Claude Desktop → Settings → Developer → Edit Config, and add:
{
"mcpServers": {
"zotero": {
"type": "stdio",
"command": "uvx",
"args": ["zotero-fulltext"]
}
}
}Save the file, then fully quit and reopen Claude Desktop (closing the window is not enough). Open a new chat and confirm the server is available.
Codex (plugin with skills)
Note: The Codex plugin marketplace is still rolling out. The install flow below may change.
codex plugin marketplace add statzhero/zotero-fulltext
codex plugin install zoteroThis installs the MCP server and four skills (find, lookup, read, within).
Codex (manual MCP only)
Requires uv (install with brew install uv or curl -LsSf https://astral.sh/uv/install.sh | sh).
Add to ~/.codex/config.toml:
[mcp_servers.zotero]
command = "uvx"
args = ["zotero-fulltext"]Restart Codex, then run codex mcp list to verify the server appears.
Design
The server is intentionally simple and read-only. It relies on Zotero's own search index rather than building a second one.
Startup builds a metadata index mapping citekeys to items and attachments.
Library changes are tracked with Zotero version headers and incremental sync.
Fulltext is fetched only on demand and cached in memory (TTL/LRU).
All outputs are bounded by default: 10 search hits, 80 paragraphs with a character budget, 20 fulltext matches.
Item results include
item_uriandfulltext_uriso clients can attach standardzotero://...resources directly.Creator roles (author, editor, translator, etc.) are preserved and grouped in results.
If a lookup finds no citekey, it returns
found=false. If a search finds nothing, it returnsresults=[]. There is no web fallback.
Tools
The server exposes five MCP tools. The slash commands above are convenience wrappers.
lookup(citekey)
Exact citekey lookup. Citekeys are resolved in order:
Native Zotero 8
citationKeyLegacy Better BibTeX
Citation Key:line inExtraDeterministic generated fallback
If an item later gains a real citekey, the generated key is kept as an alias.
search(query, collection?, tag?, limit?)
Searches Zotero with qmode=everything, collapses attachment hits to parent items, and ranks exact citekey matches first.
collections()
Lists collections in the current library.
fulltext(citekey, offset?, limit?)
Fetches indexed attachment fulltext, splits it into numbered paragraphs, and returns a bounded slice (default: 80 paragraphs). Large extracted paragraphs are split into smaller chunks, and each response has a soft character budget. If the response includes truncated=true, request the same citekey again with offset=next_offset to continue reading.
Fulltext responses include paging metadata:
Field | Meaning |
| Total available paragraph chunks for the item |
| Number of paragraph chunks in this response |
| Approximate text characters returned |
| Character budget used for this response |
| Whether more paragraph chunks remain |
| Offset to pass into the next |
fulltext_search(citekey, query, before?, after?, limit?)
Searches within a single item's paragraphized fulltext and returns matching paragraphs with surrounding context.
Environment Variables
By default the server connects to a local personal library with no authentication. Set these variables to change that:
Variable | Default | Description |
|
|
|
|
| Zotero user or group ID (required for group libraries) |
| — | API key for authenticated or remote access |
|
| Base URL for the Zotero API |
|
| Maximum characters per returned fulltext chunk |
|
| Soft character budget for each |
|
| Directory for the persistent metadata index |
|
| Sync the library index once at startup |
|
| Minimum seconds between incremental index refreshes |
|
| Time-to-live for cached fulltext paragraphs |
|
| Maximum number of documents kept in the paragraph cache |
|
| Default number of search results |
|
| Default number of paragraphs per |
|
| Default paragraphs of context around each |
ZOTERO_USER_ID is accepted as an alias for ZOTERO_LIBRARY_ID. The ZOTERO_LIBRARY_ID default of 0 applies to user libraries; group libraries require an explicit ID.
Example for a group library in Claude Code:
{
"mcpServers": {
"zotero": {
"type": "stdio",
"command": "zotero-fulltext",
"env": {
"ZOTERO_LIBRARY_TYPE": "group",
"ZOTERO_LIBRARY_ID": "12345"
}
}
}
}Related Projects
Other MCP servers for Zotero, with different design goals:
54yyyu/zotero-mcp — Feature-rich: read-write operations, optional semantic search via ChromaDB, Web API support. Heavier dependencies.
kujenga/zotero-mcp — Minimal read-only server with Web API support via pyzotero. No citekey resolution or in-document search.
kaliaboi/mcp-zotero — Cloud-only (Zotero Web API). Metadata browsing, no fulltext.
To remove an existing Zotero MCP server before switching:
claude mcp remove zoteroOr delete the zotero entry from .mcp.json / claude_desktop_config.json / ~/.codex/config.toml manually.
Requirements
Zotero 8+ with the local API enabled
Python 3.11+
Better BibTeX (optional but recommended)
License
MIT • Ulrich Atz (ulrichatz)
Available Tools
5 toolscollectionsARead-onlyIdempotent
List Zotero collections in the current library.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and idempotentHint, so the description is not required to repeat that. The description adds 'current library' as scoping context, but does not disclose any additional behavioral traits such as whether nested collections are included or how results are ordered.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, front-loaded sentence that communicates the action, object, and scope with no filler or redundant information. Every word earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool has no parameters, has an output schema, and has annotations covering its safety and idempotency, the description fully covers the necessary context. The one-sentence description is sufficient for a simple list operation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has no parameters, so the empty schema covers all cases. Per scoring guidelines, a tool with zero parameters receives a baseline of 4 since there is nothing to describe.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb 'List' with a clear resource 'Zotero collections' and scope 'current library', making its action immediately apparent. It distinguishes itself from sibling tools like 'lookup' and 'search' by explicitly being a listing operation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides no explicit guidance on when to use this tool versus alternatives such as 'lookup' or 'search'. The use case is only implied by the name and action, but there is no stated relationship or exclusionary context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
fulltextARead-onlyIdempotent
Return numbered paragraphs for a Zotero item's indexed fulltext. The citekey is a single token with no spaces (e.g. 'atz2022').
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| offset | No | ||
| citekey | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and idempotentHint=true, so the safety profile is covered. The description adds useful context about 'indexed' fulltext and 'numbered paragraphs' but does not disclose error behavior, missing fulltext handling, or effects of limit/offset.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two concise sentences with front-loaded purpose and a helpful example for the key parameter. Every sentence contributes value with no redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return format is covered. However, the description lacks guidance on when to choose this tool over fulltext_search and does not explain pagination parameters, making it adequate but not fully complete for a 3-parameter tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate. It clarifies only the citekey format ('single token with no spaces, e.g. 'atz2022''), but does not explain the semantic meaning of limit and offset (e.g., that limit controls paragraph count), leaving those parameters ambiguous.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb 'Return' and a clear resource 'numbered paragraphs for a Zotero item's indexed fulltext.' It distinguishes from siblings like fulltext_search by specifying an exact output format and per-item scope, even without naming alternatives.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage when you have a citekey and want an item's fulltext paragraphs, but it does not explicitly state when to use this tool over alternatives like fulltext_search, nor does it provide any when-not-to-use guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
fulltext_searchBRead-onlyIdempotent
Search within a Zotero item's indexed fulltext and return local paragraph context. The citekey is a single token with no spaces (e.g. 'atz2022').
| Name | Required | Description | Default |
|---|---|---|---|
| after | No | ||
| limit | No | ||
| query | Yes | ||
| before | No | ||
| citekey | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and idempotentHint=true, so the safety profile is covered. The description adds context about the 'indexed fulltext' requirement and 'local paragraph context' return, which are not in annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two concise sentences that front-load the core purpose and citekey format with no wasted words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool has 5 parameters with 0% schema coverage, and the description provides minimal parameter semantics and no usage context beyond the citekey format. The output schema exists but input semantics are incomplete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, and the description only mentions that citekey must be a single token with no spaces. There is no explanation for query, before, after, or limit, so the description does not compensate for the missing parameter documentation.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly identifies the tool as searching within a specific Zotero item's indexed fulltext and returning paragraph context, with a specific verb+resource+scope. It does not explicitly contrast with sibling tools like 'search' or 'fulltext', so it's not fully differentiated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No explicit guidance is provided on when to use this tool versus alternatives. The citekey requirement is mentioned but there is no 'use this when...' statement, leaving the agent to infer usage context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
lookupARead-onlyIdempotent
Look up a Zotero item by its exact citekey (a single token with no spaces, e.g. 'atz2022' not 'atz 2022'). Use this first when you know the citekey.
| Name | Required | Description | Default |
|---|---|---|---|
| citekey | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and idempotentHint, indicating a safe, repeatable read operation. The description adds a critical behavioral constraint: the citekey must be a single token without spaces, which prevents common input errors. It does not describe error handling for missing items, but the output schema likely covers return values, so the added context goes beyond annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences long, front-loaded with the core purpose, and includes a helpful example. Every sentence adds value: the first defines the tool and input constraint, the second gives a usage priority directive. No wasted words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple lookup tool with one parameter, read-only annotations, and an output schema, the description covers the essential aspects: what the tool does, the exact input format, and when to use it. The existence of an output schema handles return-value details, leaving no major gaps for this basic operation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema only defines 'citekey' as a string with no description (0% coverage). The description fully compensates by explaining that it must be an exact citekey, a single token with no spaces, and provides a concrete example ('atz2022'), making the parameter unambiguous and actionable.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses the verb 'look up' with the resource 'Zotero item' and the specific method 'by its exact citekey', clearly stating the tool's function. It distinguishes from siblings like 'search' by emphasizing the need for an exact citekey rather than fuzzy or broad search.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The instruction 'Use this first when you know the citekey' provides a clear when-to-use directive, implying that when the citekey is unknown, other tools such as 'search' should be used. However, it does not explicitly name the alternative tool, making the guidance clear but not fully explicit about exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
searchBRead-onlyIdempotent
Search Zotero metadata and indexed fulltext by keywords. For a known citekey (e.g. 'atz2022'), use lookup instead.
| Name | Required | Description | Default |
|---|---|---|---|
| tag | No | ||
| limit | No | ||
| query | Yes | ||
| collection | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare read-only and idempotent behavior, lowering the bar. The description adds that search covers metadata and indexed fulltext, implying a read-only search but without additional context such as result limits or query syntax. No contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with the primary purpose and a clear alternative. No wasted words; each sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With four parameters, no parameter semantics, and an output schema present, the description covers only the core keyword search behavior. It lacks explanation of filtering by tag or collection, limit semantics, or interaction with sibling fulltext tools, leaving significant gaps for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, and the description only mentions 'by keywords', which adds meaning to the query parameter. The tag, limit, and collection parameters are entirely unexplained, so the description fails to compensate for the lack of schema-level documentation.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool searches Zotero metadata and indexed fulltext by keywords. It distinguishes from lookup by directing users to use lookup for known citekeys, but does not differentiate from fulltext or fulltext_search siblings, so it is not fully distinguished.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly advises using lookup for known citekeys, providing a clear exclusion and alternative. However, it does not mention when to use fulltext or fulltext_search instead, so guidance is partial.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
5 tool updates
v0.4.0- First observed
collections - First observed
fulltext - First observed
fulltext_search - First observed
lookup - First observed
search
TDQS
Most tools have clear distinct purposes: lookup is for exact citekey metadata, fulltext retrieves paragraphs, search is global, and fulltext_search is scoped to one item. However, search and fulltext_search could be confused since both perform keyword searches, though descriptions help differentiate them.
Tool names follow mixed conventions: lookup and search are bare verbs, collections and fulltext are nouns, and fulltext_search is a noun+verb compound. There is no consistent verb_noun or resource_action pattern.
With 5 tools, the server is well-scoped for its purpose of Zotero fulltext retrieval. Each tool covers a distinct need without unnecessary bloat, fitting comfortably in the ideal 3-15 range.
The set covers lookup, search, collection listing, fulltext retrieval, and within-item search, which addresses core read-only workflows. Missing collection item listing and broader metadata browsing are minor gaps that can be worked around via search.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Remote MCP server for full read/write access to a Zotero library
Read-only MCP server exposing a user ORANO library to their own AI agent.
Search your AI chat history (ChatGPT, Claude, Codex) from any MCP client. Remote, private, read-only
MCP server unifying ERPs, CRMs, APIs and knowledge base for Claude, ChatGPT and Gemini.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceRead-only MCP server for browsing, searching, and exporting a Zotero library from AI assistants.-
- AlicenseAqualityCmaintenanceRead-only MCP server that lets Claude or any MCP client search and retrieve metadata, notes, full text, citations, and BibTeX from your local Zotero library via its built-in API.11MIT
- AlicenseNot gradedqualityCmaintenanceThis MCP server enables AI assistants like Claude to read and search your local Zotero bibliographic database directly from your machine.8MIT
- FlicenseNot gradedqualityCmaintenanceMCP server for natural-language search over a local Zotero library, enabling tools to search, retrieve, and manage paper metadata, notes, and PDF fulltext via Claude.-
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/statzhero/zotero-fulltext'
If you have feedback or need assistance with the MCP directory API, please join our Discord server