Oracle REST Data ServicesのRESTモジュールをRole based JWT profileで保護し、そのREST APIにMCP Inspectorでアクセスしてみます。
元にしている記事は以下の2本です。
OktaのOIDC認証にてAPEXアプリとそれから呼び出すORDSのREST APIを認証する
Oracle REST Data ServicesのRole based JWT profileによる保護を確認する
https://apexugj.blogspot.com/2025/12/protecting-ords-by-role-based-jwt-profile.html
記述が重複しますが、Okta Integratorでの確認作業について記載します。
OktaのAdmin Consoleよりグループを開き、グループを追加します。
グループの名前はORDSUsers、説明は「ORDS REST APIへのアクセスを許可」と記述します。
グループに再度アクセスし、グループ一覧を更新します。
作成したグループORDSUsersを開き、ユーザーを割り当てます。
グループORDSUsersにユーザーを割り当てます。
ユーザーの割り当てを完了します。
アプリケーション・メニューのアプリケーションを開き、アプリ統合を作成します。
サインイン方法としてOIDC - OpenID Connectを選択します。OIDCを選択するとアプリケーションタイプの選択が現れます。アプリケーションタイプはシングルページアプリケーションを選択します。
次へ進みます。
アプリ統合を設定します。
アプリ統合名をORDS MCPとします。付与タイプのリフレッシュトークンにチェックを入れます。
サインインリダイレクトURIにMCP InspectorのRedirect URLを設定します。ポート番号6274が使用されている場合は、ポート番号が異なるかもしれません。サインアウトリダイレクトURIは何を設定すべきか不明なので、x をクリックして削除しておきます。
割り当てのアクセス制御として選択されたグループにアクセスを制限を選択し、選択されたグループに先ほど作成したグループORDSUsersを含めます。
以上を設定し保存します。
アプリ統合としてORDS MCPが作成されます。
クライアントIDはMCP InspectorのOAuth 2.0 FlowのClient IDに設定する値です。メモしておきます。
MCP Inspectorの以下の場所です。
セキュリティのAPIを開き、認証サーバーを追加します。(タブには認可サーバーと書いてあります)
追加する認証サーバーの名前はORDSMCP、オーディエンスはapi://ordsmcp(本来ordsmcpの部分はGUIDなど、世界で一意になる値を割り当てるのが望ましい)とします。説明としてAuthentication Server for ORDS MCPを入力します。
このオーディエンスの値が、ORDS_SECURITY.CREATE_JWT_PROFILEを呼び出す際の引数
p_audienceの値になります。また、
oauth-protected-resourceの属性
resourceに指定する値になります。
以上で保存します。
追加された認証サーバーの設定タブを開き、メタデータURIを確認します。
このURLで取得できるファイルを、nginxが返す/.well-known/oauth-authorization-serverとして配置します。
URLをブラウザで開き、属性jwks_uriの値をコピーします。
この値はORDS_SECURITY.CREATE_JWT_PROFILEの引数p_jwk_urlの値になります。
また、属性issuerをの値をコピーします。この値はORDS_SECURITY.CREATE_JWT_PROFILEの引数p_issuerの値になります。
メタデータURLの末尾にある
.well-known以下を除いた部分が、
oauth-protected-resourceの
authorization_serversの値になります。
以上でORDS REST APIの保護に必要な値が集まりました。
クレームタブを開き、クレームを追加します。
追加するクレームの名前はrolesとします。トークンタイプに含めるはアクセス・トークンです。
値タイプにグループを選択し、フィルターは次で始まるでORDSを設定します。このフィルターにより、rolesクレームに先ほど作成したグループORDSUsersが含まれます。
クレームを無効化はチェックせず、含めるはいずれかのスコープを選択します。
同様の手順でscopeクレームを追加します。
追加するクレームの名前はscopeとします。トークンタイプに含めるにアクセストークン、値タイプに式を選択し、値として以下を記述します。
String.replace(Arrays.toCsvString(access.scope),","," ")
クレームを無効化はチェックせず、含めるはいずれかのスコープを選択します。
以上で作成します。
rolesクレームとscopeクレームが作成されました。
ポリシーの名前はORDS MCPとします。説明に「ORDS MCP」と記述し、次に割り当てるに次のクライアントを選択し、クライアントにORDS MCPを含めます。
アクセスポリシーとしてORDS MCPが作成されました。
ルール名はDefaultとします。デフォルトの設定は変更せず(最低限コア付与の認証コードがチェックされていれば動くはず)、ルールを作成します。
アクセス・ポリシーORDS MCPとルールDefaultが作成されます。
以上でOktaの設定は完了です。
ロール・ベースJWTプロファイルを設定します。
ORDS_SECURITY.CREATE_JWT_PROFILEを実行します。それぞれの引数には、今まで集めた設定値を割り当てます。
begin
ords_security.delete_jwt_profile;
ords_security.create_jwt_profile(
p_issuer => 'https://integrator-********.okta.com/oauth2/******************'
,p_audience => 'api://ordsmcp'
,p_jwk_url => 'https://integrator-********.okta.com/oauth2/******************/v1/keys'
,p_role_claim_name => '/roles'
);
end;
/
ビューUSER_ORDS_JWT_PROFILEを検索し、設定した内容を確認します。
select issuer,audience,jwk_url,role_claim_name from user_ords_jwt_profile
以下のスクリプトを実行し、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;
/
nginxを実行しているインスタンスに接続し、/.well-known/以下を設定します。
sudo -s
[opc@apex ~]$ sudo -s
[root@apex opc]#
nginxのドキュメント・ルートに移動します。
cd /usr/share/nginx/html[root@apex opc]# cd /usr/share/nginx/html
[root@apex html]#
ディレクトリ.well-knownがすでに存在すれば名称を変えて保存し、新たに.well-knownを作成します。
mv .well-known well-known.bak
mkdir .well-known
[root@apex html]# mv .well-known well-known.bak
[root@apex html]# mkdir .well-known
[root@apex html]#
リモートMCPサーバーのアクセスパスが
/ords/apexdev/sampleserver/mcpなので、
oauth-protected-resourceとして記述する内容は
.well-known以下の
.well-known/oauth-protected-resource/ords/apexdev/sampleserver/mcpに記述します。Entra IDでは、このファイルの位置が.well-known以下の.well-known/ords/apexdev/sampleserver/mcpでした。
今回の実装ではサーバーが401 Unauthorizedを返すときにWWW-Authenticateヘッダーを返しません。そのため、
oauth-protected-resourceの位置が定まらないのかもしれません。
ファイル
.well-known/oauth-protected-resource/ords/apexdev/sampleserver/mcpを作成し、以下を記述します。
{
"resource": "api://ordsmcp",
"authorization_servers": {
["https://integrator-*******.okta.com/oauth2/********************/"]
}
}
authorization_serversの設定で、JSON配列を{}で囲んでJSONオブジェクトにしています。構文的に間違っているように思いますが、こうしないとMCP Inspectorが
authorization_serversを認識しません。
メタデータをダウンロードし、
.well-known以下に配置します。
curl -OL https://integrator-********.okta.com/oauth2/*******************/.well-known/oauth-authorization-server
mv openid-configuration .well-known/[root@apex html]# curl -OL https://integrator-*******.okta.com/oauth2/*******************/.well-known/oauth-authorization-server
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 2624 0 2624 0 0 6777 0 --:--:-- --:--:-- --:--:-- 6762
[root@apex html]# mv oauth-authorization-server .well-known/
[root@apex html]#
以上で全体の設定が完了しました。
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に、Oktaに作成した統合アプリORDS MCPのクライアントIDを設定します。
Connectをクリックし、認証プロセスを開始します。
Oktaのサインイン画面に遷移します。ユーザー名を入力し、次へ進みます。
このユーザーはOkta Verifyを構成しています。
Okta Verifyのコードを入力し確認します。
パスワードを入力し確認します。
ユーザー認証に成功しました。
以上でRole based JWT profileで保護したORDS REST APIを、MCP Inspectorでアクセスできました。
Oktaによるユーザー認証では、スコープの指定が不要でした。
以下より、ブラウザ版のChatGPTで、このMCPサーバーをアプリとして作成してみます。ChatGPTに組み込むアプリはリソースとしてHTMLを返す必要があり、このMCPサーバーは要件を満たしてはいませんが、認証の確認はできます。
ChatGPTで認証できるように、統合アプリORDS MCPのサインインリダイレクトURIとして、以下を追加します。
https://chatgpt.com/connector_platform_oauth_redirect
ChatGPTのプランに依存すると思いますが(Plusプランで確認しています)ブラウザ版ChatGPTを開発者モードにすると、設定のアプリとコネクターに高度な設定が表示されます。
アプリを作成するをクリックします。
新しいアプリの名前はMy Oracle Appとします。説明として「Oracleデータベースに接続しSELECT文を実行します」を記述します。
MCPサーバーのURLは、MCP Inspectorに設定したURLと同じです。
https://ホスト名/ords/apexdev/sampleserver/mcp
認証に
OAuthを選択し、
OAuthクライアントIDに、Oktaに作成した統合アプリ
ORDS MCPのクライアントIDを設定します。
理解したうえで、続行しますをチェックし、作成するをクリックします。
Oktaの認証プロセスが開始します。サインイン手順はMCP Inspectorと同じなので省略します。
サインインが完了すると、作成したアプリMy Oracle Appが接続します。
アクションとしてツールのget_schemaやrun_sqlが見えているので、OAuthによる認証は成功しています。
ここで使用したMCPサーバーはChatGPTアプリとしての実装は行なっていないため、何かができるわけではありませんが、OAuthで認証できることは確認できました。
Claude Desktopではカスタムコネクタとして追加します。
Claude Desktopで認証できるように、統合アプリORDS MCPのサインインリダイレクトURIとして、以下を追加します。
https://claude.ai/api/mcp/auth_callback
Claude Desktopでも、ChatGPTと同じ設定でカスタムコネクタを追加します。
追加したカスタムコネクタMy Oracle Appを連携させます。
Oktaでの認証プロセスが完了すると、連携/連携させるというボタンが設定に変わります。
設定をクリックすると、コネクタとして利用できるツールが確認できます。
Claude DesktopのカスタムコネクタはChatGPTとは異なり、リモートMCPサーバーとして利用できるようです。
そのため、チャットから呼び出すことができました。
今回の記事は以上です。