Oracle REST Data ServicesのRESTモジュールをRole based JWT profileで保護し、そのREST APIにMCP Inspectorでアクセスしてみます。
- シングル・ページ・アプリケーションかつパブリッククライアントフローを許可しています。そのため、クライアント・シークレットは作成していません。MCP InspectorとEntra ID間での通信なので確認できていませんが、PKCEが実行されているはずです。
- アクセス・トークンに含めるrolesクレームのメンバーを、グループからアプリロールに変更しています。アプリロールにすることで、ORDS側のロールをIDではなく名前で設定できます。
以下より確認作業について記載します。
規定のディレクトリの管理のアプリの登録を開き、新規登録を開始します。
名前はORDS MCP、リダイレクトURIにシングル・ページ・アプリケーションを選択し、 リダイレクトURIにMCP InspectorのRedirect URLを設定します。ポート番号6274が使用されている場合は、ポート番号が異なるかもしれません。
http://localhost:6274/oauth/callback
Redirect URLの値は、MCP InspectorのOAuth 2.0 Flow - Redirect URLに記載されています。
アプリ
ORDS MCPが作成されます。ここに表示されている
アプリケーション(クライアント)IDをメモしておきます。
このクライアントIDは、MCP Inspectorの
OAuth 2.0 Flow -
Client IDに設定します。
アプリORDS MCPの管理のAuthentication (Preview)を開き、設定タブを選択します。
パブリッククライアントフローを許可するを有効に切り替え、保存します。
アプリORDS MCPの管理のAPIの公開を開き、アプリケーションIDのURIを追加します。
デフォルトで割り当てられる
アプリケーションIDのURIを
保存します。
この値はORDS_SECURITY.CREATE_JWT_PROFILEを呼び出す際の引数p_audienceの値になります。また、oauth-protected-resourceの属性resourceに指定する値になります。
アプリ
ORDS MCPの
概要の
エンドポイントを開きます。
OpenID ConnectメタデータドキュメントのURLをコピーします。
このURLで取得できるファイルを、nginxが返す/.well-known/openid-configurationとして配置します。
URLをブラウザで開き、属性jwks_uriの値をコピーします。
この値はORDS_SECURITY.CREATE_JWT_PROFILEの引数p_jwk_urlの値になります。
OpenID ConnectメタデータドキュメントのURLの末尾にある.well-known以下を除いた部分が、oauth-protected-resourceのauthorization_serversの値になります。
あとはアクセス・トークンのissuerとなる値があれば、ORDS REST APIの保護に必要な値が集まるのですが、issuerについてはMicrosoft Entra IDのAdmin Consoleでの確認場所が不明でした。
ORDS RESTモジュールの保護はアプリロールで実施するため、アプリロールを作成します。
アプリORDS MCPの管理のアプリロールを開きます。
アプリロールの作成をクリックします。
表示名は「
ORDS REST APIの呼び出し」とし、
許可されたメンバーの種類に
ユーザーまたはグループを選択します。
値は
ORDSUsersとします。この値がアクセス・トークンの
rolesクレームに含まれます。
説明には「
ORDS REST APIの呼び出し」と記述します。
このアプリロールを有効にしますか?をチェックします。
以上で適用をクリックします。
アプリロールが作成されます。
作成したアプリロールをユーザーに割り当てます。
アプリORDS MCPの概要を開き、エンタープライズアプリケーションに移動します。
管理の
ユーザーとグループを開き、
ユーザーまたはグループの追加を開始します。
ユーザーの
選択されていませんをクリックし、ユーザーを割り当てます。
アプリロールを割り当てる
ユーザーを
選択します。
ユーザーを選択したのち、
割り当てを実行します。アプリロール「
ORDS REST APIの呼び出し」はデフォルトで選択されているようです。

