2025年12月5日金曜日

ORDSのRESTサービスとして作成したリモートMCPサーバーをMicrosoft Entra IDで認証する

以前の記事「ORDSのRESTサービスをClaude Desktopのカスタムコネクタとして登録して呼び出す」にて、Claude Desktopのカスタムコネクタとして接続できるリモートMCPサーバーを作成しました。

本記事では、ORDSのJWTプロファイルを設定することにより、リモートMCPサーバーを保護します。認証サーバーにはMicrosoft Entra IDを使用します。MCPサーバーを組み込むクライアントとして、MCP Inspector(v0.17.5)を使用しました。

作業中にMCP Inspectorのバージョンがv0.17.2からv0.17.5に上がったのですが、その際に/.well-known/oauth-authorization-serverの参照場所が変更された結果、v0.17.2では動作しなくなりました。リモートMCPサーバーのOAuth2による保護は、まだ実装が固まっていない部分があるようです。実際、Claude Desktopのカスタムコネクタ(これ自体はまだベータ)の設定には、MCP Inspectorで設定できるスコープの設定がありません。最新のMCP Inspectorで動作が確認できないときは以下のように0.17.5を指定して実行することで、設定ミスなのかMCP Inspectorの実装が変わったのか、切り分けることができます。

npx @modelcontextprotocol/inspector@0.17.5

MCP Inspectorによる動作確認の結果です(動画はv0.17.2ですが、記事はv0.17.5向けに更新しています)。


以下に検証に使用する環境の作成手順と検証作業について紹介します。今回は、Oracle AI Database 26ai Free、Oracle APEX 24.2、Oracle REST Data Services 25.3の環境を、Google CloudのVMインスタンスに構築しています。

以下の作業を実施します。
  1. Google CloudのVMインスタンスの作成
  2. オペレーティングシステムの設定
  3. DB、APEXおよびORDSの構成
  4. nginxによるリバース・プロキシの構成
  5. APEXワークスペースの作成
  6. Microsoft Entra IDによるORDS REST API認証の実装
  7. リモートMCPサーバーの実装
  8. リモートMCPサーバーのJWTトークンによる保護

Google CloudのVMインスタンスの作成


Google CloudのコンソールよりVMインスタンスのページを開きます。開いたページから、インスタンスを作成します。


マシンの構成を開きます。

名前は任意です。本記事ではordsmcpとしました。マシンタイプに最低限必要なリソースを持つe2-standard-2 (2 vCPU、1コア、8 GBメモリ)を選択しています。


OSとストレージを開きます。

オペレーティングシステムとストレージ変更をクリックします。


オペレーティングシステムとしてRocky Linux 10を選択しました。Oracle DatabaseやOracle REST Data Servicesはコンテナとして実行するため、DBやORDSの依存性は無視できます。podmanまたはDockerとnginxおよびcertbotが実行できれば、他のオペレーティングシステムでも同等の環境は作成できるでしょう。

ディスクサイズ40GBを指定しています。


ネットワーキングを開きます。

ファイアウォールのHTTPトラフィックを許可する、および、HTTPSトラフィックを許可するをチェックします。

以上の設定でVMインスタンスを作成します。


VMインスタンスが作成されると、外部IPが割り当たります。このIPはDNSサービスにホスト名と共に登録するため、コピーしておきます。外部IPはVMインスタンスを起動する度に変わりますが、本記事の目的は検証で長期的な利用は想定していないため、問題ありません。


VMインスタンスに割り当てられた外部IPをDNSサービスに登録します。本記事ではフリーのダイナミックDNSサービスのDDNS Nowに、ホスト名ordsmcp.f5.siとして外部IPを登録しました。登録手順については割愛します。

作成したVMインスタンスへの接続手順は、SSHよりいくつか選択できます。




オペレーティングシステムの設定


VMインスタンスに接続します。rootユーザーの作業が続くので、最初にrootに切り替えます。

sudo -s

[ynakakoshi@ordsmcp ~]$ sudo -s

[root@ordsmcp ynakakoshi]# 


Podmanを含むcontainer-tools、nginxおよびunzipをインストールします。

dnf -y install container-tools nginx unzip

[root@ordsmcp ynakakoshi]# dnf -y install container-tools nginx unzip

CIQ SIG/Cloud Next for Rocky Linux 10                                      11 MB/s |  14 MB     00:01    

Google Compute Engine                                                      14 kB/s | 3.4 kB     00:00    

Google Cloud SDK                                                          255 kB/s |  54 kB     00:00    

Rocky Linux 10 - BaseOS                                                    23 MB/s | 4.1 MB     00:00    

Rocky Linux 10 - AppStream                                                 13 MB/s | 1.9 MB     00:00    

Rocky Linux 10 - Extras                                                    48 kB/s | 4.8 kB     00:00    

Dependencies resolved.

==========================================================================================================

 Package                          Architecture Version                              Repository       Size

==========================================================================================================

Installing:

 container-tools                  noarch       1-16.el10                            appstream       7.3 k

 nginx                            x86_64       2:1.26.3-1.el10                      appstream        33 k

 unzip                            x86_64       6.0-69.el10                          baseos          188 k

Upgrading:

 libselinux                       x86_64       3.9-1.el10                           baseos           97 k

 libselinux-utils                 x86_64       3.9-1.el10                           baseos          122 k

 libsemanage                      x86_64       3.9-1.el10                           baseos          122 k

 libsepol                         x86_64       3.9-1.el10                           baseos          348 k


[中略]


  python3-idna-3.7-4.el10.noarch                   python3-libsemanage-3.9-1.el10.x86_64                  

  python3-podman-3:5.5.0-1.el10.noarch             python3-requests-2.32.4-1.el10_0.noarch                

  python3-urllib3-1.26.19-2.el10.noarch            rocky-logos-httpd-100.4-7.el10.noarch                  

  shadow-utils-subid-2:4.15.0-8.el10.x86_64        skopeo-2:1.20.0-1.el10.x86_64                          

  slirp4netns-1.3.3-1.el10.x86_64                  toolbox-0.2-2.el10.x86_64                              

  udica-0.2.8-6.el10.noarch                        unzip-6.0-69.el10.x86_64                               


Complete!

[root@ordsmcp ynakakoshi]# 


certbotを含むリポジトリepel-releaseをインストールします。

dnf -y install epel-release

[root@ordsmcp ynakakoshi]# dnf -y install epel-release

Last metadata expiration check: 0:02:12 ago on Fri 05 Dec 2025 02:23:25 AM UTC.

Dependencies resolved.

==========================================================================================================

 Package                     Architecture          Version                    Repository             Size

==========================================================================================================

Installing:

 epel-release                noarch                10-7.el10_1                extras                 19 k


Transaction Summary

==========================================================================================================


[中略]


Installed:

  epel-release-10-7.el10_1.noarch                                                                         


Complete!

[root@ordsmcp ynakakoshi]# 


certbotをインストールします。

dnf -y install certbot

[root@ordsmcp ynakakoshi]# dnf -y install certbot

Last metadata expiration check: 0:01:12 ago on Fri 05 Dec 2025 02:25:42 AM UTC.

Dependencies resolved.

==========================================================================================================

 Package                             Architecture     Version                   Repository           Size

==========================================================================================================

Installing:

 certbot                             noarch           4.2.0-1.el10_1            epel                 51 k

