7
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Oracle Autonomous AI Database MCP テスト用検証環境の構築手順(覚書)

7
Posted at

はじめに

以前の記事 で、Oracle Autonomous AI Database (ADB) の MCP サーバー機能の有効化や、クライアント(AIエージェント)からの接続設定、および基本的なツール登録手順について解説しました。

本記事は、AIエージェントの推論能力を実際に検証するために構築した 「テスト用データベース環境の準備手順」 に関する覚書です。

具体的には、あえてテーブル名や列名を推測不可能(TABLE_001, C_01 など)にし、Oracle Database 23c の新機能である Annotations(アノテーション) で論理名や説明を付与した環境を構築します。

これにより、AIが自律的にメタデータを取得して正しいSQLを生成できるかをテストすることが目的です。

1. 検証用スキーマの作成と権限付与

まずは、検証用の専用ユーザー(スキーマ)を作成し、MCPサーバーや Select AI を利用するための権限を付与します。

ADMIN ユーザーでログインします。

-- ユーザーの作成
CREATE USER MCP_TEST_USER IDENTIFIED BY "Welcome_12345#_Test";

-- 基本的なロールの付与
GRANT CONNECT, RESOURCE, DWROLE, CREATE SESSION TO MCP_TEST_USER;
GRANT UNLIMITED TABLESPACE TO MCP_TEST_USER;

-- Select AI / MCPサーバー関連の権限付与
GRANT EXECUTE ON DBMS_CLOUD_AI TO MCP_TEST_USER;
GRANT EXECUTE ON DBMS_CLOUD_AI_AGENT TO MCP_TEST_USER;

-- PL/SQLなどの作成権限
GRANT CREATE PROCEDURE TO MCP_TEST_USER;

2. 難解な物理名のテーブル作成とアノテーション付与

次に、IoTデバイスのログデータを模したテーブルを10個作成します。
物理名からは内容を推測できないよう意図的に難解(TABLE_001TABLE_010C_01〜)にし、その代わりに ANNOTATIONS 句を用いてメタデータ(論理名、説明、主キー・外部キー情報、サンプル値など)を定義します。

-- 1. IoTデバイスマスタ (TABLE_001)
CREATE TABLE MCP_TEST_USER.TABLE_001 (
    C_01 NUMBER GENERATED ALWAYS AS IDENTITY ANNOTATIONS (Description 'Device ID', Is_Primary_Key 'Yes'),
    C_02 VARCHAR2(50) ANNOTATIONS (Description 'Device Type', Example 'Sensor, Gateway, Camera'),
    C_03 DATE ANNOTATIONS (Description 'Registration Date')
) ANNOTATIONS (Description 'IoT Device Master');

-- 2. ファームウェアバージョン管理 (TABLE_002)
CREATE TABLE MCP_TEST_USER.TABLE_002 (
    C_01 NUMBER GENERATED ALWAYS AS IDENTITY ANNOTATIONS (Description 'Firmware ID', Is_Primary_Key 'Yes'),
    C_02 VARCHAR2(20) ANNOTATIONS (Description 'Version String', Example 'v1.0.0'),
    C_03 DATE ANNOTATIONS (Description 'Release Date')
) ANNOTATIONS (Description 'Firmware Version Master');

-- 3. デバイス設置場所マスタ (TABLE_003)
CREATE TABLE MCP_TEST_USER.TABLE_003 (
    C_01 NUMBER GENERATED ALWAYS AS IDENTITY ANNOTATIONS (Description 'Location ID', Is_Primary_Key 'Yes'),
    C_02 NUMBER ANNOTATIONS (Description 'Device ID', Is_Foreign_Key 'Yes', Ref_Table 'TABLE_001'),
    C_03 VARCHAR2(100) ANNOTATIONS (Description 'Region Name', Example 'Tokyo-Zone-A')
) ANNOTATIONS (Description 'Device Location Mapping');

