2025年8月8日金曜日

デジタル庁が整備しているJapan DashboardからCSVを取得しAPEXで利用する

内閣府とデジタル庁が協力して整備しているJapan Dashboardが公開されています。詳しくはデジタル庁のプレスリリース「Japan Dashboard(経済・財政・人口と暮らしに関するダッシュボード)とデータカタログ」 を参照してください。

本記事では、Japan Dashboradが提供している「複数の指標を一括ダウンロードする」機能を使用してダウンロードしたCSV(Excelも選択可)を、APEXを使ってOracle Databaseにロードします。

Japan Dashboardの見方と操作方法については「Japan Dashboard(経済・財政・人口と暮らしに関するダッシュボード)の見方と操作方法」に詳しく紹介されています。

さて、Japan Dashboardですが「Japan Dashboard(経済・財政・人口と暮らしに関するダッシュボード)とデータカタログ」を読むと、ダッシュボードに含まれるぞれぞれのページへのリンクは掲載されていますが、これがJapan Dashboardへのリンクというのは見つけられませんでした。また、「指標のデータを見る」、「1つの指標を都道府県ごとにみる」、「2つの指標の関連性をみる」、「4つの指標の推移を並べてみる」、「1つの指標のデータをコピーして利用する」のページはMicrosoft Power BIで作られていて、本記事の作業で使用する「複数の指標を一括ダウンロードする」はTableau Publicで作られています。

少し基本的な操作方法を調べてみました。

Microsoft Power BIを開いてるページから他のページへ移動するには、画面下のページ番号が表示されている部分クリックすると開くリストから、移動したいページを選びます。または、左右の矢印をクリックして移動します。


全画面モードで開くと、ページ左下にページ・セレクタが表示されます。


今回使用する「複数の指標を一括ダウンロードする」は、Power BIのJapan Dashboardの「1つの指標のデータをコピーして利用する」のページを開いて、そこにある複数指標の一括ダウンロードはこちら、のこちらをクリックして開きます。


これで、Japan Dashboardの複数の指標を一括ダウンロードするページを開けます。


指標を選んでCSVファイルをダウンロードします。

大分類人口中分類高齢者割合指標すべてを選びます。条件表示期間1975から2024都道府県すべてを選びます。

以上でダウンロードをクリックします。


書式ExcelCSVを選択します。APEXはどちらもロードできます。データが文字列の場合は、列の区切りが明確なExcelが有利ですが、数値であればCSVでもあまり変わらないはずです。

ダウンロードをクリックすると、データ.csvという名称でファイルがダウンロードされます。


ダウンロードされたデータ.csvを、APEXのSQLワークショップデータ・ワークショップを使って、データベースにロードします。


データのロードを開きます。


ファイルの選択をクリックし、データ.csvを選択します。


データのロード画面が開きます。APEXのデータ・ワークショップは最初の一行に限りヘッダー(いわゆる列名)として扱うことができます。Japan Dashboardからダウンロードしたファイルはヘッダーが複数行になるため、そのままではデータをロードできません。


とりあえずCSVのデータをデータベースにロードします。

ロード先新規表を選択します。新規に作成される表は、データを一時的にロードするインターフェース表として扱います。この表名TEMP_POPとしました。

列のデータ型の使用チェックを外し、すべての列の型をVARCHAR2(4000)にします。また、列見出し最初の行にヘッダーが含まれるチェックも外し、CSVに含まれるデータはすべて文字列として、表TEMP_POPにロードするようにします。列名COL001COL002といった、位置の情報だけの列名になります。

以上でデータのロードを実行します。


表TEMP_POPにデータがロードされます。


表TEMP_POPにロードしたCSVデータを、適切に定義した表に入れ替えます。入れ替え先の表を作成する必要があります。

OpenAIのGPT-5に、データ.csvを添付した上で、以下のプロンプトによりDDLを生成するようにお願いしました。

「添付のCSVファイルをOracle Databaseに保存するために、適切な表のDDLを生成してください。表名はデータの内容から30文字以内の英語で、適切な名前になるように決めてください。列名も英語で定義をお願いします。」


生成されたDDLです。まあまあいい感じです。というか、自分で書いたらチェック制約やコメントなどは、まず付けなかったと思いますし、NUMBER型の精度も設定していないと思います。
-- Table: ELDERLY_STATS_JAPAN
CREATE TABLE ELDERLY_STATS_JAPAN (
  PREFECTURE              VARCHAR2(40 CHAR)   NOT NULL,  -- Japanese names (e.g., 全国, 都道府県名)
  YEAR                    NUMBER(4)           NOT NULL,  -- e.g., 1975..2024
  SOLO_ELDERLY_RATE_ALL   NUMBER(4,1),                  -- %
  SOLO_ELDERLY_RATE_FEMALE NUMBER(4,1),                 -- %
  SOLO_ELDERLY_RATE_MALE  NUMBER(4,1),                  -- %
  AGING_RATE              NUMBER(4,1),                  -- %

  CONSTRAINT PK_ELDERLY_STATS_JP PRIMARY KEY (PREFECTURE, YEAR),
  CONSTRAINT CHK_RATES_RANGE CHECK (
    (SOLO_ELDERLY_RATE_ALL    BETWEEN 0 AND 100 OR SOLO_ELDERLY_RATE_ALL    IS NULL) AND
    (SOLO_ELDERLY_RATE_FEMALE BETWEEN 0 AND 100 OR SOLO_ELDERLY_RATE_FEMALE IS NULL) AND
    (SOLO_ELDERLY_RATE_MALE   BETWEEN 0 AND 100 OR SOLO_ELDERLY_RATE_MALE   IS NULL) AND
    (AGING_RATE               BETWEEN 0 AND 100 OR AGING_RATE               IS NULL)
  )
);

-- Optional: comments (English)
COMMENT ON TABLE ELDERLY_STATS_JAPAN IS 'Japan elderly solo-living rates and aging rate by prefecture and year';
COMMENT ON COLUMN ELDERLY_STATS_JAPAN.PREFECTURE IS 'Prefecture name (Japanese). "全国" = Japan total';
COMMENT ON COLUMN ELDERLY_STATS_JAPAN.YEAR IS 'Census/Survey year';
COMMENT ON COLUMN ELDERLY_STATS_JAPAN.SOLO_ELDERLY_RATE_ALL IS 'Share of elderly living alone, total (%)';
COMMENT ON COLUMN ELDERLY_STATS_JAPAN.SOLO_ELDERLY_RATE_FEMALE IS 'Share of elderly living alone, female (%)';
COMMENT ON COLUMN ELDERLY_STATS_JAPAN.SOLO_ELDERLY_RATE_MALE IS 'Share of elderly living alone, male (%)';
COMMENT ON COLUMN ELDERLY_STATS_JAPAN.AGING_RATE IS 'Aging rate: share of population aged 65+ (%)';
しかし主キーがありません。以下のプロンプトで指示すると、主キー列を追加するALTER文を生成しました。

