Paparats MCP: Self-Hosted Semantic Code Search

io.github.IBazylchuk由 GitHub 帳號 IBazylchuk 發布v2.18.2更新於 Nov 4, 2026

Self-hosted semantic code search MCP for Claude Code & Cursor. Multi-repo, AST-aware, stays local.

概覽

AI 產生的概覽

自架式的 MCP 伺服器,提供跨多個儲存庫的語意程式碼搜尋,具備 AST 感知切塊、符號圖與架構記憶層。

可以做什麼
  • 在多個已建立索引的儲存庫中進行語意程式碼搜尋,帶任務前綴嵌入與信心分數
  • 透過獨立的純文件端點搜尋並讀取精選文件
  • 讀取與維護架構記憶卡片(元件、決策、經驗),記錄程式碼為何如此
  • 初始化並稽核該記憶:走訪儲存庫產生卡片、清理過期卡片、把糾正轉為經驗條目
  • 透過 HTTP 介面註冊專案、更新單一檔案,可選用 Prometheus 指標與維運主控台
適用情境
適合助理需要在一個或多個大型儲存庫中找出相關程式碼、又不想把檔案塞進上下文時使用,也適合想要地端自架、取代託管式程式碼搜尋服務的情境。純文件端點適合把精選文件搜尋開放給另一個網路中的代理。
執行需求
以本機程序執行,透過 @paparats/cli npm 套件或 Docker 映像安裝;伺服器套件本身未發佈到 npm。需要 Qdrant 執行個體(QDRANT_URL,可選 QDRANT_API_KEY)與嵌入服務(EMBED_URL),或改用 OpenAI/Voyage 供應商。可選設定包括 PAPARATS_API_KEY、PAPARATS_UI_BASIC_AUTH、PAPARATS_KNOWLEDGE_TOKENS 與 PAPARATS_KNOWLEDGE_AUDIENCE、PAPARATS_CORS_ORIGINS。
安裝前請注意
未設定 PAPARATS_API_KEY 時,伺服器對任何能連上它的人開放,應只綁定本機或 VPN。知識端點需要 PAPARATS_KNOWLEDGE_TOKENS 中的 bearer 權杖與受眾上限;若未設定 PAPARATS_KNOWLEDGE_PROJECTS,某個儲存庫 README 中誤寫的 audience 標籤就可能擴大其可提供的範圍。建立索引會把程式碼與文件送給所設定的嵌入供應商,可能是第三方。伺服器會寫入 Qdrant 集合及其 SQLite 中介資料儲存。

安裝

在 SourceWeft 中

  1. 開啟 儀表板中的 Paparats MCP: Self-Hosted Semantic Code Search,將其新增到工作區。
  2. 為需要使用其工具的對話啟用該服務。

Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。

其他 MCP 客戶端

參照 儲存庫 中的啟動說明。

README

@paparats/server

The MCP server for Paparats MCP — semantic code search over multiple repos with AST-aware chunking, a cross-chunk symbol graph, git-history per chunk, and an agent-maintained architectural memory layer.

Not published to npm. This package is consumed as a library by @paparats/indexer and shipped as a Docker image: ibaz/paparats-server. End users install through @paparats/cli.

What this package does

Three jobs in one process:

  • Indexer. AST-aware chunking (tree-sitter, 11 languages), per-chunk symbol extraction, single-parse pipeline, llama-server embedding with SQLite cache, batched Qdrant upsert. Post-index passes attach git history, ticket references, and cross-chunk symbol edges (calls / called_by / references / referenced_by).
  • Searcher. Task-prefixed embedding (nl2code / code2code / techqa), query expansion for the support tools (abbreviations, case variants, plurals, filler removal), in-memory LRU query cache with per-group invalidation, confidence scoring, token-savings telemetry.
  • MCP server. Three endpoints — /mcp (coding), /support/mcp (support) and the opt-in, docs-only /knowledge/mcp (knowledge) — each with its own tool set and system instructions. Streamable HTTP for every client, with legacy SSE routes kept. Plus an agent-maintained architectural memory layer.

Endpoints