Installing dependencies:

 fontawesome4-fonts                  noarch           1:4.7.0-23.el10           appstream           204 k

 python3-acme                        noarch           4.2.0-1.el10_1            epel                210 k

 python3-certbot                     noarch           4.2.0-1.el10_1            epel                881 k

 python3-cffi                        x86_64           1.16.0-7.el10             baseos              310 k

 python3-configargparse              noarch           1.7.1-1.el10_1            epel                 53 k

 python3-configobj 

                  noarch           5.0.8-10.el10             appstream            83 k


[中略]


  python3-ply-3.11-25.el10.noarch                     python3-pyOpenSSL-25.0.0-1.el10_1.noarch            

  python3-pycparser-2.20-16.el10.noarch               python3-pyrfc3339-1.1-20.el10_0.noarch              

  python3-pytz-2025.1-1.el10_1.noarch                 python3-typing-extensions-4.9.0-6.el10.noarch       


Complete!

[root@ordsmcp ynakakoshi]# 


ユーザーoracle、グループoinstallを作成します。

Oracle Databaseなどはコンテナ内でユーザーoracleとして実行されます。コンテナ内からホストのファイル・システムを参照するにあたって、参照するホスト側にあるディレクトリの所有者のUIDやGIDが、コンテナ内のユーザーoracleと一致するようにします。

groupadd -g 54321 oinstall
useradd -u 54321 -g 54321 oracle

[root@ordsmcp ynakakoshi]# groupadd -g 54321 oinstall

[root@ordsmcp ynakakoshi]# useradd -u 54321 -g 54321 oracle

[root@ordsmcp ynakakoshi]# 


ユーザーoracleがログインしていなくてもサービスが実行できるように、以下のコマンドを実行します。

loginctl enable-linger 54321

[root@ordsmcp ynakakoshi]# loginctl enable-linger 54321

[root@ordsmcp ynakakoshi]# 


リバース・プロキシとして使用するnginxがORDSに接続できるように、SE Linuxを設定します。

setsebool -P httpd_can_network_connect 1

[root@ordsmcp ynakakoshi]# setsebool -P httpd_can_network_connect 1

[root@ordsmcp ynakakoshi]# 


オペレーティングシステムの設定は以上で完了です。


DB、APEXおよびORDSの構成



Oracle AI Database、Oracle APEXおよびOracle REST Data Servicesを構成します。作業は先ほど作成したユーザーoracleで実施します。VMインスタンスの接続直後であれば、以下のコマンドを実行し、ユーザーoracleに切り替えます。rootから切り替える場合は、sudoは不要でs。

sudo su - oracle

[ynakakoshi@ordsmcp ~]$ sudo su - oracle

[oracle@ordsmcp ~]$ 


Oracle AI Database 26ai Freeのコンテナ・イメージをダウンロードします。

podman pull container-registry.oracle.com/database/free:latest

[oracle@ordsmcp ~]$ podman pull container-registry.oracle.com/database/free:latest

Trying to pull container-registry.oracle.com/database/free:latest...

Getting image source signatures

Copying blob 97fd3103f315 done   | 

Copying blob 867532f50b57 done   | 

Copying blob 5bf4d5bb53fa done   | 

Copying blob 359a083bb2a1 done   | 

Copying blob a788b7aca3f6 done   | 

Copying blob d564e67f1ed2 done   | 

Copying blob 3852ff38ea46 done   | 

Copying blob 325b6722024f done   | 

Copying blob d1e8ff124bb5 done   | 

Copying blob f3f45addaa5c done   | 

Copying blob 21f5b3d4bded done   | 

Copying blob c62f5145519a done   | 

Copying blob 1ae8998597b3 done   | 

Copying blob c4dd45b650b9 done   | 

Copying blob 42048da13555 done   | 

Copying blob 61135ed510cd done   | 

Copying blob e774aa72c2b3 done   | 

Copying blob 73e204b18f80 done   | 

Copying blob 2a2ff731d809 done   | 

Copying blob 0361c3d5b31e done   | 

Copying blob 78d585384f78 done   | 

Copying blob 8b75f497490b done   | 

Copying config 3c986e106c done   | 

Writing manifest to image destination

3c986e106c3e8ae13457ccd8b6638417ddfae7bcf73f75a0d4291ae14bd46116

[oracle@ordsmcp ~]$ 


Oracle REST Data Servicesのコンテナ・イメージをダウンロードします。

podman pull container-registry.oracle.com/database/ords:latest

[oracle@ordsmcp ~]$ podman pull container-registry.oracle.com/database/ords:latest

Trying to pull container-registry.oracle.com/database/ords:latest...

Getting image source signatures

Copying blob 2c2963ed5b49 done   | 

Copying blob ac06ceafe5b9 done   | 

Copying blob 9bf96270f9cf done   | 

Copying blob ac20eadf1879 done   | 

Copying blob f7212a4628d0 done   | 

Copying blob 30ffcb3cce85 done   | 

Copying blob 62e87c40596c done   | 

Copying config 760e3ba983 done   | 

Writing manifest to image destination

760e3ba983b7ae56ca1e2634e6194898d03c72edeafe3a96d27055c9597f0310

[oracle@ordsmcp ~]$ 


Oracle APEXの最新版のアーカイブをダウンロードし、/home/oracle以下に展開します。

curl -OL https://download.oracle.com/otn_software/apex/apex-latest.zip
unzip apex-latest.zip


[oracle@ordsmcp ~]$ curl -OL https://download.oracle.com/otn_software/apex/apex-latest.zip

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current

                                 Dload  Upload   Total   Spent    Left  Speed

100  289M  100  289M    0     0   122M      0  0:00:02  0:00:02 --:--:--  122M

[oracle@ordsmcp ~]$ unzip apex-latest.zip 

Archive:  apex-latest.zip

  inflating: META-INF/MANIFEST.MF    

  inflating: META-INF/ORACLE_C.SF    

  inflating: META-INF/ORACLE_C.RSA   

   creating: apex/

  inflating: apex/apex_rest_config.sql  

  inflating: apex/apex_rest_config_cdb.sql  

  inflating: apex/apex_rest_config_core.sql  

  inflating: apex/apex_rest_config_nocdb.sql  


[中略]


  inflating: apex/utilities/debug/d1.sql  

  inflating: apex/utilities/debug/d2.sql  

  inflating: apex/utilities/debug/ds.sql  

   creating: apex/utilities/support/

  inflating: apex/utilities/support/apex_verify.sql  

[oracle@ordsmcp ~]$ 


データ・ファイルを配置するディレクトリを/home/oracle/oradataとして作成します。その後、データベースのコンテナの作成と実行を行います。

構成が完了するまでログを確認します。

mkdir oradata
podman run -d --name apex-db --privileged --userns=keep-id:uid=54321,gid=54321 -p 1521:1521 -v /home/oracle/oradata:/opt/oracle/oradata -v /home/oracle/apex:/home/oracle/apex container-registry.oracle.com/database/free:latest
podman logs -f apex-db


ログにDATABASE IS READY TO USE!と出力されれば、データベースは利用可能です。ログの確認を停止し、次の作業へ移ります。

[oracle@ordsmcp ~]$ mkdir oradata

[oracle@ordsmcp ~]$ podman run -d --name apex-db --privileged --userns=keep-id:uid=54321,gid=54321 -p 1521:1521 -v /home/oracle/oradata:/opt/oracle/oradata -v /home/oracle/apex:/home/oracle/apex container-registry.oracle.com/database/free:latest

59756430b7087be08696bde1aebdb773aa526f24d63ade75a0823098fdd6c14e

