2026年3月13日金曜日

MCP Appとして日報アプリを作成する

これまでに作成した環境の上で、新規にMCP Appとして簡単な日報アプリを作ってみます。

できるだけ作業手順が簡単になるようにAPEXアプリを作成しました。GitHubのリポジトリmcp-appapp/mcp-app-helper.sqlとしてエクスポートが置いていあります。

作成した日報アプリをMCP Inspectorで実行しています。実行環境はAlways FreeのAutonomous AI Databaseです。Microsoft Entra IDでユーザー認証しています。アプリの開発にAIを使うため、開発は壊れてもよいローカルのOracle AI Database 26ai Freeのコンテナ環境で実施しています。


Claude DesktopからSQLcl MCPサーバーでデータベースに接続して、Claude Sonnet 4.6でMCPのツール本体となるPL/SQLファンクションとMCP AppのUIリソースを生成しています。Skills無しで作成しているので少し手間がかかりました。おそらくClaude Codeを使ってSkillsをきちんと用意すると、もっとアプリの完成度が上がるでしょう。

以下より作業を紹介します。UC_AIのインストールおよびmcp-appがインストールされていることを前提とします。

最初に日報を保存する表DAILY_REPORTSを作成します。これもClaude Sonnet 4.6に指示を出して作成してもらいました。

続いて、APEXアプリmcp-app-helperをインストールします。

インストール手順は通常のAPEXアプリケーションと同じです。


インストールされたら、アプリケーションの編集を開きます。


アプリケーションの名前アプリケーションの別名を変更します。アプリケーションの別名はMCP AppにアクセスするURLに現れるORDS RESTモジュール名になります。

例えばAPEXワークスペースの名前がAPEXDEVのときは、MCP AppのURLは以下になります。

http[s]://ホスト/ords/apexdev/アプリケーション別名(小文字)/mcp


アプリケーションを実行します。

ナビゲーション・メニューからHandlersを開きます。

ORDS RESTモジュールとテンプレートmcpを作成し、POSTおよびDELETEハンドラを実装します。

作成をクリックします。


英小文字のアプリケーション別名がデフォルトのモジュール名です。変更不要(変更すると動かなくなります)なので、そのまま作成します。


シャトル・アイテムでモジュールの保護を設定できます。保護するモジュールを右に移動し、Submitします。


モジュールの保護には、ロールORDSUsersおよび権限oracle.example.mcpを使用します。これらはあらかじめ作成しておく必要があります。

置換文字列G_ROLE_NAMEおよびG_PRIVILEGE_NAMEの設定を変更することにより、異なるロールと権限も使用できます。


ナビゲーション・メニューのResourcesを開きます。

作成をクリックします。


UIリソースとして以下を設定します。URLにはAPEXアプリのページにアクセスするURLの指定を想定していますが(こちらの記事を参照のこと)、今回はAIに生成させたので指定していません。

Uri: ui://daily-report/mcp-app.html
Name: Daily Report
Description: 個人の日報を報告するウィジェット。
Mime Type: text/html;profile=mcp-app (デフォルトから変更不要)

DescriptionはAIが参照するので、丁寧に書いたほうが生成されるUIリソースの精度が上がると思われます。


UIリソースのエントリが登録されました。


ナビゲーション・メニューからToolsを開きます。

ツールとしてview_daily_reportおよびupdate_daily_reportを作成します。

作成をクリックします。


作成ツールの情報として以下を設定します。AIへの指示に、この定義を参照するように指示を出すので、DescriptionInput SchemaOutput Schemaの設定は重要です。

TagsにRESTモジュール名(小文字のアプリケーション別名)を含めると、このMCP Appのtools/listのレスポンスに作成したツールが現れます。ツールとして使用するファンクションは、引数としてCLOBを受け取りCLOBを返すようにします。そのため、Function Callの記述は常にreturn ファンクション名(:parameters);にします。

Code: view_daily_report
Description: 指定された担当者の日報を表示します。
Function Call: return view_daily_report(:parameters);
Tags: dailyreport
Resource Id: Daily Report

Input SchemaおよびOutput Schemaの作成に、ベルギーのUnited Codes社が提供しているサービスJSON Schema Builderを使用しています。