http://<host>:9876/health                  – liveness probehttp://<host>:9876/metrics                 – Prometheus (PAPARATS_METRICS=true)http://<host>:9876/ui                      – operator consolehttp://<host>:9876/api/analytics/...       – analytics REST API (UI backend)
http://<host>:9876/mcp                     – MCP, coding mode (Streamable HTTP)http://<host>:9876/sse                     – MCP, coding mode (legacy SSE)http://<host>:9876/messages                – MCP, coding mode (SSE message channel)
http://<host>:9876/support/mcp             – MCP, support modehttp://<host>:9876/support/sse             – MCP, support mode (SSE)http://<host>:9876/support/messages        – MCP, support mode (SSE message channel)
http://<host>:9876/knowledge/mcp           – MCP, knowledge mode (stateless, bearer auth,                                             POST only; mounted only when configured)

POST /api/index registers a project; POST /api/file-changed and POST /api/file-deleted update single files. See docs/tools.md for the full tool inventory per endpoint.

Knowledge mode

A docs-only MCP endpoint for a consumer in another network — an agent backend behind a load balancer that may search curated documentation and nothing else. Off unless PAPARATS_KNOWLEDGE_TOKENS and PAPARATS_KNOWLEDGE_AUDIENCE are both set; one without the other stops the server at startup.

  • Tools: search_docs and get_document only. No glossary block, no resources, no workflow prompts. search_docs returns structuredContent with an outputSchema, so a wrapping service can build citations without parsing markdown.
  • Auth: Authorization: Bearer <token>, compared in constant time, checked before the request body is read. 401 + WWW-Authenticate: Bearer otherwise.
  • Scope: documents labelled with an audience in PAPARATS_KNOWLEDGE_AUDIENCE (never internal), in the projects of PAPARATS_KNOWLEDGE_PROJECTS when set. Both are intersected with PAPARATS_DOCS_AUDIENCE / PAPARATS_PROJECTS when those are set. Out-of-scope documents read exactly like missing ones.
  • Transport: stateless Streamable HTTP — a fresh server and transport per POST, no session id; GET/DELETE answer 405. 64 kB body limit, 1000-character query cap.

Documents get their audience at index time: frontmatter audience: first, then docs.audience from .paparats.yml / projects.yml, otherwise internal. An invalid frontmatter value is logged and stored as internal. See the documentation search guide.

Set PAPARATS_KNOWLEDGE_PROJECTS — otherwise a stray audience: in some code repository's README is enough to widen what the endpoint serves.

Expose only that path, POST only. For example with nginx:

