QMD MCP について
QMD MCPは、QMDを長時間稼働するStreamable HTTPサーバーとして提供し、ローカルのMarkdown検索、取得、制限付きのインデックス管理を可能にします。任意のシェル実行を許可せずに文書へアクセスしたいMCPクライアント向けです。
主な機能
- 01インデックス文書の検索と取得
- 02制限付き非同期再インデックス
- 03明示的な埋め込み処理と状態確認
- 04定期的なインデックス更新
- 05任意の再ランキング検索
活用シーン
- 01ローカルMarkdown文書の検索
- 02回答の根拠となる文書の取得
- 03定期的なインデックス更新
MCP 対応
Streamable HTTP経由で、QMDの検索、取得、ヘルスチェック、制限付き管理ツールをMCPクライアントに公開します。文書内容は既定で内部向けに返され、ユーザー向けリソース公開には明示的な承認パラメーターが必要です。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
docker run -i --rm ghcr.io/x1pher/qmd-mcp:v0.2.2ローカルサーバーにはマシン上の実行環境(Node.js 18 以上など)が必要です。設定ファイルの場所はクライアントごとに異なります。
ghcr.io/x1pher/qmd-mcp:v0.2.2Streamable HTTPツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
QMD MCP
QMD MCP は、QMD を長時間稼働する Streamable HTTP MCP サーバーとしてパッケージ化したものです。任意のシェル実行を公開することなく、QMD の検索とドキュメント取得に加えて、制限付きのインデックス保守操作を提供します。
これはコミュニティが保守する統合機能です。上流の QMD プロジェクトとは提携しておらず、承認も受けておらず、公式に保守されているものでもありません。
フィードバックと貢献
バグ報告や機能リクエストには GitHub Issues を、変更の提案にはプルリクエストをご利用ください。開発ワークフロー、テスト要件、コーディング規約については、CONTRIBUTING.md をご覧ください。セキュリティ上の問題は、SECURITY.md に記載された非公開の手順に従ってください。
リリースの変更は CHANGELOG.md に記録されています。
クイックスタート
リリースイメージは GitHub Container Registry(GHCR)で公開されています。
ghcr.io/x1pher/qmd-mcp:v0.2.2
公開パッケージは誰でも利用できるため、承認済みのリリースをプルする際に Docker で GitHub にログインする必要はありません。
本番環境へのデプロイでは、承認済みの GitHub Release から安定版のバージョンタグを選択してください。解決されたダイジェストは、不変の来歴情報およびロールバックの証跡として保持してください。
イメージは linux/amd64 と linux/arm64 をサポートしています。イメージのサイズを抑えるため、各プラットフォームのイメージには、対応する QMD のネイティブ llama ランタイムのみが含まれます。
1. ディレクトリを作成する
mkdir -p qmd/config qmd/content
cd qmd
QMD でインデックスを作成する Markdown ファイルを content/ に配置します。
2. config/index.yml を作成する
global_context: >-
This is a local Markdown knowledge base. Search results are discovery evidence;
read the source document before relying on a material claim.
collections:
docs:
path: /vault
pattern: "**/*.md"
ignore:
- "notes/**"
notes:
path: /vault/notes
pattern: "**/*.md"
includeByDefault: false
history:
path: /vault/logs
pattern: "history.md"
includeByDefault: false
embedding: false
path の値は、コンテナ内のパスを参照します。以下の Compose の例では、./content を /vault にマウントします。
embedding: false は、語彙検索のみで運用するコレクション向けの QMD MCP ラッパー拡張機能です。ファイルは引き続きインデックス化され、明示的な語彙検索(lex)で利用できますが、埋め込みの状態確認および手動の start_embed ジョブからは除外されます。大量の追記専用ログなど、ベクトルを繰り返し再構築しても有用なセマンティック検索結果が得られず、コストだけが増えるような、完全一致での検索が適したデータに使用してください。
3. compose.yml を作成する
services:
qmd-mcp:
image: ghcr.io/x1pher/qmd-mcp:v0.2.2
container_name: qmd-mcp
environment:
QMD_FORCE_CPU: "1"
QMD_REFRESH_INTERVAL_MINUTES: "15"
QMD_REFRESH_INITIAL_DELAY_SECONDS: "120"
ports:
- "127.0.0.1:8181:8181"
volumes:
- ./content:/vault:ro
- ./config:/config:ro
- qmd-data:/data
healthcheck:
test:
- CMD
- node
- -e
- >-
fetch('http://127.0.0.1:8181/health')
.then(r=>process.exit(r.ok?0:1))
.catch(()=>process.exit(1))
interval: 30s
timeout: 10s
retries: 5
start_period: 30s
restart: unless-stopped
volumes:
qmd-data:
この例では、HTTP ポートをループバックのみにバインドします。別のコンテナから QMD MCP を直接呼び出す必要がある場合は、両方のコンテナを共有 Docker ネットワークに接続し、ホスト上で広く公開する代わりに QMD のサービス名を使用してください。
QMD_FORCE_CPU=1 を設定すると、予測可能な CPU のみのデプロイになります。QMD が対応するアクセラレーションを検出するようにしたい場合は、この設定を削除するか、0 に設定してください。
4. コンテナを起動する
docker compose up -d
サービスを確認します。
curl --fail http://127.0.0.1:8181/health
Streamable HTTP MCP エンドポイントは次のとおりです。
http://127.0.0.1:8181/mcp
Docker CLI を使う方法
Compose を使わずに、同じリリースを実行できます。
docker volume create qmd-data
docker run -d \
--name qmd-mcp \
--restart unless-stopped \
-p 127.0.0.1:8181:8181 \
-e QMD_FORCE_CPU=1 \
-e QMD_REFRESH_INTERVAL_MINUTES=15 \
-e QMD_REFRESH_INITIAL_DELAY_SECONDS=120 \
-v "$PWD/content:/vault:ro" \
-v "$PWD/config:/config:ro" \
-v qmd-data:/data \
ghcr.io/x1pher/qmd-mcp:v0.2.2
QMD MCP が提供する機能
QMD MCP は、読み取りを中心とした QMD の MCP ツールを維持しながら、範囲が制限された管理操作を追加します。
healthは、インデックスと実行時の状態を報告します。start_updateは、範囲が制限された非同期ファイルシステム再インデックスジョブを開始します。start_embedは、範囲が制限された非同期埋め込みジョブを開始します。job_statusは、最近の管理ジョブを報告します。- スケジュールされた更新では、字句検索およびインデックスの状態のみを更新します。埋め込みは
start_embedで明示的に実行し、embedding: falseのコレクションは字句検索のみのままです。 - 通常の
queryは、再ランキングを無効にして実行されます。 query_rerankedでは、CPU 負荷の高い再ランキング用の別経路を利用できます。QMD_SOURCE_RELATIVE_ROOTが設定され、ソースパスを一意に解決できる場合、クエリ結果には、信頼できるファイルシステムへの引き渡しに使える正確なsource_relative_pathを含めることができます。- ドキュメント取得では、既定で内部テキストが返されます。ユーザーに表示される MCP リソースの公開には、
exposeToUser=trueとconfirmUserApprovedExposure=trueの両方が必要です。また、プレビュー/表示/オープン/レンダリング/検査の意図は承認とは見なされません。
一度に実行できる管理ジョブは 1 つだけです。完了したジョブは、メモリ上に件数を制限した履歴として保持されます。アクセスレベルと副作用を含む 9 つのツールの完全なリファレンスについては、docs/tools.md を参照してください。
実行時パス
コンテナでは、次の固定パスを使用します。
| パス | 用途 |
|---|---|
/config/index.yml | QMD コレクション設定 |
/data/index.sqlite | QMD インデックスデータベース |
/data/home | 実行時のホームディレクトリ |
/data/cache | モデルおよび実行時キャッシュ |
ソースコレクションは通常、読み取り専用でマウントしてください。再構築可能なインデックスとモデル/実行時キャッシュが含まれるため、/data は書き込み可能な状態にしておく必要があります。
設定
Dockerfile には、通常の実行時パスと HTTP リスナー向けの動作する既定値が用意されています。デプロイに必要な設定のみを上書きしてください。
| 変数 | 既定値 | 用途 |
|---|---|---|
QMD_HTTP_HOST | 0.0.0.0 | コンテナ内の HTTP リッスンアドレス |
QMD_HTTP_PORT | 8181 | HTTP リッスンポート |
QMD_CONFIG_PATH | /config/index.yml | QMD コレクション設定ファイル |
INDEX_PATH | /data/index.sqlite | QMD インデックスデータベース |
QMD_SOURCE_RELATIVE_ROOT | 未設定 | 任意の共通ソースルート。設定すると、クエリ結果に、このルートからの相対パスである正確かつ衝突のない source_relative_path 値が含まれます。 |
QMD_DEFAULT_COLLECTION | 未設定 | start_embed の既定のコレクション。未設定の場合は、設定済みコレクションの最初のものが使用されます |
QMD_FORCE_CPU | 0 | 1 に設定すると、アクセラレーションの検出を無効にして CPU の使用を強制します |
QMD_EMBED_PARALLELISM | 未設定 | 任意の QMD 埋め込み並列処理の上書き値 |
QMD_EMBED_MAX_DOCS_PER_BATCH | 8 | 手動またはスケジュールされた埋め込みバッチあたりの既定の最大ドキュメント数。有効範囲は 1~32 です |
QMD_EMBED_MAX_BATCH_MB | 16 | 手動またはスケジュールされた埋め込みバッチの既定の最大サイズ(MiB)。有効範囲は 1~128 です |
QMD_EMBED_MAX_DURATION_MS | 3600000 | 埋め込みセッションの最大時間。有効範囲は 60000~7200000 ms です |
QMD_EMBED_INTERVAL_MINUTES | 0 | 自動埋め込みチェックの間隔。0 にすると、すべての埋め込みタイマーが無効になります。整数で 0~1440 分です |
QMD_EMBED_INITIAL_DELAY_SECONDS | 120 | 最初の自動埋め込みチェックまでの遅延。整数で 0~3600 秒です |
QMD_REFRESH_INTERVAL_MINUTES | 15 | スケジュールされたインデックス更新の間隔。更新によって埋め込みが開始されることはありません。0 にすると無効になり、最大値は 1440 です |
QMD_REFRESH_INITIAL_DELAY_SECONDS | 120 | 最初のスケジュールされた更新までの遅延。有効範囲は 0~3600 です |
有効範囲が制限された数値に無効な値が指定された場合、暗黙に受け入れられるのではなく、起動時にエラーになります。QMD_SOURCE_RELATIVE_ROOT は絶対パスを公開しません。返されるのは相対ソースパスのみで、正規化したパスに曖昧な衝突がある場合は、推測せずに null を返します。
自動埋め込み
自動埋め込みはデフォルトで無効です。正の値を QMD_EMBED_INTERVAL_MINUTES に設定すると、QMD_EMBED_INITIAL_DELAY_SECONDS の経過後に定期チェックが有効になります。
各チェックでは、有効なコレクションの embedding ポリシーに基づいて、処理待ちの作業が選択されます。embedding が指定されていない場合は有効として扱われます。デフォルトの検索対象選択と QMD_DEFAULT_COLLECTION はスケジューラーを制限しません。1 つの scheduled_embed ジョブが、手動ジョブや更新と同じメンテナンスクレームの下で、対象コレクションを順番に処理します。受け入れられたチェック間では、最初に対象となるコレクションがプロセスメモリ内で順番に切り替わるため、1 つのコレクションが共有期限をいつまでも独占することはありません。ビジー状態またはアクティブなクエリがある場合、チェックはキューに作業を追加せずにスキップされます。各コレクションの処理前に、ポリシーと処理待ちの作業が再確認されます。
スケジュールされた埋め込みは、協調的な期限をまたいで再開できます。未完了のドキュメントで正常に埋め込まれたチャンクは、正確なモデル/フィンガープリントに対する内部チェックポイントとして保持され、ドキュメント全体が完了するまでは処理待ちのままとなり、次回のスケジュール実行ではスキップされます。未完了のチェックポイントグループは、ベクトル検索の結果から除外されます。手動埋め込みでは、処理が中断された未完了のドキュメントに対して、従来どおりアトミックなクリーンアップが行われます。結果にはコレクションごとの実行結果と、現在の集計済み処理待ち作業が保持されます。協調的な期限によるキャンセルはモデルの失敗ではなく、期限超過として報告されます。実際の埋め込み失敗には、従来のエラー処理が適用されます。成功、処理不要、スキップの各チェックではログは出力されません。未完了の実行では、ドキュメントの内容を含まない簡潔な概要がログに記録されます。
MCP health と HTTP /health では、scheduledEmbedding により、有効化の状態、間隔、初期遅延、直近の結果、次回の予定チェック、および再利用された埋め込みの上限が公開されます。状態はプロセス内に保持され、再起動時にリセットされます。次回チェックは予定であり、ジョブの開始が保証されるものではありません。scheduledRefresh.embeddingAutomatic: false が示すのは更新のみです。更新の動作は引き続き更新専用です。
スケジューラーは、協調的な共有時間予算を 1 つ使用します。オプションの AbortSignal は、固定された SDK、埋め込みセッション、ネイティブループへ引き渡されます。中断が検出された後は、新たなドキュメントの準備、再試行、ネイティブ評価は開始されません。すでに開始されたネイティブ呼び出しは、並列ワーカー分も含めて完了まで待機します。スケジュール実行で完了したチャンクは再計算されず、後で再開できるようチェックポイントとして保存されます。未完了のチェックポイントグループは、想定されるすべてのチャンクが揃うまで検索結果に表示されません。シャットダウン時にはスケジューラーのタイマーが解除され、ストアを閉じる前にメンテナンス処理の実際の完了を待ちます。協調的な期限では、実行中のネイティブ呼び出しの実時間を強制的に制限できません。手動埋め込みでは、コレクションごとのセッション時間と、未完了のドキュメントに対するアトミックなクリーンアップが引き続き適用されます。期間が指定されていない場合のデフォルトは 3600000 ms です。
インデックスごとにサーバーの書き込み元は 1 つにしてください。他のレプリカや直接実行する CLI による書き込みは、プロセス内のクレームの対象外です。バッチサイズのバイト数はパッキングの目標値であり、RAM の上限ではありません。デプロイ時には、適切な CPU/RAM/スワップの制限と埋め込みの並列度を設定する必要があります。クエリの延期は受け入れ時とコレクション間に適用されます。コレクションの処理中に到着したクエリには、従来の動作が適用されます。
セキュリティモデル
- コンテナーは、アップストリームの Node イメージにある非特権ユーザー
nodeとして実行されます。 - ソースコレクションは通常、読み取り専用でマウントしてください。
- インデックスとキャッシュの状態は、ソースコンテンツとは別に保持されます。
- 管理操作は、公開されているジョブ操作に限定されています。ラッパーは QMD ストア API を直接呼び出し、QMD CLI の更新フックを実行したり、任意のシェル実行を公開したりしません。
- MCP リクエスト本文は、JSON 解析の前に 1 MiB に制限されます。
- エラーメッセージでは、設定されたインデックスと設定ファイルのパスが秘匿されます。
- MCP トランスポートは認証レイヤーではありません。信頼できるネットワーク境界内で使用するか、認証済みの MCP ゲートウェイの背後に配置してください。
- 本番環境へのデプロイでは、ブランチ、
latest、その他の可変タグではなく、安定したバージョンタグを選択してください。解決されたダイジェストは、アーティファクトの証跡として保持してください。
脆弱性の報告とデプロイに関するガイダンスは SECURITY.md、プロジェクトに適用されるセキュア設計の原則、一般的な脆弱性クラス、レビュー時の期待事項は docs/SECURE-DEVELOPMENT.md を参照してください。
アップストリームとの関係
このリポジトリは、QMD のソースツリー全体をフォークしたものではありません。特定のバージョンの @tobilu/qmd パッケージを使用し、イメージのビルド時に、フェイルクローズ方式の小規模な互換性パッチセットを適用します。想定されるアップストリームのパッチ対象が正確に一致しなくなった場合、ビルドは失敗します。
現在のアップストリームバージョン、パッチ一覧、更新手順については UPSTREAM.md を参照してください。自動埋め込みの受け入れでは、動作とイメージのチェック内容を説明しています。
検証
コンテナーのビルドが主要な検証の境界です。ロックされた依存関係セットをインストールし、アップストリームのすべてのパッチを適用したうえで、完全なユニットテストとプロパティテストのスイートを実行し、JavaScript の構文をチェックしてから、ランタイムステージの前に開発専用の依存関係を削除します。CI ではイメージも起動し、MCP プロトコルを初期化して、ツールが正確に 9 個公開されていることを確認します。また、一時的な Markdown コレクションに対して実際のインデックス更新を実行し、更新後のドキュメント数を検証します。
依存関係とベースイメージの更新は Dependabot が提案します。QMD の更新は、提案されたバージョンでイメージのビルドと機能リリースの受け入れテストに合格した場合にのみ受け入れられます。
リリース
バージョンには v0.2.0 のような SemVer タグを使用します。リリースは、CI に合格した特定のコミットを指している必要があります。タグによって起動される Release ワークフローでは、次の処理を行います。
- タグが
package.jsonと一致することを確認します。 linux/amd64およびlinux/arm64イメージをビルドし、マルチアーキテクチャ対応の単一タグを公開します。- GHCR に公開します。
- 不変のイメージダイジェストを記録します。
- SBOM/プロベナンスと GitHub アテステーションを公開します。
- 対応する GitHub Release を作成します。
通常の CI では、イメージもリリースも公開しません。リリースタグは不変であり、別のコミットに再利用されることはありません。
ライセンス
QMD MCP 独自のラッパーコードは MIT ライセンスです。QMD と同梱される依存関係には、それぞれ独自のライセンスが適用されます。LICENSE と UPSTREAM.md を参照してください。
ストレージ状況を考慮したメンテナンスの実行制御
すべてのメンテナンスは既存の単一ジョブオーナーを共有し、開始前にローカルの全 I/O およびメモリ PSI avg10 を確認します。デフォルトでは、しきい値の 5% に達すると実行を保留し、圧力が解消してから 5 分間待機します。これはワークロードの実行制御であり、アラートのしきい値を変更するものではありません。読み取り/クエリサービスは引き続き利用できます。スケジュールされた埋め込み処理はコレクション間でもう一度確認し、確定済みの進捗を保持します。更新処理はアクティブなクエリに処理を譲ります。ジョブ間には 1 分間の静穏期間を設けます。一部完了または失敗した処理は、種類ごとに 30 分、60 分、以降は最大 120 分のバックオフを行うため、埋め込み処理の滞留によって通常の更新がいつまでも実行されない事態を防げます。再起動後は既存の初回起動遅延を使用します。
health.storageAdmission には、直近の判定とクールダウン時間が表示されます。QMD_IO_PSI_FULL_AVG10_MAX と QMD_MEMORY_PSI_FULL_AVG10_MAX で、範囲が制限された整数のしきい値を設定できます。PSI が存在しない場合や形式が不正な場合は、処理を黙って許可せず、実行を保留します。オプションの QMD_STORAGE_THROTTLE_FILE は、デプロイ担当者が管理する読み取り専用のアトミックな JSON キャッシュです。形式は schemaVersion:1、ISO8601 形式の observedAt、および負でない数値の throttledIOs です。スロットリングが少しでも発生していれば実行を保留します。設定済みのキャッシュが存在しない場合、古い場合、または形式が不正な場合も実行を保留します。デフォルトの最大経過時間は 10 分です(QMD_STORAGE_THROTTLE_MAX_AGE_MS)。QMD にはクラウド認証情報、API クライアント、ネットワークリクエスト、データ生成元を追加しません。サンプリングと配信は運用担当者が管理し、データ生成元の受け入れが完了する前にキャッシュを設定してはいけません。設定されていないクラウドの監視範囲は、ヘルス情報に明示されます。通常の 15 分間隔での更新と 30 分間隔での埋め込み処理のスケジュールは、引き続きデプロイ担当者が管理します。
QMD_PRESSURE_ROOT を設定すると、運用担当者が管理する絶対パスの読み取り専用ディレクトリを指定できます。このディレクトリには io と memory の PSI ファイルが含まれます。デフォルトは /proc/pressure です。統合テストでは、/proc の外部に決定的な正常/劣化状態のフィクスチャをマウントし、Docker の proc 安全性に関する制約を維持します。本番環境では実際のカーネル圧力インターフェースを使用します。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。