Skip to content

MCP OAuth ラッパーの導入と設定 ​

第10版作成 最終更新 (日本時間)
対応バージョンPleasanter 1.5.2.0 以降確認バージョン1.5.8.1

プリザンターの MCP サーバ(プリザンターの MCP)は、API キーをリクエストヘッダーかボディに載せて認証します。Claude や ChatGPT のカスタムコネクタのように OAuth(Authorization Code + PKCE)で接続する AI アプリには、そのままでは登録できません。

MCP OAuth ラッパーは、プリザンターの前に置く小さな認証サーバ兼中継です。AI アプリには OAuth の認可サーバとして見え、認可が済んだ通信だけをプリザンターの /mcp へ中継します。プリザンター本体には手を入れません。

ソースと配布物は GitHub で公開されています: vehiclevisionjp/VehicleVision.PleasanterTools.McpOAuthWrapper

このページの設定と手順は、ラッパーの最新版 v0.3.2 に対応しています。どの機能がどの版で入ったかは 機能とバージョンの対応、版ごとの変更と更新時の作業は 変更履歴 を見てください。ページ内の「v0.3.0 以降」のようなバッジは、その節の内容を使える最初の版です。

検証環境で確認してください

OAuth 認可と MCP 中継を実装した初期の版系列(v0.x)です。Docker 上のプリザンター 1.5.8.1 と PostgreSQL 17 で OAuth 認可と MCP 接続を確認しています。SQL Server 2025・PostgreSQL 17・MySQL 8.4 は、読み取り専用接続と Users テーブルの SELECT まで Docker で確認しました。Claude の組織コネクタと ChatGPT の実アカウントでの接続も確認済みです。Azure App Service と IIS でも実機で動作を確認しています。v0.x の間は、本番へ入れる前に検証環境で確かめてください。

仕組み ​

図を読み込み中…

  • 認証の根拠は API キーです。 プリザンターのログインパスワードは使いません。LDAP・パスキー・二段階認証を使っている環境でも、発行済みの API キーがあれば接続できます。ラッパーがそれらのログイン処理を代行したり、完了の証明を受け取ったりするわけではない点に注意してください。
  • API キーはラッパーに保存しません。 MCP 通信のたびに、プリザンターの Users テーブルから読み取り、その通信の間だけメモリに持ちます。トークンやセッション、OAuth の状態保存先(SQLite・KVS)にも入りません。認可とトークンには、キーの再発行を検出するための SHA-256 フィンガープリントだけが入ります。
  • プリザンターの DB は読み取り専用で参照します。 読む列は TenantId・UserId・LoginId・ApiKey・Disabled・Lockout・LoginExpirationLimit・LoginExpirationPeriod・LastLoginTime の 9 列だけで、書き込みはしません。プリザンター側の最終ログインや失敗回数、監査ログも更新されません。
  • MCP の中身は解釈しません。 GET/POST/DELETE と SSE をそのまま中継するだけなので、プリザンターのバージョンやツール定義に依存しません。受信した Authorization・X-API-Key・Cookie は取り除き、上流へはプリザンターから読んだ API キーを X-API-Key で渡します。
  • キーを再発行・削除すると、古いトークンは次の通信で拒否されます。 無効化・ロックアウト・利用期限切れのアカウントも同様です。ただし、すでに始まっている長時間の通信をその場で止める機能はありません。
  • トークンの有効期間は、アクセストークン 15 分、認可コード 2 分、リフレッシュトークン 1 日です。

個人のアカウントと共通アカウント ​

ログインしたあとの同意画面で、どのプリザンターアカウントの権限で操作するかを選べます。

選択肢操作の主体・権限
自分のアカウントログインした本人。プリザンター側の権限と監査も本人
共通アカウント管理者が SharedApiKeyUserId で指定したアカウント。操作はそのアカウントの権限で行われ、プリザンター側の監査には共通アカウントが残る

共通アカウントの選択肢は、SharedApiKeyUserId を設定したときだけ表示されます。共通アカウントの API キーそのものをログイン画面に入力した場合は、識別されるユーザーも共通アカウントになり、個人は識別できません。 個人を識別したいときは、個人のキーでログインして、共通アカウントは権限だけを借りる使い方にしてください。

導入する ​

1. 配置して起動を確認する ​

  1. Windows または Linux に ASP.NET Core Runtime 10 を入れます。.NET Runtime だけでは足りず、ASP.NET Core Runtime が必要です。

  2. Release ページで使うバージョンを選び、Assets の ZIP を取得して展開します。ZIP の名前は v0.3.2 以降が VehicleVision.PleasanterTools.McpOAuthWrapper-<バージョン>-portable.zip、v0.3.1 以前が McpOAuthWrapper.zip です。Source code の ZIP は配布アプリではありません。

  3. 展開先(VehicleVision.PleasanterTools.McpOAuthWrapper.dll、appsettings.json、App_Data/Parameters が直下にある場所)をカレントにして、接続を無効にした初期設定のまま起動します。

    text
    dotnet VehicleVision.PleasanterTools.McpOAuthWrapper.dll --urls http://127.0.0.1:5180
  4. http://127.0.0.1:5180/health/live に Healthy と表示されれば、配置とランタイムは問題ありません。この時点の /mcp は 501 を返します。Ctrl+C で止めて、以降の設定に進みます。

