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 分