-- 4. センサー温度ログ (TABLE_004)
CREATE TABLE MCP_TEST_USER.TABLE_004 (
    C_01 NUMBER GENERATED ALWAYS AS IDENTITY ANNOTATIONS (Description 'Log ID', Is_Primary_Key 'Yes'),
    C_02 NUMBER ANNOTATIONS (Description 'Device ID', Is_Foreign_Key 'Yes', Ref_Table 'TABLE_001'),
    C_03 NUMBER(5,2) ANNOTATIONS (Description 'Temperature Value in Celsius'),
    C_04 TIMESTAMP ANNOTATIONS (Description 'Log Timestamp')
) ANNOTATIONS (Description 'Sensor Temperature Logs');

-- 5. センサー湿度ログ (TABLE_005)
CREATE TABLE MCP_TEST_USER.TABLE_005 (
    C_01 NUMBER GENERATED ALWAYS AS IDENTITY ANNOTATIONS (Description 'Log ID', Is_Primary_Key 'Yes'),
    C_02 NUMBER ANNOTATIONS (Description 'Device ID', Is_Foreign_Key 'Yes', Ref_Table 'TABLE_001'),
    C_03 NUMBER(5,2) ANNOTATIONS (Description 'Humidity Value in Percentage'),
    C_04 TIMESTAMP ANNOTATIONS (Description 'Log Timestamp')
) ANNOTATIONS (Description 'Sensor Humidity Logs');

-- 6. バッテリー残量ログ (TABLE_006)
CREATE TABLE MCP_TEST_USER.TABLE_006 (
    C_01 NUMBER GENERATED ALWAYS AS IDENTITY ANNOTATIONS (Description 'Log ID', Is_Primary_Key 'Yes'),
    C_02 NUMBER ANNOTATIONS (Description 'Device ID', Is_Foreign_Key 'Yes', Ref_Table 'TABLE_001'),
    C_03 NUMBER(3) ANNOTATIONS (Description 'Battery Percentage', Example '0 to 100'),
    C_04 TIMESTAMP ANNOTATIONS (Description 'Log Timestamp')
) ANNOTATIONS (Description 'Battery Level Logs');

-- 7. エラー・アラートログ (TABLE_007)
CREATE TABLE MCP_TEST_USER.TABLE_007 (
    C_01 NUMBER GENERATED ALWAYS AS IDENTITY ANNOTATIONS (Description 'Alert ID', Is_Primary_Key 'Yes'),
    C_02 NUMBER ANNOTATIONS (Description 'Device ID', Is_Foreign_Key 'Yes', Ref_Table 'TABLE_001'),
    C_03 VARCHAR2(20) ANNOTATIONS (Description 'Error Code', Example 'ERR-001'),
    C_04 TIMESTAMP ANNOTATIONS (Description 'Alert Timestamp')
) ANNOTATIONS (Description 'Error and Alert Logs');

-- 8. メンテナンス履歴 (TABLE_008)
CREATE TABLE MCP_TEST_USER.TABLE_008 (
    C_01 NUMBER GENERATED ALWAYS AS IDENTITY ANNOTATIONS (Description 'Maintenance ID', Is_Primary_Key 'Yes'),
    C_02 NUMBER ANNOTATIONS (Description 'Device ID', Is_Foreign_Key 'Yes', Ref_Table 'TABLE_001'),
    C_03 VARCHAR2(50) ANNOTATIONS (Description 'Maintenance Type', Example 'Battery Replacement, Inspection'),
    C_04 DATE ANNOTATIONS (Description 'Maintenance Date')
) ANNOTATIONS (Description 'Device Maintenance History');

-- 9. 通信パケットログ (TABLE_009)
CREATE TABLE MCP_TEST_USER.TABLE_009 (
    C_01 NUMBER GENERATED ALWAYS AS IDENTITY ANNOTATIONS (Description 'Packet ID', Is_Primary_Key 'Yes'),
    C_02 NUMBER ANNOTATIONS (Description 'Device ID', Is_Foreign_Key 'Yes', Ref_Table 'TABLE_001'),
    C_03 NUMBER ANNOTATIONS (Description 'Data Size in Bytes'),
    C_04 TIMESTAMP ANNOTATIONS (Description 'Transmission Timestamp')
) ANNOTATIONS (Description 'Network Packet Logs');