[oracle@ordsmcp ~]$ podman logs -f apex-db

Specify a password to be used for database accounts. Oracle recommends that the password entered should be at least 8 characters in length, contain at least 1 uppercase character, 1 lower case character and 1 digit [0-9]. Note that the same password will be used for SYS, SYSTEM and PDBADMIN accounts:

Confirm the password:

Configuring Oracle Listener.

Listener configuration succeeded.

Configuring Oracle AI Database FREE.

Enter SYS user password: 

******************

Enter SYSTEM user password: 

****************

Enter PDBADMIN User Password: 

*************** 

Prepare for db operation

7% complete

Copying database files

29% complete

Creating and starting Oracle instance

30% complete

33% complete

36% complete

39% complete

43% complete

Completing Database Creation

47% complete

49% complete

50% complete

Creating Pluggable Databases

54% complete

71% complete

Executing Post Configuration Actions

93% complete

Running Custom Scripts

100% complete

Database creation complete. For details check the logfiles at:

 /opt/oracle/cfgtoollogs/dbca/FREE.

Database Information:

Global Database Name:FREE

System Identifier(SID):FREE

Look at the log file "/opt/oracle/cfgtoollogs/dbca/FREE/FREE.log" for further details.


Connect to Oracle AI Database using one of the connect strings:

     Pluggable database: 59756430b708/FREEPDB1

     Multitenant container database: 59756430b708


SQL*Plus: Release 23.26.0.0.0 - Production on Fri Dec 5 02:58:20 2025

Version 23.26.0.0.0


Copyright (c) 1982, 2025, Oracle.  All rights reserved.



Connected to:

Oracle AI Database 26ai Free Release 23.26.0.0.0 - Develop, Learn, and Run for Free

Version 23.26.0.0.0


SQL> 

System altered.


SQL> 

Pluggable database altered.


SQL> 

PL/SQL procedure successfully completed.


SQL> SQL> 

Session altered.


SQL> 

User created.


SQL> 

Grant succeeded.


SQL> 

Grant succeeded.


SQL> 

Grant succeeded.


SQL> 

User altered.


SQL> SQL> Disconnected from Oracle AI Database 26ai Free Release 23.26.0.0.0 - Develop, Learn, and Run for Free

Version 23.26.0.0.0


SQL*Plus: Release 23.26.0.0.0 - Production on Fri Dec 5 02:58:20 2025

Version 23.26.0.0.0


Copyright (c) 1982, 2025, Oracle.  All rights reserved.



Connected to:

Oracle AI Database 26ai Free Release 23.26.0.0.0 - Develop, Learn, and Run for Free

Version 23.26.0.0.0


SQL> Database closed.

Database dismounted.

ORACLE instance shut down.

SQL> ORACLE instance started.


Total System Global Area 1603373280 bytes

Fixed Size     5007584 bytes

Variable Size   402653184 bytes

Database Buffers 1191182336 bytes

Redo Buffers     4530176 bytes

Database mounted.

SQL> 

Database altered.


SQL> 

Database altered.


SQL> 

Database altered.


SQL> SQL> Disconnected from Oracle AI Database 26ai Free Release 23.26.0.0.0 - Develop, Learn, and Run for Free

Version 23.26.0.0.0

The Oracle base remains unchanged with value /opt/oracle


Executing user defined scripts

/opt/oracle/runUserScripts.sh: running /opt/oracle/scripts/extensions/setup/registerService.sh


DONE: Executing user defined scripts


The Oracle base remains unchanged with value /opt/oracle

#########################

DATABASE IS READY TO USE!

#########################

The following output is now a tail of the alert.log:

PDB$SEED(2):Opening pdb with Resource Manager plan: DEFAULT_PLAN

2025-12-05T02:58:34.792168+00:00

(3):--ATTENTION--

(3):PARALLEL_MAX_SERVERS (with value 1) is insufficient. This may affect transaction recovery performance.

Modify PARALLEL_MAX_SERVERS parameter to a value > 4 (= parallel servers count computed from parameter FAST_START_PARALLEL_ROLLBACK) in PDB ID 3

FREEPDB1(3):Autotune of undo retention is turned on. 

2025-12-05T02:58:36.272863+00:00

FREEPDB1(3):Opening pdb with Resource Manager plan: DEFAULT_PLAN

Completed: Pluggable database FREEPDB1 opened read write 

Completed: ALTER DATABASE OPEN

2025-12-05T02:58:41.098979+00:00

===========================================================

Dumping current patch information

===========================================================

No patches have been applied

===========================================================



データベースのSYSのパスワードを環境変数ORACLE_PWDに設定します。[パスワード]の部分に、パスワードとして適切な文字列を指定します。今後の作業で複数回、SYSのパスワードを指定する箇所があるため、打ち間違いなどを防止します。

その上で、作成したデータベースのSYSのパスワードを変更します。

export ORACLE_PWD=[パスワード]
podman exec -it apex-db sh setPassword.sh $ORACLE_PWD


[oracle@ordsmcp ~]$ export ORACLE_PWD=*******

[oracle@ordsmcp ~]$ podman exec -it apex-db sh setPassword.sh $ORACLE_PWD

The Oracle base remains unchanged with value /opt/oracle


SQL*Plus: Release 23.26.0.0.0 - Production on Fri Dec 5 03:03:04 2025

Version 23.26.0.0.0


Copyright (c) 1982, 2025, Oracle.  All rights reserved.



Connected to:

Oracle AI Database 26ai Free Release 23.26.0.0.0 - Develop, Learn, and Run for Free

Version 23.26.0.0.0


SQL> 

User altered.


SQL> 

User altered.


SQL> 

Session altered.


SQL> 

User altered.


SQL> Disconnected from Oracle AI Database 26ai Free Release 23.26.0.0.0 - Develop, Learn, and Run for Free

Version 23.26.0.0.0

[oracle@ordsmcp ~]$ 


コンテナapex-dbに接続し、データベースにAPEXをインストールします。

podman exec -it apex-db bash

[oracle@ordsmcp ~]$ podman exec -it apex-db bash

bash-4.4$ 


APEXのイメージが展開されたディレクトリ/home/oracle/apexへ移動し、データベースに接続してAPEXのインストールを実行します。

cd apex
export NLS_LANG=American_America.AL32UTF8
sqlplus / as sysdba
alter session set container = freepdb1;
@apexins SYSAUX SYSAUX TEMP /i/


bash-4.4$ cd apex

bash-4.4$ export NLS_LANG=American_America.AL32UTF8

bash-4.4$ sqlplus / as sysdba


SQL*Plus: Release 23.26.0.0.0 - Production on Fri Dec 5 03:08:03 2025

Version 23.26.0.0.0


Copyright (c) 1982, 2025, Oracle.  All rights reserved.



Connected to:

Oracle AI Database 26ai Free Release 23.26.0.0.0 - Develop, Learn, and Run for Free

Version 23.26.0.0.0


SQL> alter session set container = freepdb1;


Session altered.


SQL> @apexins SYSAUX SYSAUX TEMP /i/

...set_appun.sql


PL/SQL procedure successfully completed.


[中略]


The structure of the link to the Oracle APEX development environment is as follows:

http://host:port/ords/apex



timing for: Phase 3 (Switch)

Elapsed:    0.32



timing for: Complete Installation

Elapsed:   10.83


SYS> 


日本語リソースをロードします。

@load_trans JAPANESE

SYS> @load_trans JAPANESE


PL/SQL procedure successfully completed.


