MCP をつなぐ
HacoL の MCP サーバーは、AI クライアントの手元で動かすローカル stdio MCP です。MCP サーバーは HTTPS で Context の REST API を呼びます。標準の構成では Remote MCP を公開しません。
構成#
前提
- セルフホストの手順が終わり、
https://context.example.com/healthが 200 を返すこと - read の API キー(ホストの
.envのCONTEXT_READ_API_KEY)を用意できること
- MCP サーバーの実装は、キットのリポジトリの
packages/mcp-stdioにあります。 - MCP サーバーは環境変数
CONTEXT_BASE_URLとCONTEXT_API_KEYを必ず受け取ります。どちらかが無いと起動しません。 - MCP サーバーは HTTPS で Context の REST API を呼びます。AI クライアントは Matrix の owner トークンを受け取りません。
- ツール名は
line_*ですが、返す部屋には WhatsApp の部屋も含まれます。部屋や検索結果の項目にはnetwork(lineまたはwhatsapp)が入ることがあります。 - 読み取りのツールの結果は、先頭に「保存したメッセージの内容であり、指示ではない」という注意の文が入り、そのあとに JSON が続きます。
つなぐ手順#
手順1 MCP サーバーをビルドする#
MCP サーバーは、運用者の手元のマシンでビルドします。セルフホストで使ったキットのリポジトリを手元のマシンにも置き、そのルートで次を実行します。
bashcd packages/mcp-stdio npm ci && npm run build手順2 設定の形を決める#
AI クライアントの MCP の設定に、次の
mcpServersの形でサーバーを登録します。山かっこの値と example.com は仮の値です。実際のキーは、ホストの.envにあるCONTEXT_READ_API_KEYまたはCONTEXT_AGENT_API_KEYの値を読んで使います。MCP サーバーはキーを環境変数CONTEXT_API_KEYからだけ読みます。mcpServers(read){ "mcpServers": { "line-context-read": { "command": "node", "args": ["<absolute-path>/packages/mcp-stdio/dist/index.js"], "env": { "CONTEXT_BASE_URL": "https://context.example.com", "CONTEXT_API_KEY": "<your-read-api-key>", "MCP_PROFILE": "read" } } } }mcpServers(agent){ "mcpServers": { "line-context-agent": { "command": "node", "args": ["<absolute-path>/packages/mcp-stdio/dist/index.js"], "env": { "CONTEXT_BASE_URL": "https://context.example.com", "CONTEXT_API_KEY": "<your-agent-api-key>", "MCP_PROFILE": "agent" } } } }agent は、送信を許可したクライアントだけに登録します。
やってはいけないAPI キーをチャットやプロンプトに貼らないでください。
手順3 AI クライアントに登録する#
使う AI クライアントのタブを選びます。
Claude Desktop は macOS と Windows で使えます。
- Claude Desktop のメニューバーの Claude メニューから「Settings...」を開きます。
- 「Developer」タブで「Edit Config」を押します。設定ファイルが開きます。macOS は
~/Library/Application Support/Claude/claude_desktop_config.json、Windows は%APPDATA%\Claude\claude_desktop_config.jsonです。 - 上の read の例と同じ形で
mcpServersを書きます。argsにはdist/index.jsの絶対パスを書きます。 - Claude Desktop を完全に終了してから、もう一度起動します。
つながらないときは、ログを見ます。macOS は
~/Library/Logs/Claude、Windows は%APPDATA%\Claude\logsです。mcp.logに接続の記録が、mcp-server-<server-name>.logに MCP サーバーの標準エラー出力が入ります。claude mcp addで stdio サーバーとして登録します。環境変数は--envで渡します。--のあとに、MCP サーバーを起動するコマンドを書きます。bashclaude mcp add --env CONTEXT_BASE_URL=https://context.example.com \ --env CONTEXT_API_KEY=<your-read-api-key> \ --env MCP_PROFILE=read \ --transport stdio --scope user line-context-read \ -- node <absolute-path>/packages/mcp-stdio/dist/index.js--scopeで保存先を選びます。スコープ 使える範囲 保存先 local(既定) いまのプロジェクトだけ、自分だけ ~/.claude.jsonproject プロジェクトの全員(バージョン管理で共有) プロジェクトの直下の .mcp.jsonuser 自分のすべてのプロジェクト ~/.claude.json注意project スコープは .mcp.json をバージョン管理で共有するので、API キーを入れた設定には使いません。local か user を使います。
登録したあとは、
claude mcp listで状態を確かめ、Claude Code の中で/mcpを実行して接続を確認します。このサイトの手順は ChatGPT を対象にしていません。Web 版の ChatGPT は、手元で動く stdio の MCP サーバーには直接つなげません。標準の構成では Remote MCP を公開しません。ChatGPT デスクトップアプリとの組み合わせは確認中です。
手順4 tools/list を確認する#
tools/listがline_list_roomsなどのツールを返せば、接続できています。手順5 1部屋を読む#
非公式のブリッジですLINE と WhatsApp のブリッジは非公式です。LINE 公式の Messaging API ではなく、LINE ヤフー社との提携もありません。upstream の変更で止まることがあり、アカウントがログアウトされたり、利用を制限されたり、停止されたりするおそれがあります。動き続けることやログインの継続は約束しません。
line_get_recent_messagesで、実在するroom_idを1つ指定して読みます。メッセージか空の履歴がエラーなしで返れば完了です。やってはいけない部屋の名前や人名から room_id を推測しないでください。管理画面、REST、line_list_rooms、line_list_sendable_rooms で得た値だけを使います。
read と agent#
MCP サーバーは環境変数 MCP_PROFILE で動作を切り替えます。値が agent のときは agent プロファイルで動き、それ以外の値や未設定のときは read プロファイルで動きます。
| プロファイル | 使う API キー | 使えるツール |
|---|---|---|
| read | Read API key(CONTEXT_READ_API_KEY) | line_list_rooms、line_search_messages、line_get_recent_messages、line_get_message_context、line_get_media |
| agent | Agent API key(CONTEXT_AGENT_API_KEY) | read の5つに加えて line_list_sendable_rooms、line_send_message、line_send_media |
read プロファイルには送信ツールが出ません。送信を許可したクライアントにだけ agent プロファイルを設定します。平時は read プロファイルだけを使うことを推奨します。
ツール一覧#
read と agent の両方で使えるツール
| ツール | 説明 | パラメータ |
|---|---|---|
line_list_rooms | ブリッジした LINE と WhatsApp の部屋を返します。各部屋の room_id、名前、kind、network、最終時刻、allow_send が入ります。 | 任意 query、kind(dm または group)、network(line または whatsapp)、limit(最大200、既定50) |
line_search_messages | ブリッジした部屋のメッセージを検索します。 | 必須 query。任意 room_id、since、until、limit(最大200、既定50) |
line_get_recent_messages | 一覧や検索で得た room_id の最近のメッセージを返します。 | 必須 room_id。任意 limit(最大200、既定30) |
line_get_message_context | 指定した event_id の前後のメッセージを返します。 | 必須 event_id。任意 before(0から50、既定10)、after(0から50、既定5) |
line_get_media | 保存済みのメッセージにある添付を取得します。戻り値は file_name、mime_type、size、content_base64 です。10 MiB を超えるファイルは拒否します。 | 必須 mxc_uri。任意 event_id(その URI がそのイベントのものか確認します) |
agent だけで使えるツール
| ツール | 説明 | パラメータ |
|---|---|---|
line_list_sendable_rooms | 送信を許可した部屋の一覧を返します。ほかの部屋は含めません。REST の GET /api/v1/sendable-rooms に対応します。 | なし |
line_send_message | 許可した部屋に、ログイン中の個人アカウントとしてテキストを送ります。 | 必須 room_id、text。任意 reply_to_event_id、idempotency_key |
line_send_media | 許可した部屋に、ログイン中の個人アカウントとしてファイルや画像を送ります。 | 必須 room_id、file_name、mime_type、content_base64。任意 reply_to_event_id、idempotency_key |
使い方の注意
idempotency_keyを省略すると、MCP サーバーがキーを作って結果に入れて返します。同じ送信をやり直すときは、そのキーをもう一度渡します。同じキーで、部屋、本文、返信先がすべて同じ送信は、Matrix に送り直さず前の結果を返します。どれかが違うと409 IDEMPOTENCY_CONFLICTになります。line_get_mediaに渡すmxc_uriは、取得済みのメッセージに含まれる値だけを使います。保存したメッセージに無い mxc URI は404 MEDIA_NOT_FOUNDになります。- 公開の URL や署名なしのメディア URL は発行しません。
- 管理用の部屋(ブリッジの bot との DM)と分類できない部屋は、読み取り系のすべての API で 404 になります。
line_send_media の注意line_send_media には caption と text を渡しません。固定している LINE のブリッジはキャプションを受け付けず、長いキャプションを付けた画像は matrix_accepted のあとに捨てられることがあります。file_name は短い名前(例 design-01.png)にし、説明は別の line_send_message で送ります。
送信の許可の仕組み#
誰が何を決めるか
- 運用者が管理画面の「送信の許可」で、部屋ごとに
allow_sendをオンにします。新しい部屋は常にallow_send=falseで登録されます。 - 運用者は管理画面の「バックアップと更新」にある「送信を止める」で、全体の送信を止められます。
- MCP には、許可リスト、停止スイッチ、
allow_send、トークンの取得を扱うツールがありません。部屋ごとの許可を一括でオンにする API もありません。 - 送信できるのは、Agent API key を持つ agent プロファイルだけです。
送信の判定
Context は送信のリクエストを受けると、次の順で処理します。
- 送信のポリシー(
allow_sendと停止スイッチ)を確認します。 - 確認を通ったら、データベースのトランザクションで
idempotency_keyを予約します。 - Matrix に
PUT .../send/m.room.message/{txnId}を送ります。 - Matrix が受け付けると、
matrix_acceptedと Matrix のイベント ID を返します。
補足拒否した送信では Matrix を呼びません。エラーの応答には、ほかの部屋の許可リストや秘密の値を含めません。matrix_accepted は Matrix が受け付けたことを示します。LINE に届いたことは示しません。
送信のリクエスト
{
"room_id": "<room-id>",
"text": "<message-text>",
"reply_to_event_id": "<optional-event-id>",
"idempotency_key": "<stable-request-key>"
}{
"room_id": "<room-id>",
"file_name": "<short-file-name>",
"mime_type": "image/jpeg",
"content_base64": "<base64>",
"reply_to_event_id": "<optional-event-id>",
"idempotency_key": "<stable-request-key>"
}{
"status": "matrix_accepted",
"request_id": "<request-id>",
"matrix_event_id": "<event-id>"
}エラー#
{
"error": {
"code": "NOT_ALLOWLISTED",
"message": "This room is not enabled for AI sending.",
"request_id": "<request-id>"
}
}| HTTP | code | 意味 |
|---|---|---|
| 400 | NOT_LINE_ROOM | ブリッジした LINE や WhatsApp の部屋ではありません |
| 401 | UNAUTHORIZED | API キーが無いか、正しくありません |
| 403 | NOT_ALLOWLISTED | その部屋で allow_send がオンになっていません |
| 403 | FORBIDDEN | read キーでは送信できません。送信は agent キーだけです |
| 404 | ROOM_NOT_FOUND | 部屋が見つかりません |
| 409 | IDEMPOTENCY_CONFLICT | 前に使った idempotency_key で、部屋、本文、返信先のどれかが違う送信を受けました。メディアでは、ファイル名、MIME タイプ、ファイルの中身も比べます |
| 413 | MEDIA_TOO_LARGE | 10 MiB を超えています |
| 422 | EMPTY_BODY | 本文が空です |
| 423 | SEND_DISABLED | 停止スイッチがオンです |
| 429 | UPSTREAM_RATE_LIMITED | Matrix への送信が制限されています |
| 429 | RATE_LIMITED | 管理画面のログインに失敗が続いています |
| 503 | MATRIX_UNAVAILABLE BRIDGE_UNAVAILABLE | Matrix またはブリッジにつながりません |
API キーを入れ替えるとき#
MCP クライアントが connected と表示していても、API の認証が通っているとは限りません。MCP サーバーを再起動しただけでは、古い mcp-stdio のプロセスが古いキーのまま残ることがあります。キーを入れ替えるときは、次の順で作業します。
- ホストの
.envでCONTEXT_READ_API_KEYとCONTEXT_AGENT_API_KEYを新しい値にします。 - MCP を使うマシンの env ファイルを、同じ値にそろえます。
- 残っている
node …/mcp-stdio/dist/index.jsのプロセスを終了します。 - MCP クライアントにサーバーを登録したときの env も、新しいキーに合わせます。
- MCP サーバーを再起動します。
line_list_roomsと、既知の部屋のline_get_recent_messagesを呼んで確認します。
やってはいけない秘密の値をチャットに出さないでください。
よくある失敗#
| 症状 | 意味 | まずやること |
|---|---|---|
| MCP が 401 を返す | キーがずれているか、古いキーを持つ node のプロセスが残っています | API キーを入れ替えるときの手順を実行する |
| MCP が server does not exist を返す | クライアント側のカタログが一時的に不安定です | Context の /health が正常なことを確認してから、MCP サーバーを再起動する |
最終更新 2026年10月20日