-- 10. アクティベーション履歴 (TABLE_010)
CREATE TABLE MCP_TEST_USER.TABLE_010 (
    C_01 NUMBER GENERATED ALWAYS AS IDENTITY ANNOTATIONS (Description 'Activation ID', Is_Primary_Key 'Yes'),
    C_02 NUMBER ANNOTATIONS (Description 'Device ID', Is_Foreign_Key 'Yes', Ref_Table 'TABLE_001'),
    C_03 VARCHAR2(20) ANNOTATIONS (Description 'Status', Example 'Active, Inactive, Suspended'),
    C_04 TIMESTAMP ANNOTATIONS (Description 'Status Change Timestamp')
) ANNOTATIONS (Description 'Device Activation History');

3. テストデータの投入

作成した10個のテーブルに、関連性を持たせたテストデータを INSERT します。

MCP_TEST_USER ユーザーでログインします。


-- 1. IoTデバイスマスタ (TABLE_001)
INSERT INTO TABLE_001 (C_02, C_03) VALUES ('Sensor', SYSDATE - 30);
INSERT INTO TABLE_001 (C_02, C_03) VALUES ('Gateway', SYSDATE - 20);
INSERT INTO TABLE_001 (C_02, C_03) VALUES ('Camera', SYSDATE - 10);

-- 2. ファームウェアバージョン管理 (TABLE_002)
INSERT INTO TABLE_002 (C_02, C_03) VALUES ('v1.0.0', SYSDATE - 100);
INSERT INTO TABLE_002 (C_02, C_03) VALUES ('v1.1.0', SYSDATE - 50);

-- 3. デバイス設置場所マスタ (TABLE_003)
INSERT INTO TABLE_003 (C_02, C_03) VALUES (1, 'Tokyo-Zone-A');
INSERT INTO TABLE_003 (C_02, C_03) VALUES (2, 'Osaka-Zone-B');
INSERT INTO TABLE_003 (C_02, C_03) VALUES (3, 'Tokyo-Zone-C');

-- 4. センサー温度ログ (TABLE_004)
INSERT INTO TABLE_004 (C_02, C_03, C_04) VALUES (1, 24.5, SYSTIMESTAMP - INTERVAL '2' HOUR);
INSERT INTO TABLE_004 (C_02, C_03, C_04) VALUES (1, 25.1, SYSTIMESTAMP - INTERVAL '1' HOUR);
INSERT INTO TABLE_004 (C_02, C_03, C_04) VALUES (1, 25.4, SYSTIMESTAMP);

-- 5. センサー湿度ログ (TABLE_005)
INSERT INTO TABLE_005 (C_02, C_03, C_04) VALUES (1, 45.0, SYSTIMESTAMP - INTERVAL '2' HOUR);
INSERT INTO TABLE_005 (C_02, C_03, C_04) VALUES (1, 46.2, SYSTIMESTAMP - INTERVAL '1' HOUR);
INSERT INTO TABLE_005 (C_02, C_03, C_04) VALUES (1, 47.1, SYSTIMESTAMP);

-- 6. バッテリー残量ログ (TABLE_006)
INSERT INTO TABLE_006 (C_02, C_03, C_04) VALUES (1, 85, SYSTIMESTAMP - INTERVAL '2' HOUR);
INSERT INTO TABLE_006 (C_02, C_03, C_04) VALUES (2, 92, SYSTIMESTAMP - INTERVAL '1' HOUR);
INSERT INTO TABLE_006 (C_02, C_03, C_04) VALUES (3, 40, SYSTIMESTAMP);

-- 7. エラー・アラートログ (TABLE_007)
INSERT INTO TABLE_007 (C_02, C_03, C_04) VALUES (3, 'ERR-CAM-001', SYSTIMESTAMP - INTERVAL '5' HOUR);
INSERT INTO TABLE_007 (C_02, C_03, C_04) VALUES (2, 'WARN-NET-002', SYSTIMESTAMP - INTERVAL '1' HOUR);