Installing Oracle APEX translation - JAPANESE


. ORACLE

.

. Oracle APEX Hosted Development Service Installation.

..............................................................


PL/SQL procedure successfully completed.



PL/SQL procedure successfully completed.


--application/set_environment

API Last Extended:20241130

Your Current Version:20241130

This import is compatible with version: 20241130


[中略]


--application/deployment/definition

--application/deployment/checks

--application/deployment/buildoptions

--application/end_environment

... elapsed: 6.93 sec

...done

Adjust instance settings


PL/SQL procedure successfully completed.


SYS> 


APEX_PUBLIC_USERをアンロックします。

alter user apex_public_user account unlock no authentication;

SYS> alter user apex_public_user account unlock no authentication;


User altered.


SYS> 


管理者ユーザーとパスワードを設定します。

@apxchpwd

SYS> @apxchpwd

...set_appun.sql

================================================================================

This script can be used to change the password of an Oracle APEX

instance administrator. If the user does not yet exist, a user record will be

created.

================================================================================

Enter the administrator's username [ADMIN] 

User "ADMIN" does not yet exist and will be created.

Enter ADMIN's email [ADMIN] 

Enter ADMIN's password [] ***********

Created instance administrator ADMIN.


SYS> 


sqlplusを終了します。続けて、コンテナapex-dbから抜け、ホストに戻ります。

exit
exit

SYS> exit

Disconnected from Oracle AI Database 26ai Free Release 23.26.0.0.0 - Develop, Learn, and Run for Free

Version 23.26.0.0.0

bash-4.4$ exit

exit

[oracle@ordsmcp ~]$


Oracle REST Data Servicesのコンテナの作成と実行を行います。構成情報を保存するディレクトリとして/home/oracle/ords_configを作成し、コンテナ内の/etc/ords/configにマウントします。

接続先のデータベースはコンテナの外にあるため、DBHOSTはlocalhostではなく、host.containers.internalを指定します。

mkdir ords_config
podman run -d --name apex-ords --privileged --userns=keep-id:uid=54321,gid=54321 -e DBHOST=host.containers.internal -e DBPORT=1521 -e DBSERVICENAME=freepdb1 -e ORACLE_PWD=$ORACLE_PWD -p 8080:8080 -v /home/oracle/ords_config:/etc/ords/config -v /home/oracle/apex:/opt/oracle/apex container-registry.oracle.com/database/ords:latest
podman logs -f apex-ords


ORDSが正常に起動されたらログの確認を停止し、次の作業へ移ります。

[oracle@ordsmcp ~]$ mkdir ords_config

[oracle@ordsmcp ~]$ podman run -d --name apex-ords --privileged --userns=keep-id:uid=54321,gid=54321 -e DBHOST=host.containers.internal -e DBPORT=1521 -e DBSERVICENAME=freepdb1 -e ORACLE_PWD=$ORACLE_PWD -p 8080:8080 -v /home/oracle/ords_config:/etc/ords/config -v /home/oracle/apex:/opt/oracle/apex container-registry.oracle.com/database/ords:latest

870492aecdbf82e61c06b7012ae663eda57149d97ff5439114a5a3159b89decb

[oracle@ordsmcp ~]$ podman logs -f apex-ords

Testing database connection...

