MCP, MCP server
io.github.NodeDex/nodedex
io.github.NodeDex/nodedex, an MCP server listed in the PlugVet directory.
Compatibility: Not stated.
Grade B
Minor issues only, no Medium or High. Worth a quick look at the findings below before installing.
Not a guarantee. A hygiene check of the source at the commit shown, not a security audit.
Rescanned at commit 8a867511c4e2, unchanged since the check below.
PERMISSION_DELETE_FILES NETWORK_NO_FIXED_HOST NETWORK_UNNAMED_HOST SECRETS_PATH_DOTENV SECRETS_ENV_READ
Why this grade
- PERMISSION_DELETE_FILES Low
Contains a call that can delete files.
server/adapters/nodedex-capture.mjs, line 138
if (sent >= lines.length) b.fs.unlinkSync(b.file); - NETWORK_NO_FIXED_HOST Low
Makes a network call whose host is not written as a fixed address.
server/adapters/nodedex-capture-core.mjs, line 140
const res = await fetch(`${target.url}/api/reflect/trigger`, { - NETWORK_UNNAMED_HOST Low
Calls a fixed host that the description does not name.
server/adapters/nodedex-capture-core.mjs, line 140
const res = await fetch(`${target.url}/api/reflect/trigger`, { - SECRETS_PATH_DOTENV Low
Mentions a .env file.
server/adapters/nodedex-capture-core.mjs, line 30
// Process env wins; ~/.nodedex/.env is the fallback (same fill-if-unset contract - SECRETS_ENV_READ Note
Reads an environment variable whose name contains KEY, SECRET, TOKEN, PASSWORD or CREDENTIAL.
server/adapters/nodedex-capture-core.mjs, line 77
token: process.env.NODEDEX_CAPTURE_TOKEN || process.env.NODEDEX_TOKEN || "",
Any High, or two or more Medium findings, give D. One Medium gives C. Low findings or a security Note give B. Each code names a finding behind the letter.
Grades are a hygiene check of the source at the commit shown, on the date checked, not a security audit or a guarantee. The free directory grades are automated. Before release, a PlugVet engineer reviews every paid report and any grade we hold back, including all F grades, against the source code and the evidence we quote.
What was checked
Plain notes from the hygiene checks.
Permissions
Concern
can delete files.
PERMISSION_DELETE_FILES
server/adapters/nodedex-capture.mjs, line 138
if (sent >= lines.length) b.fs.unlinkSync(b.file);
server/scripts/db-encryption.mjs, line 48
for (const ext of ["-wal", "-shm"]) { const f = dbPath + ext; if (fs.existsSync(f)) try { fs.unlinkSync(f); } catch {} }
server/src/server.ts, line 138
try { if (fs.existsSync(pidFile)) fs.unlinkSync(pidFile); } catch { /* ignore */ }
Show more
server/src/middleware/reflect/pipeline.ts, line 95
fs.unlinkSync(path.join(REFLECT_TURNS_DIR, f));
server/src/store/backup.ts, line 54
try { fs.unlinkSync(path.join(backupDir, f)); } catch { /* ignore */ }
Install and update
Pass
No install-time script found, and dependencies are pinned or absent.
Network
Concern
can reach a host that is not written as a fixed address. can reach host.docker.internal. The description does not name that host. can reach openrouter.ai. The description does not name that host.
NETWORK_NO_FIXED_HOST NETWORK_UNNAMED_HOST
server/adapters/nodedex-capture-core.mjs, line 140
const res = await fetch(`${target.url}/api/reflect/trigger`, {
server/adapters/nodedex-capture.mjs, line 117
const res = await fetch(`${url}/api/reflect/trigger`, {
server/adapters/nodedex-gate.mjs, line 72
const res = await fetch(`${URL_BASE}/api/gate/check${q.size ? `?${q}` : ""}`, { signal: ctrl.signal });
Show more
server/scripts/nodedex-entry.mjs, line 284
const r = await fetch(`http://127.0.0.1:${port}/api/health`, { signal: AbortSignal.timeout(1200) });
server/scripts/nodedex-entry.mjs, line 345
const r = await fetch(`${OPENROUTER_BASE_URL}/key`, { headers: { Authorization: `Bearer ${key}` }, signal: AbortSignal.timeout(8000) });
server/scripts/nodedex-entry.mjs, line 501
const r = await fetch(`http://127.0.0.1:${m.port}/api/health`, { signal: AbortSignal.timeout(2500) });
server/scripts/nodedex-entry.mjs, line 537
console.log(` test: curl http://127.0.0.1:${s.port}/api/health`);
server/scripts/nodedex-entry.mjs, line 540
console.log(` test (run INSIDE the container): curl ${s.token ? `-H "Authorization: Bearer ${s.token}" ` : ""}http://host.docker.internal:${s.port}/api/health`);
server/scripts/nodedex-entry.mjs, line 545
console.log(`If a Docker connect fails: (1) run the in-container curl above - if it hangs, it's networking
server/src/middleware/reflect/cost-guard.ts, line 83
const r = await fetch("https://openrouter.ai/api/v1/credits", {
server/src/routes/admin.ts, line 524
const r = await fetch("https://openrouter.ai/api/v1/models", {
Secrets
Concern
reads a credential or environment file.
SECRETS_ENV_READ SECRETS_PATH_DOTENV
server/adapters/nodedex-capture-core.mjs, line 30
// Process env wins; ~/.nodedex/.env is the fallback (same fill-if-unset contract
server/adapters/nodedex-capture-core.mjs, line 39
for (const line of readFileSync(join(homedir(), ".nodedex", ".env"), "utf8").split("\n")) {
server/adapters/nodedex-capture-core.mjs, line 77
token: process.env.NODEDEX_CAPTURE_TOKEN || process.env.NODEDEX_TOKEN || "",
Show more
server/adapters/nodedex-capture-core.mjs, line 48
} catch { /* no home .env - defaults apply */ }
server/scripts/db-encryption.mjs, line 8
// encrypt: a plaintext DB → encrypted (then set the SAME key in .env so the server
server/scripts/db-encryption.mjs, line 18
const key = process.env.NODEDEX_DB_ENCRYPTION_KEY;
server/scripts/db-encryption.mjs, line 61
? " → set NODEDEX_DB_ENCRYPTION_KEY (same value) in .env so the server opens it."
server/scripts/db-encryption.mjs, line 62
: " → unset NODEDEX_DB_ENCRYPTION_KEY in .env (the DB is now plaintext).");
server/scripts/nodedex-entry.mjs, line 84
return; // no config yet - the server falls back to its own .env / defaults
server/scripts/nodedex-entry.mjs, line 111
// Precedence trap: the server loads ~/.nodedex/.env fill-if-unset AFTER us, so a bare
server/scripts/nodedex-entry.mjs, line 202
if (process.env.NODEDEX_API_TOKEN && !process.env.NODEDEX_CAPTURE_TOKEN) {
server/scripts/nodedex-entry.mjs, line 203
process.env.NODEDEX_CAPTURE_TOKEN = process.env.NODEDEX_API_TOKEN;
server/scripts/nodedex-entry.mjs, line 493
managed = [{ port, token: process.env.NODEDEX_API_TOKEN || "" }];
server/src/api-server.ts, line 78
const ADMIN_TOKEN = process.env.NODEDEX_ADMIN_TOKEN || "";
server/src/server.ts, line 50
const encryptionEnabled = !!process.env.WORKSPACE_ENCRYPTION_KEY;
server/src/engine/providers/index.ts, line 19
process.env.OPENAI_API_KEY ?? "",
Agent instructions
Pass
No instruction to ignore earlier instructions or to hide a step.
Obfuscation
Pass
No encoded or minified payload found.
Licence
Pass
A licence file is present (LICENSE).
Maintainer activity
Pass
The latest commit is within the last 365 days.
Note
Hygiene check of commit 8a867511c4e2. can delete files. can reach a host that is not written as a fixed address. can reach host.docker.internal. The description does not name that host. can reach openrouter.ai. The description does not name that host. reads a credential or environment file.
Date and source
Date checked:
github.com
Commit graded: 8a867511c4e2c51fb51cb812c0f3a1d629f42f8e
This link goes to the original host. PlugVet does not host or check what you download from there, and installing it is your own decision and risk.