-- 8. メンテナンス履歴 (TABLE_008)
INSERT INTO TABLE_008 (C_02, C_03, C_04) VALUES (1, 'Battery Replacement', SYSDATE - 5);
INSERT INTO TABLE_008 (C_02, C_03, C_04) VALUES (3, 'Lens Cleaning', SYSDATE - 2);

-- 9. 通信パケットログ (TABLE_009)
INSERT INTO TABLE_009 (C_02, C_03, C_04) VALUES (2, 1024, SYSTIMESTAMP - INTERVAL '10' MINUTE);
INSERT INTO TABLE_009 (C_02, C_03, C_04) VALUES (2, 2048, SYSTIMESTAMP - INTERVAL '5' MINUTE);
INSERT INTO TABLE_009 (C_02, C_03, C_04) VALUES (2, 512, SYSTIMESTAMP);

-- 10. アクティベーション履歴 (TABLE_010)
INSERT INTO TABLE_010 (C_02, C_03, C_04) VALUES (1, 'Active', SYSTIMESTAMP - INTERVAL '30' DAY);
INSERT INTO TABLE_010 (C_02, C_03, C_04) VALUES (2, 'Active', SYSTIMESTAMP - INTERVAL '20' DAY);
INSERT INTO TABLE_010 (C_02, C_03, C_04) VALUES (3, 'Active', SYSTIMESTAMP - INTERVAL '10' DAY);

COMMIT;

4. MCPサーバー向けカスタムツール (Select AI Agent Tools) の作成

AIエージェントが、スキーマ内の難解なテーブル・列情報を自律的に調査できるようにするための MCP カスタムツールを作成します。
前回の記事で紹介した内容の応用として、今回は offsetlimit を用いたページネーション対応を実装しています。

【重要】ツールの作成実行ユーザーについて
DBMS_CLOUD_AI_AGENT.CREATE_TOOL を用いたツールの登録は、ADMINではなく、実際にMCPサーバーでログインするテスト用ユーザー(今回であれば MCP_TEST_USER)として接続して実行する必要があります。
ADMINで作成すると、テストユーザー (MCP_TEST_USER) からのログイン時にツールが検出されません。

テーブルメタデータ取得ツール (GET_TABLE_METADATA)

現在ログインしているスキーマ内の全テーブル名と、付与されたテーブルレベルのアノテーション一覧を取得します。

CREATE OR REPLACE FUNCTION GET_TABLE_METADATA (
    offset      IN NUMBER,
    limit       IN NUMBER
) RETURN CLOB AS
    V_SQL  CLOB;
    V_JSON CLOB;
BEGIN
    V_SQL := 'SELECT NVL(JSON_ARRAYAGG(JSON_OBJECT(*) RETURNING CLOB), ''[]'') AS json_output '
             || 'FROM ( '
             || '  SELECT t.table_name, '
             || '         (SELECT JSON_ARRAYAGG(JSON_OBJECT(''annotation_name'' VALUE a.annotation_name, ''annotation_value'' VALUE a.annotation_value)) '
             || '          FROM all_annotations_usage a '
             || '          WHERE a.annotation_owner = t.owner AND a.object_name = t.table_name AND a.object_type = ''TABLE'' AND a.column_name IS NULL) AS annotations '
             || '  FROM all_tables t '
             || '  WHERE t.owner = SYS_CONTEXT(''USERENV'', ''CURRENT_USER'') '
             || '  ORDER BY t.table_name '
             || '  OFFSET :off ROWS FETCH NEXT :lim ROWS ONLY '
             || ')';
             
    EXECUTE IMMEDIATE V_SQL INTO V_JSON USING offset, limit;
    RETURN V_JSON;
END;
/

BEGIN
  DBMS_CLOUD_AI_AGENT.CREATE_TOOL (
    tool_name  => 'GET_TABLE_METADATA',
    attributes => '{"instruction": "Returns table names and their annotations...",
       "function": "GET_TABLE_METADATA",
       "tool_inputs": [{"name":"offset","description" : "Pagination parameter..."},
                       {"name":"limit","description"  : "Pagination parameter..."}
                      ]}'
  );