INFO : Attempt 1: Connecting to sys/*****@host.containers.internal:1521/freepdb1 as sysdba...

INFO : Database connection successful.

INFO : The Oracle REST Data Services are not installed on your database.

INFO : Installing The Oracle REST Data Services 25.3.1.

INFO : ORDS_PWD env var is not set, using generated value WVF*zG80644^

INFO : The Oracle REST Data Services 25.3.1 has been installed correctly on your database.

INFO : The container found Oracle APEX version 24.2.0 in the mounted volume.

INFO : The Oracle APEX 24.2.0 is already installed in your database.

INFO : Set plsql.gateway.mode proxied after Oracle APEX was installed.

INFO : Setup standalone.static.path /opt/oracle/apex/images.

INFO : Starting the Oracle REST Data Services instance.

2025-12-05T03:53:36Z INFO   ORDS has not detected the option '--config' and this will be set up to the default directory.


ORDS: Release 25.3 Production on Fri Dec 05 03:53:40 2025


Copyright (c) 2010, 2025, Oracle.


Configuration:

  /etc/ords/config


2025-12-05T03:53:43.668Z INFO        HTTP and HTTP/2 cleartext listening on host: 0.0.0.0 port: 8080

2025-12-05T03:53:43.825Z INFO        Disabling document root because the specified folder does not exist: /etc/ords/config/global/doc_root

2025-12-05T03:53:43.829Z INFO        Default forwarding from / to contextRoot configured.

2025-12-05T03:53:44.114Z SEVERE      ORAMLVERSION null

2025-12-05T03:53:44.132Z INFO        Oracle API for MongoDB listening on port: 27017

2025-12-05T03:53:44.134Z INFO        The Oracle API for MongoDB connection string is: 

         mongodb://[{user}:{password}@]localhost:27017/{user}?authMechanism=PLAIN&authSource=$external&ssl=true&retryWrites=false&loadBalanced=true

2025-12-05T03:53:53.957Z INFO        Configuration properties for: |default|lo|

db.connectionType=basic

db.hostname=host.containers.internal

db.port=1521

db.servicename=freepdb1

db.username=ORDS_PUBLIC_USER

feature.sdw=true

plsql.gateway.mode=proxied

restEnabledSql.active=true

security.requestValidationFunction=ords_util.authorize_plsql_gateway

database.api.enabled=true

mongo.enabled=true

standalone.access.log=/tmp/ords_access_logs/

standalone.static.path=/opt/oracle/apex/images

file.encoding=ANSI_X3.4-1968

file.separator=/

java.awt.headless=true

java.class.path=/opt/oracle/ords/ords.war

java.class.version=61.0

java.home=/opt/graalvm-ee-java17

java.io.tmpdir=/tmp

java.library.path=/usr/java/packages/lib:/usr/lib64:/lib64:/lib:/usr/lib

java.runtime.name=Java(TM) SE Runtime Environment

java.runtime.version=17.0.11+7-LTS-jvmci-21.3-b51

java.specification.name=Java Platform API Specification

java.specification.vendor=Oracle Corporation

java.specification.version=17

java.vendor=Oracle Corporation

java.vendor.url=https://java.oracle.com/

java.vendor.url.bug=https://bugreport.java.com/bugreport/

java.vendor.version=GraalVM EE 21.3.10

java.version=17.0.11

java.version.date=2024-04-16

java.vm.compressedOopsMode=32-bit

java.vm.info=mixed mode, sharing

java.vm.name=Java HotSpot(TM) 64-Bit Server VM

java.vm.specification.name=Java Virtual Machine Specification

java.vm.specification.vendor=Oracle Corporation

java.vm.specification.version=17

java.vm.vendor=Oracle Corporation

java.vm.version=17.0.11+7-LTS-jvmci-21.3-b51

jdk.debug=release

jdk.internal.vm.ci.enabled=true

line.separator=


native.encoding=ANSI_X3.4-1968

oracle.dbtools.cmdline.ShellCommand=ords

oracle.dbtools.cmdline.home=/opt/oracle/ords

oracle.dbtools.launcher.executable.jar.path=/opt/oracle/ords/ords.war

os.arch=amd64

os.name=Linux

os.version=6.12.0-55.41.1+2.1.el10_0_ciq.x86_64

path.separator=:

sun.arch.data.model=64

sun.boot.library.path=/opt/graalvm-ee-java17/lib

sun.cpu.endian=little

sun.io.unicode.encoding=UnicodeLittle

sun.java.command=/opt/oracle/ords/ords.war --config /etc/ords/config serve

sun.java.launcher=SUN_STANDARD

sun.jnu.encoding=ANSI_X3.4-1968

sun.management.compiler=HotSpot 64-Bit Tiered Compilers

user.country=US

user.dir=/etc/ords/config

user.home=/home/oracle

user.language=en

user.name=oracle

user.timezone=UTC

resource.templates.enabled=false

db.password=******

conf.use.wallet=true


2025-12-05T03:53:53.965Z WARNING     *** jdbc.MaxLimit in configuration |default|lo| is using a value of 10, this setting may not be sized adequately for a production environment ***

2025-12-05T03:53:54.659Z INFO        Created Pool: |default|lo|-2025-12-05T03-53-52.350317727Z at: 2025-12-05T03:53:52.350317727Z

2025-12-05T03:53:55.171Z INFO        


Mapped local pools from /etc/ords/config/databases:

  /ords/                              => default                        => VALID     



2025-12-05T03:53:55.200Z INFO        Oracle REST Data Services initialized

Oracle REST Data Services version : 25.3.1.r2891312

Oracle REST Data Services server info: jetty/12.0.25

Oracle REST Data Services java info: Java HotSpot(TM) 64-Bit Server VM GraalVM EE 21.3.10 (build 17.0.11+7-LTS-jvmci-21.3-b51 mixed mode, sharing)


2025-12-05T03:53:55.460Z INFO        RequestMonitor 1

2025-12-05T03:53:55.462Z INFO        TransactionMonitor 1

2025-12-05T03:53:55.463Z INFO        AccessLogMonitor 1 0

2025-12-05T03:53:55.461Z INFO        CursorMonitor 1

2025-12-05T03:53:55.466Z INFO        WatchdogMonitor 1



以上でAPEXおよびORDSにアクセスできるようになりました。ただし、ORDSはポート8080で接続を待ち受けているため、Google Cloudのファイアウォールルールとして、ポート8080への接続を許可するルールを作成する必要があります。


nginxによるリバース・プロキシの構成



nginxによるリバース・プロキシを構成します。nginxにてHTTPS接続を受け付け、バックエンドのORDSとは、httpで通信します。OAuth2による認証に必要なoauth-protected-resourceの内容は、nginxによってクライアントに返します。

nginxはコンテナではなくホストで実行します。作業はrootユーザーにて実施します。

sudo -s

[ynakakoshi@ordsmcp ~]$ sudo -s

[root@ordsmcp ynakakoshi]# 


certbotを実行し、Let's Encryptより証明書を取得します。デフォルトでは楕円曲線暗号の鍵を生成するようです。ORDSでの利用を考えている場合は--key-type rsaをオプションとして追加し、RSAの鍵を生成します。

以下の例ではホスト名にordsmcp.f5.siを指定していますが、作業の際には割り当てているホスト名に置き換えます。

certbot certonly --standalone -d ordsmcp.f5.si

[root@ordsmcp ynakakoshi]# certbot certonly --standalone -d ordsmcp.f5.si

Saving debug log to /var/log/letsencrypt/letsencrypt.log

Enter email address or hit Enter to skip.

 (Enter 'c' to cancel): [申請者のメールアドレス]


- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Please read the Terms of Service at:

https://letsencrypt.org/documents/LE-SA-v1.6-August-18-2025.pdf

You must agree in order to register with the ACME server. Do you agree?

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

(Y)es/(N)o: Y


- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Would you be willing, once your first certificate is successfully issued, to

share your email address with the Electronic Frontier Foundation, a founding

partner of the Let's Encrypt project and the non-profit organization that

develops Certbot? We'd like to send you email about our work encrypting the web,

EFF news, campaigns, and ways to support digital freedom.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

(Y)es/(N)o: N

Account registered.

Requesting a certificate for ordsmcp.f5.si


Successfully received certificate.

Certificate is saved at: /etc/letsencrypt/live/ordsmcp.f5.si/fullchain.pem

Key is saved at:         /etc/letsencrypt/live/ordsmcp.f5.si/privkey.pem

This certificate expires on 2026-03-05.

These files will be updated when the certificate renews.

Certbot has set up a scheduled task to automatically renew this certificate in the background.


- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

If you like Certbot, please consider supporting our work by:

 * Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate

 * Donating to EFF:                    https://eff.org/donate-le

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

[root@ordsmcp ynakakoshi]# 


nginx構成ファイルを置き換えます。

/etc/nginx/nginx.confを以下に置き換えます。

デバッグ用途に、ORDSへ送信されるヘッダーやリクエスト本体をログに出力する設定を含めています(有効にはしていません)。

TLSを有効にしたサーバーの設定ファイルを、/etc/nginx/conf.d/01-server.confとして作成します。ホスト名のordsmcp.f5.siの部分は、適切なホスト名に置き換えます。

ORDSおよびAPEXへのリバース・プロキシの設定、および、OAuth2の認証で使用するファイルを配置する/.well-known/を設定するファイルとして、/etc/nginx/default.d/01-apex.confを作成します。

nginxに関する設定ファイルを配置しました。nginxを起動します。

systemctl enable nginx
systemctl start nginx


[root@ordsmcp conf.d]# systemctl enable nginx

Created symlink '/etc/systemd/system/multi-user.target.wants/nginx.service' → '/usr/lib/systemd/system/nginx.service'.

[root@ordsmcp conf.d]# systemctl start nginx

[root@ordsmcp conf.d]# 


nginxではhttpsからhttpへのリバース・プロキシを構成しているため、Oracle REST Data Servicesのsecurity.httpsHeaderCheck"X-Forwarded-Proto: https"を設定します。

ユーザーoracleに切り替えコンテナapex-ordsに接続して、ordsコマンドを実行します。

su - oracle
podman exec -it apex-ords bash
ords --config /etc/ords/config config set security.httpsHeaderCheck "X-Forwarded-Proto: https"


[root@ordsmcp ynakakoshi]# su - oracle

Last login: Fri Dec  5 02:40:02 UTC 2025 on pts/3

[oracle@ordsmcp ~]$ podman exec -it apex-ords bash

[oracle@870492aecdbf ords]$ ords --config /etc/ords/config config set security.httpsHeaderCheck "X-Forwarded-Proto: https"


ORDS: Release 25.3 Production on Fri Dec 05 05:50:13 2025


Copyright (c) 2010, 2025, Oracle.


Configuration:

  /etc/ords/config


The global setting named: security.httpsHeaderCheck was set to: X-Forwarded-Proto: https

[oracle@870492aecdbf ords]$ 


コンテナapex-ordsから抜け、再起動して設定を反映します。

exit
podman restart apex-ords

[oracle@870492aecdbf ords]$ exit

exit

[oracle@ordsmcp ~]$ podman restart apex-ords

WARN[0010] StopSignal SIGTERM failed to stop container apex-ords in 10 seconds, resorting to SIGKILL 

apex-ords

[oracle@ordsmcp ~]$ 


以上でAPEXおよびORDSの環境が構築できました。


APEXワークスペースの作成



APEXのワークスペースを作成します。以下のようなリンクに、手元のブラウザからアクセスします。

https://ホスト名/ords/

Oracle APEXの実行をクリックします。


ワークスペースのサインイン画面を下にスクロールし、管理を開きます。


APEXの管理サービスにサインインします。

ユーザー名は通常はADMINパスワード@apxchpwd実行時に設定した値を入力します。


初回サインイン時はワークスペースが作成されていないため、ワークスペースの作成を案内されます。

ワークスペースの作成をクリックします。


作成するワークスペース名APEXDEVとします。

へ進みます。


APEXワークスペースに紐づけるワークスペース・スキーマを作成します。

既存のスキーマを再利用いいえを選択します。スキーマ名はAutonomous Databaseのルールに合わせ、WKSP_APEXDEVとします。スキーマのパスワードとして、適切な文字列を設定します。領域割当て制限(MB)10000を選択します。

へ進みます。


ワークスペースの管理者ユーザーを作成します。

管理者のユーザー名admin管理者のパスワード適切な文字列を設定します。管理者パスワードは初回サインイン時に変更を求められるため、ここで設定したパスワードは初回サインイン時に変更されます。さらに必須項目である電子メールを設定します。

へ進みます。


確認画面が表示されます。

ワークスペースの作成をクリックします。


ワークスペースが作成されます。完了をクリックします。


管理サービスでの作業は完了です。管理サービスからサインアウトします。


サインイン・ページに戻り、作成したワークスペースAPEXDEVにサインインします。


ワークスペースに先ほど作成したapexdevユーザーadmin、それにパスワードを入力し、サインインをクリックします。


初回サインイン時に初期パスワードの変更を求められます。

変更するパスワード2箇所に入力し、パスワードの変更をクリックします。


APEXのアプリケーション・ビルダーの画面が開きます。


以上で、APEXやORDSのアプリケーション開発を始められることろまで構成できました。


Microsoft Entra IDによるORDS REST API認証の実装



以前の記事「Microsoft Entra IDのOIDC認証にてAPEXアプリとそれから呼び出すORDSのREST APIを認証する」に沿って作業し、ORDSのRESTサービスをMicrosoft Entra IDで保護できるように構成します。

Microsoft Entra IDにアプリを登録します。

AzureのコンソールからMicrosoft Entra IDの画面を開きます。

サイド・メニューよりアプリの登録を開きます。


新規登録をクリックします。


Microsoft Entra IDに登録するアプリケーションの名前ORDS MCPとします。サポートされているアカウントの種類この組織ディレクトリのみに含まれるアカウント(既存のディレクトリのみ - シングル・テナント)を選んでいますが、これは契約に依存するかと思います。今回の作業は、Microsoft Entra IDの無料枠の範囲で実施しています。

アプリケーションのタイプとしてWebを選択し、リダイレクトURIは以下を指定します。

https://[ホスト名]/ords/apex_authentication.callback

以上を設定し、登録をクリックします。


アプリケーションが登録されます。

画面に表示されているアプリケーション(クライアント)IDは、APEXのWeb資格証明クライアントIDの値になります。コピーして保存しておきます。

証明書またはシークレットの追加をクリックし、シークレットを作成します。


新しいクライアント・シークレットをクリックします。


説明を入力し、追加をクリックします。


作成されたシークレット(シークレットIDではない)は、APEXのWeb資格証明クライアント・シークレットの値になります。コピーして保存しておきます。


概要に戻り、エンドポイントを開きます。


OpenID Connectメタデータドキュメントの値をコピーして保存します。この値が、APEXアプリケーションの認証スキーム検出URLになります。


APIの公開を開き、Scopeの追加をクリックします。


アプリケーションIDのURIの設定を求められます。この値はJWTのaud属性の値、つまりaudienceの値になります。

保存してから続けるをクリックします。


スコープ名myordsappとします。ORDSに設定する権限はこのスコープ名と一致させます。同意できるのはだれですか?管理者とユーザー管理者の同意の表示名ORDS REST APIの呼び出し管理者の同意の説明ORDS REST APIの呼び出しを許可します。とします。状態有効とします。

以上で、スコープの追加をクリックします。


スコープが追加されます。追加されたスコープ(api:で始まる値)をコピーして保存します。この値は、APEXアプリケーションの認証スキーム有効範囲に設定します。


Microsoft Entra IDでの作業は以上です。

VMインスタンスに接続し、ユーザーoracleに切り替えます。

sudo su - oracle

[ynakakoshi@ordsmcp ~]$ sudo su - oracle

Last login: Fri Dec  5 05:49:47 UTC 2025 on pts/0

[oracle@ordsmcp ~]$ 


コンテナapex-dbに接続します。PDBのFREEPDB1にユーザーSYSで接続し、スキーマへのACLの追加や、MLE/JavaScriptの実行権限の付与を実施します。

podman exec -it apex-db bash
sqlplus sys/[SYSのパスワード]@localhost/freepdb1 as sysdba

[oracle@ordsmcp ~]$ podman exec -it apex-db bash

bash-4.4$ sqlplus sys/********@localhost/freepdb1 as sysdba 


SQL*Plus: Release 23.26.0.0.0 - Production on Fri Dec 5 06:39:36 2025

Version 23.26.0.0.0


Copyright (c) 1982, 2025, Oracle.  All rights reserved.



Connected to:

Oracle AI Database 26ai Free Release 23.26.0.0.0 - Develop, Learn, and Run for Free

Version 23.26.0.0.0


SQL> 


以下のスクリプトを実行します。ワークスペース・スキーマ名がWKSP_APEXDEVとは異なる場合は、WKSP_APEXDEVの部分を置き換えて実行します。


SQL> begin

    dbms_network_acl_admin.append_host_ace(

        host => '*',

        ace => xs$ace_type(

            privilege_list => xs$name_list('http','http_proxy'),

            principal_name => APEX_APPLICATION.g_flow_schema_owner,

            principal_type => xs_acl.ptype_db

        )

    );

    commit;

end;

/


begin

    dbms_network_acl_admin.append_host_ace(

        host => '*',

        ace => xs$ace_type(

            privilege_list => xs$name_list('http','http_proxy'),

            principal_name => 'WKSP_APEXDEV',

            principal_type => xs_acl.ptype_db

        )

    );

    commit;

end;

/


GRANT EXECUTE ON JAVASCRIPT TO WKSP_APEXDEV;

GRANT EXECUTE DYNAMIC MLE TO WKSP_APEXDEV;


exit;  2    3    4    5    6    7    8    9   10   11   12  

PL/SQL procedure successfully completed.


SQL> SQL>   2    3    4    5    6    7    8    9   10   11   12  

PL/SQL procedure successfully completed.


SQL> SQL> 

Grant succeeded.


SQL> 

Grant succeeded.


SQL> SQL> 

Disconnected from Oracle AI Database 26ai Free Release 23.26.0.0.0 - Develop, Learn, and Run for Free

Version 23.26.0.0.0

bash-4.4$ 


以下のAPEXアプリケーションをインポートします。検証用のAPEXアプリケーションやORDSのRESTサービスを作成します。
https://github.com/ujnak/apexapps/blob/master/exports/ords-jwt-test-mcp.zip

アプリケーション・ビルダーよりインポートを実行します。


インポートするファイルとしてords-jwt-test-mcp.zipを選択します。

へ進みます。


アプリケーションのインストールを実行します。


テスト用のAPEXアプリケーションが参照しているWeb資格証明Microsoft Entra ID JWT Testが作成されます。すでに存在しますいいえであれば、クライアントIDまたはユーザー名にEntra IDで作成したアプリORDS MCPアプリケーション(クライアント)IDを入力します。また、クライアント・シークレットシークレットの値を入力します。

これらの値は後からでも、ワークスペース・ユーテリティWeb資格証明から変更できます。

へ進みます。


サポートするオブジェクトのインストールを実行します。


APEXアプリケーションがインストールされます。

アプリケーションの編集をクリックし、設定を更新します。


アプリケーション設定置換を開き、G_REST_URLホスト部分を、このAPEXインスタンスを指すホスト名に置き換えます。


共有コンポーネント認証スキームを開きます。


認証スキームMicrosoft Entra IDを開きます。


検出URLにMicrosoft Entra IDのエンドポイントで確認したOpenID Connectメタデータドキュメントの値を設定します。このURLはテナントIDを含みます。有効範囲api:で始まるスコープを追加します。

以上を変更し、変更の適用をクリックします。


この状態でアプリケーションを実行してみます。


Microsoft Entra IDによるサインインに成功すると、APEXアプリケーションが開きます。APEXアプリケーションの認証には成功しますが、REST APIについてはまだ認証の設定ができていません。

APEXアプリケーションが受け取ったJWTの内容がパースされ、User Infoのリージョンに表示されています。この中のaudissの値をコピーします。audは、ORDS_SECURITY.CREATE_JWT_PROFILEの引数p_audienceの値になります。issは引数p_issuerの値になります。




続いて、Entra IDのOpenID ConnectメタデータドキュメントのURLをブラウザで開きます。URLは以下の形式です。
https://login.microsoftonline.com/テナントID/v2.0/.well-known/openid-configuration

メタデータドキュメントに含まれるjwks_uriの値をコピーします。この値は引数p_jwk_urlの値になります。


ORDS_SECURITY.CREATE_JWT_PROFILEの実行に必要な値は、すべて確認できました。

VMインスタンスに接続し、rootユーザーに切り替えます。

sudo -s

[ynakakoshi@ordsmcp ~]$ sudo -s

[root@ordsmcp ynakakoshi]# 


デフォルトのウォレットではLet's Encryptでの証明書の検証ができないようです。そのため、Oracle Walletを作成します。

CA証明書chain.pemとサーバー証明書cert.pemを、Oracle Databaseが動いているコンテナから参照できるディレクトリにコピーし、所有者をユーザーoracleに変更します。

cp /etc/letsencrypt/live/ホスト名/cert.pem /home/oracle/apex/
cp /etc/letsencrypt/live/ホスト名/chain.pem /home/oracle/apex/
chown oracle:oinstall /home/oracle/apex/*.pem


[root@ordsmcp ynakakoshi]# cp /etc/letsencrypt/live/ordsmcp.f5.si/cert.pem /home/oracle/apex/

[root@ordsmcp ynakakoshi]# cp /etc/letsencrypt/live/ordsmcp.f5.si/chain.pem /home/oracle/apex/

[root@ordsmcp ynakakoshi]# chown oracle:oinstall /home/oracle/apex/*.pem

[root@ordsmcp ynakakoshi]# 


ユーザーoracleに切り替え、コンテナapex-dbに接続します。

su - oracle
podman exec -it apex-db bash


[root@ordsmcp ynakakoshi]# su - oracle

Last login: Fri Dec  5 08:53:53 UTC 2025 on pts/0

[oracle@ordsmcp ~]$ podman exec -it apex-db bash

bash-4.4$ 


Oracle Walletを/home/oracle/walletに作成し、信頼できる証明書としてchain.pemおよびcert.pemを追加します。

orapki wallet create -wallet /home/oracle/wallet -pwd [パスワード] -auto_login
orapki wallet add -wallet /home/oracle/wallet -cert apex/chain.pem -trusted_cert -pwd [パスワード]
orapki wallet add -wallet /home/oracle/wallet -cert apex/cert.pem -trusted_cert -pwd [パスワード]


bash-4.4$ orapki wallet create -wallet /home/oracle/wallet -pwd Oracle1234 -auto_login

Oracle PKI Tool Release 23.0.0.0.0 - Production

Version 23.0.0.0.0

Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved.


Operation is successfully completed.

bash-4.4$ orapki wallet add -wallet /home/oracle/wallet -cert apex/chain.pem -trusted_cert -pwd Oracle1234

Oracle PKI Tool Release 23.0.0.0.0 - Production

Version 23.0.0.0.0

Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved.


Operation is successfully completed.

bash-4.4$ orapki wallet add -wallet /home/oracle/wallet -cert apex/cert.pem -trusted_cert -pwd Oracle1234

Oracle PKI Tool Release 23.0.0.0.0 - Production

Version 23.0.0.0.0

Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved.


Operation is successfully completed.

bash-4.4$ 


sqlplusでスキーマWKSP_APEXDEVに接続し、JWTプロファイルを作成します。

sqlplus wksp_apexdev@localhost/freepdb1

bash-4.4$ sqlplus wksp_apexdev@localhost/freepdb1


SQL*Plus: Release 23.26.0.0.0 - Production on Fri Dec 5 09:06:09 2025

Version 23.26.0.0.0


Copyright (c) 1982, 2025, Oracle.  All rights reserved.


Enter password: *********


Connected to:

Oracle AI Database 26ai Free Release 23.26.0.0.0 - Develop, Learn, and Run for Free

Version 23.26.0.0.0


SQL> 


ORDS_SECURITY.CREATE_JWT_PROFILEを実行します。
begin
    ords_security.create_jwt_profile(
        p_issuer => 'issの値'
        ,p_audience => 'audの値'
        ,p_jwk_url => 'jwks_uriの値'
    );
end;
/

SQL> begin

    ords_security.create_jwt_profile(

        p_issuer => 'https://sts.windows.net/********-****-****-****-***********/'

        ,p_audience => 'api://********-****-****-****-***********'

        ,p_jwk_url => 'https://login.microsoftonline.com/********-****-****-****-***********/discovery/v2.0/keys'

    );