「表ELDERLY_STATS_JAPANに、主キーとなる代理キーを列IDとして追加してください。値は数値を自動採番してください。」

さらに「元のCREATE TABLE文を更新してください。」と指示して、以下のDDLを得ました。
-- Table: ELDERLY_STATS_JAPAN
CREATE TABLE ELDERLY_STATS_JAPAN (
  ID                      NUMBER GENERATED ALWAYS AS IDENTITY
                            (START WITH 1 INCREMENT BY 1 NOCACHE) NOT NULL,
  PREFECTURE              VARCHAR2(40 CHAR)   NOT NULL,  -- Japanese names (e.g., 全国, 都道府県名)
  YEAR                    NUMBER(4)           NOT NULL,  -- e.g., 1975..2024
  SOLO_ELDERLY_RATE_ALL   NUMBER(4,1),                  -- %
  SOLO_ELDERLY_RATE_FEMALE NUMBER(4,1),                 -- %
  SOLO_ELDERLY_RATE_MALE  NUMBER(4,1),                  -- %
  AGING_RATE              NUMBER(4,1),                  -- %

  CONSTRAINT PK_ELDERLY_STATS_JP PRIMARY KEY (ID),
  CONSTRAINT UQ_ELDERLY_PREF_YEAR UNIQUE (PREFECTURE, YEAR),
  CONSTRAINT CHK_RATES_RANGE CHECK (
    (SOLO_ELDERLY_RATE_ALL    BETWEEN 0 AND 100 OR SOLO_ELDERLY_RATE_ALL    IS NULL) AND
    (SOLO_ELDERLY_RATE_FEMALE BETWEEN 0 AND 100 OR SOLO_ELDERLY_RATE_FEMALE IS NULL) AND
    (SOLO_ELDERLY_RATE_MALE   BETWEEN 0 AND 100 OR SOLO_ELDERLY_RATE_MALE   IS NULL) AND
    (AGING_RATE               BETWEEN 0 AND 100 OR AGING_RATE               IS NULL)
  )
);

-- Comments
COMMENT ON TABLE ELDERLY_STATS_JAPAN IS 'Japan elderly solo-living rates and aging rate by prefecture and year';
COMMENT ON COLUMN ELDERLY_STATS_JAPAN.ID IS 'Surrogate primary key, auto-generated';
COMMENT ON COLUMN ELDERLY_STATS_JAPAN.PREFECTURE IS 'Prefecture name (Japanese). "全国" = Japan total';
COMMENT ON COLUMN ELDERLY_STATS_JAPAN.YEAR IS 'Census/Survey year';
COMMENT ON COLUMN ELDERLY_STATS_JAPAN.SOLO_ELDERLY_RATE_ALL IS 'Share of elderly living alone, total (%)';
COMMENT ON COLUMN ELDERLY_STATS_JAPAN.SOLO_ELDERLY_RATE_FEMALE IS 'Share of elderly living alone, female (%)';
COMMENT ON COLUMN ELDERLY_STATS_JAPAN.SOLO_ELDERLY_RATE_MALE IS 'Share of elderly living alone, male (%)';
COMMENT ON COLUMN ELDERLY_STATS_JAPAN.AGING_RATE IS 'Aging rate: share of population aged 65+ (%)';
これをSQLワークショップSQLスクリプトで実行します。


確認画面が開くので即時実行をクリックします。DDLは正常に実行され、表ELDERLY_STATS_JAPANが作成されます。


表TEMP_POPの内容を表ELDERLY_STATS_JAPANに投入します。SQLコマンドで以下のSQLを実行します。
insert into elderly_stats_japan(prefecture, year, solo_elderly_rate_all, solo_elderly_rate_female, solo_elderly_rate_male, aging_rate)
select col002, to_number(col003), to_number(col004), to_number(col005), to_number(col006), to_number(col007) from temp_pop where id > 3;


以上でJapan Dashboardからダウンロードした指標を、Oracle Databaseにロードできました。

折角なので、これらの指標をチャート表示するAPEXアプリケーションを作成してみます。

アプリケーション作成ウィザードを起動し、ホーム・ページを削除して代わりにファセット検索のページを追加します。

アプリケーションの名前高齢化指標とします。


ファセット検索のページ名高齢化指標とします。ソースのは先ほど作成したELDERLY_STATS_JAPANです。

以上の設定でアプリケーションを作成します。


作成されたアプリケーションを実行すると、ホーム・ページとして以下が表示されます。


このページに、「一人暮らしの高齢者割合(全体)」、「一人暮らしの高齢者割合(女性)」、「一人暮らしの高齢者割合(男性)」、「高齢化率(人口総数に対する65歳以上の割合)」の4つの折れ線グラフを追加します。

ページ・デザイナ高齢化指標のページを開きます。

検索結果を表示するクラシック・レポートのリージョンElderly Stats Japan静的IDを設定します。これから作成するチャート・リージョンのソースは、ここで設定する静的IDを指定して、ファセット検索の検索結果を参照します。

静的IDELDERLY_STATS_JAPANとします。

ファセットのP1_YEARP1_AGING_RATEは用途が無いのでコメント・アウトします。


レポート・リージョンの検索結果を参照して、表データを返すパイプライン表関数get_fs_elderly_stats_japanを作成します。以下のコードを実行します。

表ELDERY_STATS_JAPANを作成したDDLの実行と同様に、SQLワークショップSQLスクリプトを使って実行できます。



チャートを表示するリージョンを作成します。

識別名前SOLO_ELDERLY_RATE_ALLタイトル一人暮らしの高齢者割合(全体)とします。タイプチャートです。

ソースSQL問合せに、先ほど作成したパイプライン表関数get_fs_elderly_stats_japanを使用したSELECT文を記述します。チャートが表示される時点での、リージョンElderly Stats Japanにファセットが適用された検索結果が返されます。
select prefecture, year,
    solo_elderly_rate_all
from table(
    get_fs_elderly_stats_japan(:APP_PAGE_ID, 'ELDERLY_STATS_JAPAN')
)
where solo_elderly_rate_all is not null

リージョンの属性を開きます。