END;
/

列メタデータ取得ツール (GET_COLUMN_METADATA)

指定したテーブル内の列名、データ型、および列レベルのアノテーションを取得します。

CREATE OR REPLACE FUNCTION GET_COLUMN_METADATA (
    table_name  IN VARCHAR2,
    offset      IN NUMBER,
    limit       IN NUMBER
) RETURN CLOB AS
    V_SQL  CLOB;
    V_JSON CLOB;
BEGIN
    V_SQL := 'SELECT NVL(JSON_ARRAYAGG(JSON_OBJECT(*) RETURNING CLOB), ''[]'') AS json_output '
             || 'FROM ( '
             || '  SELECT c.column_name, c.data_type, '
             || '         (SELECT JSON_ARRAYAGG(JSON_OBJECT(''annotation_name'' VALUE a.annotation_name, ''annotation_value'' VALUE a.annotation_value)) '
             || '          FROM all_annotations_usage a '
             || '          WHERE a.annotation_owner = c.owner AND a.object_name = c.table_name AND a.object_type = ''TABLE'' AND a.column_name = c.column_name) AS annotations '
             || '  FROM all_tab_columns c '
             || '  WHERE c.owner = SYS_CONTEXT(''USERENV'', ''CURRENT_USER'') AND c.table_name = :tab '
             || '  ORDER BY c.column_id '
             || '  OFFSET :off ROWS FETCH NEXT :lim ROWS ONLY '
             || ')';
             
    EXECUTE IMMEDIATE V_SQL INTO V_JSON USING table_name, offset, limit;
    RETURN V_JSON;
END;
/

BEGIN
  DBMS_CLOUD_AI_AGENT.CREATE_TOOL (
    tool_name  => 'GET_COLUMN_METADATA',
    attributes => '{"instruction": "Returns column names, data types, and their annotations...",
       "function": "GET_COLUMN_METADATA",
       "tool_inputs": [{"name":"table_name","description" : "Table name (e.g. TABLE_001)"},
                       {"name":"offset","description" : "Pagination parameter..."},
                       {"name":"limit","description"  : "Pagination parameter..."}
                      ]}'
  );
END;
/

データ取得(SQL実行)ツール (EXECUTE_SQL)

AIがメタデータを元に組み立てたSELECT文を実行し、結果をJSON形式で返します。

CREATE OR REPLACE FUNCTION EXECUTE_SQL(
    query    IN CLOB,
    offset   IN NUMBER,
    limit    IN NUMBER
) RETURN CLOB
AS
    v_sql      CLOB;
    v_json     CLOB;
BEGIN
    v_sql := 'SELECT NVL(JSON_ARRAYAGG(JSON_OBJECT(*) RETURNING CLOB), ''[]'') AS json_output ' ||
        'FROM ( ' ||
        '  SELECT * FROM ( ' || query || ' ) sub_q ' ||
        '  OFFSET :off ROWS FETCH NEXT :lim ROWS ONLY ' ||
        ')';
    EXECUTE IMMEDIATE v_sql INTO v_json USING offset, limit;
    RETURN v_json;
END;
/

BEGIN
  DBMS_CLOUD_AI_AGENT.CREATE_TOOL (
    tool_name  => 'EXECUTE_SQL',
    attributes => '{"instruction": "Run given read-only SELECT SQL query...",
       "function": "EXECUTE_SQL",
       "tool_inputs": [{"name":"query","description"  : "SELECT SQL statement..."},
                       {"name":"offset","description" : "Pagination parameter..."},
                       {"name":"limit","description"  : "Pagination parameter..."}
                      ]}'
  );
END;
/

5. 確認

MCP Inspectorを使って、正しく MCP のツールとして公開されているか確認します。

Transport Type には "Streamable HTTP" を指定し、URL には下記の URL を指定します。

https://dataaccess.adb.{region-identifier}.oraclecloudapps.com/adb/mcp/v1/databases/{database-ocid}

image.png

Connect をクリックするとユーザー名とパスワード入力画面が表示されるので、下記の情報を指定

