2026年7月10日金曜日

ORDS 26.2のMCPサーバーを構成する - Microsoft Entra ID編

先日の記事「ORDS 26.2のMCPサーバーを構成する - Auth0編」では、MCPサーバーの認証/認可にAuth0を使用しました。今回の記事では、IdMとしてMicrosoft Entra IDを使用します。

ORDS MCPサーバーから接続するデータベースおよびORDSのコンテナの準備は、記事「ORDS 26.2のMCPサーバーを構成する - Auth0編」と同じです。ORDS MCPサーバーが動作するコンテナを実行しAuth0の構成を始める直前まで、Auth0の記事にそって作業を進めます。

ORDS MCPサーバーへの接続確認にMCP Inspectorを使用します。検証結果を先に書くと、Microsoft Entra IDが発行したアクセス・トークンでORDS MCPサーバーへ接続できませんでした。最終的に以下の課題が残りました。
  • ORDS MCPサーバーは、アクセス・トークンの"scope"クレームにグローバル・スコープ "urn:oracle:dbtools:ords:mcpserver:all" が含まれることを期待しているようです。Microsoft Entra IDが発行するアクセス・トークンは"scp"クレームにグローバル・スコープを含みます。Oktaも同様の仕様ですが、Oktaではカスタム・クレームとして"scope"を追加できました。Entra IDではClaims Mapping Policyで対応できる可能性はありますが、検証で使用しているFreeライセンスでは確認できません。
  • ORDS MCPサーバーは、アクセス・トークンの"aud"クレームの値がMCPサーバーのエンドポイントURLであることを期待しているようです。Microsoft Entra IDが発行するアクセス・トークンの"aud"クレームの値は、アプリケーション(クライアント)IDになります。アクセス・トークンのバージョンを1にすると対応できるかもしれませんが、その場合は、アプリケーションIDのURIにhttp://localhost:8585/mcpを設定できません。
MCP InspectorでORDS MCPサーバーにアクセスし、Microsoft Entra IDからアクセス・トークンを取得するまでが確認できた内容です。

以下より、構成作業について紹介します。


WWW-Authenticateヘッダーのワークアラウンド