チャートタイプ折れ線を選択します。X軸は列YEARつまり年なので、本来は設定時間軸タイプ有効、つまり時間として設定すべきです。ただし、その場合は列YEARの型はDATEまたはTIMESTAMPである必要があります。年だけであれば、数値として扱ってもほぼ問題ないため、時間軸タイプは設定しません。

都道府県および全国がシリーズになるため、凡例表示オンにします。


ひとつだけあるシリーズ名前ALLとします。実際のシリーズは列のマッピングシリーズ名として設定する列PREFECUTERの値になるため、この名前はなんでもかまいません。

ソース位置としてリージョン・ソースを選択します。

列のマッピングラベル(X軸)はYEAR(Y軸)はSOLO_ELDERLY_RATE_ALLを選択します。


チャートの設定は以上です。

リージョンElderly Stats Japanでの検索が完了した後に、このチャートSOLO_ELDERLY_RATE_ALLをリフレッシュする動的アクションを作成します。

作成する動的アクション名前afterRefresh Reportタイミングイベントリフレッシュ後選択タイプリージョンリージョンElderly Status Japanです。


TRUEアクションリフレッシュを選択し、影響を受ける要素選択タイプリージョンリージョンとしてリフレッシュ対象であるSOLO_ELDERLY_RATE_ALLを設定します。


以上でチャートは完成です。

ファセット検索で指定した都道府県が、一人暮らしの高齢者割合(全体)のチャートに表示されます。


後は、ほぼ同じ手順で「一人暮らしの高齢者割合(女性)」、「一人暮らしの高齢者割合(男性)」、「高齢化率(人口総数に対する65歳以上の割合)」の3つのチャートを作成します。

リージョンを重複させた後にリージョン名や列名を変更すると、すぐにチャートを作成できます。


チャートのレイアウトを調整すると、以下のようなAPEXアプリケーションが作成されます。


今回作成したAPEXアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/japan-dashboard-elderly-stats.zip

Oracle APEXのアプリケーション作成の参考になれば幸いです。

LM Studioでgpt-oss:120bを実行しSQLclのMCPサーバーを呼び出してデータベースに問い合わせる

人気のあるローカルLLMランタイムにOllamaLM Studioがあります。どちらもOpenAIが最近リリースしたオープンウェイトモデルgpt-oss:120bgpt-oss:20bに対応しています。

LM StudioではフロントエンドのアプリケーションにMCPサーバーを追加することができます。本記事ではLM StudioにMCPサーバーとしてSQLclを追加し、ローカルLLMとしてgpt-oss:120bを実行して、データベースに自然言語で問い合わせを行ってみます。

作業環境はApple Macbook Pro(M4 128GB)です。LLMを動かすだけで70GB程度のメモリを使用します。gpt-oss:20bは20GB程度のメモリを使用します。双方ともMXFP4で量子化されたモデルが対象です。作業環境となるコンピュータにはあらかじめ、LM Studioとpodmanをインストールしておきます。

データベースについては、こちらの記事「Ollamaでgpt-oss:20bを実行しOpen WebUIからSQLclのMCPサーバーを呼び出す」のデータベースの準備で作成したコンテナsales-dbを使用します。Oracle Database 23ai Freeにsales_history(スキーマSH)のサンプル・データをインストールしています。また、サンプル・データにたいして読み込み権限しか持たないデータベース・ユーザーmcpuserが作成されています。

コンテナsales-dbを実行します。

podman start sales-db

% podman start sales-db

sales-db

% 


ローカルにインストールしているSQLclを使用してMCPサーバーを実行すると、VS Codeなどで使用しているデータベース接続もMCPサーバーから利用可能になります。

今回はMCPサーバー専用のSQLclをコンテナで実行します。Oracle Container RegistryよりSQLclのコンテナ・イメージを取得します。

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

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

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

Getting image source signatures

Copying blob sha256:868d7396c28bb01216fb0529ee04fa61b3f2d0abf397ccdb0a39acfb5ff45458

Copying blob sha256:698aee9470ef0d32633e2423dc3b5e16af1fbd10e5245a13145ece9984c96f26

Copying blob sha256:4bc021afff70ffc5b463d429bba763fc99220db548ac2cb8fba8d4df8c84a3c9

Copying blob sha256:806ed6d6ab84d056e19068db243c0cffdb0d9eae1c6f097e990f304ac1e7b55e

Copying blob sha256:22a33186b552e320dd6d69ee1c32b7cc24a0fb1fb0ca752b7a3af1f5c8af660f

Copying config sha256:e2b0fb8809c1033d352e2e6b484547e1766d7a59329b64a945cdaa112cf02feb

Writing manifest to image destination

e2b0fb8809c1033d352e2e6b484547e1766d7a59329b64a945cdaa112cf02feb

% 


SQLclを実行するコンテナとしてoracle-mcpを作成し実行します。

podman run -it --name oracle-mcp container-registry.oracle.com/database/sqlcl:latest

SQLclのプロンプトが返されます。

% podman run -it --name oracle-mcp container-registry.oracle.com/database/sqlcl:latest



SQLcl: Release 25.2 Production on Fri Aug 08 02:14:54 2025


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


SQL> 


コンテナsales-dbで実行されているデータベースへの接続を保存します。接続名はmydbとします。

conn -save mydb -savepwd mcpuser/mcpuser@host.containers.internal/freepdb1
exit


exitするとSQLclが終了するため、コンテナoracle-mcpも終了します。

SQL> conn -save mydb -savepwd mcpuser/mcpuser@host.containers.internal/freepdb1

Name: mydb

Connect String: host.containers.internal/freepdb1

User: mcpuser

Password: ******

Connected.

SQL> exit

Disconnected from Oracle Database 23ai Free Release 23.0.0.0.0 - Develop, Learn, and Run for Free

Version 23.8.0.25.04

% 


作成したコンテナoracle-mcpを実行します。

podman start oracle-mcp

% podman start oracle-mcp

oracle-mcp

% podman ps

CONTAINER ID  IMAGE                                                COMMAND               CREATED        STATUS                    PORTS                   NAMES

bcb0a1128f1c  container-registry.oracle.com/database/free:latest   /bin/bash -c $ORA...  19 hours ago   Up 47 minutes (starting)  0.0.0.0:1521->1521/tcp  sales-db

ef2d41ef5fd0  container-registry.oracle.com/database/sqlcl:latest  /nolog                4 minutes ago  Up 3 seconds (starting)                           oracle-mcp

% 


コンテナoracle-mcpを使ってMCPサーバーを実行します。

podman exec -i oracle-mcp sql -mcp

% podman exec -i oracle-mcp sql -mcp

---------- MCP SERVER STARTUP ----------

MCP Server started successfully on Fri Aug 08 02:33:02 UTC 2025