Input Schema:
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "title": "view_daily_report",
  "properties": {
    "employeeName": {
      "type": "string",
      "description": "The employee who wrote the daily report."
    },
    "reportDate": {
      "type": "string",
      "description": "Target date of the daily report."
    }
  },
  "required": [
    "reportDate"
  ]
}
Output Schema:
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "title": "view_daily_report",
  "properties": {
    "employeeName": {
      "type": "string",
      "description": "The employee who wrote the daily report."
    },
    "reportDate": {
      "type": "string",
      "description": "Target date of the daily report."
    },
    "summary": {
      "type": "string",
      "description": "Summary of the day"
    },
    "tomorrowPlan": {
      "type": "string",
      "description": "Tomorrow Plan"
    }
  }
}

以下のプロンプトでPL/SQLファンクションを作成しています。

「ビューOJ_MCP_UC_AI_TOOLSで定義されているview_daily_reportの本体となるPL/SQLのファンクションを生成してください。入力はINPUT_SCHEMAで定義されているJSONのCLOB、戻り値はOUTPUT_SCHEMAで定義されているCLOBの形式になります。 PL/SQLファンクションの操作対象は表DAILY_REPORTSです。」

SQLclのMCPサーバーを使用すると、ファンクションの作成に必要な情報をデータベースから引き出してくれます。


AIが生成したコードはmcp-app/daily-reports以下に置いてあります。

同様の手順でツールupdate_daily_reportを作成します。

Code: update_daily_report
Description: 指定された担当者の日報を作成または更新します。
Function Call: return update_daily_report(:parameters);
Tags: dailyreport

Input Schema:
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "title": "update_daily_report",
  "description": "Update Daily Report",
  "properties": {
    "employeeName": {
      "type": "string",
      "description": "The employee who wrote the daily report."
    },
    "reportDate": {
      "type": "string",
      "description": "Target date of the daily report."
    },
    "summary": {
      "type": "string",
      "description": "Summary of the day"
    },
    "tomorrowPlan": {
      "type": "string",
      "description": "Tomorrow Plan"
    }
  },
  "required": [
    "reportDate"
  ]
}
Output Schema:
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "title": "update_daily_report",
  "description": "Update Daily Report",
  "properties": {
    "employeeName": {
      "type": "string",
      "description": "The employee who wrote the daily report."
    },
    "reportDate": {
      "type": "string",
      "description": "Target date of the daily report."
    },
    "summary": {
      "type": "string",
      "description": "Summary of the day"
    },
    "tomorrowPlan": {
      "type": "string",
      "description": "Tomorrow Plan"
    }
  }
}

ツールのDescription、入力および出力パラメータのJSONスキーマ定義、操作の対象となる表のメタデータを参照できるためか、あまりやり取りせずに意図したファンクションが作成されました。修正が必要な部分がないとは言えないですが、Skillsの定義などで対応可能だと思います。


以上でツールが登録できました。

この状態でUIリソースを、以下のプロンプトで作成してもらいました。

「このツールをMCP App(SEP-1865)として表示するHTML/JavaScript/CSSのバンドルを生成して、OJ_MCP_UI_RESOURCESのTEXTを更新して。」

さすがに適当すぎて、何回もやり取りが必要でした。ただ、最終的に動くUIリソースがあったので、それを参照するように指示をしたところ、動きました。

「oj_mcp_ui_resourcesに含まれるget_current_userは、ボタンのクリックが動作します。」

おそらく、これもSkillsを用意していればもっと精度は上がったと予想されます。

とはいえ、以上の作業で動作するMCP Appが作成できました。

これまでの作業で作成したファンクションなどをAutonomous AI Databaseにコピーして、ADBでの動作を確認しています。UIリソースについてはコピーの手間を少なくするため、APEXアプリにBundleページを作成しています。


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

2026年3月11日水曜日

APEXアプリケーションのページ生成をMCP Appの簡易バンドラとして利用する

更新:2026年3月12日 - コードはGitHubへ移行

MCP Apps(SEP-1865)はiframe中に描画されるため、外部URLへのアクセスが制限されています。そのため、メソッドresources/readのtextとして読み出すUIリソースは、HTMLにJavaScriptとCSSをバンドルして1つにまとめることが推奨されています。公式ドキュメントではVite(vite-plugin-singlefile)が紹介されていますが、Oracle APEXでは使用できません。

その代わりにAPEXのページ・レンダリングを流用して、JavaScriptとCSSをHTMLにバンドルしてみます。ただし、ESモジュールext-appsをバンドルするのは手間がかかりすぎるため、これだけはresources/readが返す_meta属性に、以下のcsp指定を含めることでJavaScriptの読み込みと実行を許可しています。

{ "ui": { "csp": { "resourceDomains": ["https://cdn.jsdelivr.net"] }}}

以下よりAPEXのページ・レンダリングの流用手順について説明します。