ORDS MCPサーバー(エンドポイントURLはhttp://localhost:8585/mcp)にアクセス・トークン無しでアクセスしたときに、以下のWWW-Authenticateヘッダーが返されます。

確認のために実行したcurlコマンドです。

curl -v -X POST http://localhost:8585/mcp |& grep WWW-Authenticate:

ords-mcp2 % curl -v -X POST http://localhost:8585/mcp |& grep WWW-Authenticate:

< WWW-Authenticate: Bearer error="invalid_request", resource_metadata="http://localhost:8585/.well-known/oauth-protected-resource/mcp", scope="urn:oracle:dbtools:ords:mcpserver:all"

ords-mcp2 % 


WWW-Authenticateヘッダーに含まれるscope属性として、ORDS MCPサーバーのグローバル・スコープurn:oracle:dbtools:ords:mcpserver:allが返されています。Microsoft Entra IDではscopeはアプリケーションID URIで修飾される必要があります。

今回の作業ではアプリケーションID URIhttp://localhost:8585/mcpと設定しています。そのため、scopeの値は http://localhost:8585/mcp/urn:oracle:dbtools:ords:mcpserver:all になります。

ワークアラウンドとして、OpenRestyのリバース・プロキシでWWW-Authenticateヘッダーを入れ替えています。

ORDS MCPサーバーを実行しているコンテナに接続し、OpenRestyの構成ファイルをエディタで開きます。

docker exec -it ords-mcp bash
vi /usr/local/openresty/nginx/conf/nginx.conf

ords-mcp2 % docker exec -it ords-mcp bash

[oracle@a7bdb9847eb3 ~]$ vi /usr/local/openresty/nginx/conf/nginx.conf


コメントのTemporary workaround for Entra ID以下の2行のコメント・アウトを外します。
            # Temporary workaround for Microsoft Entra ID
            more_set_headers -s '401'
                'WWW-Authenticate: Bearer error="invalid_request", resource_metadata="http://localhost:8585/.well-known/oauth-protected-resource/mcp", scope="http://localhost:8585/mcp/urn:oracle:dbtools:ords:mcpserver:all"';
変更を保存したのち、コンテナを抜けて再起動します。

exit
docker restart ords-mcp

[oracle@a7bdb9847eb3 ~]$ exit

exit

ords-mcp2 % docker restart ords-mcp

ords-mcp

ords-mcp2 % 


再度curlコマンドを実行し、WWW-Authenticateヘッダーのscope属性が変更されていることを確認します。

ords-mcp2 % curl -v -X POST http://localhost:8585/mcp |& grep WWW-Authenticate:

< WWW-Authenticate: Bearer error="invalid_request", resource_metadata="http://localhost:8585/.well-known/oauth-protected-resource/mcp", scope="http://localhost:8585/mcp/urn:oracle:dbtools:ords:mcpserver:all"

ords-mcp2 % 


変更が確認できればワークアラウンドの適用は完了です。

Dockerfileを修正してコンテナ・イメージを作成し直すと、コンテナを作成するたびにnginx.confを修正する手間を省けます。


Microsoft Entra IDのアプリケーション構成



作業の多くは記事「Role based JWT profileで保護したORDS REST APIにアクセスする - Microsoft Entra ID編」と重なりますが、省略せずに紹介します。

Microsoft Azureのコンソールより、Microsoft Entra IDを開きます。

サイド・メニューの管理アプリの登録を開き、新規作成を実行します。


名前ORDS MCP2とします。APIに対応するアプリケーションであるため、リダイレクトURIは設定しません。リダイレクトURIは、この後に作成するクライアントに対応するアプリケーションORDS MCP2 Clientに設定します。

アプリケーションを登録します。


マニフェストを開き、アクセス・トークンのバージョンを2に変更します。


マニフェスト(Microsoft Graphアプリマニフェスト)の"api"に含まれる"requestedAccessTokenVersion"の値を2に変更します。

変更後、保存します。


以上で、アプリケーションIDのURIとしてhttp://localhost:8585/mcpを設定できるようになりました。

APIの公開を開き、アプリケーションIDのURI追加します。


アプリケーションIDのURIhttp://localhost:8585/mcpを設定します。

保存をクリックします。


ORDS MCPサーバーのグローバル・スコープ urn:oracle:dbtools:ords:mcpserver:all を追加します。

Scopeの追加をクリックします。


スコープ名urn:oracle:dbtools:ords:mcpserver:allです。同意できるのはだれですか?管理者とユーザーを選択します。

管理者の同意の表示名管理者の同意の説明の双方に「Access to ORDS MCP Server」と記述します。

状態有効を選択し、スコープの追加を実行します。


ORDS MCPサーバーのアクセス制御にロールを使用します。Microsoft Entra IDでは、アプリロールとしてORDS_MCP_HRを作成し、利用できるコネクション・プールを制御します。アプリロールは、アクセス・トークンのrolesクレームに含まれます。

アプリロールを開き、アプリロールの作成をクリックします。


表示名Sample Schema Human Resources許可されたメンバーの種類両方(ユーザー/グループ+アプリケーション)を選択します。

ORDS_MCP_HR説明Sample Schema Human Resourcesと記述します。

このアプリロールを有効にしますか?チェックし、適用をクリックします。


作成したアプリロールORDS_MCP_HRをEntra IDのユーザーに割り当てます。

ユーザーへのアプリロールの割り当ては、エンタープライズアプリケーションに移動して実施します。

概要から、ローカルディレクトリでのマネージドアプリケーションのリンクを開きます。


管理ユーザーとグループを開き、ユーザーまたはグループの追加をクリックします。


ユーザー選択されていませんをクリックし、ユーザーを選択します。


先ほど作成したアプリロールORDS_MCP_HRを割り当てるユーザーを選択し、選択をクリックします。


割り当てるロール「Sample Schema Human Resources」(値はORDS_MCP_HR)は、すでに選択されています。

割り当てをクリックします。


以上でユーザーにアプリロールORDS_MCP_HRが割り当てられました。

規定のディレクトリに戻り、アプリの登録を開きます。すべてのアプリケーションから、先ほど作成したORDS MCP2を開きます。


APIのアクセス許可を開き、アクセス許可の追加をクリックします。


所属する組織で使用しているAPIを開き、ORDS MCP2を探して選択します。


アプリケーションの許可を選択します。

アクセス許可としてアプリロールORDS_MCP_HRが表示されます。このORDS_MCP_HRチェックして、アクセス許可の追加を実行します。


アクセス許可ORDS_MCP_HRが追加されました。

アクセス許可の追加を再度クリックします。


先ほどと同様に、所属する組織で使用しているAPIを開き、ORDS MCP2を探して選択します。

今度は委任されたアクセス許可を選択し、アクセス許可として表示されたORDS MCPサーバーのグローバル・スコープ urn:oracle:dbtools:ords:mcpserver:all をチェックして、アクセス許可の追加を実行します。


以上でアクセス許可の設定ができました。


Microsoft Entra IDが発行するアクセス・トークンに、ユーザーを一意に識別できるクレームとしてupnを含めます。

Auth0、Okta、Oracle IAMが発行するアクセス・トークンではsub(subject)クレームの値によりユーザーを識別できますが、Microsoft Entra IDではsubクレームでユーザーを一意に識別するのは困難です。

ORDSのJWTプロファイルによる認証および認可の仕組みでは、Microsoft Entra IDのアクセス・トークンのupnクレームの値をユーザーの識別子として認識します。ORDS MCPサーバーについてはMicrosoft Entra IDでの接続ができなかったため、upnクレームをユーザーの識別子として認識するかどうか不明ですが、アクセス・トークン(およびIDトークン)にupnクレームを追加しておきます。

トークン構成を開き、オプションの要求の追加をクリックします。


トークンの種類アクセスを選択し、要求に含まれるupnをチェックします。これはOAuth2のアクセス・トークンに、クレームとしてupnを追加するという作業です。

以上で追加をクリックします。


Microsoft Graph profileのアクセス許可を有効にしますチェックして、追加します。


アクセス・トークンに要求としてupnが追加されました。

要求upnに設定される値を調整します。要求upn3点メニューをクリックし、編集を実行します。


UPNの編集画面で、外部認証済みはいハッシュ記号の置換はいに設定します。

以上で保存します。


必ずしも必要ではないようですが、IDトークンについても同様の操作を行い、クレームとしてupnを追加します。

オプションの要求としてupnが、IDトークンアクセス・トークンに追加されました。


次にクライアントに対応したアプリケーションを作成します。

規定のディレクトリ管理アプリの登録を開き、新規登録を実行します。


作成するアプリケーションの名前ORDS MCP2 Clientとします。リダイレクトURIは複数のURIを設定するため、ここでの設定は省略します。

以上で登録します。


アプリケーションORDS MCP2 Clientが作成されます。

後ほどAPIのアプリケーションORDS MCP2への紐付けに使うため、アプリケーション(クライアント)IDをコピーしておきます。その後に、リダイレクトURIを追加するのリンクを開きます。


リダイレクトURIを構成します。

今回はMCPクライアントとしてMCP Inspectorを使用します。

リダイレクトURIの追加をクリックし、MCP InspectorのリダイレクトURIを追加します。


MCP Inspectorでは、プラットフォームにシングルページアプリケーションを選択します。


以下のURIをリダイレクトURIとして設定し、構成を実行します。

http://localhost:6274/oauth/callback
http://localhost:6274/oauth/callback/debug

2つのURIを構成するため、2回同じ操作を実施します。


MCP InspectorのリダイレクトURIが設定できました。

設定を開き、パブリッククライアントフローを許可します。


パブリッククライアントフローを許可する有効にし、変更を保存します。


アプリの登録に戻り、アプリケーションORDS MCP2を開きます。


APIの公開を開き、クライアントアプリケーションの追加を実行します。


クライアントIDに、クライアントに対応するアプリケーションORDS MCP2 Clientアプリケーション(クライアント)IDを設定します。

承認済みのスコープをチェックし、アプリケーションの追加を実行します。


承認済みのクライアント・アプリケーションとしてORDS MCP2 Clientが追加されます。


以上でEntra IDの設定は完了です。

ORDS MCPサーバーを構成するグローバル・プロパティの値を確認します。

アプリケーションORDS MCP2概要を開き、エンドポイントを開きます。


エンドポイントのOpenID Connectメタデータドキュメントに注目します。


OpenID Connectメタデータドキュメントを返すURLの末尾の/.well-known/openid-configurationを除いた部分が、グローバル・プロパティmcp.security.jwt.profile.authorization.server.urlの値になります。

mcp.security.jwt.profile.authorization.server.url = https://login.microsoftonline.com/[テナントID]/v2.0

OpenID Connectメタデータドキュメントをブラウザで開きます。


属性issuerの値が、グローバル・プロパティmcp.security.jwt.profile.issuerの値になります。

mcp.security.jwt.profile.issuer = https://login.microsoftonline.com/[テナントID]/v2.0

属性jwks_uriの値が、グローバル・プロパティmcp.security.jwt.profile.jwk.urlの値になります。

mcp.security.jwt.profile.jwk.url = https://login.microsoftonline.com/[テナントID]/discovery/v2.0/key

グローバル・プロパティmcp.security.jwt.profile.audienceの値はhttp://localhost:8585/mcpです。

mcp.security.jwt.profile.audience = http://localhost:8585/mcp

グローバル・プロパティmcp.security.jwt.profile.role.claim.nameの値は/rolesです。

mcp.security.jwt.profile.role.claim.name = /roles

以上で、ORDS MCPサーバーを構成するグローバル・プロパティの値についても収集できました。



ORDS MCPサーバーの構成




ORDSの構成に移ります。

コンテナに接続して、ORDSの構成コマンドを実行します。

docker exec -it ords-mcp bash

ords-mcp2 % docker exec -it ords-mcp bash

[oracle@a7bdb9847eb3 ~]$ 


ORDSのグローバル・プロパティを設定します。xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxxxxxの部分は、テナントIDに置き換えます。
ords --config /etc/ords/config config set --global feature.mcp true
ords --config /etc/ords/config config set --global mcp.security.jwt.profile.issuer https://login.microsoftonline.com/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxxxxx/v2.0
ords --config /etc/ords/config config set --global mcp.security.jwt.profile.audience http://localhost:8585/mcp
ords --config /etc/ords/config config set --global mcp.security.jwt.profile.jwk.url https://login.microsoftonline.com/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxxxxx/discovery/v2.0/keys
ords --config /etc/ords/config config set --global mcp.security.jwt.profile.authorization.server.url https://login.microsoftonline.com/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxxxxx/v2.0
ords --config /etc/ords/config config set --global mcp.security.jwt.profile.role.claim.name /roles
続いて、スキーマHRに接続するコネクション・プールとしてmcp-hrを構成します。ORDS MCPサーバーはコンテナ内で実行されているため、コンテナ外にあるデータベースの接続先としてhost.docker.internalを設定しています。

ロールによるアクセス制御を行うため、mcp.roleORDS_MCP_HRを設定しています。
ords --config /etc/ords/config config --db-pool mcp-hr set db.connectionType basic
ords --config /etc/ords/config config --db-pool mcp-hr set db.hostname host.docker.internal
ords --config /etc/ords/config config --db-pool mcp-hr set db.port 1521
ords --config /etc/ords/config config --db-pool mcp-hr set db.servicename freepdb1
ords --config /etc/ords/config config --db-pool mcp-hr set db.username HR
ords --config /etc/ords/config config --db-pool mcp-hr set db.description "Sample Schema Human Resources"
ords --config /etc/ords/config config --db-pool mcp-hr set mcp.role ORDS_MCP_HR
コネクション・プールmcp-hrがデータベースに接続する際に使用するパスワードを設定します。スキーマHRに設定したパスワードです。

ords --config /etc/ords/config config --db-pool mcp-hr secret db.password

[oracle@aeba9d22c0f9 ~]$ ords --config /etc/ords/config config --db-pool mcp-hr secret db.password


ORDS: Release 26.2 Production on Wed Jul 08 06:44:35 2026


Copyright (c) 2010, 2026, Oracle.


Configuration:

  /etc/ords/config


Enter the database password: ********

Confirm password: ********

[oracle@aeba9d22c0f9 ~]$ 


コンテナから抜けて再起動します。

exit
docker restart ords-mcp


[oracle@a7bdb9847eb3 ~]$ exit

exit

ords-mcp2 % docker restart ords-mcp

ords-mcp

ords-mcp2 % 




MCP Inspectorによる接続確認



MCP Inspectorを起動し、MCPサーバーに接続します。

npx @modelcontextprotocol/inspector

ORDS MCPサーバーに接続するにあたって、以下を設定します。

Transport Type: Streamable HTTP
URL; http://localhost:8585/mcp
Connection Type: Direct
OAuth2 2.0 Flow Client ID: アプリケーションORDS MCP2 Clientのアプリケーション(クライアント)ID
Scope: http://localhost:8585/mcp/urn:oracle:dbtools:ords:mcpserver:all

OAuth2 2.0 Flow Client IDに設定する値は、アプリケーションORDS MCP2 Clientの概要にあるアプリケーション(クライアント)IDから取得します。


ここでConnectをクリックしても、Entra IDに発行してもらったアクセス・トークンではhttp://localhost:8585/mcpのPOSTリクエストが401 Unauthorizedを返すため、認証しては失敗を繰り返します。

アクセス・トークンの取得までの動作を確認するため、Open Auth Settingsをクリックします。


Quick OAuth Flowを実行します。


Entra IDへのサインインを求められます。


OAuth Flow ProgressAuthentication Completeまで進みます。

Authentication Completeの下にAccess Tokenのノードがあります。開くと、Entra IDが発行したアクセス・トークンを参照できます。


発行されたアクセス・トークンをjwt.ioなどのJWTデバッガで確認すると、audクレームはアプリケーションORDS MCP2のアプリケーション(クライアント)IDであること、グローバル・スコープ urn:oracle:dbtools:ords:mcpserver:all scpクレームで渡されていること、upnクレームが含まれていること、rolesクレームにロールORDS_MCP_HRが含まれていることが確認できます。


今回の記事は以上になります。