Skip to main content
Glama
MaxPopov
by MaxPopov

wikijs-mcp-google-auth

既存のWiki.js 2.5.xの上に構築するMCPレイヤー: 企業ユーザーがGoogle Workspaceでサインインし、LLM(claude.ai、Claude Desktop、任意のMCPクライアント)を通じてウィキを操作します — その操作はすべて、ユーザー自身のWiki.js権限の範囲内に厳密に制限されます。

コア原則: **Authorization(認可)の唯一の情報源はWiki.jsです。**MCPサーバーは独自のユーザー/グループ/権限を持たず、グローバルAPIキーも持ちません。すべての操作は個々のユーザーのネイテ下で実行されますが、許可/拒否(Groups / Permissions / Page Rules)を決定するのはWiki.js自身です。

Google Workspace ──OAuth/OIDC──▶ MCP Server ──signed assertion──▶ Wiki.js
                                     │         auth module "mcpdelegation"
                                     │         → refreshToken() → native JWT
                                     │
 MCP client (claude.ai / Desktop) ◀──┴── tools: search / get / list /
                                          create / update / delete / whoami
                                          (all via GraphQL with the user's JWT)

コンポーネンシ

デイレクオリ

説

Packages/wikijs-auth-odule/

Wiki.2.5.x向けカスタム認証モジユール — MCPサーバーが署キーょ。RS256のアサーションを検証し、ネイテイブなWiki.js JWTを返します(詳細

Packages/mcp-sever/

収metry リモートMCPサーバー(Streamable HTTP): Google OIDC の上に構築された、MCPクライアント向けの OAuth 21認可サーバー + トークンブロカ‑ + ツール

packages/e2e-ui/

テスト専用: ブラウザUI e2e(Playwright)と、単独で動くダミーのGoogleIdPエミュレータ

deploy/docker-compose.dev.yml

分離されたテスト環境(Wiki.js2.5.303 + Postgres + ACLシート) — 開発/CI専用

deploy/docker-compose.e2e.ym

フォールUI e2eスタック(伪IdP + Wiki.js + MCP + Playwright) — テスト専用

e2e/prod

本番用にはMCPのサーバーのみをデプPル可能: 既存のWiki.jsを参照

e2deploy/seed/run.mjs

テスト用スタンドにシードを投入するエントリポイント(see .mjsはライブラリ)

Related MCP server: wikijs-mcp

動作のしクミ

  1. MCPクライアントは s://mcp.company.com/mcpに接続し、OAuth 2.21(ではないのです)を実行します。GoogleはDCRをサポートしていないため、 MCPサーバー自体がクライアント向けの認可サーバーとなり、Googleはユーザーの認証にのみ使用されます。Googleトークンがサーバーから外部に出ることはありません。クライアントが受け取るのは、MCPサーバー独自の不透明トークンです。Googleログイン後、ユーザーはのアプリとリダイレクトURIを明示するコンセント画面を表示されます — この防策は、confused-deputy対策です。第三者が登録したクライアントは、ユーザーに知られることなくトークンを取得できますことができません。この承認はユーザーごと・クライアントごとに記憶されます。

  2. Googleのid_token(署名、iss、aud、email_verified、**hd = ご自分のWorkspaceドメイン)を検証します。

  3. MCPサーバーのトークンブローカーが、GoogleアイデンティティをネイティブのWiki.js JWTに交換します。短時間限のRS256アサーション(TTL 60秒、一意の jti)を検証し、標準のGraphQLミューテーションauthentication.loginをmcpdelegation スストラテジーで呼び出します。Wiki.jsモジュールが検証し、メールでユーザーを解決し、標準のrefreshToken()フローでJWTを返します。JWTはキャッシュされ、有効期限前にリフレッシュされます。

  4. すべてのツール呼び出しは、Authorization: Bearer <user' aSh JWT>を付与えてWiki.js GraphQLに送信します。氏限のないページは読み取ることも変更もできず、検索や一覧にも現れません — e2eテスト(異なるグループの2人のユーザーの許可/拒否マトリクス)に検証されています。

ツール

ツール

内容

whoami

ユーザーの身元と、Wiki.jsにおけるグループ、権限(アクセス診断)

search_wiki

全文検索。結果はユーザーの権限にでフィルタされます

get_page

idまたはパスでページを取得(メタデータ+完全なマークダウン)

list_pages

ユーザーに表示可能なページ(パスのプレフィックスでフィルタ可)

create_page

ページの作成(マークダウン)

update_page

更新: read-merge-write(読み取り→マージ→書き込み)。指定しなかったフィールドは保持

delete_page

削除(破壊的操作。delete:pagesの権限はWiki.jsが確認)


Wiki.jsとの統合: ステップバイステップ

準備するもの: ファイルシステム/Docker設定にアクセスできるWiki.js 2応用例.x(2.5.303で検証)、公開HTTPSエンドポイントを用意するMCPサーバー用ホスト、WorkspaceのGoogle Cloud Consoleへの管理者アクセス。

ステップ1. Wiki.jsに認証モジュールをインストール

Docker: wikiサービスにボリュームを追加し、コンテナを再起動します:

services:
  wiki:
    image: ghcr.io/requarks/wiki:2.5.303
    volumes:
      - /opt/wikijs-mcp/wikijs-auth-module:/wiki/server/modules/authentication/mcpdelegation:ro

(子のリポジ)/の内包物をを上記で指定した収納先へ配置してください。設定先ディレクトリ名は必ずmcpdelegationとします。このリポジトリのontent on the mount path。)

Bare metal: packages/wikijs-auth-module/ を <wiki>/server/modules/authentication/mcpdelegation/ にコピーし、Wiki.jsを再起動します。

設定が完了すると(ステップ3)、Wiki.jsのログに AuthenticationStrategy MCP Delegation: [ OK ] と表示されます。

Important: 設定先のディレクトリ名は必ず上記説明のとおりにしてください。

ステップ2. アサーション用の鍵を生成

openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out mcp-assertion-key.pem
openssl pkey -in mcp-assertion-key.pem -pubout -out mcp-assertion-key.pub.pem

秘密鍵(mcp-assertion-key.pem)はMCPサーバーのホストにだけ置きます。公開鍵は次のステップでWiki.jsに読み込みます。

スステップ3. Wiki.jsの管理画面でストゴリーを設定

Administration → Auth → Add Strategy → MCP Delegation の順に進みます:

  • アサーション公開鍵(PEM) — mcp-assertion-key.pub.pemの内容;

  • 想定オーディエンス/発行使者(Expected Audience / Issuer) — デフォルトのまま(urn::wikijs:mcp-delegation / urn:wikijs-mcp-google-auth);

  • ユーザー検索プロバイダーの優先順位(User Lookup Provider Priority) — メールでユーザーを検索するプロバイダーの順番。ご社のユーザーがGoog/オOIDCでサインインしていれ、そちらを最優先にします(モジュールキーの google、oidc、local も使えます)

  • (任意)セルフ登録(Self-registration) + ドメインのホワイトリスト + グループの自動登録 — MCPを介した初回リクエストで新しいWorkspaceユーザーが自動作成されます

  • 保存します。

ストリージーの instanceキーがー覧に表示されます(これがMCPサーバーのWIKIJS_STRATEGYKEYになります。UIから手動作成した場合は、Wiki.jsがuuid(UUID)を生成するので、それをコピーしてください)。

TFA(多 要の素認証)が有効:なアカウントは委任(delegation)経由では利用できません。MCPサーバーは明確なエラーを返します。

ステップ4. GoogleのOAuthクライアントを作成

Google Cloud Console → APIs & Services → Credntials → Create credentials → OAuth client ID:

  • プリケーションタイプ: Web application;

  • リダイレクトURI: https://mcp.company.com/auth/google/callback(ご自身のPUBLIC_URL に /oauth/google/callback を追加したもの);

  • OAuthの同意画面: Internal(ご自身のWorkspaceのみ)。

Client ID とClient Secretを保存します。

ステップ5. MCPサーバーをデプロイ

cd deploy
cp .env.example .env        # fill in the values
mkdir -p keys && cp /path/to/mcp-assertion-key.pem keys/
chmod 644 keys/mcp-assertion-key.pem   # the container runs as non-root node (uid 1000)
docker compose -f docker-compose.prod.yml up -d

このコンテナーは、リソースのない node ユーザーで動走します。マウントする鍵ファイルは、そのユーザーが読めるよう(chmod644)にしておく必要があります。秘密鍵そのものは、ホストのkeys/ディレクトリの権限によって保護されます。

env の変数:

変数

値

MCP_IMAGE

タグ付きイメージ(バージョンがdev/mainにマージされると、Release on main ワークフローがghcr.io/owner→wikijs-mcp-sever:vX.Y.Zを自動公開します。ローカル・ビルドする場合はdocker build -f packages/mcp-server/Dockerfile -t wikijs-mcp-server:local .

PUBLIC_URL

MCPサーバーのパブルなHTTPS URL

WIKIJS_URL

Wiki.jsのURL(内部URL推奨)

WIKIJS_STRATEGY_KEY

ステップ3 で設定したストラテジーのインスタンスキー(その名前にした場合mcpdelegation

GOGLE_CLITSTRUCT_ / GOGLE_CLIENT_SECRET

ステップ4で取得したもの

GOOGLE_ALLOWED_DOMAIN

ご自身の片paceのドメイン(例:company.com) — このドメイン外のアカウントは拒否されます

ポート8000の前側にTLSルバースプロキシーを置きます。最小限のngin构成概要:

server {
  listen 443 ssl http2;
  server_name mcp.company.com;
  # ssl_certificate ...; ssl_certificate_key ...;
  location / {
    proxy_pass http://127.0.0.1:8000;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto https;
    proxy_set_header Host $host;
    proxy_buffering off;          # streamable HTTP
  }
}

確認: curl https://mcp.company.com/h`h`が`{ok`:true}`を返す、`curl https://mcp.company.com/.well-known/oauth-authorization-server`がOAuthメタデーたを返すことを。

ステップ6. クライアントを接続

とale-c(Tea/ Enterprise): Settings(設定) → Connectors(コネクター) → Add urustom connector → URL: https://mcp.company.com/mcp。初回クリック時にクライアントOAuth(クライアント登録→Googleログイン→完了)を実行します。

Claude Desktop: Settings → Connectors → 同様のカスタム・コネクターを追加(または古いバージョンではmcp-remoteを使用)。

**MCP Ingector(診断): npx @modelcontextprotocol/inspector→ Transport: **Streamable HTTP** → URL:https://mcp.company.com/mcp` → Open Auth → フローを順にこなします。

ステップ7. 動作確認

LLMチャットで:

  1. 「Wikiには誰として入っていますか?」 → whoami ツールが、あなたのメール、グループ、Wiki.jsの権限を表示します。

  2. アクセス権のあるページを検索/表示してもらう → 成功します。

  3. 権限のないページを求めると、明確な拒否(Wiki.jsがこの操作を拒否まっした…)へ。そのページが検索や一覧結果にも現れません。


ローカル開発

npm ci
npm run stand:up      # Wiki.js 2.5.303 + Postgres (docker)
npm run stand:seed    # finalize + groups/users/pages + strategy + dev keys
npm test              # unit tests (auth module + OAuth provider)
npm run build && npm run e2e   # in-process e2e: delegation, OAuth, tools — against a live stand
npm run stand:down

テスト用のユーザー: admin@example.com/admin1234!(Administrator)、john@example.com(Engineering。/management/*には不可)、kate@example.com(Management)。すべてのPRで高速のチェック(CI:lint + unit + build)を実行し、重めのdocker e2e(e2e)とブラウザui-e2eはdev/mainへのプッシュ時(すなわちマージ前)のみ実行ので、PRループを遅さません。

ブラウザ UI e2e(Playwright)を異なるロールで実行

別のdockerスタックdeploy/docker-compose.e2e.ymlが、ダミーのGoogle IdPエミュレータ(packages/e2e-ui/idp/ — 実際のGoogleの代わりにロールセレクタ付きのログインページ)と Wiki内部(Wiki.js)、MCPサーバー、Playwrightランナーを起動します。ランナーは、ブラウザのOAuth+同意フロー全体を異なるロール(John/Kate/ドメイン外)でド駆ーブします。エミュレーたとPlaywrightこのe2eのスタックでのみ動きます — 本番・開発用イメージムに込まれません。

C=deploy/docker-compose.e2e.yml
docker compose -f $C build mcp
docker compose -f $C up -d db wiki idp   # no --wait on wiki: the seed script is the readiness gate
docker compose -f $C run --rm seed
docker compose -f $C up -d --wait mcp
docker compose -f $C run --rm playwright     # exit code = test result
docker compose -f $C down -v

これは次の流れを検証します。ロールとしてログイン → 同意画面にクライアント名が表示される → 承認 → whoami と、そのロールにスコープされたページ(John は management/* を見られないが、Kate は見られる)。拒否 → access_denied。ドメイン外のアカウントは同意の前に拒否されます。専用の CI ワークフロー(ui-e2e)が dev/main へのプッシュのたびにこれを実行します。

スタンドに対して MCP サーバーを手動で実行する:

PUBLIC_URL=http://localhost:8000 \
WIKIJS_URL=http://127.0.0.1:3000 \
MCP_ASSERTION_PRIVATE_KEY_FILE=deploy/keys/mcp-assertion-key.pem \
GOOGLE_CLIENT_ID=... GOOGLE_CLIENT_SECRET=... GOOGLE_ALLOWED_DOMAIN=example.com \
npm run dev -w @wikijs-mcp/server

リリース

リリースは自動化されています。dev ブランチでルートの package.json の version を上げ、dev → main の PR を開いてマージしてください。すると Release on main ワークフローが、main へのプッシュ時にビルドして ghcr.io/<owner>/wikijs-mcp-server:vX.Y.Z(+ :latest)をプッシュし、git タグ vX.Y.Z と GitHub Release を作成します。これらはすべて組み込みの GITHUB_TOKEN のかで1回の実行で完了します(PAT/secret の設定は不要)。バージョンが変更されてなければ何も起こらないので、通常の main へのマージではリリースは作られません。

これを機能させるために一度だけ必要なリポジトリ設定: Settings → Actions → General → Workflow permissions = Read and write permissions。また、タグをルールセットで保護している場合は、GitHub Actions が v* タグを作成できるようにしてください。

セキュリティメモ

  • アサーション: RS256、TTL 60 秒、一意の jti、リプレイ対策。秘密キーは MCP サーバーにのみ存在します。秘密キーが盗まれると、任意の wiki ユーザーとしてサインインできることを意味する為、ルート秘密情報として扱い、ローテ—ションしてください(新しい鍵ぺア + ストラテジ内の公開キーを更新)。

  • Google アイデンティティ: 正規の識別子は iss+sub です。email はルクアップに使われるだけです。hd ドメインはパラメーターではなく、署名的な id_token から検証されます。

  • 混同したデピュティ防御: 認可コードが発行される前に、ユーザーはクライアントごとの同意画面を通ります(requireConsent による無効化は、信頼できる最初のスクリーン・トのみ認められます)。これにより、DCR が自分用の OAuth クライアントを登録した攻撃者が、被害者のトークンを黙って取得することを防ぎます。

  • Wiki.js レート制限: authentication.login は IP ごとに毎分5回までで、委任ログインはすべて MCP サーバーの IP から行わます。ブローカーは JWT をキャッシュ(デフォルト30分)し、制限に達したら待機してリトライするので、通常運用では気付きませんが、大量オンボーディング時は最大1分の遅延が発生します。

  • 失効: 標準の OAuth の /revoke(トークンごと)。Wiki.js でユーザーを無効化すると、次回の JWT リフレッシュ(≤30分)で委任が失効します。SESSION_STORE_FILE を削除して MCP サーバーを再起動すると、すべてのセッションが一度に破棄されます。

  • 監査: すべてのツール呼び出しは構造化された形式(whoam, which tool, ok/denied)でログされ、ページ内容はログされません。

  • MCP エンドポイント: Bearer 専用、トークンごとに毎分120リクエスト、セキュリティヘッダー付き。OAuth エンドポイントは SDK 組み込みのレートリミットで保護されています。

制約と今後の予定

  • RAG/セマンティック検索は別の将来のサービスです。ブラグインポイントは準備済みです。search_wiki は SearchBackend インターフェースを通じて実装されています(src/search/ — v1 は Wiki.js のネイティブ検索。RAG サービスはユーザーの Wiki.js の JWT を受け取り、ACL モデルを維持します)。docs/rag-integration.md を参照てください。

  • 単一の MCP サーバーインスタンス(FileStore + インメモリエリプレイキャッシュ)。HA には共有ストア(Redis)が必要 — KVStore インターフェースはすでに抽出済みです。

  • Wiki.js 3.x は認証の仕組みが異なるめ、このモジュールは 2.5.x を対象としています。

ライセンス

Apache-2.0

Related MCP Connectors

Related MCP Servers