今回の作業に使用するAPEXアプリケーションとしてsampleserverが作成済みと仮定します。

MCP App向けのHTMLの生成に使用するページ・テンプレートを作成します。

共有コンポーネントを開きます。


ユーザー・インターフェーステンプレートを開きます。


タイプページテンプレートのうち、装飾の最も少ないMinimal (No Navigation)コピーし、MCP App向けに改修します。


新規テンプレート名MCP2新規テンプレート識別子MCP2とします。(今回の記事を書くにあたって、すでにMCPを使っているためMCP2にしています)

コピーをクリックします。


テンプレートMCP2が作成されました。これを編集するために開きます。


ページ・テンプレートの定義ヘッダー本体フッターを以下に置き換えます。HTMLのレンダリング先はブラウザではなく、単にリージョンに配置したHTMLとページに定義したJavaScriptとCSSが、ひとつのページのHTMLとして出力されればよいだけです。そのため、使用しない定義はすべて削除します。



置換文字列の&BROWSER_LANGUAGE.アプリケーション定義グローバリゼーションの、アプリケーションのプライマリ言語として設定した言語に置き換えられます。


置換文字列#TITLE#は、ページ・プロパティのタイトルで置き換えられます。


置換文字列#PAGE_CSS#は、ページ・プロパティのCSSインラインで置き換えられます。


置換文字列#HEAD#は、ページ・プロパティのHTMLヘッダーで置き換えられます。


置換文字列#BODY#は、Bodyに配置したコンテンツで置き換えられます。APEXのコンポーネントはChatGPTやClaude Desktopでは扱えないため、配置できるのは静的コンテンツのリージョンに限られます。


置換文字列#PAGE_JAVASCRIPT#は、ページ・プロパティのJavaScriptファンクションおよびグローバル変数の宣言に置き換えられます。


以上の設定が、生成されるHTMLのページに埋め込まれる情報です。

APEXのテンプレートによるレイアウトも行わないため、テンプレートのレイアウトについても装飾を除きます。

レイアウトコンテナ・テンプレート#ROWS#行テンプレート#COLUMNS#列テンプレート#CONTENT#に変更します。


MCP App向けのテンプレートは以上でとりあえず完成です。変更を保存します。

続いて、MCP App用のHTMLを生成するページを作成します。

ページの作成を開始します。


空白ページを選択します。


ページの名前get-current-user-appとします。ページ・モード標準ナビゲーションは使用できないので両方ともオフにします。

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


空白のページが作成されます。

外観ページ・テンプレートとして、先ほど作成したページ・テンプレートMCP2を設定します。

ページ・プロパティの別名は、HTMLの生成時に引数として使用します。


MCP Appで使用するHTMLは、外部よりHTTPのGETメソッドでページを呼び出して生成します。そのため、ページ・プロパティのセキュリティ認証パブリック・ページに変更し、認証せずにページにアクセスできるようにします。


記事「MCP AppをOracle DatabaseとOracle REST Data Servicesで実装する」で作成したMCP App - Get Current Userと同等のUIリソースを作成します。

JavaScriptファンクションおよびグローバル変数の宣言に以下を記述します。


CSSインラインに以下を記述します。



MCP Appに表示するHTMLを記述する静的コンテンツのリージョンを作成します。識別名前Contentとします。

外観テンプレートなしを選択し、ソースHTMLが修飾無しでBodyに記載されるようにします。

ソースHTMLに以下を記述します。


以上でとりあえずページは完成です。

ページを実行すると生成されるHTMLを確認できます。


JavaScriptは動きません。HTMLとCSSの効果と生成されたHTMLに限り確認できます。


apex_web_service.make_rest_requestでこのページを呼び出し、取得したHTMLで表OJ_MCP_APP_RESOURCEの列TEXTをアップデートします。

この作業を行なうプロシージャUPDATE_APP_TEXT_FROM_APEX_PAGEをパッケージOJ_MCP_APP_UTILSに追加しています。処理内容は以下になります。

JavaScriptではext-appsをESモジュールとして扱います。APEXのページ・プロセスはページ・プロパティのJavaScriptファンクションおよびグローバル変数の宣言に記載されたコードを単に<script>...</script>で埋め込みます。これだとESモジュールを扱えないため、APEXのページ・プロセスが生成したHTMLに含まれるscriptタグにtype="module"を追加しています。

あとはこのプロシージャを実行し、MCP AppのUIとなるリソースを登録します。