2. プリザンターと DB を用意する ​

  • プリザンターの MCP サーバを有効にします(有効化の手順)。
  • 接続するユーザー(と、使うなら共通アカウント)の API キーをプリザンターで発行します。キーが未発行のアカウントはログインできません。
  • Users テーブルだけを SELECT できる読み取り専用の DB ユーザーを用意します。プリザンター本体の管理者接続を持ち込まないでください。

ラッパーの App_Data/Parameters/Rds.json に接続を書きます。付属の Rds.example.json をコピーして編集します。

powershell
Copy-Item App_Data/Parameters/General.example.json App_Data/Parameters/General.json
Copy-Item App_Data/Parameters/Rds.example.json App_Data/Parameters/Rds.json
json
{
  "Dbms": "PostgreSQL",
  "Provider": "Local",
  "SaConnectionString": "",
  "OwnerConnectionString": "",
  "UserConnectionString": "Server=localhost;Database=Implem.Pleasanter;UID=mcp_reader;PWD=CHANGE_ME;Search Path='\"Implem.Pleasanter\"'",
  "SqlCommandTimeOut": 30
}
  • Dbms は SQLServer・PostgreSQL・MySQL のどれかです。
  • 使うのは UserConnectionString だけです。SaConnectionString と OwnerConnectionString は空にします。
  • 接続文字列の #ServiceName# のようなプレースホルダーは展開されません。
  • UserConnectionString は環境変数 MCP_RDS_UserConnectionString でも上書きできます。SqlCommandTimeOut は 1〜120 秒です。
  • ラッパーはプリザンターの Authentication.json・Security.json を使いません。プリザンター側の設定を変える必要もありません。

DBMS ごとの接続文字列の例です(値は例示です)。

DBMSUserConnectionString の例
SQL ServerServer=sql.example;Database=Implem.Pleasanter;User ID=mcp_reader;Password=CHANGE_ME;Encrypt=True
PostgreSQLHost=pg.example;Database=Implem.Pleasanter;Username=mcp_reader;Password=CHANGE_ME;Search Path='"Implem.Pleasanter"'
MySQLServer=mysql.example;Database=Implem.Pleasanter;User ID=mcp_reader;Password=CHANGE_ME
  • PostgreSQL で大文字やピリオドを含むスキーマ名は二重引用符で囲みます。JSON の中では \" と書きます。
  • SQL Server は接続ユーザーの既定スキーマから Users が見えることを確認します。ラッパーは Encrypt=True を必須にし、Encrypt=Strict も使えます。信頼できるサーバー証明書を用意してください。TrustServerCertificate=True は、隔離した開発環境の自己署名証明書にだけ使います。

3. General.json を設定する ​

ラッパー専用の設定は App_Data/Parameters/General.json にフラットな形式で書きます(appsettings.json は編集しません)。プリザンターからコピーせず、付属の General.example.json から作ってください。環境変数 MCP_GENERAL_項目名(例: MCP_GENERAL_CertificatePassword、配列は MCP_GENERAL_Clients__0__ClientId)でも上書きでき、環境変数のほうが優先されます。