Press Ctrl+C to stop the server

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

^C

% 


MCPサーバーの起動を確認した後、CTRL+Cを入力してMCPサーバーを停止します。

LM Studioを起動し、Model SearchからOpenAI's gpt-oss 120BまたはOpenAI's gpt-oss 20Bをダウンロードします。


モデルのダウンドードが完了したらロードします。Context lengthはできるだけ大きい値にします。


チャットの入力フィールドの下にアイコンがプラグのボタンがあります。これをクリックしてツールの構成画面を開きます。


Installをクリックし、Edit mcp.jsonを実行します。


「MCPサーバーは便利だけど危険だよ、信頼できるMCPサーバーだけを追加してね」といった警告が表示されます。Got itをクリックします。


mcp.jsonとして以下を記述します。他のMCPサーバーが登録済みの場合は、sqlclの部分を追加します。
{
  "mcpServers": {
    "sqlcl": {
      "command": "podman",
      "args": [
        "exec",
        "-i",
        "oracle-mcp",
        "sql",
        "-mcp"
      ]
    }
  }
}
ボタンSaveをクリックし、mcp.jsonを保存します。右側のパネルにSQLclのMCPサーバーが提供しているツールが一覧されます。


以上でLM StudioにOracle DatabaseのMCPサーバーが組み込まれました。

この後はLM Studioで新規にチャットを開始して、自由に質問します。

接続できるデータベースや接続できるユーザーは制限されています。データベースに対して可能な操作も、ほとんどSELECTのみになっています。また、ユーザーMCPUSERは表領域USERSに対してクオータを10Mバイトしか割り当てていないため、大量のデータをアップロードする、といったこともできません。

今回は適用していませんが、Oracle Databaseが持つResource Managerの機能を使うとCPUリソースなども制限できます。


保存した接続mydbでデータベースに接続して、sales_historyのサンプル・データに問い合わせを行いました。ツール呼び出しでできることを制限しているので、確認せずに実行しています。


原因は分かりませんが、同一のチャット・セッションで複数のMCPサーバーを起動することがあるようです。psで確認すると"podman exec -i oracle-mcp sql -mcp"というコマンドが複数実行されていることが確認できます。

その場合、MCPサーバーを実行しているコンテナoracle-mcpを再起動すると状況が改善しました。

podman restart oracle-mcp

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

2025年8月7日木曜日

Ollamaでgpt-oss:20bを実行しOpen WebUIからSQLclのMCPサーバーを呼び出す

OpenAIからリリースされたgpt-oss:20bOllamaで実行し、SQLclのMCPサーバーをツールとして呼び出してデータベースに問い合わせを発行します。チャットを受け付けるフロントエンドにOpen WebUIを使用し、Open WebUIからSQLclのMCPサーバーを呼び出すために、mcpoを使用します。

作業にはApple SiliconのMacbook Pro(M4 128GB)を使用します。Open WebUI、mcpoおよびOracle Databaseはそれぞれ、podmanを使ってコンテナとして実行します。

以下の作業を行います。
  1. データベースにサンプル・スキーマSHをインストールし、SQLclのMCPサーバーが使用するデータベース・ユーザーMCPUSERを作成します。
  2. mcpoとSQLclをインストールしたコンテナ・イメージを作成します。作成したコンテナ・イメージからコンテナの作成と実行を行い、コンテナにSQLclが参照するデータベースへの接続情報を保存します。
  3. Ollamaにgpt-oss:20bをロードし実行します。
  4. Open WebUIをコンテナとして実行します。
  5. ブラウザからOpen WebUIにアクセスし、ツールとしてSQLclを組み込んだmcpoを設定します。
  6. チャットを行い動作を確認します。

データベースの準備



Oracle Database 23ai Freeのコンテナ・イメージからコンテナsales-dbを作成し実行します。オプションとして-p 1521:1521を指定し、ホストからデータベースにネット接続できるようにします。

podman run -d --name sales-db -p 1521:1521 container-registry.oracle.com/database/free:latest

% podman run -d --name sales-db -p 1521:1521 container-registry.oracle.com/database/free:latest

f0c94a522a9b3c32fba7fa3295774de338c8958bdf63a0df15b1491232d12a30

% 


コンテナのログにDATABASE IS READY TO USE!と出力されていることを確認します。出力されていれば、データベースは利用できます。

podman logs sales-db

% podman logs sales-db   

Starting Oracle Net Listener.

Oracle Net Listener started.

Starting Oracle Database instance FREE.

Oracle Database instance FREE started.


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:

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

2025-08-07T00:44:35.601724+00:00

Completed: Pluggable database FREEPDB1 opened read write 

Completed: ALTER DATABASE OPEN

2025-08-07T00:44:35.741920+00:00

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

Dumping current patch information

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

No patches have been applied

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

% 


SYSおよびSYSTEMのパスワードを設定します。デフォルトではランダムなパスワードが設定されています。

podman exec sales-db ./setPassword.sh <SYSのパスワード>

% podman exec sales-db ./setPassword.sh *******

The Oracle base remains unchanged with value /opt/oracle


SQL*Plus: Release 23.0.0.0.0 - Production on Thu Aug 7 00:48:52 2025

Version 23.8.0.25.04


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



Connected to:

Oracle Database 23ai Free Release 23.0.0.0.0 - Develop, Learn, and Run for Free

Version 23.8.0.25.04


SQL> 

User altered.


SQL> 

User altered.


SQL> 

Session altered.


SQL> 

User altered.


SQL> Disconnected from Oracle Database 23ai Free Release 23.0.0.0.0 - Develop, Learn, and Run for Free

Version 23.8.0.25.04

% 


Oracle Database Sample Schemas 23cのv23.3をダウンロードします。

curl -OL https://github.com/oracle-samples/db-sample-schemas/archive/refs/tags/v23.3.zip


% curl -OL https://github.com/oracle-samples/db-sample-schemas/archive/refs/tags/v23.3.zip

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

                                 Dload  Upload   Total   Spent    Left  Speed

  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0

100 11.6M    0 11.6M    0     0  3674k      0 --:--:--  0:00:03 --:--:-- 4709k

% 


ダウンロードしたv23.3.zipを解凍し、sales_historyのサンプル・データをインストールします。インストール作業にSQLclを使用します。


データベースにユーザーSYSTEMで接続し、sh_install.sqlを実行します。スクリプトを実行すると、新規に作成するスキーマSHに設定するパスワードの入力を求められます。この後の作業でデータベースにスキーマSHで接続するため、入力するパスワードは覚えておきます。