Username : MCP_TEST_USER
Password : Welcome_12345#_Test

image.png

List Tools をクリックすると、Select AI Agent Tools として登録したツール一覧が表示されます。
試しに GET_TABLE_METADATA を実行したら、期待どおりテーブルの一覧が取得出来ました。

image.png

[
  {
    "TABLE_NAME": "TABLE_001",
    "ANNOTATIONS": [
      {
        "annotation_name": "DESCRIPTION",
        "annotation_value": "IoT Device Master"
      }
    ]
  },
  {
    "TABLE_NAME": "TABLE_002",
    "ANNOTATIONS": [
      {
        "annotation_name": "DESCRIPTION",
        "annotation_value": "Firmware Version Master"
      }
    ]
  },
  {
    "TABLE_NAME": "TABLE_003",
    "ANNOTATIONS": [
      {
        "annotation_name": "DESCRIPTION",
        "annotation_value": "Device Location Mapping"
      }
    ]
  },
  {
    "TABLE_NAME": "TABLE_004",
    "ANNOTATIONS": [
      {
        "annotation_name": "DESCRIPTION",
        "annotation_value": "Sensor Temperature Logs"
      }
    ]
  },
  {
    "TABLE_NAME": "TABLE_005",
    "ANNOTATIONS": [
      {
        "annotation_name": "DESCRIPTION",
        "annotation_value": "Sensor Humidity Logs"
      }
    ]
  },
  {
    "TABLE_NAME": "TABLE_006",
    "ANNOTATIONS": [
      {
        "annotation_name": "DESCRIPTION",
        "annotation_value": "Battery Level Logs"
      }
    ]
  },
  {
    "TABLE_NAME": "TABLE_007",
    "ANNOTATIONS": [
      {
        "annotation_name": "DESCRIPTION",
        "annotation_value": "Error and Alert Logs"
      }
    ]
  },
  {
    "TABLE_NAME": "TABLE_008",
    "ANNOTATIONS": [
      {
        "annotation_name": "DESCRIPTION",
        "annotation_value": "Device Maintenance History"
      }
    ]
  },
  {
    "TABLE_NAME": "TABLE_009",
    "ANNOTATIONS": [
      {
        "annotation_name": "DESCRIPTION",
        "annotation_value": "Network Packet Logs"
      }
    ]
  },
  {
    "TABLE_NAME": "TABLE_010",
    "ANNOTATIONS": [
      {
        "annotation_name": "DESCRIPTION",
        "annotation_value": "Device Activation History"
      }
    ]
  }
]

試しに AI エージェント (Gemini CLI) と連携させて、下記のように質問してみました。
期待どおり回答してくれています。

東京のゾーン(Tokyo-Zone)に設置されているすべてのデバイスの、現在のバッテリー残量の一覧を取得して表形式でまとめてください。

image.png
image.png
image.png
image.png

その他のサンプル質問は下記のとおりです。

1: 単一テーブルの基礎的な検索
「データベース内に格納されているIoTデバイスのログの中から、温度ログのデータを調べてください。直近の温度の平均値は何度ですか?」
(期待する動き: TABLE_004を特定し、C_03とC_04を使って平均を計算する)

2: 複雑な分析と推論
「現在バッテリー残量が50%を下回っており、かつ過去にエラーやアラートが発生したことがあるデバイスのIDと、その設置場所をリストアップしてください。」
(期待する動き: 複数テーブルを横断調査し、サブクエリやJOINを駆使したSQLを自律的に構築する)

おわりに

これで、例えば AIエージェントに「温度ログのデータを調べて」と指示した場合に、エージェントが自律的に GET_TABLE_METADATATABLE_004 を特定し、GET_COLUMN_METADATA で列の意味や型を理解した上で、適切なSQLを組み立てて EXECUTE_SQL でデータを取得する、という一連の推論プロセスをテストする準備が整いました。

前回の記事の構築手順と合わせて、本テスト環境を活用することで、Autonomous AI Database と MCP サーバーを用いた高度な AI エージェント連携の検証が可能になります。

7
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?