項目設定内容
Enabled設定が済んだら true。初期値 false の間、/mcp は 501
Issuerラッパー専用ホストのルートの HTTPS URL。AI アプリに登録するコネクタ URL は Issuer + mcp
PleasanterUrl接続先プリザンターのベース HTTPS URL。サブパス可(例 https://pleasanter.example/portal → MCP の接続先は https://pleasanter.example/portal/mcp)。末尾の / は自動補完
TenantId接続を許可するテナント ID
DatabaseTimeZoneIdプリザンター本体が DB に日時を保存するときのタイムゾーン。初期値 UTC、日本時間なら Asia/Tokyo
SharedApiKeyUserId選択肢に加える共通アカウントの UserId(数値)。同じテナント内に限る。null なら共通アカウントの選択肢を出さない
StateStoreOAuth の状態の保存先。Sqlite(既定)または Redis(Valkey 互換 KVS 可)
StateDirectorySQLite モードの OAuth 状態・Data Protection の鍵の置き場。自動生成した証明書(certificates フォルダー)の置き場でもある。初期値 App_Data/Wrapper。Redis モードでも、証明書を自動生成する用途があれば使う
SigningCertificatePath / EncryptionCertificatePathファイル方式の秘密鍵付き PFX のパス。他の方式を使う用途は空にする
SigningCertificateBase64 / EncryptionCertificateBase64 v0.3.0 以降Base64 方式の秘密鍵付き PFX。環境変数 MCP_GENERAL_SigningCertificateBase64/MCP_GENERAL_EncryptionCertificateBase64 から渡す
SigningCertificateThumbprint / EncryptionCertificateThumbprint、CertificateStoreName、CertificateStoreLocation v0.3.0 以降Windows 証明書ストアの拇印(40 桁)と、ストアの名前・場所(既定 My/CurrentUser)
SigningCertificateCloud / EncryptionCertificateCloud v0.3.0 以降クラウドのシークレットから取得する方式。Provider・SecretId・Version・Region・OciAuthentication(既定 InstancePrincipal)・OciConfigProfile(既定 DEFAULT)
CertificatePassword2枚の PFX に共通のパスワード。Key Vault の証明書から取得する PFX では空。General.json に平文で書かず、環境変数 MCP_GENERAL_CertificatePassword か秘密管理から渡す
TrustedProxyAddressesHTTPS を終端するプロキシの送信元 IP の一覧(転送ヘッダーを 1 段だけ信頼)
AllowedOriginsMCP リクエストで許可する Origin の追加一覧(完全一致)。既定で同一 Origin と Origin なしは許可
Clients事前登録する OAuth クライアント(ClientId・DisplayName・RedirectUris)
AllowDynamicClientRegistration / AllowedRedirectUris動的クライアント登録(DCR)を使うか、許可するリダイレクト URI の一覧
MaxDynamicClientsDCR で作れるクライアント数の上限。初期値 100(1〜10000)。超えると 503

プロキシ配下では TrustedProxyAddresses を必ず設定する

HTTPS 終端のプロキシやロードバランサーの後ろに置くとき、これを設定しないと、全ユーザーが同じ接続元に見えます。ログイン試行の制限は接続元 IP ごとに 15 分で 5 回なので、全員でその回数を共有してしまいます。転送ヘッダーが処理されずに届いたときは、警告がログに出ます。

  • 公開 URL と、実際に届く Host・スキームが一致しないリクエストは拒否されます。プロキシは公開ホストの X-Forwarded-Host と X-Forwarded-Proto: https を送ってください。同じマシンのプロキシから 127.0.0.1:5180 へ転送するなら、Issuer に公開 URL、TrustedProxyAddresses に 127.0.0.1 を指定します。外部からアプリの HTTP ポートへ直接届かない配置にします。
  • appsettings.json の AllowedHosts は既定の * のままで構いません(ヘルスチェック以外は、アプリが自分で Issuer と照合します)。
  • OAuth の PKCE・接続先検証・アカウント状態の検証・ログイン試行制限・MCP の Origin 検証は常に有効で、無効にする設定はありません。ユーザーや接続元 IP の許可リストも持たないので、入口でプリザンター本体と同等のネットワーク制限をかけてください。
  • 実行環境は Production にします(Windows は $env:ASPNETCORE_ENVIRONMENT = 'Production'、Linux は export ASPNETCORE_ENVIRONMENT=Production)。AllowDevelopmentHttp(HTTP の許可)は Development 専用で、Production で true にすると起動しません。
  • 状態の置き場と証明書は、アプリの実行アカウントだけが読み書きできるようにします。状態の置き場を消すと、発行済みの認可・トークン・セッションが使えなくなり、全員が再接続することになります。公開 HTTPS 用の証明書はプロキシ側の設定で、ここで指定する PFX は OAuth と状態保護用です。

OAuth 用の証明書を選ぶ v0.3.0 以降 ​

署名用・暗号化用の証明書は、用途ごとに方式を 1 つだけ選びます。公開 HTTPS の証明書とは別のもので、OAuth のトークンの署名と、状態(Data Protection の鍵)の保護に使います。接続を有効にして起動するとき、環境(Production か Development か)に関係なく、次のどれかで読み込みます。

方式設定備考
自動生成(既定)その用途の Path・Base64・Thumbprint・Cloud をすべて未指定StateDirectory の永続化が必要
ファイルSigningCertificatePath/EncryptionCertificatePath秘密鍵付き PFX。相対パスはアプリのコンテンツルート基準
Base64SigningCertificateBase64/EncryptionCertificateBase64PFX 全体の Base64。メモリ上で読み込む
Windows 証明書ストアSigningCertificateThumbprint/EncryptionCertificateThumbprintWindows のみ。非エクスポート鍵も使える
クラウドSigningCertificateCloud/EncryptionCertificateCloudAzure・AWS・GCP・OCI のシークレットから起動時に取得
  • 二重指定、取得失敗、不正な PFX、秘密鍵の欠落、有効期間外、RSA 2048 ビット未満、Key Usage の不一致、秘密鍵を使えない権限は、起動エラーになります。明示した方式が失敗したときに、自動生成へ切り替わることはありません。 エラーメッセージには秘密値を含めません。
  • 署名用の Key Usage は DigitalSignature、暗号化用は KeyEncipherment です。自己署名でよく、CA の発行やルート証明書の配布は要りません。
  • 根拠は CertificateLoader.cs(v0.3.2)です。

v0.2.0 以前は設定が違います

v0.2.0 以前は、Production では署名用・暗号化用の PFX のパス(SigningCertificatePath/EncryptionCertificatePath)が両方必須で、Development だけが開発用の証明書を使いました。v0.3.0 以降は、未指定なら自動生成され、Development でも同じ読み込みになります。v0.2.0 以前の設定(両方にパスを指定)は、そのまま使えます。

自動生成 ​

未指定の用途は、初回起動時に有効期限 10 年の自己署名 RSA 4096 ビット証明書を作り、StateDirectory/certificates/signing.pfx と encryption.pfx に保存します。再起動後は保存済みの PFX を読み込みます。期限切れや破損があっても上書きしません。同時に起動しても、先に保存された証明書を使います。

  • 新しく作る certificates フォルダーは、Windows では実行アカウントだけに権限を付け、Linux ではフォルダー 700・PFX 600 で作ります。すでにあるフォルダーの権限は変えないので、配置側で実行アカウントだけに制限してください。
  • CertificatePassword を設定すると、その値で PFX を保護します。未設定ならパスワードなしの PFX になるため、ファイルの権限とバックアップの保護が必要です。あとからパスワードを変えると、既存の PFX を読み込めません。
  • StateDirectory は、配布物の更新で上書きされない場所にし、OAuth の状態と一緒に保持してください。PFX を削除して再生成すると、同名でも別の鍵になるため、発行済みのトークンや保護済みの状態が使えなくなり、再認可が必要になります。証明書の削除を更新手順にしないでください。
  • 複数台構成(Redis)では、証明書のフォルダーを共有するか、ほかの方式で同じ証明書を全台に渡します。台ごとに別々の証明書を生成すると、状態を共有できません。
ファイル方式で自分で用意する ​

次の手順は、自己署名の証明書を自分で作ってファイル方式で使う場合です。自動生成を使うなら不要です。OpenIddict の公式資料に沿って、HTTPS 用とは別の RSA 4096 ビットの自己署名証明書を 2 枚作ります。

生成作業には Windows/Linux の PowerShell 7(pwsh)を使います。アプリの実行環境に PowerShell 7 を入れる必要はなく、管理用の端末で作って配置できます。次のコードを実行すると、カレントディレクトリーの oauth-certificates に PFX を作り、有効期間を 2 年間に設定します。パスワードは画面に表示せず入力します。

powershell
$ErrorActionPreference = 'Stop'
$certificateDirectory = Join-Path $PWD 'oauth-certificates'
foreach ($name in @('signing', 'encryption')) {
    if (Test-Path (Join-Path $certificateDirectory "$name.pfx")) {
        throw "$name.pfx が既にあります。既存の証明書を上書きしないでください。"
    }
}
New-Item -ItemType Directory -Path $certificateDirectory -Force | Out-Null
$securePassword = Read-Host '2枚の PFX に共通のパスワード' -AsSecureString
$password = [System.Net.NetworkCredential]::new('', $securePassword).Password
if ([string]::IsNullOrWhiteSpace($password)) { throw 'パスワードを入力してください。' }

foreach ($name in @('signing', 'encryption')) {
    $rsa = [System.Security.Cryptography.RSA]::Create(4096)
    $request = [System.Security.Cryptography.X509Certificates.CertificateRequest]::new(
        "CN=McpOAuthWrapper $name", $rsa,
        [System.Security.Cryptography.HashAlgorithmName]::SHA256,
        [System.Security.Cryptography.RSASignaturePadding]::Pkcs1)
    $usage = if ($name -eq 'signing') {
        [System.Security.Cryptography.X509Certificates.X509KeyUsageFlags]::DigitalSignature
    } else {
        [System.Security.Cryptography.X509Certificates.X509KeyUsageFlags]::KeyEncipherment
    }
    $request.CertificateExtensions.Add(
        [System.Security.Cryptography.X509Certificates.X509KeyUsageExtension]::new($usage, $true))
    $now = [DateTimeOffset]::UtcNow
    $certificate = $request.CreateSelfSigned($now.AddMinutes(-5), $now.AddYears(2))
    try {
        $pfx = $certificate.Export(
            [System.Security.Cryptography.X509Certificates.X509ContentType]::Pfx, $password)
        [System.IO.File]::WriteAllBytes((Join-Path $certificateDirectory "$name.pfx"), $pfx)
    } finally {
        $certificate.Dispose()
        $rsa.Dispose()
    }
}
Remove-Variable password, pfx
$securePassword.Dispose()

生成した signing.pfx と encryption.pfx を、配布物の更新で上書きされない保護されたディレクトリーへ配置し、アプリ実行アカウントに読み取り権限を付けます。Linux では専用アカウントを所有者にして、ディレクトリーは 700、PFX は 600 などに制限します。PFX とパスワードを Git や公開 ZIP に含めないでください。

General.json の該当項目を、配置先に合わせて次のように設定します。以下は Windows の例です。Linux では /var/lib/mcp-oauth-wrapper/certs/signing.pfx などの絶対パスに置き換えます。

json
{
  "SigningCertificatePath": "C:\\ProgramData\\McpOAuthWrapper\\Certs\\signing.pfx",
  "EncryptionCertificatePath": "C:\\ProgramData\\McpOAuthWrapper\\Certs\\encryption.pfx"
}

相対パスはアプリのコンテンツルートを基準に解決されるため、配置時は絶対パスを指定します。CertificatePassword は上で入力した共通パスワードを環境変数 MCP_GENERAL_CertificatePassword として実行プロセスへ渡します。Azure App Service では「環境変数」のアプリ設定にこの名前で登録し、保存して再起動します。IIS や OS サービスでもアプリの実行プロセスに渡してください。生成用端末で環境変数を設定しただけでは配置先には反映されません。

PFX の有効期限を管理し、期限前に更新します。暗号化用証明書は Data Protection の鍵の保護にも使用するため、更新時は既存の状態領域と旧証明書をバックアップしてください。

Windows 証明書ストアから読み込む ​

マシンの個人ストアから読み込む例です。拇印は実際の 40 桁に置き換えます。

json
{
  "SigningCertificateThumbprint": "<署名証明書の拇印>",
  "EncryptionCertificateThumbprint": "<暗号化証明書の拇印>",
  "CertificateStoreName": "My",
  "CertificateStoreLocation": "LocalMachine"
}

既定は My/CurrentUser です。IIS では LocalMachine を選び、アプリケーションプールの実行アカウントに秘密鍵の読み取り・利用権限を付けます。秘密鍵はエクスポートできなくても、OS の暗号プロバイダー経由で署名・復号できます。Windows 以外では使えません(Linux のキーストアは対象外)。

クラウドのシークレットから読み込む ​

Azure・AWS・GCP・OCI のシークレットに入れた PFX を、各社の SDK で起動時に取得します。取得した PFX はローカルに保存せず、メモリ上で読み込みます。クラウド側でバージョンを変えても、反映には再起動が必要です。環境変数で渡すときは、階層を __ で区切ります(例: MCP_GENERAL_SigningCertificateCloud__Provider)。

ProviderSecretId備考
Azurehttps://<vault>.vault.azure.net/secrets/<名前>/<バージョン>(/secrets/ の URI。バージョンは省略可)Version は使わず URI に含める。認証は DefaultAzureCredential
AWSシークレットの ARN などRegion 必須。Version 空なら AWSCURRENT。SecretBinary の PFX、または SecretString に PFX 全体の Base64。JSON の SecretString は不可
GCPprojects/<project>/secrets/<名前>/versions/<番号 or latest>Version は空にする。シークレットのペイロードに PFX のバイト列。認証は Application Default Credentials
OCIシークレットの OCIDRegion 必須。Version は正の整数(空なら現在の版)。内容は Base64。OciAuthentication は InstancePrincipal(既定)・ResourcePrincipal・ConfigFile

Azure の設定例です。

json
{
  "SigningCertificateCloud": {
    "Provider": "Azure",
    "SecretId": "https://<vault>.vault.azure.net/secrets/mcp-oauth-signing/<version>"
  },
  "EncryptionCertificateCloud": {
    "Provider": "Azure",
    "SecretId": "https://<vault>.vault.azure.net/secrets/mcp-oauth-encryption/<version>"
  }
}
  • パスワード付きの PFX は CertificatePassword で渡します。取得に失敗したら起動しません。非エクスポート鍵や HSM への署名・復号の委譲には対応しません。
  • 各社の認証・権限・ネットワーク経路を通した実環境の試験は、ソース側の資料で未実施とされています。配置後に、認可から MCP 接続まで確かめてください。
  • 取得先の検証は CloudCertificateReader.cs(v0.3.2)にあります。
証明書の交換 ​

各用途で読み込むのは 1 世代だけで、複数世代を同時に登録する入れ替えには対応しません。暗号化用の証明書は、保存済みの Data Protection の鍵の復号にも使うため、単純に差し替えると既存の認可・トークン・セッションが使えなくなります。旧証明書と状態をバックアップし、再認可を伴う更新として計画してください。複数台では、Secret の自動更新で台ごとに別の鍵を取得しないよう、バージョンを固定します。

4. AI アプリを登録する ​

AI アプリに登録するコネクタ URL は Issuer + mcp(例: https://mcp.example.jp/mcp)です。プリザンターの URL ではありません。

登録の方式は 2 通りです。

  • 事前登録: Clients に ClientId・DisplayName・RedirectUris を書きます。リダイレクト URI は完全一致で、ワイルドカードは使えません。公開クライアントとして Authorization Code + PKCE(S256)で動きます。
  • 動的登録(DCR): クライアントが自分で登録を要求する方式です。AllowDynamicClientRegistration を true にし、AllowedRedirectUris にクライアントの管理画面が示すリダイレクト URI を完全一致で書きます。登録エンドポイントは /connect/register です。有効にしただけでは任意のリダイレクト先は受け付けません。登録は認証なしで受け付けるため、同じ名前とリダイレクト先の再登録は同じ client_id を返し、総数は MaxDynamicClients で制限されます。

Claude と ChatGPT は DCR を使います。具体的な手順は Claude・ChatGPT から接続する にまとめています。

対応しないもの

このバージョンは、DCR と事前登録した公開クライアントに対応します。Client ID Metadata Documents(CIMD)と、クライアントシークレットを使う認証には対応しません。

Clients から項目を外しても、OAuth の状態に残っている登録は自動では消えません。クライアントを廃止するときは、ラッパーを止めて、SQLite モードなら状態の置き場、Redis モードなら専用の名前空間の OAuth 状態とキーを作り直し(全認可を無効にし)、残すクライアントを登録し直します。全ユーザーが再接続します。

5. 有効にして確認する ​

General.json の Enabled を true にして、展開先をカレントにして再起動します。常時運用では、同じコマンドを OS のサービス管理やホスティングの仕組みに登録し、カレントディレクトリ・実行アカウント・秘密の環境変数・状態の置き場の永続化を指定します。

URL用途
/health/live起動の確認
/.well-known/oauth-protected-resourcediscovery(保護リソースのメタデータ)
/.well-known/oauth-authorization-serverdiscovery(認可サーバーのメタデータ)

そのうえで、個人のアカウントと共通アカウントの両方で接続し、プリザンター側の権限と監査の主体、API キーの再発行・削除、アカウントの無効化が意図どおり効くことを確かめます。

配置先ごとの注意 ​

Azure App Service(Windows) ​

.NET 10 の Windows App Service に置けます。

  1. HTTPS のみを有効にし、対応するプランでは Always On を有効にします。SQLite モードではインスタンス数を 1 に固定します。

  2. プライベートな DB には VNet 統合などで経路を作り、Users の必要列だけ読める接続を用意します。

  3. Issuer は App Service の公開 HTTPS URL にします。秘密はアプリ設定の MCP_RDS_UserConnectionString・MCP_GENERAL_CertificatePassword で渡します。

  4. 証明書は、自動生成(v0.3.0 以降の既定)、後述の Key Vault 方式、または前述のファイル配置方式から選びます。状態の置き場と、自動生成・ファイル方式の PFX は、Kudu で確認した %HOME% 配下(例 data/McpOAuthWrapper)に置き、StateDirectory と証明書パスに絶対パスで書きます。更新で上書きされる wwwroot には置かないでください。

  5. DLL と web.config が直下にある ZIP を作り、ZIP デプロイします。秘密入りの ZIP は公開しません。

    text
    az webapp deploy --resource-group <リソースグループ> --name <アプリ名> --src-path <配置ZIP> --type zip
  6. アプリ設定に ASPNETCORE_ENVIRONMENT=Production を入れます。IIS 統合の転送設定は既定のまま使うので TrustedProxyAddresses は空にし、追加のリバースプロキシを置く場合だけ明示します。

Azure Key Vault から証明書を読み込む v0.3.0 以降 ​

v0.3.0 以降の配布物を使用してください。v0.2.0 以前の配布物は証明書の Base64 入力に対応していません。

以下は App Service の Key Vault 参照で Base64 設定へ渡す方法です。SigningCertificateCloud/EncryptionCertificateCloud の Azure(前述)で、ラッパーが直接取得する方法もあります。

App Service の Key Vault 参照で、証明書のシークレットをアプリ設定へ渡します。ラッパーは Base64 の PFX をメモリ上で読み込むため、証明書ファイルの手動配置は不要です。SQLite モードの状態領域は引き続き永続化します。

1. Key Vault に2枚の証明書を用意する ​

署名用 mcp-oauth-signing と暗号化用 mcp-oauth-encryption を用意します。次は Azure CLI が利用できる管理用端末の PowerShell 7 で、自己署名・RSA 4096・有効期間2年・エクスポート可能な秘密鍵・PFX 形式の2枚を生成する例です。作成するアカウントには Key Vault Certificates Officer などの作成権限が必要です。

powershell
$vaultName = '<Key Vault 名>'
foreach ($purpose in @('signing', 'encryption')) {
    $usage = if ($purpose -eq 'signing') { 'digitalSignature' } else { 'keyEncipherment' }
    $policy = @{
        issuerParameters = @{ name = 'Self' }
        keyProperties = @{ keyType = 'RSA'; keySize = 4096; exportable = $true; reuseKey = $false }
        secretProperties = @{ contentType = 'application/x-pkcs12' }
        x509CertificateProperties = @{
            subject = "CN=McpOAuthWrapper $purpose"
            keyUsage = @($usage)
            validityInMonths = 24
        }
    }
    $policyFile = Join-Path $PWD "mcp-oauth-$purpose-policy.json"
    $policy | ConvertTo-Json -Depth 5 | Set-Content -LiteralPath $policyFile -Encoding utf8NoBOM
    az keyvault certificate create --vault-name $vaultName --name "mcp-oauth-$purpose" --policy "@$policyFile" --output none
    if ($LASTEXITCODE -ne 0) { throw "$purpose 証明書の作成に失敗しました。" }
}

Key Vault の「証明書」の現在のバージョンに表示される「シークレット識別子」を控えます。参照先は /certificates/ ではなく /secrets/ の URL です。証明書と同名のシークレットから秘密鍵付き PFX を取得するため、エクスポート不可の鍵や RSA-HSM は使用できません。証明書の構成とエクスポート条件も参照してください。

2. App Service に読み取り権限を付ける ​

App Service の「ID」でシステム割り当てマネージド ID を有効にします。Key Vault の「アクセス制御(IAM)」で、その ID に Key Vault Secrets User を割り当てます。アクセスポリシー方式の場合は、シークレットの Get 権限を付けます。証明書の公開部分だけを取得する権限では足りません。

Key Vault のネットワークを制限している場合は、App Service の VNet 統合と Private Endpoint などで到達できる経路も用意します。

3. App Service のアプリ設定を登録する ​

App Service の「設定 → 環境変数 → アプリ設定」に、次の値を登録します。シークレット識別子は実際のバージョン付き URL に置き換えます。

名前値
MCP_GENERAL_SigningCertificateBase64@Microsoft.KeyVault(SecretUri=https://<vault>.vault.azure.net/secrets/mcp-oauth-signing/<version>)
MCP_GENERAL_EncryptionCertificateBase64@Microsoft.KeyVault(SecretUri=https://<vault>.vault.azure.net/secrets/mcp-oauth-encryption/<version>)
ASPNETCORE_ENVIRONMENTProduction

General.json と環境変数の SigningCertificatePath/EncryptionCertificatePath は空にします。各用途で Path と Base64 を両方設定すると起動を拒否します。Base64 の実値を General.json や公開するファイルに書かないでください。

Key Vault の「証明書」から取得する PFX のパスワードは空です。CertificatePassword は空にし、以前の MCP_GENERAL_CertificatePassword が残っている場合は削除します。パスワード付き PFX を独自に Base64 化して「シークレット」に保存した場合だけ、そのパスワードを MCP_GENERAL_CertificatePassword の Key Vault 参照などで渡します。証明書をインポートするときのパスワードとは区別してください。

設定を保存し、ポータルで Key Vault 参照が解決されていることを確認してから再起動します。権限やネットワーク経路が不足して参照文字列がそのまま届く場合、証明書エラーで起動を止めます。解決後は /health/live、discovery、OAuth 認可から MCP 接続までを確認してください。

4. 証明書を更新する ​

証明書は起動時に読み込むため、更新の適用には再起動が必要です。上の例はバージョンを固定し、新しい証明書が意図せず適用されることを防ぎます。暗号化用証明書を変えると、旧証明書で保護した Data Protection の鍵と既存の状態を復号できなくなります。複数インスタンスでは同じバージョンを揃えてください。

鍵を変更する更新では、停止して状態領域と旧バージョンを保全し、参照を新しいバージョンへ変更したうえで、専用の OAuth 状態と Data Protection の鍵を作り直し、利用者に再接続してもらいます。SQLite では StateDirectory、Redis ではラッパー専用の名前空間が対象です。旧鍵を使った状態を保持したまま自動で切り替える機能はありません。

Windows IIS ​

  1. IIS を有効にしたあと、.NET 10 の Hosting Bundle を入れて IIS を再起動します(ASP.NET Core Runtime 単体では IIS 用モジュールが入りません)。
  2. 配布物を C:\Apps\McpOAuthWrapper のような場所に展開し、生成済みの web.config を保持します。
  3. 専用のアプリケーションプールを作ります。.NET CLR は「マネージドコードなし」、32 ビットアプリケーションは無効、ワーカープロセス数は 1 にし、SQLite の状態を同時に触らないよう重複リサイクルを無効にします。
  4. 専用サイトに HTTPS バインドと公開用証明書を設定し、匿名認証を有効にします。Issuer はこのサイトのルートの HTTPS URL です。
  5. 状態の置き場(例 C:\ProgramData\McpOAuthWrapper\State)と OAuth 用 PFX は配置先の外の保護したフォルダーに置きます。IIS AppPool\<プール名> に、アプリと証明書の読み取り、状態の置き場の変更権限を付けます。
  6. 接続文字列と証明書パスワードは、保護したパラメータファイルかプロセスの環境変数で渡します。

更新するときは、サイトを停止するか app_offline.htm を置いて止まったことを確認し、状態・設定・証明書を残して配布物を入れ替えます。終わったら app_offline.htm を消して再起動します。

複数台構成(Redis/Valkey 互換 KVS) ​

既定の SQLite モードは単一インスタンス専用です。ログイン試行制限のロックもプロセス内だけなので、複数台にすると制限が台ごとに別になります。複数台にするときは、OAuth の状態を KVS に置きます。プリザンターの Users を読む Rds.json は引き続き必要です。

json
{
  "StateStore": "Redis",
  "KvsKeyPrefix": "pleasanter-mcp-oauth"
}
  • 接続文字列は環境変数 MCP_GENERAL_KvsConnectionString で渡します(TLS なら kvs.example:6380,ssl=true,user=wrapper,password=<接続用パスワード> の形式)。資格情報を設定例や配布 ZIP に入れないでください。
  • KVS に置くのは、OAuth クライアント、認可・トークンの状態、同意の識別子、ログイン試行回数、Data Protection のキーです。API キーそのものは置きません。
  • Redis モードでは、ローカルの oauth.db や Data Protection のキーファイルは作りません。証明書を自動生成する用途(v0.3.0 以降)だけは StateDirectory/certificates を使うので、全台でそのフォルダーを共有するか、同じ証明書をファイル・Base64・Windows 証明書ストア・クラウドの方式で全台に渡します。v0.2.0 以前は StateDirectory を使いません。
  • 共有する全インスタンスで、Issuer・テナント・クライアントなどの設定、KvsKeyPrefix、署名・暗号化証明書を揃えます。別のラッパーは別の KvsKeyPrefix にします。
  • KVS は、意図せずキーが追い出されない noeviction にし、必要な可用性と永続化を用意します。状態やキーを失うと再接続が必要です。障害時に SQLite へ切り替える機能はなく、SQLite と Redis の状態を相互に移す機能もありません(モードを切り替えたら全員が再接続)。
  • 認可コードと同意の二重使用、状態の同時更新、失効済みトークンの復活は、KVS の中でアトミックに拒否されます。ログイン試行は 15 分、同意は 5 分の TTL で、失効・期限切れの状態は 5 分ごとに整理されます。

Redis 8.2 と Valkey 9.1.2 の Docker で、認可・更新・失効・MCP 中継、API キーが保存されないこと、再起動後の利用、別インスタンスとの競合を確認しています。Redis Cluster 構成は未確認です。Azure App Service・IIS では、配置後に認可から MCP 接続までを確認してください。

更新するとき ​

版ごとの注意 ​

版ごとの変更の全体は 変更履歴 にあります。更新時に作業が要るものだけを挙げます。

更新作業
v0.1.0 から v0.2.0 以降既存の General.json から ApiKeyLoginId と、環境変数 MCP_GENERAL_ApiKeyLoginId を削除する。ログイン画面は API キーだけの入力になる(共通アカウントの選択、接続への同意、API キーを保存しない仕組みは変わらない)
v0.2.0 から v0.3.0 以降設定の追加は不要。証明書のパスを両方指定している環境は、そのまま動く。パスを省略した用途は、自動生成される(StateDirectory の永続化と、書き込み権限が要る)
v0.3.0 から v0.3.1・v0.3.2アプリの動作は変わらない。v0.3.2 は配布 ZIP の名前が変わるので、取得するファイル名を確かめる

根拠は API キーだけの入力に変更したソース差分と、v0.2.0 から v0.3.0 までの差分です。

v0.2.0 の変更については、ソース側の検証記録に合成 Users による HTTP テストと画面の確認が記載されています。KVS・プリザンター実機・AI アプリ経由の再検証は、この変更時点では実施されていません。前述の実機確認と区別して、更新先の環境で接続を確かめてください。

配布物を入れ替える ​

  • 更新は、アプリを止め、新しい配布 ZIP を別のディレクトリーに展開し、Rds.json・General.json・証明書・状態の置き場を引き継ぎ、起動確認してから転送先を切り替えます。
  • OAuth の DB 構造を自動で移行する仕組みはありません。リリースの変更内容を確認し、構造が変わる更新では再認可が必要になることがあります。
  • v0.1.0 より前のパスワード認証だった版から更新したときは、既存の認可を引き継げません。発行済みの API キーで再接続してください(古いトークンは拒否されます)。旧バージョンの appsettings.json の Bridge セクションにあった項目は General.json の最上位へ移し、環境変数 Bridge__項目名 は MCP_GENERAL_項目名 に直します。

トラブルシュート ​

症状確認すること
起動時にランタイム不足と出るASP.NET Core Runtime 10 を入れたか(IIS なら Hosting Bundle)
/mcp が 501General.json の Enabled が false のままではないか
接続が 400Issuer と、公開ホスト・HTTPS・転送ヘッダーが一致しているか
ログインできない入力した API キー、キー所有者の状態、TenantId。失敗が続いたら 15 分待つ
共通アカウントのキーが使えないと表示される共通アカウントのキー発行、アカウントの状態、TenantId
DB 接続エラーDbms、読み取り専用接続、Users の SELECT 権限、ネットワーク経路
起動時に「証明書を読み込めません」と出る(v0.3.0 以降)用途ごとに方式が 1 つだけか、PFX・パスワード・秘密鍵・有効期限、保存先の権限、クラウドの認証と権限、Key Vault 参照が解決されているか
AI アプリが接続できない登録したリダイレクト URI の完全一致、PKCE S256、公開 URL と証明書

関連ページ ​

変更履歴

第10版ツールのマニュアルをツール別の独立した構成にし、変更履歴とバージョン別の機能差を追加した
第9版Azure Key VaultでOAuth証明書を管理する手順を追加
第8版MCP OAuthの導入手順に証明書の生成方法を追加
第7版IndexCreator の操作手順と MCP OAuth v0.2.0 の接続方法を更新する
第6版ツールの取扱説明で、カタカナで通じる用語(バージョン・ユーザー・フォント・リダイレクト URI など)を日本語に直しすぎないよう修正
第5版ツールの取扱説明の用語を、日本語に寄せすぎない表記に修正
第4版MCP OAuth ラッパーのページの余分な空行を削除
第3版MCP OAuth ラッパーを Azure App Service と IIS の実機で確認済みと明記
第2版Claude の組織コネクタと ChatGPT での接続を実アカウントで確認済みと明記
第1版MCP OAuth ラッパーの導入と設定のページを追加