スキーマSHのデフォルト表領域上書きの設定はデフォルトのままで、変更は不要です。


unzip v23.3.zip
cd db-sample-schemas-23.3/sales_history
sql system/[パスワード]@localhost/freepdb1
@sh_install


% unzip v23.3.zip 

Archive:  v23.3.zip

e3325a83e56c516815844025418a96ecaf219751

   creating: db-sample-schemas-23.3

 extracting: db-sample-schemas-23.3/.gitignore  

  inflating: db-sample-schemas-23.3/LICENSE.txt  

  inflating: db-sample-schemas-23.3/README.md  

  inflating: db-sample-schemas-23.3/README.txt  

  inflating: db-sample-schemas-23.3/SECURITY.md  


[中略]


  inflating: db-sample-schemas-23.3/sales_history/sh_install.sql  

  inflating: db-sample-schemas-23.3/sales_history/sh_populate.sql  

  inflating: db-sample-schemas-23.3/sales_history/sh_uninstall.sql  

  inflating: db-sample-schemas-23.3/sales_history/supplementary_demographics.csv  

  inflating: db-sample-schemas-23.3/sales_history/times.csv  

% cd db-sample-schemas-23.3/sales_history 

sales_history % sql system/*******@localhost/freepdb1



SQLcl: 木 8月 07 10:08:22 2025のリリース25.2 Production


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


Last Successful login time: 木 8月  07 2025 10:08:23 +09:00


接続先:

Oracle Database 23ai Free Release 23.0.0.0.0 - Develop, Learn, and Run for Free

Version 23.8.0.25.04


SQL> @sh_install


Thank you for installing the Oracle Sales History Sample Schema.

This installation script will automatically exit your database session

at the end of the installation or if any error is encountered.

The entire installation will be logged into the 'sh_install.log' log file.


Enter a password for the user SH: ******



Enter a tablespace for SH [USERS]: 

Do you want to overwrite the schema, if it already exists? [YES|no]: 


Start time: 07-AUG-25 01.09.00.140452 AM +00:00                                      

******  Creating COUNTRIES table ....


Table COUNTRIESは作成されました。


******  Creating CUSTOMERS table ....


Table CUSTOMERSは作成されました。


******  Creating PROMOTIONS table ....


Table PROMOTIONSは作成されました。


[中略]


Installation verification    

____________________________ 

Verification:                


Table                            provided    actual 

_____________________________ ___________ _________ 

channels                                5         5 

costs                               82112     82112 

countries                              35        35 

customers                           55500     55500 

products                               72        72 

promotions                            503       503 

sales                              918843    918843 

times                                1826      1826 

supplementary_demographics           4500      4500 


Thank you!                                                  

___________________________________________________________ 

The installation of the sample schema is now finished.      

Please check the installation verification output above.    

                                                            

You will now be disconnected from the database.             

                                                            

Thank you for using Oracle Database!                        

                                                            

Oracle Database 23ai Free Release 23.0.0.0.0 - Develop, Learn, and Run for Free

Version 23.8.0.25.04から切断されました

sales_history % 


スキーマSHに接続し、マテリアライズド・ビューCAL_MONTH_SALES_MVFWEEK_PSCAT_SALES_MVを完全リフレッシュします。
begin
     dbms_mview.refresh('CAL_MONTH_SALES_MV', method => 'C');
     dbms_mview.refresh('FWEEK_PSCAT_SALES_MV', method => 'C');
end;
/

sales_history % sql sh/********@localhost/freepdb1



SQLcl: 木 8月 07 10:17:01 2025のリリース25.2 Production


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


接続先:

Oracle Database 23ai Free Release 23.0.0.0.0 - Develop, Learn, and Run for Free

Version 23.8.0.25.04


SQL> begin

  2      dbms_mview.refresh('CAL_MONTH_SALES_MV', method => 'C');

  3      dbms_mview.refresh('FWEEK_PSCAT_SALES_MV', method => 'C');

  4  end;

  5* /


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


SQL> exit

Oracle Database 23ai Free Release 23.0.0.0.0 - Develop, Learn, and Run for Free

Version 23.8.0.25.04から切断されました

sales_history % 


以上でサンプル・データセットのsales_historyがインストールできました。

SQLclのMCPサーバーがsales_historyのサンプル・データセットを参照できるように、特別なデータベース・ユーザーを作成します。サンプル・データセットの参照だけを許可し、データセットの変更は許可しません。

データベースにSYS AS SYSDBAで接続し、データベース・ユーザーとしてMCPUSERを作成します。

create user mcpuser identified by mcpuser;
grant connect,resource to mcpuser;
alter user mcpuser quota 10m on users;

sales_history % sql sys/******@localhost/freepdb1 as sysdba



SQLcl: 木 8月 07 10:30:27 2025のリリース25.2 Production


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


接続先:

Oracle Database 23ai Free Release 23.0.0.0.0 - Develop, Learn, and Run for Free

Version 23.8.0.25.04


SQL> create user mcpuser identified by mcpuser;


User MCPUSERは作成されました。


SQL> grant connect,resource to mcpuser;


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


SQL> alter user mcpuser quota 10m on users;


User MCPUSERが変更されました。


SQL> 


作成したデータベース・ユーザーMCPUSERに、スキーマSHが持つ表やビューのSELECT権限を与えます。

grant select any table on schema sh to mcpuser;

SQL> grant select any table on schema sh to mcpuser;


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


SQL> exit

Oracle Database 23ai Free Release 23.0.0.0.0 - Develop, Learn, and Run for Free

Version 23.8.0.25.04から切断されました

sales_history % 


データベースにユーザーMCPUSERで接続し、スキーマSHの表やビューを参照するシノニムを作成します。
set serveroutput on
declare
    l_statement varchar2(32767);
    l_select    varchar2(32767);
    l_count     number;
begin
    for r in (
        select owner, object_name from all_objects
        where owner = 'SH' and object_type in ('TABLE','VIEW')
          and instr(object_name,'$') = 0
    )
    loop
        if true then
            /* create synonym */
            l_statement := 'create synonym ' || r.object_name || ' for ' || r.owner || '.' || r.object_name;
            dbms_output.put_line(l_statement);
            execute immediate l_statement;
            -- verify synonym by counting rows
            l_select    := 'select count(*) into :cnt from ' || r.object_name;
            execute immediate l_select into l_count;
            dbms_output.put_line(l_select || ' / ' || l_count);
        else
            /* drop synonym */
            l_statement := 'drop synonym ' || r.object_name;
            dbms_output.put_line(l_statement);
            execute immediate l_statement;
        end if;
    end loop;
end;