end;

/  2    3    4    5    6    7    8  


PL/SQL procedure successfully completed.


SQL> 


以上でORDSのRESTサービスのJWTに保護が設定できました。

APEXのアプリケーション・ビルダーに戻り、ページ・デザイナでホーム・ページを開きます。


RESTサービスを呼び出す動的コンテンツのリージョンREST API Responseを選択します。ソースCLOBを返すPL/SQLファンクション本体を若干修正します。


APEX_WEB_SERVICE.MAKE_REST_REQUESTの引数p_wallet_pathに、file:///home/oracle/walletを指定します。


以上の変更を行い、APEXアプリケーションを実行します。

以下のようにUser InfoとREST API Responseの双方のリージョンに、正常な処理結果が表示されます。


これで、ORDSのRESTサービスが、Microsoft Entra IDが発行したJWTで認証されるようになりました。


リモートMCPサーバーの実装



VMインスタンスに作成したAPEX/ORDSの環境にリモートMCPサーバーを実装します。以前の記事「ORDSのRESTサービスをClaude Desktopのカスタムコネクタとして登録して呼び出す」に沿って、RESTモジュールsampleserverを作成します。

以下のAPEXアプリケーションをワークスペースにインポートします。
https://github.com/ujnak/apexapps/blob/master/exports/chat-with-generative-ai-hc-242.zip

