{
  "slug": "io-github-andrea9293-mcp-documentation-server",
  "name": "io.github.andrea9293/mcp-documentation-server",
  "title": "mcp-documentation-server",
  "description": "Local-first document management and semantic search for AI coding agents",
  "version": "1.15.3",
  "publishedAt": "2026-08-27T13:14:26.273279Z",
  "updatedAt": "2026-08-27T13:14:26.273279Z",
  "repoUrl": "https://github.com/andrea9293/mcp-documentation-server",
  "websiteUrl": null,
  "namespace": {
    "type": "github",
    "owner": "andrea9293"
  },
  "kind": "local",
  "packages": [
    {
      "registryType": "npm",
      "identifier": "@andrea9293/mcp-documentation-server",
      "version": "1.15.3",
      "transport": "stdio",
      "runtimeHint": null
    }
  ],
  "remotes": [],
  "envVars": [],
  "category": "files-docs",
  "subcategory": "more",
  "company": "",
  "categoryAuto": true,
  "checks": [
    {
      "id": "source-linked",
      "label": "Source repository linked",
      "result": "pass",
      "detail": "https://github.com/andrea9293/mcp-documentation-server"
    },
    {
      "id": "version-pinned",
      "label": "Version pinned",
      "result": "pass",
      "detail": "Every package has an explicit version"
    },
    {
      "id": "secrets-requested",
      "label": "Secrets requested",
      "result": "info",
      "detail": "Asks for no secrets"
    },
    {
      "id": "known-registry",
      "label": "Known package registry",
      "result": "pass",
      "detail": "All packages come from npm, PyPI, OCI, NuGet or MCPB"
    },
    {
      "id": "namespace",
      "label": "Namespace ownership",
      "result": "info",
      "detail": "Name verified via GitHub account andrea9293"
    },
    {
      "id": "meta-text",
      "label": "Registry text aimed at the AI",
      "result": "pass",
      "detail": "Description and settings contain no hidden characters or instructions to the AI"
    },
    {
      "id": "install-scripts",
      "label": "Install scripts",
      "result": "pass",
      "detail": "@andrea9293/mcp-documentation-server@1.15.3 runs nothing at install"
    },
    {
      "id": "code-flags",
      "label": "Code red flags",
      "result": "pass",
      "detail": "Read 14 files in @andrea9293/mcp-documentation-server@1.15.3: no obfuscation, encoded execution, credential reads or data-collection endpoints found"
    },
    {
      "id": "ai-text",
      "label": "Text aimed at the AI",
      "result": "pass",
      "detail": "No hidden characters or instructions to the AI in 14 files, including comments and the README"
    }
  ],
  "scannedAt": "2026-10-29",
  "level": "Scanned",
  "install": [
    {
      "label": "Claude Desktop (npm)",
      "kind": "claude_desktop_json",
      "text": "{\n  \"mcpServers\": {\n    \"mcp-documentation-server\": {\n      \"command\": \"npx\",\n      \"args\": [\n        \"-y\",\n        \"@andrea9293/mcp-documentation-server@1.15.3\"\n      ]\n    }\n  }\n}"
    }
  ],
  "curated": true,
  "stars": 343,
  "archived": false,
  "pushedAt": "2026-08-27T13:13:02Z",
  "review": {
    "package": "@andrea9293/mcp-documentation-server",
    "version": "1.15.3",
    "at": "2026-10-31",
    "files": 12,
    "lines": 2994,
    "verdict": "fail",
    "summary": "Keeps a local searchable library of documents for your AI, with an optional Google Gemini 'AI search' that uploads the whole file to Google when you set a Gemini key. It is marked as failing because it also starts a web page on your computer (port 3080) with no password. Any program on your machine, and possibly any website you visit, can add documents or upload files through it. Set START_WEB_UI=false to turn the web page off.",
    "hosts": [
      {
        "host": "huggingface.co (Xenova/all-MiniLM-L6-v2 or MCP_EMBEDDING_MODEL, via @xenova/transformers)",
        "when": "first time a document is added or searched (lazy model load); dependency behaviour",
        "sends": "model download requests"
      },
      {
        "host": "generativelanguage.googleapis.com (Google Gemini Files + generateContent API, model gemini-2.5-flash)",
        "when": "only when search_documents_with_ai or POST /api/search-ai is called and GEMINI_API_KEY is set",
        "sends": "the original stored document file (upload), the search query, and GEMINI_API_KEY; it also lists and deletes files in the Gemini account"
      },
      {
        "host": "127.0.0.1:3080 (listens; WEB_HOST/WEB_PORT configurable, 0.0.0.0 exposes it to the network)",
        "when": "started automatically with the MCP server unless START_WEB_UI=false, and runs the whole time",
        "sends": "serves an unauthenticated REST API to list/read/add/delete documents, search, upload files and process uploads"
      }
    ],
    "env": [
      {
        "name": "GEMINI_API_KEY",
        "sent_to": "Google Gemini API only (enables search_documents_with_ai); not logged"
      },
      {
        "name": "MCP_BASE_DIR",
        "sent_to": "local only: data directory (default ~/.mcp-documentation-server)"
      },
      {
        "name": "MCP_EMBEDDING_MODEL",
        "sent_to": "chooses which model is downloaded from Hugging Face"
      },
      {
        "name": "START_WEB_UI / WEB_PORT / WEB_HOST",
        "sent_to": "local web UI control"
      },
      {
        "name": "MCP_CACHE_ENABLED / MCP_CACHE_SIZE / MCP_STREAMING_ENABLED / MCP_STREAM_FILE_SIZE_LIMIT / MCP_STREAM_CHUNK_SIZE",
        "sent_to": "local tuning only"
      },
      {
        "name": ".env file in the working directory (dotenv/config)",
        "sent_to": "loaded into process env at startup"
      }
    ],
    "local": "Reads and writes ~/.mcp-documentation-server (document databases, copies, original uploads, Gemini file mappings) and its uploads folder; process_uploads reads every .txt, .md and .pdf there. MCP tool input never names a file path. The web UI upload route saves under the client-supplied filename, which multer 2 strips of paths.",
    "exec": "None. No child_process, eval or shell. Only fixed dynamic import('fs'/'fs/promises').",
    "telemetry": "None.",
    "tools": [
      "add_document",
      "delete_document",
      "search_documents",
      "get_document",
      "list_documents",
      "search_all_documents",
      "get_context_window",
      "search_documents_with_ai (only if GEMINI_API_KEY set)",
      "get_ui_url (only if web UI enabled, the default)",
      "get_uploads_path",
      "process_uploads",
      "list_uploads_files"
    ],
    "toolText": "clean of injection. Descriptions contain benign behavioural guidance for the AI: 'Use this tool only when user explicitly requests it' (get_document), 'Always tell the user if result is truncated', a hint_for_llm field pointing to get_context_window, and get_ui_url telling the AI to give the user the web UI URL. None of it hides anything from the user or targets other servers.",
    "deps": [
      "dotenv",
      "fastmcp",
      "zod",
      "express",
      "multer",
      "@xenova/transformers",
      "unpdf",
      "@orama/orama",
      "@orama/plugin-data-persistence",
      "@google/genai"
    ],
    "findings": [
      {
        "severity": "high",
        "at": "dist/web-server.js:44-53,206-221",
        "what": "The auto-started web UI accepts file uploads with no login and no Origin or CSRF check, and multipart forms are a CORS \"simple\" request, so any web page the user visits can upload into it. (The reviewer also raised \"../\" in the filename writing outside the uploads folder; multer 2 parses with busboy, which strips paths from filenames, so that part is unlikely.) With WEB_HOST=0.0.0.0 anyone on the network can upload."
      },
      {
        "severity": "high",
        "at": "dist/web-server.js:24-25,83-97,195-204 + server.js:283-305",
        "what": "The web UI starts by default (START_WEB_UI defaults on) with no authentication. express.urlencoded allows cross-site HTML form POSTs to /api/documents and /api/uploads/process, so any website can plant documents in the knowledge base. The AI later retrieves them as trusted search results, a persistent prompt-injection channel. With no Host-header check, DNS rebinding could also read all stored documents."
      },
      {
        "severity": "note",
        "at": "dist/gemini-search-service.js:187-201",
        "what": "After each AI search it lists all files in the user's Gemini Files API project and deletes every file not in ACTIVE state, including files uploaded by other apps using the same API key."
      },
      {
        "severity": "note",
        "at": "dist/gemini-search-service.js:80-98",
        "what": "When GEMINI_API_KEY is set, search_documents_with_ai uploads the full original document file to Google Gemini. This is disclosed in the tool description ('using Gemini AI'), but users should know whole files leave the machine."
      },
      {
        "severity": "note",
        "at": "dist/embedding-provider.js:48-62",
        "what": "The embedding model is downloaded from Hugging Face on first use (transformers.js default)."
      },
      {
        "severity": "note",
        "at": "dist/server.js:50-77",
        "what": "delete_document permanently removes the document, its chunks and its stored files with no confirmation step."
      },
      {
        "severity": "info",
        "at": "dist/document-manager.js:120,167",
        "what": "Search queries and document titles are written to stderr logs (local only)."
      },
      {
        "severity": "info",
        "at": "dist/web-server.js:27-31",
        "what": "The web UI's static front-end (dist/public / src/public) is served by this code but was not part of the reviewed file set, so the browser-side UI code is unverified."
      }
    ]
  },
  "health": {
    "score": 40,
    "parts": {
      "popularity": 0.5183439441216948,
      "activity": 0.5868981754213018,
      "issues": 0.9090909090909091,
      "security": 0
    },
    "fail": 1,
    "warn": 0,
    "raw": {
      "stars": 343,
      "forks": 45,
      "downloads": 233,
      "hn": {
        "n": 0,
        "pts": 0,
        "t": []
      },
      "issuesOpen": 1,
      "issuesClosed": 10,
      "prsMerged": 18,
      "commits90": 2,
      "release": "2026-07-15T12:43:45Z",
      "pushed": "2026-08-27T13:13:02Z",
      "growth": null,
      "growthDays": null,
      "archived": false
    },
    "at": "2026-10-31T07:42:38.200Z"
  }
}
