🐷

LibreChat + MCP で Gemini 3 × 社内システム連携を Docker で検証してみた

に公開

はじめに

前回の記事で、WEB版Gemini(gemini.google.com)から社内MCPサーバーに直接つなぐのは無理で、有料の Gemini API + Function Calling を使うのが現実解、というところまで検討しました。

👉 Workspace版Geminiの無料連携に限界を感じて、API契約をしようかなと思った話

今回はその検証編として、実際に Docker でローカルに環境を立てて試してみます。ただ API 直結でもう一つ壁があって、最新の Gemini 3 はまだ remote MCP 連携に未対応(対応済みは Gemini 2.5 系。Gemini 3 は近日対応予定とのこと)。せっかくなら最新を使いたい…ということで、MCPクライアントを肩代わりしてくれる LibreChat 経由なら Gemini 3 でも社内MCP連携できる、と気づいたのが今回の構成です。

あわせて重視したのがGoogleアカウントを軸にしたセキュリティ。新しいアカウント管理は増やしたくないので、LibreChat の Googleソーシャルログインを使い、将来は Cloud Run 側でも Googleアカウントによる接続制限をかけて、ログインから社内データアクセスまで一気通貫でセキュアに繋げる狙いです。

この構成のキモ(先に結論)

  • ログイン認証(誰か)と Gemini APIキー(共有1本)を完全分離
  • 本人情報は Gemini を経由せず LibreChat → MCPサーバーへ直接渡る(なりすまし不可)
  • LibreChat が MCPクライアントになるので Gemini 3 でも動く

構成図

[ユーザー] ──Googleログイン──▶ LibreChat(ローカルDocker)
                                  │ モデル: Gemini(generateContent経由)
                                  │ MCPクライアントとして社内MCPを実行
                                  │ X-User-Email: ログイン本人のメール を自動注入

                          社内MCPサーバー(FastMCP / streamable-http)
                                  │ ヘッダのメールを読む

                          社内システム REST API(メールで出し分け)

前提

  • Docker Desktop / git(今回は macOS Apple Silicon。MongoDB もそのまま起動できた)
  • Gemini APIキー(Google AI Studio で無料発行)
  • 社用 Google Workspace アカウント(ソーシャルログイン用)

フォルダ構成

LibreChat と MCPサーバーを兄弟フォルダに置きます。

ai-chat/
├── LibreChat/        ← 公式リポジトリ
└── mcp-server/       ← 自作MCPサーバー

手順1:LibreChat のクローンと初期設定

cd ~/work/ai-chat
git clone https://github.com/danny-avila/LibreChat.git
cd LibreChat
cp .env.example .env

このプロジェクトでは .example から3ファイルをコピーして作るのが基本です(.env / docker-compose.override.yml / librechat.yaml)。

手順2:Gemini を「共有キー+変更不可」に設定(.env

# Gemini APIキー(実キーを直接記入=全員で共有・UIに入力欄が出ない=変更不可)
GOOGLE_KEY=AIzaSy...(実際のキー)

⚠️ GOOGLE_KEYGemini APIキー。次の手順の GOOGLE_CLIENT_ID/SECRET(ログインOAuth)とは別物です。

手順3:Googleソーシャルログインを設定

3-1. Google Cloud Console で OAuth クライアントを作成

  1. Google Auth Platform を初期設定(メニュー →「Google Auth Platform」→ 未設定なら「始める / GET STARTED」)
    • ブランディング:アプリ名・ユーザーサポートメールを入力
    • 対象:User Type を 「内部(Internal)」 に設定
      → 自社 Workspace ドメインのアカウントだけログイン可能=実質的なドメイン制限
  2. 「クライアント」→「クライアントを作成」
    • アプリの種類:ウェブアプリケーション
    • 承認済みのリダイレクト URIhttp://localhost:3080/oauth/google/callback
  3. 発行された クライアントID / クライアントシークレット を控える

3-2. .env に追記

# Googleソーシャルログイン
GOOGLE_CLIENT_ID=xxxx.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=xxxx
GOOGLE_CALLBACK_URL=/oauth/google/callback
# DOMAIN_CLIENT / DOMAIN_SERVER は .env デフォルト(http://localhost:3080)のままでOK

# ログイン方法をGoogleだけに限定
ALLOW_SOCIAL_LOGIN=true
ALLOW_SOCIAL_REGISTRATION=true
ALLOW_EMAIL_LOGIN=false
ALLOW_REGISTRATION=false

【ログイン画面が「Googleでログイン」だけになった状態】

手順4:設定ファイルを用意(example からコピー)

4-1. docker-compose.override.yml

cp docker-compose.override.yml.example docker-compose.override.yml

services: と「USE LIBRECHAT CONFIG FILE」のコメントを外し、mcp-server サービスを追記。有効行が以下になればOK:

services:

  api:
    volumes:
      - ./librechat.yaml:/app/librechat.yaml

  # 外部フォルダのMCPサーバーを同じcomposeで起動
  mcp-server:
    build:
      context: ../mcp-server      # LibreChatリポジトリの「外」
    expose:
      - "8080"
    restart: unless-stopped

4-2. librechat.yaml

cp librechat.example.yaml librechat.yaml

トップレベルに SSRF許可 + MCP定義を追記:

# 内部MCPサーバーをSSRF保護の例外として許可(host:port 形式)
mcpSettings:
  allowedAddresses:
    - 'mcp-server:8080'

mcpServers:
  echo-identity:
    type: streamable-http
    url: http://mcp-server:8080/mcp        # 同一composeのサービス名で到達
    headers:
      X-User-Email: "{{LIBRECHAT_USER_EMAIL}}"   # ★Googleログイン本人のメールが自動で入る

⚠️ 最重要の落とし穴{{LIBRECHAT_USER_EMAIL}}librechat.yaml に書いたMCPサーバーでのみ有効。画面UIから追加したサーバーではセキュリティ上ブロックされます。

⚠️ mcpServers: はトップレベルキー。行頭インデント0/有効な定義は1つだけgrep -n '^mcpServers:' librechat.yaml が1行なら正常)。