APEXのページを呼び出せるURLを引数p_page_urlに与えます。
begin
oj_mcp_app_utils.update_app_text_from_apex_page(
    p_resource_name => 'get_current_user',
    p_resource_uri  => 'ui://get-current-user/mcp-app.html',
    p_page_url => 'http://host.docker.internal:8181/ords/apexdev/sampleserver/get-current-user-app'
);
commit;
end;
/
登録されたUIリソースは、MCP InspectorのResourcesより確認できます。


Appsタブからアプリを実行し、APEXのページとして作成したHTMLでMCP Appを表示できます。


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

2026年3月6日金曜日

MCP AppをOracle DatabaseとOracle REST Data Servicesで実装する

更新:2026年3月12日 - コードはGitHubへ移行

以下の2つの記事で実装したリモートMCPサーバーのフレームワークを使って、MCP Appを実装します。
作業環境は、UC Local APEX Devで作成した手元のOracle Database FreeおよびORDSのコンテナを使用します。利用方法については、こちらの記事「United CodesのUC Local APEX Devを使ってOracle APEXのローカル開発環境を作成する」で紹介しています。

ローカル環境へは以下のURLでアクセスします。


以下のコマンドを実行してAPEXのワークスペースを作成します。以下の例ではワークスペースをapexdevとして作成しています。

local-26ai.sh create-user apexdev

APEXのワークスペースとしてapexdev、管理者ユーザーapexdev、それとデフォルト・パーシング・スキーマとなるスキーマAPEXDEVが作成されます。Autonomous AI Databaseでワークスペースを作成した場合は、スキーマWKSP_APEXDEVが作成されます。UC Local APEX Devではスキーマ名に接頭辞WKSP_は付きません。

管理者ユーザーのデフォルトのパスワードはWelcome_1です。

mcp-app % local-26ai.sh create-user apexdev

loaded .env file


SQLcl: 金 3月 06 16:36:42 2026のリリース25.4 Production


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


接続先:

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

Version 23.26.1.0.0



USER    

_______ 

SYS     


[中略]


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

Version 23.26.1.0.0から切断されました

>>>>

saved sqlcl connection

connect with 'sql -name local-26ai-apexdev'

mcp-app % 


作成されたスキーマにUC_AIをLogger付きで導入します。Loggerを個別にスキーマにインストールするためには、CREATE ANY CONTEXT権限が必要です。

FREEPDB1にSYSで接続し、スキーマAPEXDEVに権限を与えます。

sql -name local-26ai-sys
grant create any context to apexdev;
exit;

mcp-app % sql -name local-26ai-sys


SQLcl: 金 3月 06 16:41:57 2026のリリース25.4 Production


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


接続先:

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

Version 23.26.1.0.0


SQL> grant create any context to apexdev;


Grantが正常に実行されました。


SQL> exit

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

Version 23.26.1.0.0から切断されました

mcp-app % 


UC_AIのリポジトリをクローンします。

git clone https://github.com/United-Codes/uc_ai.git

mcp-app % git clone https://github.com/United-Codes/uc_ai.git

Cloning into 'uc_ai'...

remote: Enumerating objects: 2703, done.

remote: Counting objects: 100% (421/421), done.

remote: Compressing objects: 100% (288/288), done.

remote: Total 2703 (delta 177), reused 212 (delta 120), pack-reused 2282 (from 1)

Receiving objects: 100% (2703/2703), 6.26 MiB | 8.64 MiB/s, done.

Resolving deltas: 100% (1770/1770), done.

mcp-app % 


クローンしたリポジトリに移動し、install_with_logger.sqlを実行します。

cd uc_ai
sql -name local-26ai-apexdev @install_with_logger
exit

mcp-app % cd uc_ai

uc_ai % sql -name local-26ai-apexdev @install_with_logger


SQLcl: 金 3月 06 16:48:33 2026のリリース25.4 Production


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


接続先:

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

Version 23.26.1.0.0


Installing UC AI with logger

_____________________________________________________________________________

User has all required privileges, installation will continue.

_____________________________________________________________________________




[中略]


Package Body UC_AIがコンパイルされました


Running post-installation scripts...

Logger package detected. Setting USE_LOGGER flag to TRUE.

Successfully compiled uc_ai_logger package with USE_LOGGER flag.



PL/SQLプロシージャが正常に完了しました。


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

UC AI installation complete!

Refer to the documentation for usage instructions: https://www.united-codes.com/products/uc-ai/docs/

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

Installation Complete!

SQL> exit

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

Version 23.26.1.0.0から切断されました

uc_ai % 


