Zotero MCP server: search, citations, add by DOI, safe writes, semantic search and PDF page images for Claude, ChatGPT and any MCP client. TypeScript, local-first.
Drift inferred · capture-to-capture
No drift recorded — single capability capture; advisories appear once its surface changes.
transport stdio · streamable-http · http
verified
reported
listed in the official MCP registry counts 0 tools · 0 res
· 0 prompts
permission surface via code analysis
No tools enumerated yet for this server.
prompt-surface
shipped agent-instruction files + hidden-content / dangerous-code findings —
quoted from the analyzed source
analyzed commit 3bf2637 · analyzer v33 · 4d ago
danger signals1
- suspicious endpoint 169.254.169.254 (cloud metadata) oscardvs-zoteus-3bf2637/tests/lib/cimd.test.ts :124
for (const url of ['https://169.254.169.254/cimd', 'https://127.0.0.1/x', 'https://10.0.0.5/x', 'https://[::1]/x']) {
evidence-backed
findings quoted directly from the published source artifact — not inferred
code files: 316
filesystem 60
- fs oscardvs-zoteus-3bf2637/bench/two-stage-search.ts :17
import { mkdtempSync, rmSync, statSync } from 'node:fs'; - fs (weak) oscardvs-zoteus-3bf2637/scripts/mcpb-bundle.ts :37
} from 'node:fs'; - fs (weak) oscardvs-zoteus-3bf2637/scripts/smoke-live.mjs :33
import { existsSync, mkdtempSync, writeFileSync } from 'node:fs'; - fs oscardvs-zoteus-3bf2637/src/api/attachments.ts :2
import { readFile, writeFile, stat } from 'node:fs/promises'; - fs oscardvs-zoteus-3bf2637/src/api/local-writes.ts :2
import { readFileSync, writeFileSync, mkdirSync } from 'node:fs'; - fs oscardvs-zoteus-3bf2637/src/auth/store.ts :2
import { readFile, writeFile, rename, mkdir } from 'node:fs/promises'; - fs oscardvs-zoteus-3bf2637/src/codex/generate.ts :1
import { writeFile, mkdir } from 'node:fs/promises'; - fs oscardvs-zoteus-3bf2637/src/features/attachments/bytes.ts :1
import { readdir, readFile, stat } from 'node:fs/promises'; - fs oscardvs-zoteus-3bf2637/src/features/attachments/store.ts :1
import { readFile } from 'node:fs/promises'; - fs oscardvs-zoteus-3bf2637/src/features/search/index-manager.ts :1
import { statSync } from 'node:fs'; - fs oscardvs-zoteus-3bf2637/src/features/search/persistence.ts :1
import { readFile, writeFile, mkdir, rename, unlink } from 'node:fs/promises'; - fs oscardvs-zoteus-3bf2637/src/features/search/repair.ts :1
import { unlink } from 'node:fs/promises';
show 28 more
- fs oscardvs-zoteus-3bf2637/src/features/search/sqlite-index.ts :3
import { existsSync } from 'node:fs'; - fs oscardvs-zoteus-3bf2637/src/lib/caller-path.ts :1
import { realpath } from 'node:fs/promises'; - fs oscardvs-zoteus-3bf2637/src/lib/logger.ts :3
import { createWriteStream, type WriteStream } from 'node:fs'; - fs oscardvs-zoteus-3bf2637/src/lib/update-check.ts :1
import { readFile, writeFile, mkdir } from 'node:fs/promises'; - fs oscardvs-zoteus-3bf2637/src/lib/usage/store.ts :18
import { existsSync, mkdirSync, renameSync } from 'node:fs'; - fs oscardvs-zoteus-3bf2637/src/tools/attachment.ts :4
import { existsSync } from 'node:fs'; - fs oscardvs-zoteus-3bf2637/src/tools/pdf-images.ts :3
import { mkdir, writeFile } from 'node:fs/promises'; - fs oscardvs-zoteus-3bf2637/src/tools/tag-audit.ts :2
import { readFile } from 'node:fs/promises'; - fs (weak) oscardvs-zoteus-3bf2637/tests/api/attachments.test.ts :2
import { writeFile, readFile, rm } from 'node:fs/promises'; - fs (weak) oscardvs-zoteus-3bf2637/tests/api/local-writes.test.ts :2
import { mkdtempSync, readFileSync, existsSync } from 'node:fs'; - fs (weak) oscardvs-zoteus-3bf2637/tests/auth/store.test.ts :2
import { mkdtemp, rm, writeFile, readFile } from 'node:fs/promises'; - fs (weak) oscardvs-zoteus-3bf2637/tests/e2e/live-writes.test.ts :2
import { writeFile, readFile, rm } from 'node:fs/promises'; - fs (weak) oscardvs-zoteus-3bf2637/tests/features/accent-folding.test.ts :2
import { mkdtempSync } from 'node:fs'; - fs (weak) oscardvs-zoteus-3bf2637/tests/features/attachment-bytes.test.ts :2
import { mkdtemp, mkdir, writeFile, rm } from 'node:fs/promises'; - fs (weak) oscardvs-zoteus-3bf2637/tests/features/embedder-degradation.test.ts :2
import { mkdtempSync, mkdirSync, writeFileSync } from 'node:fs'; - fs (weak) oscardvs-zoteus-3bf2637/tests/features/embedding-rate-math.test.ts :2
import { readFileSync } from 'node:fs'; - fs (weak) oscardvs-zoteus-3bf2637/tests/features/pdf-images.test.ts :2
import { readFile } from 'node:fs/promises'; - fs (weak) oscardvs-zoteus-3bf2637/tests/features/search-async.test.ts :4
import { readFile } from 'node:fs/promises'; - fs (weak) oscardvs-zoteus-3bf2637/tests/features/search-backends.test.ts :2
import { mkdtempSync, writeFileSync, existsSync } from 'node:fs'; - fs (weak) oscardvs-zoteus-3bf2637/tests/features/search-corruption.test.ts :2
import { mkdtempSync, writeFileSync, openSync, writeSync, closeSync, mkdirSync, rmSync } from 'node:fs'; - fs (weak) oscardvs-zoteus-3bf2637/tests/features/search-droplist.test.ts :2
import { mkdtempSync } from 'node:fs'; - fs (weak) oscardvs-zoteus-3bf2637/tests/features/search-fulltext-resume.test.ts :2
import { mkdtempSync } from 'node:fs'; - fs (weak) oscardvs-zoteus-3bf2637/tests/features/search-incremental-update.test.ts :2
import { mkdtempSync } from 'node:fs'; - fs (weak) oscardvs-zoteus-3bf2637/tests/features/search-library-guard.test.ts :2
import { mkdtempSync } from 'node:fs'; - fs (weak) oscardvs-zoteus-3bf2637/tests/features/search-pause.test.ts :2
import { mkdtemp, readFile } from 'node:fs/promises'; - fs (weak) oscardvs-zoteus-3bf2637/tests/features/search-repair.test.ts :2
import { mkdtempSync, writeFileSync, openSync, writeSync, closeSync, existsSync, readFileSync } from 'node:fs'; - fs (weak) oscardvs-zoteus-3bf2637/tests/features/search-resume.test.ts :2
import { mkdtempSync, readFileSync } from 'node:fs'; - fs (weak) oscardvs-zoteus-3bf2637/tests/features/search-salvage-library.test.ts :2
import { mkdtempSync, readdirSync } from 'node:fs';
20 more not shown — this panel samples each group; the count above is the real total.
shell / exec 3
- shell (weak) oscardvs-zoteus-3bf2637/scripts/mcpb-bundle.ts :26
import { execFileSync } from 'node:child_process'; - shell oscardvs-zoteus-3bf2637/src/features/search/embeddings.ts :740
private spawn(specifier: string): Promise<Extractor> { - shell (weak) oscardvs-zoteus-3bf2637/tests/features/search-backends.test.ts :3
import { spawn } from 'node:child_process';
network 27
- net (weak) oscardvs-zoteus-3bf2637/scripts/smoke-live.mjs :32
import { createServer } from 'node:http'; - net (weak) oscardvs-zoteus-3bf2637/scripts/usage-report.ts :35
const res = await fetch(`${remote.replace(/\/$/, '')}/usage.json?days=${days}`, { - net oscardvs-zoteus-3bf2637/src/api/connector-writes.ts :59
const res = await this.fetcher.fetch(`${this.base}/connector/ping`, { method: 'GET' }, { maxRetries: 0 }); - net oscardvs-zoteus-3bf2637/src/api/http.ts :44
async fetch( - net oscardvs-zoteus-3bf2637/src/api/local-client.ts :154
const res = await this.fetcher.fetch( - net oscardvs-zoteus-3bf2637/src/api/local-writes.ts :104
const res = await this.fetcher.fetch( - net oscardvs-zoteus-3bf2637/src/api/web-client.ts :169
const res = await this.fetcher.fetch(url, { method: 'GET', headers: this.headers() }); - net oscardvs-zoteus-3bf2637/src/features/attachments/store.ts :92
const res = await ctx.fetcher.fetch(url, { method: 'GET' }, { maxRetries: 2, deadlineMs: 300_000 }); - net oscardvs-zoteus-3bf2637/src/features/citation/translation-server.ts :22
const res = await this.fetcher.fetch(`${this.baseUrl}/`, { method: 'GET' }, { maxRetries: 0 }); - net oscardvs-zoteus-3bf2637/src/features/scholar/crossref.ts :42
const res = await this.fetcher.fetch(`${BASE}/works/${stripDoi(doi)}${m}`, { method: 'GET' }, { maxRetries: 1 }); - net oscardvs-zoteus-3bf2637/src/features/scholar/openalex.ts :84
const res = await this.fetcher.fetch(url, { method: 'GET', headers: this.headers }, { maxRetries: 1 }); - net oscardvs-zoteus-3bf2637/src/features/search/embeddings.ts :995
fetch('https://api.openai.com/v1/embeddings', {
show 15 more
- net oscardvs-zoteus-3bf2637/src/index.ts :22
import type { Server } from 'node:http'; - net oscardvs-zoteus-3bf2637/src/lib/cimd.ts :11
// fetch (TOCTOU). Operators serving a directory connector should set an allowlist. - net oscardvs-zoteus-3bf2637/src/lib/lifecycle.ts :1
import type { Server } from 'node:http'; - net oscardvs-zoteus-3bf2637/src/tools/import.ts :43
const item = await arxivItem(parsed.value, (url, init) => ctx.fetcher.fetch(url, init, { maxRetries: 0, deadlineMs: 60_000 })); - net oscardvs-zoteus-3bf2637/src/transports/http.ts :1
import http from 'node:http'; - net (weak) oscardvs-zoteus-3bf2637/tests/api/http.test.ts :21
const res = await f.fetch('https://example.test/x'); - net (weak) oscardvs-zoteus-3bf2637/tests/integration/cimd-metadata.test.ts :3
import type { Server } from 'node:http'; - net (weak) oscardvs-zoteus-3bf2637/tests/integration/dns-rebinding.test.ts :3
import type { Server } from 'node:http'; - net (weak) oscardvs-zoteus-3bf2637/tests/integration/graceful-shutdown.test.ts :3
import http from 'node:http'; - net (weak) oscardvs-zoteus-3bf2637/tests/integration/health-endpoints.test.ts :2
import type { Server } from 'node:http'; - net (weak) oscardvs-zoteus-3bf2637/tests/integration/http-sessions.test.ts :6
import type { Server } from 'node:http'; - net (weak) oscardvs-zoteus-3bf2637/tests/integration/http.test.ts :6
import type { Server } from 'node:http'; - net (weak) oscardvs-zoteus-3bf2637/tests/integration/multitenant.test.ts :5
import type { Server } from 'node:http'; - net (weak) oscardvs-zoteus-3bf2637/tests/integration/oauth-flow.test.ts :2
import net from 'node:net'; - net (weak) oscardvs-zoteus-3bf2637/tests/integration/usage-endpoints.test.ts :2
import type { Server } from 'node:http';
secrets 7
- secrets (weak) oscardvs-zoteus-3bf2637/scripts/usage-report.ts :34
const token = arg('token') ?? process.env.ZOTEUS_METRICS_TOKEN; - secrets oscardvs-zoteus-3bf2637/src/features/search/embeddings.ts :1054
if (!process.env.OPENAI_API_KEY) { - secrets (weak) oscardvs-zoteus-3bf2637/tests/e2e/live-writes.test.ts :15
const enabled = Boolean(process.env.ZOTERO_API_KEY) && process.env.ZOTEUS_E2E_WRITE === 'true'; - secrets (weak) oscardvs-zoteus-3bf2637/tests/e2e/live.test.ts :6
const hasKey = Boolean(process.env.ZOTERO_API_KEY); - secrets (weak) oscardvs-zoteus-3bf2637/tests/features/embedder-degradation.test.ts :80
const previous = process.env.OPENAI_API_KEY; - secrets (weak) oscardvs-zoteus-3bf2637/tests/features/embedding-config.test.ts :174
const previous = process.env.OPENAI_API_KEY; - secrets (weak) oscardvs-zoteus-3bf2637/tests/features/search-electron-fulltext.test.ts :166
process.env.OPENAI_API_KEY = 'sk-test';
install hooks 2
- prepare oscardvs-zoteus-3bf2637/package.json :50
npm run build - prepublishOnly oscardvs-zoteus-3bf2637/package.json :51
npm run build
declared dependencies 18
- @modelcontextprotocol/sdk@^1.29.0
- citeproc@^2.4.63
- cors@^2.8.6
- express@^5.2.1
- express-rate-limit@^8.5.2
- zod@^3.25.76
- @types/cors@^2.8.19
- @types/express@^5.0.6
- @types/node@^22.10.0
- @typescript-eslint/eslint-plugin@^8.18.0
- @typescript-eslint/parser@^8.18.0
- eslint@^8.57.1
show 6 more
- pkce-challenge@^5.0.1
- prettier@^3.4.2
- tsx@^4.19.2
- typescript@^5.7.2
- vitest@^2.1.8
- pdfjs-dist@5.6.205
perm:untrusted 2
- untrusted (weak) oscardvs-zoteus-3bf2637/tests/integration/oauth-flow.test.ts :114
const consentHtml = await (await fetch(authUrl)).text(); - untrusted (weak) oscardvs-zoteus-3bf2637/tests/integration/usage-endpoints.test.ts :45
const text = await (await fetch(`${await serve()}/metrics`)).text();
transport_posture 1
- binds all interfaces (0.0.0.0) oscardvs-zoteus-3bf2637/tests/integration/dns-rebinding.test.ts :37
await expect(startHttp(bareServer(), { port: 0, host: '0.0.0.0' })).rejects.toThrow(/loopback/i);