アプリケーションとともにサポート・オブジェクトとして、表OPENAI_TOOLSとファンクションget_schemarun_sqlが作成され、属性などの定義情報が表に挿入されます。

次にリモートMCPサーバーの実装をサポート・スクリプトとして含む、以下のAPEXアプリケーションをインポートします。
https://github.com/ujnak/apexapps/blob/master/exports/mcp_handler.zip

APEXアプリケーションがインストールされると、パッケージMCP_HTTP_SERVER_PKGMCP_SAMPLEが作成されます。またORDSのRESTサービスとしてsampleseverが作成されます。

インストールされたAPEXアプリケーションを実行します。

作成をクリックし、ORDSのRESTサービスとMCPサーバーの実装を紐付けます。


Ords Url/ords/apexdev/sampleserverを指定します。Apex App IDはデフォルトで、このアプリケーション自身のアプリケーションIDになります。変更は不要です。Apex Page IDもこのAPEXアプリケーションのホーム・ページのIDになります。変更は不要です。これらはAPEXセッションを開始する際に使用します。

Package NameMCP_SAMPLEを指定します。このパッケージにMCPサーバーに必要なinitialize、tools/list、tools/callなどに対応した処理が、プロシージャとして実装されています。

Log Level4Tool SetCountriesを選択します。Tool SetのCountriesにはget_schemaおよびrun_sqlがツールとして含まれています。

