opensolr-mcp について
opensolr-mcpは、AIエージェントにマネージド Apache Solr の検索と文書処理を提供します。BM25 とベクトル検索、サーバー側の埋め込み生成、ローカルファイルのインデックス化、画像・OCR処理、検索結果に基づく RAG 回答を組み合わせています。
主な機能
- 01BM25 とベクトルのハイブリッド検索
- 02サーバー側の埋め込み生成とインデックス化
- 03PDF のページ単位検索と閲覧
- 04ローカルファイルの抽出と OCR
- 05画像検索と根拠に基づく RAG 回答
活用シーン
- 01キーワードと意味検索で文書を検索
- 02PDF やスキャンファイルのフォルダーを索引化
- 03写真からカタログ商品を検索
- 04索引化した文書に基づく回答を生成
MCP 対応
MCP サーバーとして、Opensolr の検索、索引化、文書、画像、インデックス管理ツールを MCP クライアントに公開します。Opensolr アカウントへの接続にはメールアドレスと API キーを使います。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
uvx opensolr-mcpOPENSOLR_EMAILOpensolr account email; try the shared demo account [email protected], whose indexes are deleted after 3 days and can be changed or deleted by anyone else using it, or get your own at https://opensolr.com/register (free forever, no card)OPENSOLR_API_KEYシークレットOpensolr API key, found under Account > API in the control panel; the shared demo account's key is 420b8b23e7b12dc8ab838932145a5065 (preloaded index mcp_demo_d1__dense with 300 news articles, limits per index are 200 MB bandwidth and 50 MB disk, anything created is deleted after 3 days and other people can change or delete it)ローカルサーバーにはマシン上の実行環境(Node.js 18 以上など)が必要です。設定ファイルの場所はクライアントごとに異なります。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
opensolr-mcp
mcp-name: com.opensolr/opensolr-mcp
Opensolr 用の MCP(Model Context Protocol)サーバーです。あらゆる AI エージェントで、管理された Apache Solr 検索をツールとして利用できます。ハイブリッド検索(BM25 + kNN)、サーバー側の GPU 埋め込み、ドキュメントのインデックス作成(ローカルのファイルやフォルダーにも対応。PDF はページごと、スキャン画像は OCR 経由)、根拠に基づく RAG 回答を利用できます。
実際のニュースインデックスでのライブデモ(ハイブリッド検索 + AI 回答): https://search.opensolr.com/news__dense?q=how+am+I+supposed+to+save+money%3F
設定が必要な埋め込みモデルはありません。運用が必要なベクトルデータベースもありません。API キーは 1 つだけです。
ツール
| ツール | 機能 |
|---|---|
opensolr_search | Solr フィルターと日付範囲を指定した、ハイブリッド検索(キーワード + セマンティック)またはセマンティック検索。PDF は最も関連性の高いページが返され、そのページを開くリンクも付属します |
opensolr_search_by_image | 写真で検索します。Opensolr が写真の視覚的なラベル、OCR テキスト、バーコードや QR コードを読み取り、それらの語句で検索します(画像ベクトルは保存されません) |
opensolr_read_document | 検索結果を 1 件全文表示します。PDF はページごと、それ以外のドキュメントは 1 つのテキストとして読み取ります |
opensolr_ai_answer | 根拠に基づく RAG 回答です。ハイブリッド検索の上位結果が LLM のコンテキストになります。ホスト型検索 UI と同じパイプラインを使用します |
opensolr_index_files | ローカルのファイルまたはフォルダー全体のインデックスを作成します。PDF はページごとに 1 ドキュメントとして扱い、Word/RTF/OpenDocument/テキスト/HTML に対応します。スキャン画像や写真は OCR 経由で処理します |
opensolr_extract_text | インデックスを作成せずにローカルファイルを読み取ります。テキスト、画像の OCR、ページごとの PDF 読み取りに対応します |
opensolr_describe_image | 写真に何が写っているか(1 文)、印字されたテキスト、ラベル、バーコードを読み取ります |
opensolr_add_documents | プレーンテキストとメタデータのインデックスを作成します(埋め込みはサーバー側で行われます) |
opensolr_delete_documents | ID を指定してドキュメントを削除します |
opensolr_list_indexes / opensolr_index_info | アカウントのインデックスを確認します |
opensolr_create_index | opensolr_vector_regions にあるリージョンにベクトルインデックスをプロビジョニングします(環境 ID、またはライブリストと照合する us のような短縮形を指定できます) |
opensolr_vector_regions | ベクトルに対応したリージョンのライブリストを取得します |
opensolr_check_schema | 各ツールに必要な機能(データ取り込み、ベクトル検索とハイブリッド検索、PDF ページ、キーワード検索)がインデックスに備わっているか、また備わっていない場合はその理由を正確に確認します |
opensolr_apply_schema | ベクトルリージョン内のインデックスに Opensolr ベクトルスキーマをインストールします(設定を置き換えます。ドキュメントが含まれている場合は force を指定します) |
セットアップ
opensolr.com/register で無料の Opensolr アカウント(カード不要、永久無料)を作成し、Account から API キーをコピーしてください。
アカウントなしで試す
公開デモアカウントがあります。パッケージの接続先に指定すれば、サインアップなしでREADMEの内容をすぐに試せます。
export [email protected]
export OPENSOLR_API_KEY=420b8b23e7b12dc8ab838932145a5065
mcp_demo_d1__dense にはニュース記事が300件読み込み済みなので、接続した瞬間から検索、フィルタリング、根拠に基づく回答を試せます。書き込みも可能です。アカウントに独自のインデックスを作成し、データを取り込んでクエリを実行できます。この共有キーでは削除できないため、ここにあるインデックスを手動で削除したり、再設定したりすることはできません。作成したものは3日後に自動的に削除されます。
利用時には、次の点にご注意ください。
- ここで作成したものは、3日後にすべて削除されます。 警告やエクスポートなしで自動的に削除されます。作成したインデックスと、その中のすべてのドキュメントが対象です。
- このアカウントは、このページを読んでいる全員で共有しています。 作成したインデックスは他の人にも表示され、他の人がドキュメントを追加できます。同様に、他の人のインデックスにも追加できます。このキーではインデックスの削除や再設定はできません(無効になっています)が、実際の情報、個人情報、クライアント所有の情報は絶対に登録しないでください。
- 上限はインデックスごとに設定されており、意図的に小さくしています。 インデックスごとに、帯域幅は200 MB、ディスク容量は50 MBです。先に上限に達するのは帯域幅です。デモ、チュートリアル、概念実証には十分ですが、アプリケーションには足りません。
非公開で自分だけが使え、来週もそのまま利用できるインデックスが必要になったら、独自のキーを取得してください — ずっと無料、カード不要 — その後、上記の2つの変数を変更します。コードのほかの部分を変更する必要はありません。
Claude Desktop / Claude Code
{
"mcpServers": {
"opensolr": {
"command": "uvx",
"args": ["opensolr-mcp"],
"env": {
"OPENSOLR_EMAIL": "[email protected]",
"OPENSOLR_API_KEY": "YOUR_OPENSOLR_API_KEY"
}
}
}
}
Cursor / Windsurf / その他のMCPクライアント
同じ形式で設定します。stdio トランスポートを使用し、コマンドは uvx opensolr-mcp(または pipx run opensolr-mcp)です。環境変数に OPENSOLR_EMAIL と OPENSOLR_API_KEY を設定します。
エージェントとのセッション例
あなた: FAQの回答をインデックス化してから、返金に関する情報をすべて見つけてください。
エージェントは
opensolr_add_documents(index="faq__dense", texts=[...])を呼び出し、続けてopensolr_search(index="faq__dense", query="refund policy", hybrid=True)を実行します。BM25は「refund」という正確な単語を拾い、kNNは「顧客に返金する」という表現を拾い、スコアはドキュメントごとに統合されます。
写真で検索する
opensolr_search_by_image を使うと、テキストクエリの代わりに写真で検索できます。Opensolrは画像を3つの方法で読み取ります。視覚的なラベル(画像に描かれているもの)、OCRテキスト(画像に印字された文字)、バーコードやQRコードがあればその内容です。それらを単語に変換して通常の検索を実行します。画像ベクトルは保存されません。
opensolr_search_by_image(index="catalog__dense", image_path="/tmp/shelf.jpg",
using="auto", k=5)
# using: "auto" (engine's choice) | "meaning" (visual labels) |
# "text" (OCR only) | "code" (exact barcode/QR) | "all" (everything)
# -> { "read": {text, mode, labels, codes}, "results": [...] }
search_mode、mode、alpha、fresh_bias、filter_query、date_from、date_to、group_pages は、opensolr_search と同じように動作します。
ローカルのファイルとフォルダー:PDF はページごとに、スキャン画像は OCR で読み取り
opensolr_index_files は、サーバーが実行されているマシン上のファイル、またはフォルダー全体をインデックス化します。各ファイルは Opensolr のサーバーで読み取られます。テキスト、画像内のテキスト(100 を超える言語の OCR)、テキストのない画像の簡単な説明が処理されます。PDF はページごとに 1 つのドキュメントとしてインデックス化されるため、200 ページのファイル内のどこかに答えが含まれている場合でも、そのファイル全体ではなく、答えが載っているページが検索結果に表示されます。Word、RTF、OpenDocument、テキスト、HTML、画像ファイル(スキャン画像、書類を撮影した写真)は、それぞれ 1 つのドキュメントになります。
opensolr_index_files(index="contracts__dense", path="~/Documents/contracts",
pattern="*.pdf", metadata={"team": "legal"})
# -> {"documents": [{path, source, uri, id}], "pending": [], "failed": [], "jobs": [...]}
- データは一度だけ送信されます。アカウントがすでに送信したファイル(内容が同じもの)は再アップロードされず、同じファイルを再度送信すると、そのドキュメントが置き換えられます。
- 各ドキュメントの
uriはhttps://ingest.opensolr.com/<index>/<source>です。sourceは送信したフォルダーからのファイルのパス(meta_sourceにも記録されます)で、日付にはファイルの更新日時が使われるため、ローカルファイルでも日付範囲で絞り込めます。 - 大きなファイルはバックグラウンドで読み取られます。
wait_secondsの経過後も読み取り中のファイルはpendingに返されます。それらをインデックス化するには、同じパスを指定してツールを再度呼び出します(同じファイルが二度送信されることはありません)。 - OCR で読み取る画像は、AI リクエスト 1 回の 0.5 回分としてカウントされます。一度読み取り済みのファイルは無料です。
opensolr_extract_text は、インデックス化せずに同じ読み取りを実行します。各ファイルのテキストを返し、PDF はページごと(page、text、is_ocr、lang)に返します。エージェントはこれを使って、契約書、スキャンした請求書、レポートフォルダーを自分で読み取ることができます。
opensolr_describe_image は、画像に何が写っているか、何が書かれているかを返します。caption(1 文の説明)、text(OCR)、labels、バーコード/QR の codes が含まれます。
検索結果の PDF ページ
PDF がページごとに保存されているインデックス(上記のファイル、rtf を指定して Data Ingestion に送信した PDF、Web Crawler で検出した PDF)では、opensolr_search は各 PDF を最適なページとして一度だけ返します。
{"title": "Master services agreement", "page": 14,
"page_url": "https://example.com/msa.pdf#page=14", # opens the PDF at that page
"document_id": "9f2c...", # for opensolr_read_document
"more_pages": [{"page": 3, "page_url": "...#page=3"}, ...], # its other matching pages
"matching_pages": 4, "uri": "https://example.com/msa.pdf", ...}
group_pages=false を指定すると、ページが個別の検索結果として返されます。opensolr_read_document は、あらゆる検索結果を全文で読み取ります。PDF はページ順に(page_from/page_to)、それ以外のドキュメントは 1 つのテキストとして読み取ります。
期間を指定した検索
date_from と date_to(YYYY-MM-DD。両日を含み、どちらか一方は省略可能)を指定すると、その期間内の日付(creation_date)が付いたドキュメントだけが対象になります。他のすべてのオプション(fresh_bias を含む)と併用できます。
検索演算子
クエリ文字列では、検索ボックスでおなじみの演算子を使用できます。キーワード、ハイブリッド、純粋なベクトルのすべてのモードで機能します。
| 演算子 | 意味 | 例 |
|---|---|---|
"word1 word2" | フレーズ — これらの単語がこの順序で連続していること | "machine learning" |
+word | 必須 — すべての検索結果に含まれること | +laptop 15 inch gaming |
+"word1 word2" | 必須フレーズ | +"13 inch" |
-word | 除外 — 含まれるドキュメントをすべて除外 | laptop -refurbished |
-"word1 word2" | 除外フレーズ | -"open box" |
組み合わせて使うこともできます。+laptop +"13 inch" -refurbished は、13 インチのノートパソコンだけを返し、再生品は一切含めません。
先頭に + または - を付けた語(単語またはフレーズ)はフィルターとなり、検索結果全体に適用されます。ベクトルを使う場合、これは重要です。ハイブリッド検索のセマンティック側には否定の概念がないため、-refurbished を単なるクエリテキストとして扱うと、再生品を除外するどころか、実際には検索結果の上位に引き寄せてしまいます。フィルターとして指定すれば、検索のどちら側で見つかったドキュメントにも適用され、除外は確実に行われます。
接頭辞のないフレーズ(+ を前に付けない "machine learning")は、フィルターではなくキーワード側の関連度を高めるシグナルです。必ず適用したい場合は、+"machine learning" を使用してください。
+ と - は単語の先頭にある場合にのみ演算子として扱われるため、e-mail、covid-19、1+1 は文字列どおりに検索されます。
注記
- ベクトルインデックスはベクトルリージョンにあります。これらは、Solr のバージョンを問わず、Web クローラーを実行する Opensolr サーバーです。リージョンの一覧は随時更新され、パッケージには書き込まれません。
opensolr_vector_regionsは、現在新しいインデックスを受け付けているリージョン(環境 ID、国、Solr のバージョン)を返します。location=には、この一覧にある環境 ID、またはus、de、fiなどの短縮形を指定できます。短縮形は、環境 ID または国をもとに最新の一覧と照合されます。追加の専用リージョンはリクエストに応じてデプロイできます(有料の追加オプション):[email protected]。 - すべてのインデックスは通常の Apache Solr でもあり、ネイティブの
/selectAPI を利用できます。ツール経由でしか使えない機能はありません。 - LangChain 向けの Python 版:
langchain-opensolr· 製品ページ:opensolr.com/langchain
書き込みの仕組み(Data Ingestion API)
書き込みには Opensolr のData Ingestion APIを使用します。Drupal および WordPress のコネクターと同じパイプラインです。これは非同期で実行されます。ドキュメントがキューに登録されると、埋め込み、センチメント、言語、およびクローラーと同一の派生フィールドがすべてサーバー側で計算され、約 1 分以内にドキュメントを検索できるようになります。進行状況は、ジョブごとのステータスボードが表示されるControl Panel → Data Ingestion(キュー待ち/処理中/完了/失敗、およびジョブごとの処理済み/成功/失敗ドキュメント数)と、ingest_status API で確認できます。各ドキュメントの識別子は uri です(Solr の ID は md5(uri))。メタデータに実際の URL({"uri": "https://..."})を渡すか、ID をもとに決定的な URL が生成されます。同じ uri を再送信すると、ドキュメントが更新されます。{"rtf": True, "uri": "https://.../file.pdf"} を渡すと、サーバーが PDF/DOCX/XLSX からテキストを抽出します。
字句検索のみのモード
ベクトルが不要ですか?純粋なキーワード検索では、埋め込みの呼び出しを完全に省略でき、AI クォータを消費しません。title、description、text フィールドがある Opensolr インデックスであれば、ベクトルリージョン外のインデックスや古い Solr バージョンを含めて、どれでも利用できます(インデックスの要件を参照)。
インデックスの要件
このパッケージのすべての機能は、ベクトルリージョンにあり、Opensolr ベクトルスキーマ(すべての Opensolr ベクトルインデックスで使用される設定)を備えた Opensolr インデックスで実行されます。このパッケージから作成したインデックス(create_index、create_if_missing)には、どちらも備わっています。ほかの場所で作成したインデックスには、備わっていない場合があります。ベクトルリージョン以外のサーバーにある場合や、独自のスキーマを使用している場合です。ベクトルリージョンとは、Solr のバージョンにかかわらず、Web クローラーを実行する Opensolr サーバーです。新しいインデックスを作成できるリージョンは、パッケージ内のリストではなく、最新の vector_regions リストから取得します。
チェックは自動で行われます。 パッケージがインデックスに初めてアクセスするとき、プラットフォームに一度だけ、そのインデックスが要求された処理に対応できるかを問い合わせます。クライアントごとにインデックスあたり1回で、クライアントの存続中は結果が保持され、検索のたびに実行されることはありません。チェック自体を実行できない場合(ネットワークエラー、プラットフォームのビジー状態など)も、処理はブロックされず、これまでどおり実行されます。チェックは5分後に再試行されます。インデックスが Opensolr ベクトルスキーマと異なる場合は、理由と修正方法を含む警告が opensolr ロガーに一度だけ記録されます。
チェックによって制限されるのは、ほかの方法では動作しない機能だけです。
| 機能 | 必要な用途 | 利用できない場合 |
|---|---|---|
ingestion | データ取り込み:ドキュメントの追加とファイルのインデックス作成 | インデックスがベクトルリージョン以外にある場合は、ドキュメントやバイトデータを送信する前に拒否されます |
vector_search | ベクトル検索とハイブリッド検索 | 適切なサイズのベクトルフィールドがインデックスにない場合は、埋め込みの費用が発生する前に拒否されます |
pdf_pages | 検索結果で PDF のページをグループ化 | これまでどおり、結果はグループ化されずに返されます |
keyword_search | キーワード検索(字句検索) | ブロックされることはありません |
エラーには状況が正確に示されます。 ブロックされた処理は、.index、.capability、.report(チェックの全内容)を持つ OpensolrSchemaError(OpensolrError のサブクラス)を送出します。メッセージには、すべての理由と修正方法が含まれます。
Index 'shop_it' cannot take documents or files through Data Ingestion. Index shop_it
is on IT-SOLR-9-6 (Milano, Italy), which is not a vector region: Data Ingestion,
server-side embeddings and hybrid search run only on the servers of a vector region
(DE-SOLR-9 (Germany, Solr 9.00), FINLAND9 (Finland, Solr 9.60), ...). This index
cannot be made ready: create a new index in one of the vector regions (...), for
example with create_index, and send your documents there.
Solr 自体がリクエストを拒否した場合、OpensolrSolrError に Solr 独自の理由とインデックス名が含まれます。引き続き httpx.HTTPStatusError でもあるため、以前この例外を捕捉していたコードはそのまま動作します。
from opensolr_mcp.client import OpensolrClient, OpensolrSchemaError
client = OpensolrClient(email, api_key)
try:
client.ingest_files("shop_it", "~/Documents/catalog")
except OpensolrSchemaError as e:
print(e.capability, e.report["fix"]["action"]) # ingestion new_index
詳細を確認し、修正可能なものを修正します。
client.check_schema("shop_it") # ready, capabilities, server, Solr version, missing / different fields, problems, fix
client.apply_schema("shop_it", force=False) # installs the Opensolr vector schema; force=True when the index holds documents
apply_schema を使うと、設定が変更された、または未設定のベクトルリージョンのインデックスを再作成せずに、このパッケージのすべての機能に対応させることができます。すべての Opensolr ベクトルインデックスで使用される同じ設定をインストールし、インデックスの設定を置き換えます。すでにドキュメントが含まれるインデックスには force=True が必要です。これらのドキュメントには書き込み時のフィールドがそのまま残るため、再送信する必要があります。ベクトルリージョン以外にあるインデックスには適用できません。vector_regions に含まれるリージョンで新しいインデックスを作成し、ドキュメントをそちらに送信してください。このパッケージがスキーマを自動でインストールすることはありません。
エージェントでは、同じ2つの呼び出しが opensolr_check_schema と opensolr_apply_schema というツールになります。そのほかのツールはすべて独自にチェックを実行し、拒否する場合は上記のメッセージを返します。
インデックスのスキーマ
ドキュメントは Opensolr のドキュメントモデル(title、description、text、meta_* カスタムフィールド)に従います。すべてのフィールドと型サフィックスを含むスキーマ全体については、インデックススキーマリファレンスで説明しています。独自のコピーを確認するには、コントロールパネル → インデックスをクリック → 設定 → ファイルを編集 → schema.xml の順に進みます。手間をかけずにデータを入力したい場合は、コントロールパネルのWeb クローラー(インデックスツール → WebCrawler)を設定してください。サイトの URL を追加して検証すると、Opensolr がサイト全体をインデックス化します。
検索チューニング
検索(検索と RAG のグラウンディング)は、プラットフォームの調整済みパイプラインを通じて実行されます。グローバルなデフォルト → インデックスに保存された 検索チューニング(コントロールパネル → インデックス設定 → 検索チューニング:セマンティック検索と字句検索のバランス、フィールドの重み、最小一致数、検索モード、ベクトル候補プール、コンテンツ品質ブースト) → tuning による呼び出しごとのオプションの上書き:
tuning={"search_mode": "keywords_required", "fw_title": 0.2,
"mm": "strict", "vector_topk": 500, "quality_boost": 0.3}
デフォルトはプラットフォームの PHP 設定と完全に一致します。コントロールパネルで一度カスタマイズするか、コードから呼び出しごとに設定できます。
新しい結果へのバイアス
古い文書を隠さずに、新しい文書の順位を上げます。各スコアに creation_date に基づく鮮度曲線を掛けます。今日公開された文書は重みが最大となり、1 年後には約半分になります。
store.similarity_search_with_score("solar inverter warranty", fresh_bias=True)
client.hybrid_search(index, query, fresh_bias=True)
client.ai_answer(index, question, tuning={"fresh_bias": 1})
これは並べ替えのみを行い、フィルタリングはしません。どちらの場合もヒット数は同じで、古い文書にアクセスできなくなることはありません。また、creation_date のない文書は、最下位に押し下げられるのではなく、その位置を維持します。このブーストは最終スコア全体に適用されるため、ベクトルのみ、キーワードのみ、融合されたハイブリッドランキングの3つすべての検索方式で有効です。デフォルトでは無効です。
これは、ホスト型 Opensolr 検索ページで訪問者が並べ替えオプションの横にある Fresh 切り替えで設定できるものと同じです。そのため、こちらでもあちらでも、クエリは同じように動作します。
fresh_biasとfreshness_boostは別々の設定項目で、名前が似ているため混同されやすいものです。freshness_boostは日数で指定する固定期間で、それより古いものはすべてフィルタリングされ、ヒット数が減少します。fresh_biasは何もフィルタリングしません。
テスト方法
すべてのリリースは、モックを使わず、稼働中の Opensolr インフラストラクチャに対して検証されます。
- ユニットテスト(オフライン):稼働中のリージョンリストに対するロケーションの照合、フィルターから fq へのマッピング、クエリ構築、エスケープ処理。
- エンドツーエンドテストスイート:非同期のデータ取り込みキューを通じた書き込みパス全体(キュー登録 → サーバー側でのエンリッチメント → 検索可能化)、セマンティック/ハイブリッド/字句検索、メタデータのラウンドトリップ、フィルター、ID のラウンドトリップ(ユーザー指定の ID と Solr の
md5(uri)ID)、ID による削除とクエリによる削除。 - 実コーパスでの検証:opensolr.com 自身の本番検索インデックスを複製した340文書に対して検索を実行します。検証項目:キーワードの重複がゼロの純粋なセマンティック検索結果(「災害後にデータを復旧するにはどうすればよいですか」→バックアップと復元に関する文書)、言語をまたいだクエリ(ルーマニア語のクエリ → 英語のコンテンツ)、ハイブリッドモードでの完全一致語句の表示、4つすべてのハイブリッドモード、0 → 1 の全アルファ範囲。
- PDF 取り込み:
rtf:trueを使用して実際の PDF を取り込み、サーバー側でテキストを抽出(13k 文字以上)、コンテンツタイプを自動検出した後、その内容に対する純粋なセマンティッククエリで検索します。
各リリース前に、ツールを実際に使用して検証します(検索モード、待機を伴う取り込み、ステータス確認、削除、RAG の回答)。RAG のグラウンディングはエンドツーエンドで検証されます。取り込んだ PDF からしか回答できない質問に対して、PDF から抽出したテキストを出典とする正しい回答が返されます。
MIT ライセンス。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。