ユーザーにアプリロールが割り当てられました。確認するため、ユーザーを開きます。
アプリケーションを開きます。
選択したユーザーにアプリケーション
ORDS MCPのアプリロール「
ORDS REST APIの呼び出し」が割り当たっていることを確認します。
Microsoft Entra IDでの設定は以上です。
以下のスクリプトを実行し、Oracle REST Data Servicesに権限oracle.example.mcpを作成(すでに存在する場合は再定義)します。ロールとしてORDSUsersを作成し、RESTモジュールsampleserverを保護します。
declare
l_roles owa.vc_arr;
l_modules owa.vc_arr;
l_patterns owa.vc_arr;
begin
ords.create_role(
p_role_name => 'ORDSUsers'
);
l_modules(1) := 'sampleserver';
l_roles(1) := 'ORDSUsers';
ords.define_privilege(
p_privilege_name => 'oracle.example.mcp',
p_label => 'Priviledge for MCP',
p_roles => l_roles,
p_modules => l_modules,
p_patterns => l_patterns -- no assignment
);
end;
/
issuerがわからないため、ORDS_SECURITY.CREATE_JWT_PROFILEの実行より先に、/.well-known/以下を設定します。
nginxを実行しているインスタンスに接続します。
rootユーザーで作業します。
sudo -s
[opc@apex ~]$ sudo -s
[root@apex opc]#
nginxのドキュメント・ルートに移動します。
cd /usr/share/nginx/html
[root@apex html]# cd /usr/share/nginx/html
[root@apex html]#
認証フローで参照されるファイルを配置するディレクトリを作成します。
mkdir -p .well-known/ords/apexdev/sampleserver
[root@apex html]# mkdir -p .well-known/ords/apexdev/sampleserver
[root@apex html]#
リモートMCPサーバーのアクセスパスが
/ords/apexdev/sampleserver/mcpなので、oauth-protected-resourceとして記述する内容は.well-known以下の
.well-known/ords/apexdev/sampleserver/mcpに記述します。Oktaでは、このファイルの位置が.well-known以下の
.well-known/oauth-protected-resource/ords/apexdev/sampleserver/mcpでした。
今回の実装ではサーバーが401 Unauthorizedを返すときにWWW-Authenticateヘッダーを返しません。そのため、oauth-protected-resourceの位置が定まらないのかもしれません。
ファイル
.well-known/ords/apexdev/sampleserver/mcpを作成し、以下を記述します。
{
"resource": "api://********-****-****-****-************",
"authorization_servers": {
["https://login.microsoftonline.com/********-****-****-****-************/"]
}
}
authorization_serversの設定で、JSON配列を{}で囲んでJSONオブジェクトにしています。構文的に間違っているように思いますが、こうしないとMCP Inspectorがauthorization_serversを認識しません。
OpenID Connectメタデータドキュメントをダウンロードし、
.well-known以下に配置します。
curl -OL https://login.microsoftonline.com/*******-****-****-****-***********/v2.0/.well-known/openid-configurationmv openid-configuration .well-known/[root@apex html]# curl -OL https://login.microsoftonline.com/********-****-****-****-************/v2.0/.well-known/openid-configuration
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 1965 100 1965 0 0 3286 0 --:--:-- --:--:-- --:--:-- 3291
[root@apex html]# mv openid-configuration .well-known/
[root@apex html]#
/etc/nginx/nginx.confを開き、ヘッダー情報がログに出力される
extended.logが有効になるように、
access_logのコメントを変更します。
#access_log /var/log/nginx/access.log main;
access_log /var/log/nginx/extended.log extended;
#access_log /var/log/nginx/body.log body;
nginxをリロードします。
nginx -s reload
[root@apex html]# nginx -s reload
[root@apex html]#
extended.logの出力を監視します。
tail -f /var/log/nginx/extended.log
[root@apex html]# tail -f /var/log/nginx/extended.log
MCP Inspectorを起動します。
npx @modelcontextprotocol/inspector
Transport TypeにStreamable HTTPを選択し、URLにORDSのRESTモジュールとして実装されているサンプルのMCPサーバーのURLを設定します。
https://ホスト名/ords/apexdev/sampleserver/mcp
OAuth 2.0 FlowのClient IDに、Microsoft Entra IDに作成したORDS MCPのアプリケーション(クライアント)IDを設定します。
まだJWTプロファイルを作成していないためEntra IDのサインインが成功しても、ORDS REST APIは401 Unauthorizedを返します。そのため、ギブアップするまでサインインが繰り返されます。
Connectをクリックし、認証プロセスを開始します。
サインインのプロセスが開始します。サインインするアカウントを選択します。
Authenticatorを使うように構成しているアカウントなので、通知の送信を要求されます。
Authenticatorを操作します。
サインインの状態を維持しますか?は、はいといいえのどちらを選択してもかまいません。
アクセス許可の承諾を求められます。
承諾をクリックします。
ユーザー認証に成功していると、extented.logにauthorizationヘッダーのBearerで与えられているアクセス・トークンが出力されます。ORDSは必ず401を返すため、何度もサインインを繰り返します。アクセス・トークンが取得できた時点で、MCP InspectorをCtrl+Cで中断します。
jwt.ioにアクセスし、アクセス・トークンをデコードします。
デコードされたアクセス・トークンの内容を確認します。
最初に、ORDS_SECURITY.CREATE_JWT_PROFILEの引数p_issuerの値になるiss属性を確認します。
iss属性は問題ありませんが、以下の2つの問題が見つかりました。
- aud属性つまりaudienceがapi://で始まる値になっていない。
- アクセス・トークンにrolesクレームが含まれていない。
Microsoft Entra IDでは、アクセス・トークンのaud属性(audience)を
アプリケーション(クライアント)IDとするには、そのアプリケーションに作成したスコープをリクエストに含める必要があるようです。(
Microsoft Entra IDについて、それほど詳しくはないので、違う可能性もあります。)
そのため、JWTプロファイルの保護には使用しませんが、スコープを作成します。
アプリORDS MCPの管理のAPIの公開を開き、Scopeの追加をクリックします。
スコープ名は
oracle.example.dummy.mcpとします。
同意できるのはだれですか?は
管理者とユーザー、
管理者の同意の表示名は
Entra IDのaudience設定用、
管理者の同意の説明は
Entra IDのaudience設定用とします。とします。
状態は
有効とします。
以上で、
スコープの追加をクリックします。
追加されたスコープをコピーします。
このスコープは
MCP Inspectorの
OAuth 2.0 Flowの
Scopeに指定します。
アクセス・トークンからissuerの値が取得できたので、ORDS_SECURITY.CREATE_JWT_PROFILEを実行します。引数p_role_claim_nameには/rolesを指定します。
begin
ords_security.delete_jwt_profile;
ords_security.create_jwt_profile(
p_issuer => 'issの値'
,p_audience => 'audの値'
,p_jwk_url => 'jwks_uriの値'
,p_role_claim_name => '/roles'
);
end;
/
ビューUSER_ORDS_JWT_PROFILEを検索し、設定内容を確認します。
select issuer,audience,jwk_url,role_claim_name from user_ords_jwt_profile
OAuth 2.0 Flowにaudienceを含むスコープが設定されていると、MCP InspectorでのOAuth2の認証が成功します。audienceが適切に選択されていると、アクセス・トークンにrolesクレームとアプリロールORDSUsersが含まれるようになります。
以上でRole based JWT profileで保護したORDS REST APIを、MCP Inspectorでアクセスできました。
Microsoft Entra IDではスコープの指定が必須であったため、ChatGPTのアプリとコネクターまたはClaude Desktopのカスタムコネクタとして使用するのは難しそうです。
Oracle Linux 10との違い
Oracle Linux 10ではデフォルトでfirewalldが実行されます。以下のようにfirewalldを無効化することもできますが、今回はhttpとhttpsへの接続許可を与えています。
[opc@apex ~]$ sudo systemctl stop firewalld
[opc@apex ~]$ sudo systemctl disable firewalld
Removed '/etc/systemd/system/multi-user.target.wants/firewalld.service'.
Removed '/etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service'.
[opc@apex ~]$
以下、実行したコマンドです。
[opc@apex ~]$ sudo firewall-cmd --add-service=https
success
[opc@apex ~]$ sudo firewall-cmd --add-service=http
success
[opc@apex ~]$ sudo firewall-cmd --runtime-to-permanent
success
[opc@apex ~]$ sudo firewall-cmd --reload
success
[opc@apex ~]$ sudo firewall-cmd --list-all
public (default, active)
target: default
ingress-priority: 0
egress-priority: 0
icmp-block-inversion: no
interfaces: enp0s5
sources:
services: dhcpv6-client http https ssh
ports:
protocols:
forward: yes
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
[opc@apex ~]$
Rocky Linux 10ではcertbotを含むリポジトリを追加するために
epel-releaseをインストールしました。Oracle CloudのComputeインスタンスのOracle Linux 10にはEPELのリポジトリが構成されていたため、以下のコマンドで有効化しています。
sudo dnf config-manager --enable ol10_u0_developer_EPEL
[opc@apex ~]$ sudo dnf config-manager --enable ol10_u0_developer_EPEL
[opc@apex ~]$
リポジトリol10_u0_developer_EPELはファイル/etc/yum.repos.d/oracle-epel-ol10.repoで定義されています。リポジトリ名にu0(baseurlにも0が含まれる)が含まれているため、Oracle Linux 10のリリースが10.1、10.2と上がっていくと名前が変わるかもしれません。
その他では、Computeインスタンス作成時にブート・ボリュームのサイズを100GBに変更しました。Oracle Cloudではブート・ボリュームのサイズを拡張しても、作成されたインスタンスのファイル・システムのサイズはそのままなので、ルート・ファイル・システムのサイズを拡張しています。この手順については、他に解説があると思うので割愛します。
今回の記事は以上になります。
完