APEXのワークスペースにサインインし、MCPサーバーがセッション管理に使用するAPEXアプリケーションを作成します。


アプリケーション・ビルダーを開きます。


アプリケーションの作成を開始します。


APEXアプリケーションは存在するだけでよいです。IDの数値はスクリプト実行時に使用するので、覚えておきます。

アプリケーションの作成を実行します。


アプリケーションが作成されます。APEXでの作業は以上で完了です。


リモートMCPサーバーを実装するスクリプトsetup-sample-mcp-server.sqlをダウンロードします。スクリプトの先頭で定義されているAPEX_APP_IDに先ほど作成したAPEXアプリケーションのIDを指定します。ORDS_PATH_PREFIXには、APEXのワークスペースの名前を英子文字で指定します。

以上の変更を行い、スクリプトを実行します。

sql -name local-26ai-apexdev @ setup-sample-mcp-server.sql


mcp-app % sql -name local-26ai-apexdev @ setup-sample-mcp-server.sql


SQLcl: 金 3月 06 17:03:03 2026のリリース25.4 Production


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


接続先:

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

Version 23.26.1.0.0



PL/SQLプロシージャが正常に完了しました。



PL/SQLプロシージャが正常に完了しました。



Function GET_SCHEMAがコンパイルされました



Function RUN_SQLがコンパイルされました



Function GET_CURRENT_USERがコンパイルされました



PL/SQLプロシージャが正常に完了しました。



PL/SQLプロシージャが正常に完了しました。



PL/SQLプロシージャが正常に完了しました。



PL/SQLプロシージャが正常に完了しました。



Package MCP_HTTP_SERVER_PKGがコンパイルされました



Package Body MCP_HTTP_SERVER_PKGがコンパイルされました



Package MCP_SAMPLEがコンパイルされました



Package Body MCP_SAMPLEがコンパイルされました



PL/SQLプロシージャが正常に完了しました。



PL/SQLプロシージャが正常に完了しました。



PL/SQLプロシージャが正常に完了しました。


SQL> exit

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

Version 23.26.1.0.0から切断されました

mcp-app % 


上記のスクリプトでは、MCP Appとなるツールget_current_userにHTML/JavaScript/CSSのリソースがほとんど記述されていません。

PL/SQLのコードを一切変更せずに、ユーザー・インターフェースだけをClaudeに書いてもらうために、リソースの部分だけを別ファイルにしています。Claudeが生成したコードは以下です。1行だけcallServerToolの引数を古い仕様で認識していてコードの修正が明後日の方向に進んだので、手動で修正しました。

sql -name local-26ai-apexdev @ update-ui-get-current-user.sql


mcp-app % sql -name local-26ai-apexdev @ update-ui-get-current-user.sql 


SQLcl: 金 3月 06 17:12:15 2026のリリース25.4 Production


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


接続先:

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

Version 23.26.1.0.0



PL/SQLプロシージャが正常に完了しました。


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

Version 23.26.1.0.0から切断されました

mcp-app % 


今回はOpenID Connectによるユーザー認証は不要なので、ORDSのRESTサービスの保護を解除します。

sql -name local-26ai-apexdev @ unprotect-sampleserver.sql

mcp-app % sql -name local-26ai-apexdev @ unprotect-sampleserver.sql


SQLcl: 金 3月 06 17:17:33 2026のリリース25.4 Production


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


接続先:

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

Version 23.26.1.0.0



PL/SQLプロシージャが正常に完了しました。


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

Version 23.26.1.0.0から切断されました

mcp-app % 


以上で実装作業は完了です。

MCP Inspectorを実行します。

npx @modelcontextprotocol/inspector

Transport TypeStreamable HTTPURLに以下を指定します。

http://localhost:8181/ords/apexdev/sampleserver/mcp

Connect を実行します。


Appsタブを開きます。


MCP Appsとしてリソースが定義されているツールget_current_userがリストされます。

get_current_userをクリックすると、ユーザー・インターフェースが表示されます。


ユーザー・インターフェースにあるボタンGet Current Userをクリックします。


ツールget_current_userが呼び出され、ユーザー名として(ユーザー認証を実装していないため)スキーマ名APEXDEVが表示されます。


Autonomous AI Databaseを対象にして上記のスクリプトを実行して、OpenAI ChatGPTにアプリとして登録すると、以下の様にChatGPTにアプリが埋め込まれて操作することができました。


Claudeでカスタムコネクタとして登録しても、アプリを埋め込めなかったです。

まだ、クライアントによる差異はあるようです。

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