nginx
location = /knowledge/mcp {  limit_except POST { deny all; }  client_max_body_size 64k;  proxy_pass http://paparats:9876;  proxy_http_version 1.1;  proxy_buffering off; # responses stream as text/event-stream}location / {  return 404;}

Architectural memory

Code search tells the agent what the code does. The arch-memory layer tells it why — and the agent maintains that knowledge itself, across sessions, without you authoring a single doc.

Three card kinds in a separate Qdrant collection per group (paparats_<group>_arch), embedded with qwen3-embedding-0.6b (1024d, last-pooled):

KindFieldsIdempotency
Componentname, summary (markdown: Does / Owns / Does not / Touched when), files, neighbours, anchorsBy name (structural)
Decisiontitle, context, decision, alternatives_rejected, consequences, scope, supersedesServer-side similarity gate
Lessonrule, why, when, scope, severity, evidenceServer-side similarity gate

Similarity gate (cosine on qwen3-embedding-0.6b):

  • >= 0.85 → duplicate. Decisions are refused so the agent must reconcile or supersede. Lessons bump updatedAt on the existing card (Reflexion "rule confirmed").
  • 0.70 – 0.85 → similar. Nothing is written; the agent should refine wording or pass supersedes.
  • < 0.70 → accepted as a new card.

supersedes bypasses the gate and marks the prior decision status=superseded so it disappears from default search but stays in history.

Reading via arch_context accepts min_score (default 0.45). Each returned card carries an updated N ago stamp and the cosine score so the agent can detect stale or low-confidence hits.

Bootstrap with init_arch_memory — a workflow prompt analogous to /init in Claude Code. Walks the repo, identifies 8-20 components by domain boundary, writes the cards. Followed by audit_architecture (sweep stale cards) and record_lesson_from_correction (turn user corrections into structured lessons).

MCP resources:

  • arch://schema — full card-schema reference.
  • arch://stats/{group} — live counts (total / by kind / by status) and oldest/newest updatedAt.

Prometheus metrics (PAPARATS_METRICS=true):

  • paparats_arch_context_calls_total{group} — counter
  • paparats_arch_write_total{kind, status} — counter labelled by gate outcome
  • paparats_arch_search_score — histogram of cosine scores from arch_context
  • paparats_arch_collection_size{group, kind, status} — gauge

arch_context is read-only on both MCP endpoints. arch_record_* is support-only — recording belongs to the architectural-review workflow.

Module map

ModuleResponsibility
types.tsShared interfaces
lib.tsPublic library entry point (re-exports for programmatic use)
config.ts.paparats.yml reader, 11 language profiles, autoProjectConfig()
app.tsExpress app factory, HTTP API routes, request wiring
index.tsServer bootstrap — starts HTTP server, wires components, graceful shutdown
ast-chunker.tsAST-based chunking via tree-sitter
chunker.tsRegex chunking fallback (4 strategies)
ast-symbol-extractor.tsAST-based per-chunk symbol extraction
ast-queries.tsTree-sitter S-expression queries per language
tree-sitter-parser.tsWASM tree-sitter manager — lazy grammar loading
symbol-graph.tsCross-chunk symbol edges
embeddings.tsllama-server provider + SQLite cache + cached wrapper
indexer.tsGroup-aware Qdrant indexing — createQdrantClient(), toCollectionName(), single-parse chunkFile()
searcher.tsVector search, query expansion (support tools only), cache, metrics
query-expansion.tsAbbreviation / case / plural / filler expansion
task-prefixes.tsQuery-type detection + bge-code-v1 / Qwen3 query instructions
query-cache.tsIn-memory LRU cache with TTL and per-group invalidation
metrics.tsPrometheus metrics (prom-client) + NoOpMetrics fallback
metadata.tsTag resolution + auto-detection from directory structure
metadata-db.tsSQLite store for git commits, tickets, symbol edges
git-metadata.tsGit history extraction — diff-hunk mapping to chunks
ticket-extractor.tsJira / GitHub / custom ticket parsing
mcp-handler.tsMCP protocol — coding, support and knowledge endpoints with isolated tool sets and instructions
knowledge-mode.tsKnowledge mode — env parsing, bearer auth, body limit, scope intersection
arch/types.tsArchitectural-memory types
arch/collection.tsPer-group paparats_<group>_arch collection lifecycle
arch/text-embeddings.tsqwen3-embedding-0.6b text embedder via llama-server
arch/store.tsCRUD + server-side similarity gate + stats() aggregation
arch/context.tsarch_context query — top-N across kinds with min_score and age stamps

Configuration (env vars)

VariableDefaultNotes
PORT9876HTTP port
QDRANT_URLhttp://localhost:6333Qdrant endpoint (https → port 443, http → 6333)
QDRANT_API_KEY—Qdrant Cloud API key
EMBED_URLhttp://127.0.0.1:18434Embed server endpoint (llama-swap; internal port 8080, host port 18434 in the generated stack)
EMBED_BATCH_SIZE—Embeddings per llama-server call
EMBED_TTL0Idle seconds before a model unloads; 0 = never (default)
EMBEDDING_PROVIDERllamaCode embedding provider: llama | openai | voyage
EMBEDDING_MODELbge-code-v1Code embedding model
EMBEDDING_DIMENSIONS1536Code embedding dimensions
TEXT_EMBEDDING_PROVIDERllamallama, openai or voyage for the arch layer
TEXT_EMBEDDING_MODELqwen3-embedding-0.6bArch-layer text embedding model
TEXT_EMBEDDING_DIMENSIONS1024Arch-layer text embedding dimensions
PAPARATS_METRICSfalseSet to true to expose /metrics
PAPARATS_PROJECTS—Comma-separated allow-list of project names
PAPARATS_DOCS_AUDIENCE—Comma-separated audience ceiling for search_docs / get_document on the coding and support endpoints
PAPARATS_KNOWLEDGE_TOKENS—Comma-separated bearer tokens (≥ 16 characters) for /knowledge/mcp. Set together with PAPARATS_KNOWLEDGE_AUDIENCE, or neither
PAPARATS_KNOWLEDGE_AUDIENCE—Audience ceiling of /knowledge/mcp; internal is refused
PAPARATS_KNOWLEDGE_PROJECTS—Optional project allowlist of /knowledge/mcp — recommended
PAPARATS_API_KEY—Optional: comma-separated keys (≥ 16 characters); every route but /health and /knowledge/mcp then wants Authorization: Bearer <key>. Unset, the server is open (localhost, VPN). A malformed key stops startup
PAPARATS_UI_BASIC_AUTH—user:pass for /ui, /api/analytics/... and /api/module-map/... (else they take the API key as a basic-auth password); a malformed value stops startup
PAPARATS_CORS_ORIGINS—Comma-separated exact origins (e.g. https://app.example.com) browsers may call the server from. Unset = no CORS headers, and any request whose Origin is neither this server nor listed gets 403. Requests without Origin (MCP clients, curl) are unaffected
OTEL_*—Standard OpenTelemetry env vars (Tempo / Honeycomb / Datadog / Elastic APM)

Programmatic use (library)

The package.json exports map points at dist/lib.js, not the server bootstrap. Importing @paparats/server does not start the HTTP server — @paparats/indexer uses this to embed the Indexer class as a library:

ts
import { Indexer, createQdrantClient } from '@paparats/server';
const qdrant = createQdrantClient({ url: process.env.QDRANT_URL! });const indexer = new Indexer({ qdrant, /* ... */ });await indexer.indexProject(group, project);

Docker

bash
docker pull ibaz/paparats-server:latestdocker run --rm -p 9876:9876 \  -e QDRANT_URL=http://qdrant:6333 \  -e EMBED_URL=http://embed:8080 \  ibaz/paparats-server:latest

See examples/docker-compose for a complete stack (Qdrant + embed server + server + indexer).

Development

bash
yarn installyarn workspace @paparats/server buildyarn workspace @paparats/server testyarn workspace @paparats/server typecheck

Related packages

PackagePurpose
@paparats/cliOne-command installer, project management, search
@paparats/indexerAutomated multi-repo indexer (uses this as a library)
@paparats/sharedShared utilities (path validation, gitignore, excludes)
ibaz/paparats-embedllama.cpp llama-server + llama-swap with pre-baked bge-code-v1 and qwen3-embedding-0.6b

License

MIT

來源:packages/server/README.md,提交 393a5cb

工具

0
SourceWeft 曾在隔離沙箱中以無憑證方式啟動該軟體包一次,以列出其工具,但未能完成:該軟體包類型無法在沙箱中執行。

版本歷史

15
  1. v2.18.2最新Nov 4, 2026
  2. v2.18.1Nov 3, 2026
  3. v2.17.0Nov 1, 2026
  4. v2.16.9Oct 30, 2026
  5. v2.16.8Oct 30, 2026
  6. v2.16.7Oct 30, 2026
  7. v2.16.6Oct 29, 2026
  8. v2.15.0Oct 26, 2026
  9. v2.14.1Oct 26, 2026
  10. v2.12.1Oct 26, 2026
  11. v2.11.3Oct 25, 2026
  12. v2.11.2Oct 25, 2026
  13. v2.9.0Oct 13, 2026
  14. v2.8.0Oct 7, 2026
  15. v2.7.0Sep 16, 2026

評分

已滿足適用檢查項的 50%

該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。

  • 近 30 天內可連通25 分

    請保持端點能夠回應 MCP 握手;SourceWeft 每 30 天探測一次。

  • 已宣告認證方式10 分

    請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。

  • 已列出工具15 分

    請讓伺服器在無憑證時回應 tools/list,或發布可在沙箱中無憑證啟動的軟體包。

  • 描述必需15 分
  • 圖示10 分
  • 文件15 分
  • 授權條款10 分