手順5:MCPサーバーを作る(mcp-server/)

cd ..
mkdir mcp-server
cd mcp-server

mcp_server.py(届いたメールを返す確認用)

from fastmcp import FastMCP
from fastmcp.server.dependencies import get_http_headers

# ステートレスは環境変数 FASTMCP_STATELESS_HTTP=true で指定(Dockerfile側)
mcp = FastMCP("echo_identity")

@mcp.tool
def whoami() -> dict:
    """LibreChatから届いたヘッダを返す(本人メール確認用)"""
    h = get_http_headers()
    return {"x_user_email": h.get("x-user-email"), "all_headers": dict(h)}

if __name__ == "__main__":
    mcp.run(transport="streamable-http", host="0.0.0.0", port=8080)

Dockerfile

FROM python:3.12-slim
WORKDIR /app
# ステートレスHTTP(リクエスト毎に独立=別ユーザーのヘッダ混入を防ぐ)
ENV FASTMCP_STATELESS_HTTP=true
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY mcp_server.py .
EXPOSE 8080
CMD ["python", "mcp_server.py"]

requirements.txt

fastmcp
httpx

手順6:起動して動作確認

cd ~/work/ai-chat/LibreChat
docker compose up -d --build      # MCPサーバーもビルドして起動
docker compose ps                 # 全コンテナ Up を確認

docker compose up -d --build で起動】

ブラウザで http://localhost:3080 → Googleログイン → モデルに gemini-3.5-flash を選択 → echo-identity(whoami)ツールを有効化 → 「whoami ツールを実行して」と入力。

【チャットでMCPツール echo-identity を有効化】

返ってきた JSON の x_user_email が自分のGoogleメールになっていれば成功です。

【whoami の結果JSON(x_user_email に自分のメール)】


ハマりどころ:実際に出た2つのエラーと対処

エラー① MCPサーバーが起動直後にクラッシュ(Restartingループ)

TypeError: FastMCP() no longer accepts `stateless_http`.
Pass `stateless_http` to `run_http_async()` or `http_app()`, or set FASTMCP_STATELESS_HTTP.
  • 原因:FastMCP 3.x で FastMCP(stateless_http=True) が廃止された。
  • 対処:コンストラクタ引数を削除し、DockerfileENV FASTMCP_STATELESS_HTTP=true
  • 成功確認:起動ログに transport 'streamable-http' (stateless) on http://0.0.0.0:8080/mcp

エラー② LibreChat が MCP に繋がらない

[MCP][echo-identity] Failed to initialize: Domain "http://mcp-server:8080" is not allowed
  • 原因:LibreChat の SSRF保護が内部アドレスを既定でブロック。
  • 対処librechat.yamlmcpSettings.allowedAddresses: ['mcp-server:8080'] を追加 → docker compose restart api
  • ⚠️ allowedDomains に内部アドレスを入れると厳格ホワイトリスト化して公開先まで全ブロック。内部許可は必ず allowedAddresses(host:port) を使う。
  • 成功確認:ログに Tools: whoamiInitialized with 1 configured server and 1 tool.

まとめ

無事、Googleアカウントでログインして、メールアドレスをMCPサーバーに送ることができました。

MCPサーバーに送ったメールアドレスで個人の特定ができたらいいなと考えています。ただ、まだまだ考えることはいっぱいです。セッションの使い回しで別ユーザーのヘッダを拾ったりしないよね。そもそもGeminiに送っていいデータの粒度ってどれくらい?個人情報の扱いは?LibreChatでWeb検索するのは別契約が必要じゃん等々。

これを発展させるか、別のやり方を検討するか、GoogleがMCPサーバーの利用に寛容になってくれるのを祈るか、もう少し考えていこうと思います。

株式会社スプリックス IT戦略部・SPRIX Enginieering Lab

Discussion