Paparats MCP: Self-Hosted Semantic Code Search について
Paparats MCPは、複数リポジトリを扱うチーム向けのセルフホスト可能なセマンティックコード検索サーバーです。AST対応のインデックス、シンボル関係、Git履歴、エージェントが管理するアーキテクチャメモリを組み合わせます。
主な機能
- 0111言語のAST対応インデックス
- 02チャンク間のシンボルグラフ
- 03Git履歴とチケットメタデータ
- 04クエリ拡張付きセマンティック検索
- 05エージェント管理のアーキテクチャメモリ
活用シーン
- 01複数リポジトリのコード検索
- 02コードチャンク間のシンボル関係の追跡
- 03アーキテクチャ上の決定や教訓の確認
- 04スコープ制限付きエンドポイントでの文書検索
MCP 対応
コーディング用とサポート用のツールを別々のMCPエンドポイントで公開し、任意で文書専用エンドポイントも提供します。MCPクライアントはStreamable HTTPで接続でき、従来のSSEルートも利用できます。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
@paparats/server
Paparats MCP の MCP サーバーです。複数のリポジトリを対象に、AST を考慮したチャンク分割、チャンク間のシンボルグラフ、チャンクごとの Git 履歴、エージェントが管理するアーキテクチャメモリレイヤーを備えたセマンティックコード検索を提供します。
npm では公開されていません。 このパッケージは
@paparats/indexerのライブラリとして利用され、Docker イメージとして配布されます:ibaz/paparats-server。 エンドユーザーは@paparats/cliを通じてインストールします。
このパッケージの機能
1つのプロセスで3つの役割を担います。
- インデクサー。 AST を考慮したチャンク分割(tree-sitter、11言語)、チャンクごとのシンボル抽出、単一パースのパイプライン、SQLite キャッシュを備えた llama-server による埋め込み、バッチ処理による Qdrant へのアップサート。インデックス作成後の処理で、Git 履歴、チケット参照、チャンク間のシンボルエッジ(calls / called_by / references / referenced_by)を追加します。
- 検索機能。 タスクプレフィックス付き埋め込み(
nl2code/code2code/techqa)、サポート用ツールのクエリ拡張(略語、大小文字のバリエーション、複数形、フィラーの削除)、グループごとの無効化に対応したメモリ内 LRU クエリキャッシュ、信頼度スコアリング、トークン削減のテレメトリー。 - MCP サーバー。 3つのエンドポイント —
/mcp(コーディング)、/support/mcp(サポート)、オプトイン方式のドキュメント専用/knowledge/mcp(ナレッジ) — を提供し、それぞれ独自のツールセットとシステム指示を備えます。すべてのクライアント向けの Streamable HTTP に加え、従来の SSE ルートも維持しています。さらに、エージェントが管理するアーキテクチャメモリレイヤーも備えています。
エンドポイント
http://<host>:9876/health – liveness probe
http://<host>:9876/metrics – Prometheus (PAPARATS_METRICS=true)
http://<host>:9876/ui – operator console
http://<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 (SSE / Cursor)
http://<host>:9876/messages – MCP, coding mode (SSE message channel)
http://<host>:9876/support/mcp – MCP, support mode
http://<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 はプロジェクトを登録し、POST /api/file-changed と POST /api/file-deleted は単一ファイルを更新します。
各エンドポイントのツール一覧については、docs/tools.md を参照してください。
ナレッジモード
別のネットワークにある利用者向けのドキュメント専用 MCP エンドポイントです。ロードバランサーの背後にあるエージェントバックエンドが、厳選されたドキュメントのみを検索できるようにします。PAPARATS_KNOWLEDGE_TOKENS と PAPARATS_KNOWLEDGE_AUDIENCE の両方が設定されていない限り無効です。片方だけが設定されている場合、サーバーは起動時に停止します。
- ツール:
search_docsとget_documentのみです。用語集ブロック、リソース、ワークフロープロンプトはありません。search_docsはoutputSchemaを含むstructuredContentを返すため、ラッパーサービスは Markdown を解析せずに引用を作成できます。 - 認証:
Authorization: Bearer <token>を使用し、定数時間で比較します。リクエストボディを読み取る前に検証します。それ以外の場合は401とWWW-Authenticate: Bearerを返します。 - スコープ:
PAPARATS_KNOWLEDGE_AUDIENCEに含まれるオーディエンスがラベル付けされたドキュメントを対象とします(internalは対象外)。PAPARATS_KNOWLEDGE_PROJECTSが設定されている場合は、そのプロジェクト内のドキュメントに限定します。PAPARATS_DOCS_AUDIENCE/PAPARATS_PROJECTSが設定されている場合は、両方の条件との共通範囲に限定します。スコープ外のドキュメントは、存在しないドキュメントとまったく同じように扱われます。 - トランスポート: ステートレスな Streamable HTTP です。リクエストごとに新しいサーバーとトランスポートを使用し、セッション ID はありません。
GET/DELETEには405を返します。ボディサイズの上限は64 kB、クエリ文字数の上限は1000文字です。
ドキュメントのオーディエンスはインデックス作成時に設定されます。まず frontmatter の audience: を使用し、次に .paparats.yml / projects.yml の docs.audience を使用します。どちらもない場合は internal になります。無効な frontmatter 値はログに記録され、internal として保存されます。ドキュメント検索ガイドを参照してください。
PAPARATS_KNOWLEDGE_PROJECTS を設定してください。 これを設定しないと、コードリポジトリの README に意図せず含まれた audience: によって、エンドポイントが提供する範囲が広がる可能性があります。
そのパスのみを公開し、POST のみを許可してください。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;
}
アーキテクチャメモリ
コード検索によって、エージェントはコードが何をするかを把握できます。arch-memory レイヤーは、なぜそうするのかを伝えます。そしてエージェントは、あなたがドキュメントを1つも作成しなくても、セッションをまたいでその知識を自ら維持します。
カードは3種類あり、グループごとに別々の Qdrant コレクション(paparats_<group>_arch)に保存されます。qwen3-embedding-0.6b(1024d、last-pooled)で埋め込みます。
| 種類 | フィールド | 冪等性 |
|---|---|---|
| コンポーネント | name、summary(markdown:Does / Owns / Does not / Touched when)、files、neighbours、anchors | name による(構造的) |
| 決定 | title、context、decision、alternatives_rejected、consequences、scope、supersedes | サーバー側の類似度ゲート |
| 教訓 | rule、why、when、scope、severity、evidence | サーバー側の類似度ゲート |
類似度ゲート(qwen3-embedding-0.6b によるコサイン類似度):
>= 0.85→ 重複です。決定は拒否されるため、エージェントは内容を調整するか、既存の決定を置き換える必要があります。教訓は既存カードのupdatedAtを更新します(Reflexion の「ルール確認済み」)。0.70 – 0.85→ 類似しています。何も書き込まれません。エージェントは表現を洗練するか、supersedesを渡します。< 0.70→ 新しいカードとして受け入れられます。
supersedes はゲートを迂回し、以前の決定を status=superseded に設定します。これにより、その決定はデフォルトの検索結果から除外されますが、履歴には残ります。
arch_context による読み取りでは、min_score(デフォルトは 0.45)を指定できます。返される各カードには updated N ago の表示とコサインスコアが含まれるため、エージェントは古い結果や信頼度の低い結果を検出できます。
init_arch_memory によるブートストラップ — Claude Code の /init に相当するワークフロープロンプトです。リポジトリを調べ、ドメイン境界に基づいて8~20個のコンポーネントを特定し、カードを作成します。その後、audit_architecture(古いカードの確認)と record_lesson_from_correction(ユーザーからの修正を構造化された教訓に変換)を実行します。
MCP リソース:
arch://schema— カードスキーマの完全なリファレンスです。arch://stats/{group}— 現在の件数(合計/種類別/ステータス別)と、最も古いupdatedAtおよび最も新しいupdatedAtです。
Prometheus メトリクス(PAPARATS_METRICS=true):
paparats_arch_context_calls_total{group}— カウンターpaparats_arch_write_total{kind, status}— ゲートの結果をラベルとして持つカウンターpaparats_arch_search_score—arch_contextのコサインスコアのヒストグラムpaparats_arch_collection_size{group, kind, status}— ゲージ
arch_context は、両方の MCP エンドポイントで読み取り専用です。arch_record_* はサポート専用です。記録はアーキテクチャレビューのワークフローに含まれます。
モジュール一覧
| モジュール | 役割 |
|---|---|
types.ts | 共通インターフェース |
lib.ts | 公開ライブラリーのエントリーポイント(プログラムから使用するための再エクスポート) |
config.ts | .paparats.yml リーダー、11 の言語プロファイル、autoProjectConfig() |
app.ts | Express アプリファクトリー、HTTP API ルート、リクエストの配線 |
index.ts | サーバーのブートストラップ — HTTP サーバーの起動、コンポーネントの配線、グレースフルシャットダウン |
ast-chunker.ts | tree-sitter による AST ベースのチャンク分割 |
chunker.ts | 正規表現によるチャンク分割のフォールバック(4 つの戦略) |
ast-symbol-extractor.ts | AST ベースのチャンクごとのシンボル抽出 |
ast-queries.ts | 各言語向けの Tree-sitter S 式クエリー |
tree-sitter-parser.ts | WASM Tree-sitter マネージャー — 文法を遅延読み込み |
symbol-graph.ts | チャンク間のシンボルエッジ |
embeddings.ts | llama-server プロバイダー + SQLite キャッシュ + キャッシュラッパー |
indexer.ts | グループ対応の Qdrant インデックス作成 — createQdrantClient()、toCollectionName()、単一解析の chunkFile() |
searcher.ts | クエリー拡張、キャッシュ、メトリクスを備えたベクトル検索 |
query-expansion.ts | 略語/大文字・小文字/複数形/フィラーの拡張 |
task-prefixes.ts | クエリータイプの検出 + bge-code-v1 / Qwen3 クエリー指示 |
query-cache.ts | TTL およびグループ単位の無効化に対応したインメモリー LRU キャッシュ |
metrics.ts | Prometheus メトリクス(prom-client)+ NoOpMetrics フォールバック |
metadata.ts | タグの解決 + ディレクトリー構造からの自動検出 |
metadata-db.ts | Git コミット、チケット、シンボルエッジ用の SQLite ストア |
git-metadata.ts | Git 履歴の抽出 — 差分ハンクとチャンクのマッピング |
ticket-extractor.ts | Jira / GitHub / カスタムチケットの解析 |
mcp-handler.ts | MCP プロトコル — 独立したツールセットと指示を備えたコーディング、サポート、ナレッジのエンドポイント |
knowledge-mode.ts | ナレッジモード — 環境変数の解析、ベアラートークン認証、本文サイズ上限、スコープの共通部分 |
arch/types.ts | アーキテクチャメモリーの型 |
arch/collection.ts | グループごとの paparats_<group>_arch コレクションのライフサイクル |
arch/text-embeddings.ts | llama-server による qwen3-embedding-0.6b テキスト埋め込みモデル |
arch/store.ts | CRUD + サーバー側の類似度ゲート + stats() 集計 |
arch/context.ts | arch_context クエリー — min_score と経過時間スタンプを用いた、種別を横断する上位 N 件 |
設定(環境変数)
| 変数 | デフォルト | 備考 |
|---|---|---|
PORT | 9876 | HTTP ポート |
QDRANT_URL | http://localhost:6333 | Qdrant エンドポイント(https → ポート 443、http → 6333) |
QDRANT_API_KEY | — | Qdrant Cloud API キー |
EMBED_URL | http://127.0.0.1:18434 | 埋め込みサーバーのエンドポイント(llama-swap。生成されたスタックでは内部ポート 8080、ホストポート 18434) |
EMBED_BATCH_SIZE | — | llama-server の呼び出しごとの埋め込み数 |
EMBED_TTL | 0 | モデルがアンロードされるまでのアイドル秒数。0 = なし(デフォルト) |
EMBEDDING_PROVIDER | llama | コード埋め込みプロバイダー:llama | openai | voyage |
EMBEDDING_MODEL | bge-code-v1 | コード埋め込みモデル |
EMBEDDING_DIMENSIONS | 1536 | コード埋め込みの次元数 |
TEXT_EMBEDDING_PROVIDER | llama | アーキテクチャ層での llama または openai |
TEXT_EMBEDDING_MODEL | qwen3-embedding-0.6b | アーキテクチャ層のテキスト埋め込みモデル |
TEXT_EMBEDDING_DIMENSIONS | 1024 | アーキテクチャ層のテキスト埋め込みの次元数 |
PAPARATS_METRICS | false | /metrics を公開するには true に設定 |
PAPARATS_PROJECTS | — | 許可リストにするプロジェクト名(カンマ区切り) |
PAPARATS_DOCS_AUDIENCE | — | コーディングおよびサポートのエンドポイントにある search_docs / get_document のオーディエンス上限 |
PAPARATS_KNOWLEDGE_TOKENS | — | /knowledge/mcp 用のベアラートークン(16 文字以上、カンマ区切り)。PAPARATS_KNOWLEDGE_AUDIENCE と同時に設定するか、どちらも設定しないでください |
PAPARATS_KNOWLEDGE_AUDIENCE | — | /knowledge/mcp のオーディエンス上限。internal は拒否されます |
PAPARATS_KNOWLEDGE_PROJECTS | — | /knowledge/mcp の任意のプロジェクト許可リスト — 設定を推奨します |
PAPARATS_UI_BASIC_AUTH | — | /ui および /api/analytics/... 用の user:pass。形式が正しくない値を設定すると起動が停止します |
PAPARATS_CORS_ORIGINS | — | サーバーへの呼び出しを許可するブラウザーのオリジン(例:https://app.example.com、カンマ区切りの完全一致)。未設定の場合、CORS ヘッダーは付与されません。また、Origin がこのサーバーまたはリスト内のいずれでもないリクエストは 403 になります。Origin のないリクエスト(MCP クライアント、curl)には影響しません |
OTEL_* | — | OpenTelemetry の標準環境変数(Tempo / Honeycomb / Datadog / Elastic APM) |
プログラムからの利用(ライブラリ)
package.json の exports マップは、サーバーのブートストラップではなく dist/lib.js を指しています。
@paparats/server をインポートしても、HTTP サーバーは起動しません。@paparats/indexer はこれを利用して、Indexer クラスをライブラリとして組み込みます。
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
docker pull ibaz/paparats-server:latest
docker run --rm -p 9876:9876 \
-e QDRANT_URL=http://qdrant:6333 \
-e EMBED_URL=http://embed:8080 \
ibaz/paparats-server:latest
スタック全体(Qdrant + 埋め込みサーバー + サーバー + インデクサー)については、examples/docker-compose をご覧ください。
開発
yarn install
yarn workspace @paparats/server build
yarn workspace @paparats/server test
yarn workspace @paparats/server typecheck
関連パッケージ
| パッケージ | 用途 |
|---|---|
| @paparats/cli | ワンコマンドインストーラー、プロジェクト管理、検索 |
| @paparats/indexer | 自動化されたマルチリポジトリーインデクサー(ライブラリーとしてこれを使用) |
| @paparats/shared | 共通ユーティリティ(パス検証、gitignore、除外設定) |
| ibaz/paparats-embed | llama.cpp llama-server + llama-swap と、bge-code-v1 および qwen3-embedding-0.6b を事前に組み込んだもの |
ライセンス
MIT
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。