sales_history % sql mcpuser/mcpuser@localhost/freepdb1



SQLcl: 木 8月 07 10:57:26 2025のリリース25.2 Production


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


接続先:

Oracle Database 23ai Free Release 23.0.0.0.0 - Develop, Learn, and Run for Free

Version 23.8.0.25.04


SQL> set serveroutput on

SQL> declare

  2      l_statement varchar2(32767);

  3      l_select    varchar2(32767);

  4      l_count     number;

  5  begin

  6      for r in (

  7          select owner, object_name from all_objects

  8          where owner = 'SH' and object_type in ('TABLE','VIEW')

  9            and instr(object_name,'$') = 0

 10      )

 11      loop

 12          if true then

 13              /* create synonym */

 14              l_statement := 'create synonym ' || r.object_name || ' for ' || r.owner || '.' || r.object_name;

 15              dbms_output.put_line(l_statement);

 16              execute immediate l_statement;

 17              -- verify synonym by counting rows

 18              l_select    := 'select count(*) into :cnt from ' || r.object_name;

 19              execute immediate l_select into l_count;

 20              dbms_output.put_line(l_select || ' / ' || l_count);

 21          else

 22              /* drop synonym */

 23              l_statement := 'drop synonym ' || r.object_name;

 24              dbms_output.put_line(l_statement);

 25              execute immediate l_statement;

 26          end if;

 27      end loop;

 28  end;

 29* /

create synonym CAL_MONTH_SALES_MV for SH.CAL_MONTH_SALES_MV

select count(*) into :cnt from CAL_MONTH_SALES_MV / 48

create synonym CHANNELS for SH.CHANNELS

select count(*) into :cnt from CHANNELS / 5

create synonym COSTS for SH.COSTS

select count(*) into :cnt from COSTS / 82112

create synonym COUNTRIES for SH.COUNTRIES

select count(*) into :cnt from COUNTRIES / 35

create synonym CUSTOMERS for SH.CUSTOMERS

select count(*) into :cnt from CUSTOMERS / 55500

create synonym FWEEK_PSCAT_SALES_MV for SH.FWEEK_PSCAT_SALES_MV

select count(*) into :cnt from FWEEK_PSCAT_SALES_MV / 10512

create synonym PRODUCTS for SH.PRODUCTS

select count(*) into :cnt from PRODUCTS / 72

create synonym PROFITS for SH.PROFITS

select count(*) into :cnt from PROFITS / 916039

create synonym PROMOTIONS for SH.PROMOTIONS

select count(*) into :cnt from PROMOTIONS / 503

create synonym SALES for SH.SALES

select count(*) into :cnt from SALES / 918843

create synonym SUPPLEMENTARY_DEMOGRAPHICS for SH.SUPPLEMENTARY_DEMOGRAPHICS

select count(*) into :cnt from SUPPLEMENTARY_DEMOGRAPHICS / 4500

create synonym TIMES for SH.TIMES

select count(*) into :cnt from TIMES / 1826



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


SQL> exit

Oracle Database 23ai Free Release 23.0.0.0.0 - Develop, Learn, and Run for Free

Version 23.8.0.25.04から切断されました

sales_history % 


参照可能な表のメタデータを、JSONドキュメントとして取得しておきます。スキーマSHで接続して以下のコードを実行します。スプール先のファイル名はmetadata.jsonとします。
set serveroutput on
set feedback off
spool metadata.json
declare
    l_metadata json;
    l_count    pls_integer;
begin
    l_count := 0;
    dbms_output.put_line('[');
    for r in (
        select object_name from all_objects
        where owner = 'SH' and object_type in ('TABLE','VIEW')
          and instr(object_name,'$') = 0
    )
    loop
        if l_count > 0 then
            dbms_output.put_line(',');
        end if;
        l_metadata := dbms_developer.get_metadata(r.object_name,level => 'BASIC');
        -- remove scheme from object info.
        select json_transform(l_metadata, remove '$.objectInfo.schema') into l_metadata;
        dbms_output.put_line(json_serialize(l_metadata pretty));
        l_count := l_count + 1;
    end loop;
    dbms_output.put_line(']');
end;
/
spool off

