MCP OAuth ラッパーの導入と設定
プリザンターの 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. 配置して起動を確認する
Windows または Linux に ASP.NET Core Runtime 10 を入れます。.NET Runtime だけでは足りず、ASP.NET Core Runtime が必要です。
Release ページで使うバージョンを選び、Assets の ZIP を取得して展開します。ZIP の名前は v0.3.2 以降が
VehicleVision.PleasanterTools.McpOAuthWrapper-<バージョン>-portable.zip、v0.3.1 以前がMcpOAuthWrapper.zipです。Source code の ZIP は配布アプリではありません。展開先(
VehicleVision.PleasanterTools.McpOAuthWrapper.dll、appsettings.json、App_Data/Parametersが直下にある場所)をカレントにして、接続を無効にした初期設定のまま起動します。textdotnet VehicleVision.PleasanterTools.McpOAuthWrapper.dll --urls http://127.0.0.1:5180http://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 をコピーして編集します。
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{
"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 ごとの接続文字列の例です(値は例示です)。
| DBMS | UserConnectionString の例 |
|---|---|
| SQL Server | Server=sql.example;Database=Implem.Pleasanter;User ID=mcp_reader;Password=CHANGE_ME;Encrypt=True |
| PostgreSQL | Host=pg.example;Database=Implem.Pleasanter;Username=mcp_reader;Password=CHANGE_ME;Search Path='"Implem.Pleasanter"' |
| MySQL | Server=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 なら共通アカウントの選択肢を出さない |
StateStore | OAuth の状態の保存先。Sqlite(既定)または Redis(Valkey 互換 KVS 可) |
StateDirectory | SQLite モードの 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) |
CertificatePassword | 2枚の PFX に共通のパスワード。Key Vault の証明書から取得する PFX では空。General.json に平文で書かず、環境変数 MCP_GENERAL_CertificatePassword か秘密管理から渡す |
TrustedProxyAddresses | HTTPS を終端するプロキシの送信元 IP の一覧(転送ヘッダーを 1 段だけ信頼) |
AllowedOrigins | MCP リクエストで許可する Origin の追加一覧(完全一致)。既定で同一 Origin と Origin なしは許可 |
Clients | 事前登録する OAuth クライアント(ClientId・DisplayName・RedirectUris) |
AllowDynamicClientRegistration / AllowedRedirectUris | 動的クライアント登録(DCR)を使うか、許可するリダイレクト URI の一覧 |
MaxDynamicClients | DCR で作れるクライアント数の上限。初期値 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。相対パスはアプリのコンテンツルート基準 |
| Base64 | SigningCertificateBase64/EncryptionCertificateBase64 | PFX 全体の Base64。メモリ上で読み込む |
| Windows 証明書ストア | SigningCertificateThumbprint/EncryptionCertificateThumbprint | Windows のみ。非エクスポート鍵も使える |
| クラウド | SigningCertificateCloud/EncryptionCertificateCloud | Azure・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 年間に設定します。パスワードは画面に表示せず入力します。
$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 などの絶対パスに置き換えます。
{
"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 桁に置き換えます。
{
"SigningCertificateThumbprint": "<署名証明書の拇印>",
"EncryptionCertificateThumbprint": "<暗号化証明書の拇印>",
"CertificateStoreName": "My",
"CertificateStoreLocation": "LocalMachine"
}既定は My/CurrentUser です。IIS では LocalMachine を選び、アプリケーションプールの実行アカウントに秘密鍵の読み取り・利用権限を付けます。秘密鍵はエクスポートできなくても、OS の暗号プロバイダー経由で署名・復号できます。Windows 以外では使えません(Linux のキーストアは対象外)。
クラウドのシークレットから読み込む
Azure・AWS・GCP・OCI のシークレットに入れた PFX を、各社の SDK で起動時に取得します。取得した PFX はローカルに保存せず、メモリ上で読み込みます。クラウド側でバージョンを変えても、反映には再起動が必要です。環境変数で渡すときは、階層を __ で区切ります(例: MCP_GENERAL_SigningCertificateCloud__Provider)。
| Provider | SecretId | 備考 |
|---|---|---|
Azure | https://<vault>.vault.azure.net/secrets/<名前>/<バージョン>(/secrets/ の URI。バージョンは省略可) | Version は使わず URI に含める。認証は DefaultAzureCredential |
AWS | シークレットの ARN など | Region 必須。Version 空なら AWSCURRENT。SecretBinary の PFX、または SecretString に PFX 全体の Base64。JSON の SecretString は不可 |
GCP | projects/<project>/secrets/<名前>/versions/<番号 or latest> | Version は空にする。シークレットのペイロードに PFX のバイト列。認証は Application Default Credentials |
OCI | シークレットの OCID | Region 必須。Version は正の整数(空なら現在の版)。内容は Base64。OciAuthentication は InstancePrincipal(既定)・ResourcePrincipal・ConfigFile |
Azure の設定例です。
{
"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-resource | discovery(保護リソースのメタデータ) |
/.well-known/oauth-authorization-server | discovery(認可サーバーのメタデータ) |
そのうえで、個人のアカウントと共通アカウントの両方で接続し、プリザンター側の権限と監査の主体、API キーの再発行・削除、アカウントの無効化が意図どおり効くことを確かめます。
配置先ごとの注意
Azure App Service(Windows)
.NET 10 の Windows App Service に置けます。
HTTPS のみを有効にし、対応するプランでは Always On を有効にします。SQLite モードではインスタンス数を 1 に固定します。
プライベートな DB には VNet 統合などで経路を作り、Users の必要列だけ読める接続を用意します。
Issuerは App Service の公開 HTTPS URL にします。秘密はアプリ設定のMCP_RDS_UserConnectionString・MCP_GENERAL_CertificatePasswordで渡します。証明書は、自動生成(v0.3.0 以降の既定)、後述の Key Vault 方式、または前述のファイル配置方式から選びます。状態の置き場と、自動生成・ファイル方式の PFX は、Kudu で確認した
%HOME%配下(例data/McpOAuthWrapper)に置き、StateDirectoryと証明書パスに絶対パスで書きます。更新で上書きされるwwwrootには置かないでください。DLL と
web.configが直下にある ZIP を作り、ZIP デプロイします。秘密入りの ZIP は公開しません。textaz webapp deploy --resource-group <リソースグループ> --name <アプリ名> --src-path <配置ZIP> --type zipアプリ設定に
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 などの作成権限が必要です。
$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_ENVIRONMENT | Production |
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
- IIS を有効にしたあと、.NET 10 の Hosting Bundle を入れて IIS を再起動します(ASP.NET Core Runtime 単体では IIS 用モジュールが入りません)。
- 配布物を
C:\Apps\McpOAuthWrapperのような場所に展開し、生成済みのweb.configを保持します。 - 専用のアプリケーションプールを作ります。.NET CLR は「マネージドコードなし」、32 ビットアプリケーションは無効、ワーカープロセス数は 1 にし、SQLite の状態を同時に触らないよう重複リサイクルを無効にします。
- 専用サイトに HTTPS バインドと公開用証明書を設定し、匿名認証を有効にします。
Issuerはこのサイトのルートの HTTPS URL です。 - 状態の置き場(例
C:\ProgramData\McpOAuthWrapper\State)と OAuth 用 PFX は配置先の外の保護したフォルダーに置きます。IIS AppPool\<プール名>に、アプリと証明書の読み取り、状態の置き場の変更権限を付けます。 - 接続文字列と証明書パスワードは、保護したパラメータファイルかプロセスの環境変数で渡します。
更新するときは、サイトを停止するか app_offline.htm を置いて止まったことを確認し、状態・設定・証明書を残して配布物を入れ替えます。終わったら app_offline.htm を消して再起動します。
複数台構成(Redis/Valkey 互換 KVS)
既定の SQLite モードは単一インスタンス専用です。ログイン試行制限のロックもプロセス内だけなので、複数台にすると制限が台ごとに別になります。複数台にするときは、OAuth の状態を KVS に置きます。プリザンターの Users を読む Rds.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 が 501 | General.json の Enabled が false のままではないか |
| 接続が 400 | Issuer と、公開ホスト・HTTPS・転送ヘッダーが一致しているか |
| ログインできない | 入力した API キー、キー所有者の状態、TenantId。失敗が続いたら 15 分待つ |
| 共通アカウントのキーが使えないと表示される | 共通アカウントのキー発行、アカウントの状態、TenantId |
| DB 接続エラー | Dbms、読み取り専用接続、Users の SELECT 権限、ネットワーク経路 |
| 起動時に「証明書を読み込めません」と出る(v0.3.0 以降) | 用途ごとに方式が 1 つだけか、PFX・パスワード・秘密鍵・有効期限、保存先の権限、クラウドの認証と権限、Key Vault 参照が解決されているか |
| AI アプリが接続できない | 登録したリダイレクト URI の完全一致、PKCE S256、公開 URL と証明書 |
関連ページ
- 機能とバージョンの対応 — 版ごとの機能差と、版ごとの互換性
- 変更履歴 — v0.1.0 から最新版までの変更と、更新時の作業
- プリザンターの MCP — MCP サーバの仕組みとツール、安全な公開のしかた
- Claude・ChatGPT から接続する — AI アプリ側の登録手順と、接続時の画面