以上で作成をクリックします。


/ords/apexdev/sampleserverとパッケージMCP_SAMPLEの紐付けができました。


今のところ、ワークスペース・スキーマに何もデータが含まれていません。

SQLワークショップユーティリティサンプル・データセットを開き、のデータをインストールします。


へ進みます。


データセットのインストールを実行します。


データセットがインストールされます。終了をクリックします。


サンプルデータセットの国のインストールが完了しました。


RESTサービスsampleserverの保護を解除し、MCP Inspectorから呼び出して動作確認をします。

SQLワークショップRESTfulサービスを開き、権限oracle.example.mcpを選択します。

保護されたモジュールからsampleserverを除外し、変更の適用をクリックします。


手元のPCからMCP Inspectorを起動します。

npx @modelcontextprotocol/inspector

Transport TypeStreamable HTTPを選択し、URLに以下を指定します。VMインスタンスのホストを指す、以下のURLを設定します。

https://ホスト名/ords/apexdev/sampleserver/mcp

Authenticationに関する設定はせず、Connectをクリックします。


MCPサーバーへ接続されます。Toolsタブを開き、List Toolsを実行します。


Toolsget_schemaを選択し、Run Toolをクリックします。


スキーマWKSP_APEXDEVにある表および列の情報が返されます。


Toolsrun_sqlを選択し、sqlに以下を記述します。

select * from eba_countries

Run Toolをクリックすると、表EBA_COUNTRIESの内容が返されます。


以上でリモートMCPサーバーの動作が確認できました。


リモートMCPサーバーのJWTトークンによる保護



リモートMCPサーバー(正確にはRESTモジュールsampleserver)を、Microsoft Entra IDが発行したJWTで保護します。

MCP InspectorのRedirect URLをEntra IDのアプリに追加します。


アプリケーションORDS MCPの概要から、リダイレクトURIのリンクを開きます。


プラットフォームの追加をクリックします。


シングルページアプリケーションを選択します。


リダイレクトURIとしてMCP InspectorのRedirect URLを設定します。本記事の環境では以下でした。

http://localhost:6274/oauth/callback

以上で構成をクリックします。


以上でMCP InspectorがアプリケーションORDS MCPとして認証できるようになりました。

OAuth2による認証の開始時に要求されたリソース・メタデータをnginxが返すように、/.well-known/以下にファイルを作成します。

VMインスタンスに接続し、rootユーザーに切り替えます。

sudo -s

[ynakakoshi@ordsmcp ~]$ sudo -s

[root@ordsmcp ynakakoshi]# 


nginxのドキュメント・ルートに移動します。

cd /usr/share/nginx/html

認証フローで参照されるファイルを配置するディレクトリを作成します。

リモートMCPサーバーのアクセスパスが/ords/apexdev/sampleserver/mcpなので、oauth-protected-resourceとして記述する内容は.well-known以下のords/apexdev/sampleserver/mcpに記述します。

mkdir -p .well-known/ords/apexdev/sampleserver

[root@ordsmcp html]# mkdir -p .well-known/ords/apexdev/sampleserver

[root@ordsmcp html]# 


ファイル.well-known/ords/apexdev/sampleserver/mcpを作成し、以下を記述します。resourceORDS_SECURITY.CREATE_JWT_PROFILEの引数p_audienceに与えた値、issuerp_issuerに与えた値です。authorization_serversには、OpenID Connectメタデータドキュメントの.well-knownが始まる前までのURLを設定します。

authorization_serversの設定で、JSON配列を{}で囲んでJSONオブジェクトにしています。構文的に間違っているように思いますが、こうしないとMCP Inspectorがauthorization_serversを認識しません。
{
  "resource": "api://********-****-****-****-************",
  "issuer": "https://sts.windows.net/********-****-****-****-************/",
  "authorization_servers": {
    ["https://login.microsoftonline.com/********-****-****-****-************/oauth2/v2.0/"]
  }
}

[root@ordsmcp html]# cat > .well-known/ords/apexdev/sampleserver/mcp

{

  "resource": "api://********-****-****-****-************",

  "issuer": "https://sts.windows.net/********-****-****-****-************/",

  "authorization_servers": {

    ["https://login.microsoftonline.com/********-****-****-****-************/oauth2/v2.0/"]

  }

}

[root@ordsmcp html]# 


OpenID Connectメタデータドキュメントをダウンロードし、.well-known以下に配置します。

curl -OL https://login.microsoftonline.com/*******-****-****-****-***********/v2.0/.well-known/openid-configuration
mv openid-configuration .well-known/

[root@ordsmcp 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   3393      0 --:--:-- --:--:-- --:--:--  3399

[root@ordsmcp html]# mv openid-configuration .well-known/

[root@ordsmcp html]# 


OpenID Connectメタデータドキュメントは認可サーバー(Authorization Server)
から取得するはずだと思うのですが、なぜかMCPサーバーを参照します。MCP Inspectorのv0.17.5よりoauth-authorization-serverがなければopenid-configurationを参照するように変わっています。

以上でoauth-protected-resourceとoauth-authorization-serverとして返すファイルを、MCPサーバーに配置できました。

APEXの画面に戻り、RESTfulサービスを開きます。

権限myordsappを選択し、保護されたモジュールsampleserverを含めます。

変更の適用をクリックし、リモートMCPサーバーへのOAuth2での保護を適用します。


以上でリモートMCPサーバー(ORDSのRESTモジュールsampleserver)の保護も完了です。

MCP Inspectorを起動します。

npx @modelcontextprotocol/inspector

OAuth2.0 FlowClient IDにEntra IDのアプリORDS MCPアプリケーション(クライアント)IDを設定します。Scopeにapi:で始まるスコープapi://********-****-****-****-************/myordsappを設定します。Client Secretは設定不要です。

Connectをクリックします。


Microsoft Entra IDによるサインインのプロセスが開始します。


Authenticatorを構成しているため、通知の送信を求められます。


Authenticatorの操作を求められます。


サインインの状態を維持するかどうか確認されます。


ユーザー認証に成功し、MCPサーバーのツールを呼び出すことができます。


Authタブを開くと、OAuthの認証フローの進捗を確認できます。


どうにも納得がいかない設定はいくつかありますが、とりあえずMicrosoft Entra IDのOAuth2で、ORDSのRESTサービスで作成したリモートMCPサーバーを保護できました。

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