sales_history % sql sh/*******@localhost/freepdb1



SQLcl: 木 8月 07 12:01:42 2025のリリース25.2 Production


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


接続先:

Oracle Database 23ai Free Release 23.0.0.0.0 - Develop, Learn, and Run for Free

Version 23.8.0.25.04


SQL> set serveroutput on

SQL> set feedback off

SQL> spool metadata.json

SQL> declare

  2      l_metadata json;

  3      l_count    pls_integer;

  4  begin

  5      l_count := 0;

  6      dbms_output.put_line('[');

  7      for r in (

  8          select object_name from all_objects

  9          where owner = 'SH' and object_type in ('TABLE','VIEW')

 10            and instr(object_name,'$') = 0

 11      )

 12      loop

 13          if l_count > 0 then

 14              dbms_output.put_line(',');

 15          end if;

 16          l_metadata := dbms_developer.get_metadata(r.object_name,level => 'BASIC');

 17          -- remove scheme from object info.

 18          select json_transform(l_metadata, remove '$.objectInfo.schema') into l_metadata;

 19          dbms_output.put_line(json_serialize(l_metadata pretty));

 20          l_count := l_count + 1;

 21      end loop;

 22      dbms_output.put_line(']');

 23  end;

 24* /

[

{

  "objectType" : "TABLE",

  "objectInfo" :

  {

    "name" : "CAL_MONTH_SALES_MV",

    "columns" :

    [

      {

        "name" : "CALENDAR_MONTH_DESC",

        "notNull" : true,

        "dataType" :

        {

          "type" : "VARCHAR2",

          "length" : 8,

          "sizeUnits" : "BYTE"

        }

      },

      {

        "name" : "DOLLARS",

        "notNull" : false,

        "dataType" :

        {

          "type" : "NUMBER"

        }

      }

    ]

  },

  "etag" : "8C9210395BE477CBC7AA962A9F82E790"

}

,

{

  "objectType" : "TABLE",

  "objectInfo" :

  {

    "name" : "CHANNELS",

    "columns" :

    [

      {

        "name" : "CHANNEL_ID",

        "notNull" : true,

        "dataType" :

        {

          "type" : "NUMBER"

        }

      },

      {

        "name" : "CHANNEL_DESC",

        "notNull" : true,

        "dataType" :


[中略]


      {

        "name" : "END_OF_FIS_YEAR",

        "notNull" : true,

        "dataType" :

        {

          "type" : "DATE"

        }

      }

    ]

  },

  "etag" : "16A2DBCED85E5EF2F3A14DDDB492ABFD"

}

]


SQL> spool off

SQL> exit

Oracle Database 23ai Free Release 23.0.0.0.0 - Develop, Learn, and Run for Free

Version 23.8.0.25.04から切断されました

sales_history %


以上でデータベースの準備は完了です。


mcpoとSQLclを組み込んだコンテナの実行



mcpoとSQLclを組み込んだコンテナ・イメージを作成します。mcpoはOpen WebUI向けに、MCPサーバーをOpenAPI互換のHTTPサーバーとしてにアクセスできるようにする、一種の代理サーバーです。詳しくはmcpoのGitHubのページを参照してください。

コンテナ・イメージの作成に、以下のDockerfileを使用します。


コンテナ・イメージに組み込むSQLclをダウンロードします。

curl -OL https://download.oracle.com/otn_software/java/sqldeveloper/sqlcl-latest.zip

コンテナ・イメージを作成します。

podman build -f Dockerfile -t mcpo:latest

% curl -OL https://download.oracle.com/otn_software/java/sqldeveloper/sqlcl-latest.zip


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

                                 Dload  Upload   Total   Spent    Left  Speed

100 87.8M  100 87.8M    0     0  9800k      0  0:00:09  0:00:09 --:--:-- 9359k

% podman build -f Dockerfile -t mcpo:latest  

STEP 1/12: FROM oraclelinux:9

STEP 2/12: RUN dnf update -y &&     dnf install -y sudo passwd unzip python3.12 python3.12-pip npm java-21-openjdk-headless &&     dnf clean all

--> Using cache 23e0b3aa2d45ddd2b3bf2e0181677e0a187370adc22398e8c9c97b735058ea83

--> 23e0b3aa2d45

STEP 3/12: ENV API_KEY=top-secret

--> 241ef719729a

STEP 4/12: RUN pip3.12 install --no-cache-dir mcpo

Collecting mcpo

  Obtaining dependency information for mcpo from https://files.pythonhosted.org/packages/3b/b2/54aab11bfcb7cdd574d1796dcaecf8f93e4d92d150286ba0d2d6e68b9524/mcpo-0.0.17-py3-none-any.whl.metadata

  Downloading mcpo-0.0.17-py3-none-any.whl.metadata (7.0 kB)

Collecting click>=8.1.8 (from mcpo)

  Obtaining dependency information for click>=8.1.8 from https://files.pythonhosted.org/packages/85/32/10bb5764d90a8eee674e9dc6f4db6a0ab47c8c4d0d83c27f7c39ac415a4d/click-8.2.1-py3-none-any.whl.metadata

  Downloading click-8.2.1-py3-none-any.whl.metadata (2.5 kB)

Collecting fastapi>=0.115.12 (from mcpo)

  Obtaining dependency information for fastapi>=0.115.12 from https://files.pythonhosted.org/packages/e5/47/d63c60f59a59467fda0f93f46335c9d18526d7071f025cb5b89d5353ea42/fastapi-0.116.1-py3-none-any.whl.metadata

  Downloading fastapi-0.116.1-py3-none-any.whl.metadata (28 kB)

Collecting mcp>=1.12.1 (from mcpo)


[中略]


--> ddbcfb283d6d

STEP 11/12: EXPOSE 8000

--> 02e68addb64b

STEP 12/12: CMD ["sh","-c","mcpo --port 8000 --api-key $API_KEY -- /home/oracle/sqlcl/bin/sql -mcp"]

COMMIT mcpo:latest

--> 6c4e198228ed

Successfully tagged localhost/mcpo:latest

6c4e198228eddbd7daf7c9e7426e57da09179adea3567944b3fb8a2465338cf9

% 


コンテナ・イメージがlocalhost/mcpo:latestとして作成されます。

作成されたコンテナ・イメージをもとに、コンテナmcpoを作成して実行します。環境変数API_KEYとしてOpenAPIのサーバーにアクセスする際に必要なAPIキーを指定しています。psなどの出力よりAPIキーが見えてしまうので、実運用を検討する場合は一工夫が必要です。

podman run -e API_KEY=my_secret -p 8091:8000 --name mcpo mcpo:latest

私の環境ではホストのポート8000が使用済みだったため、オプション-p 8091:8000を指定することにより、ホスト・ポートの8091番でOpenAPIのリクエストを受け付けるようにしています。

 % podman run -e API_KEY=my_secret -p 8091:8000 --name mcpo mcpo:latest


2025-08-07 03:24:40,514 - INFO - Starting MCPO Server...

2025-08-07 03:24:40,514 - INFO -   Name: MCP OpenAPI Proxy

2025-08-07 03:24:40,514 - INFO -   Version: 1.0

2025-08-07 03:24:40,514 - INFO -   Description: Automatically generated API from MCP Tool Schemas

2025-08-07 03:24:40,514 - INFO -   Hostname: 928ffdcd4c04

2025-08-07 03:24:40,514 - INFO -   Port: 8000

2025-08-07 03:24:40,514 - INFO -   API Key: Provided

2025-08-07 03:24:40,514 - INFO -   CORS Allowed Origins: ['*']

2025-08-07 03:24:40,514 - INFO -   Path Prefix: /

2025-08-07 03:24:40,514 - INFO - Configuring for a single Stdio MCP Server with command: /home/oracle/sqlcl/bin/sql -mcp

2025-08-07 03:24:40,514 - INFO - Uvicorn server starting...

INFO:     Started server process [1]

INFO:     Waiting for application startup.

OpenJDK 64-Bit Server VM warning: Unable to get SVE vector length on this system. Disabling SVE. Specify -XX:UseSVE=0 to shun this warning.

---------- MCP SERVER STARTUP ----------

MCP Server started successfully on Thu Aug 07 03:24:40 UTC 2025

Press Ctrl+C to stop the server

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

Aug 07, 2025 3:24:41 AM io.modelcontextprotocol.server.McpAsyncServer$AsyncServerImpl lambda$asyncInitializeRequestHandler$5

INFO: Client initialize request - Protocol: 2025-06-18, Capabilities: ClientCapabilities[experimental=null, roots=null, sampling=null], Info: Implementation[name=mcp, version=0.1.0]

Aug 07, 2025 3:24:41 AM io.modelcontextprotocol.server.McpAsyncServer$AsyncServerImpl lambda$asyncInitializeRequestHandler$5

WARNING: Client requested unsupported protocol version: 2025-06-18, so the server will sugggest the 2024-11-05 version instead

INFO:     Application startup complete.

INFO:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)

Starting MCP OpenAPI Proxy on 0.0.0.0:8000 with command: /home/oracle/sqlcl/bin/sql -mcp

INFO:     10.88.0.6:33308 - "GET /openapi.json HTTP/1.1" 200 OK

INFO:     10.88.0.6:33308 - "GET /favicon.ico HTTP/1.1" 404 Not Found



mcpoにアクセスして、動作を確認します。mcpoサーバーのopenapi.jsonを表示します。

http://localhost:8091/openapi.json

SQLclのMCPサーバーが提供しているツールの仕様が、OpenAPIのドキュメントとして表示されます。


コンテナmcpoに接続して、データベースへの接続を設定します。

podman exec -it mcpo sh

% podman exec -it mcpo sh 

sh-5.1$ 


SQLclを実行し、先ほど構成したデータベースにユーザーmcpuserで接続する設定を保存します。mcpoはpodmanのコンテナとして実行されているため、接続先のホストとして、localhostの代わりにhost.containers.internalを指定します。

./sqlcl/bin/sql /nolog
conn -save mydb -savepwd mcpuser/mcpuser@host.containers.internal/freepdb1
exit
exit

sh-5.1$ ./sqlcl/bin/sql /nolog

OpenJDK 64-Bit Server VM warning: Unable to get SVE vector length on this system. Disabling SVE. Specify -XX:UseSVE=0 to shun this warning.



SQLcl: Release 25.2 Production on Thu Aug 07 03:31:31 2025


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


/bin/bash: line 1: tput: command not found

/bin/bash: line 1: tput: command not found

SQL> conn -save mydb -savepwd mcpuser/mcpuser@host.containers.internal/freepdb1

Name: mydb

Connect String: host.containers.internal/freepdb1

User: mcpuser

Password: ******

Connected.

SQL> exit

Disconnected from Oracle Database 23ai Free Release 23.0.0.0.0 - Develop, Learn, and Run for Free

Version 23.8.0.25.04

sh-5.1$ exit

exit

%  


以上でmcpoとSQLclの準備は完了です。



Ollamaとgpt-oss:20bの実行



Ollamaでgpt-oss:20bを実行する方法については、巷に沢山の情報があると思います。以下のようにOllamaを実行し、モデルとしてgpt-oss:20bを選択します。


SettingsContext lengthは大きい値に変更しておきます。


Ollamaとgpt-oss:20bの準備は以上で完了です。


Open WebUIの実行



Open WebUIのコンテナを作成して実行します。Open WebUIでツール呼び出しをサポートしているのはバージョン0.6以上なので、タグにlatestが付いたイメージをもとにします。

最初に、設定その他を保存するボリュームを作成します。

podman volume create open-webui

% podman volume create open-webui

open-webui

% 


コンテナopen-webuiを作成し実行します。

podman run -d -p 3000:8080 -v open-webui:/app/backend/data -e OLLAMA_BASE_URL=http://host.containers.internal:11434 --name open-webui --restart always ghcr.io/open-webui/open-webui:latest

% podman run -d -p 3000:8080 -v open-webui:/app/backend/data -e OLLAMA_BASE_URL=http://host.containers.internal:11434 --name open-webui --restart always ghcr.io/open-webui/open-webui:latest

ff13fa1ee43b4b98be34e875900259f8f754cd4286e4f4e308ff428030cafd73

ynakakoshi@Ns-Macbook ~ % 


以上でOpen WebUIが実行されました。私の環境ではポート8080が使用済みだったため、オプション-p 3000:8080を指定しホスト・ポートの3000番でOpen WebUIにアクセスするようにしています。


ブラウザからアクセスすると、以下の画面が開きます。


Open WebUIが起動するまで、時間がかかる場合があります。そのような場合は、コンテナopen-webuiのログを確認します。

podman logs open-webui -f




mcpoをツールとして追加



Open WebUIの初期設定を行い、先ほど準備したmcpoをツールに追加します。

開始をクリックし、管理者アカウントを作成します。


管理者アカウントを作成すると、チャットの画面が開きます。

アカウントのメニューから設定を開きます。


設定ツールを開き、接続を追加をクリックします。


mcpoのサーバーにアクセスするURLを、URLに指定します。

Open WebUIのサーバーはコンテナ内で実行されていますが、ここで追加するツール呼び出しはブラウザから行われます。そのため、接続先のホストはhost.containers.internalではなくlocalhostになります。

URLとしてhttp://localhost:8091を設定し、Authにmcpoのコンテナ実行時に環境変数API_KEYとして設定した値をBearer以降に設定します。

リフレッシュのアイコンをクリックすると接続の確認ができます。これはAPIサーバーへの接続のみを確認し(openapi.jsonの取得)、APIキーが正しいかどうかは確認していないようです。

以上で接続を保存します。


以上で操作でツール・サーバーが追加されます。


Open WebUIでは管理者パネルにもツールの設定があります。管理者は、すべてのユーザーや限定されたグループが利用できるツールを設定できます。

しかし、管理者パネルツールを追加する際に接続の確認を実行すると、必ず失敗します。これは、管理者パネルからの接続の確認はコンテナ内で実行しているサーバーが行うため、localhostではなくhost.containers.internalでないと、コンテナの外にアクセスできないためです。


以上でツール呼び出しを行う設定が完了しました。


動作確認



新しいチャットを開始します。利用可能ツールとしてが表示されます。


利用可能ツールをクリックすると、利用可能ツールとしてsqlcl-mcp-server - v1.0.0が設定されていることが確認できます。

ツールを開くと、SQLclのMCPサーバーが提供しているツールの詳細が表示されます。


後は好きなようにチャットします。

「データベースmydbに接続して。」


先ほど出力したmetadata.jsonをファイルとしてアップロードします。アップロードしたmetadata.jsonだけを参照して、Oracle Databaseのカタログは参照せずにSQLを生成するように指示します。プロンプトはClaudeにmetadata.jsonを渡して生成してもらいました。


「これから生成するSQLは、metadata.jsonの情報のみを参照し、Oracle Databaseのカタログは参照しないでください。」

放っておくとカタログを検索するのですが、すべてシノニムにしているためカタログを検索しても情報は見つかりません。


「一番売り上げの多い製品を教えて。」


Claude Sonnet 4だと、生成したSELECT文の実行に失敗すると、SELECT文を生成し直して再度ツールを呼び出して実行しますが、Open WebUIとmcpoの組み合わせでは、再実行を指示する必要がありました。

「実行結果を表示してもらえますか?」


Claudeと比較するのはさすがに酷だとは思いますが、とりあえずは動いていますし、それもノートPCで動いているというのは、かなりの進歩だと思います。

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