ブログ

【SAP Fiori×GCP】手軽な構成でMCP対応AIエージェントアプリを作成してみた

この記事をSNSでシェア!

はじめに

ここ数年、AI機能が搭載されたアプリが急増していますね。

自社のアプリにもAI機能を組み込みたいと考えている担当者や開発者の皆様も多いのではないでしょうか? 私たちBS事業部が日々のアプリ開発で主に使用しているSAP Fiori。今回はこれに、Google CloudのVertex AIとMCP(Model Context Protocol)を組み合わせて、まずは簡単な構成でAIエージェントアプリを作成してみました!

今回作成したアプリは、「自然言語で質問するだけで、BigQueryのデータを取得して答えてくれる」手軽なチャットアプリです。 よく使っている環境で手軽に検証を始めてみたので、その手順をご紹介します。

※なお、本記事で言及しているサービス内容などは、2026年3月時点の情報に基づいています。あらかじめご了承ください。

本記事の構成

今回は、フロントエンド(SAP側)はUI(プロンプト入力、結果表示)と中継の役割、AIの処理はバックエンド(Google側)に任せるシンプルな構成で作成しています。

サービス役割
SAP Fioriユーザーがプロンプト(指示)を入力し、AIからの回答を表示するチャットUI画面
SAP CAPFiori と Google Cloud の橋渡し役。ユーザーからのリクエストをVertex AIにHTTPで中継
SAP BTPアプリのホスティングと認証(ユーザーログイン)を管理
Vertex AI Agent Engine今回のAIの実行環境
Agent Development Kit (ADK) エージェントのフレームワーク
Gemini今回使用するモデル(gemini-2.0-flash)
Cloud API RegistryGCP内のMCPサーバー(今回はbigquery.googleapis.comを使用)
BigQueryデータウェアハウスMCPサーバー経由でデータを取得/操作

処理の流れ

ユーザーが画面に入力したプロンプトは、まず Fiori アプリから SAP のバックエンド(CAP)へ渡り、そこからクラウド上で動く AI エージェントに送られます。
AIエージェントは、まず背後にある生成AIモデルを利用して、ユーザーの入力を解釈します。そのうえで、「データが必要だ」と自ら判断したときだけ、ツールやAPIのカタログを経由し、自律的にBigQueryなどの情報を参照してくれます。
得られた情報をもとに回答文が組み立てられると、そのテキストはエージェントから CAP、さらに Fiori を経由してユーザー側の画面に表示されます。

補足

  • SAP 側:入力・表示と CAP まで(AI の中身は持たない)
  • クラウド側:判断・ツール実行・回答の生成が主役
  • データ参照なしの質問では、カタログ〜DW の矢印は基本スキップ

実装の中身

Fiori

Fioriアプリ側はAIの複雑なロジックを一切持たず、UI(ユーザーインターフェース)とリクエストの受け渡しに徹します。

サンプルコード
// Main.controller.js の抜粋例
onInit: function () {
  var oModel = this.getView().getModel();
  if (!oModel.getProperty("/sessionId")) {
    // 会話のつながり用(初回のみ生成)
    oModel.setProperty("/sessionId", "sess-" + Date.now());
  }
  if (oModel.getProperty("/agentResultText") === undefined) {
    oModel.setProperty("/agentResultText", "");
  }
  // this._url は manifest の dataSources 等から組み立てた CAP のベース URL
},

onSendMessage: function () {
  var oInput = this.byId("messageInput");
  var prompt = (oInput && oInput.getValue()) ? oInput.getValue().trim() : "";
  if (!prompt) {
    sap.m.MessageToast.show("プロンプトを入力してください");
    return;
  }

  var oModel = this.getView().getModel();
  var sessionId = oModel.getProperty("/sessionId");
  var base = this._url; // 例: https://<your-cap-host>
  var url = base + "/odata/v2/MCPService/askAi"
    + "?prompt='" + encodeURIComponent(prompt) + "'"
    + "&sessionId='" + encodeURIComponent(sessionId) + "'";

  sap.ui.core.BusyIndicator.show(0);
  var that = this;
  this._baseController.execAPI("POST", url, null)
    .then(function (data) {
      var text = (data && data.d && data.d.askAi != null)
        ? String(data.d.askAi)
        : "";
      oModel.setProperty("/agentResultText", text);
    })
    .catch(function (err) {
      var msg = (err && err.message) ? err.message : String(err);
      sap.m.MessageToast.show("エラー: " + msg);
    })
    .finally(function () {
      sap.ui.core.BusyIndicator.hide();
    });
}

CAP

CAPのコードはシンプルで、複雑なロジックはほぼありません。HTTPの転送処理(ルーター)を書くだけのイメージで実装できます。

  1. Fiori が OData で CAP のエンドポイントを呼ぶ。
  2. CAP が Vertex AI Agent Engine の APIにそのまま POST送信する。
  3. 返ってきた文字列(AIの最終回答 output)を、OData の戻り値として Fiori へ返す。
サンプルコード
// ハンドラのサンプル
@Component
@ServiceName("MCPService")
public class McpServiceHandler implements EventHandler {

  @Autowired
  private VertexAgentClient vertexAgentClient;

  @On(event = "askAi")
  public void handleAskAi(AskAiContext context) {
    try {
      String answer = vertexAgentClient.query(
          context.getPrompt(),
          context.getSessionId()
      );
      context.setResult(answer);
    } catch (Exception e) {
      context.setResult("Error: " + e.getMessage());
    }
  }
}
// Vertex AI Agent Engine への POST処理
public String query(String prompt, String sessionId) throws Exception {
  String region = System.getenv("GCP_REGION");
  String project = System.getenv("GCP_PROJECT_ID");
  String agentId = System.getenv("VERTEX_AGENT_ENGINE_ID");

  String token = obtainBearerToken(); // サービスアカウント等(鍵はリポジトリに含めない)

  String url = String.format(
      "https://%s-aiplatform.googleapis.com/v1beta1/projects/%s/locations/%s/reasoningEngines/%s:query",
      region, project, region, agentId);

  Map<String, Object> inner = new HashMap<>();
  inner.put("input", prompt);
  inner.put("session_id", sessionId != null ? sessionId : "");

  Map<String, Object> body = new HashMap<>();
  body.put("input", inner);

  HttpHeaders headers = new HttpHeaders();
  headers.setContentType(MediaType.APPLICATION_JSON);
  headers.setBearerAuth(token);

  RestTemplate rt = new RestTemplate();
  ResponseEntity<Map> res = rt.postForEntity(
      url, new HttpEntity<>(body, headers), Map.class);

  if (res.getBody() == null) return "";
  Object out = res.getBody().get("output");
  return out != null ? out.toString() : "";
}

// obtainBearerToken() は google-auth-library 等で
// サービスアカウント JSON を読み、cloud-platform スコープでトークン取得、など

ADK と Gemini

バックエンドのエージェントは、Google提供のオープンソースフレームワーク「ADK」とPythonを使って記述しています。これをVertex AI Agent Engineにデプロイする構成です。 ADKを使うと、Geminiモデルを頭脳として「プロンプト解釈 → 使うべきツールの判断 → 実行 → 回答生成」という自律的なループをとても短いコードで簡単に実装できます。

サンプルコード
from google.adk.agents.llm_agent import LlmAgent as Agent
from google.adk.runners import Runner
from google.adk.sessions import InMemorySessionService
from google.genai import types

class DemoAgentApp:
    def __init__(self, toolset, app_name: str = "demo_app"):
        self.app_name = app_name
        self.session_service = InMemorySessionService()
        self.agent = Agent(
            model="gemini-2.0-flash",
            name="demo_bigquery_agent",
            instruction=(
                "与えられたツールだけを使い、事実に基づいて簡潔に日本語で答えてください。"
            ),
            tools=[toolset],
        )

    def query(self, user_text: str, session_id: str, user_id: str = "demo_user") -> str:
        runner = Runner(
            agent=self.agent,
            app_name=self.app_name,
            session_service=self.session_service,
        )
        msg = types.Content(
            role="user",
            parts=[types.Part(text=user_text)],
        )
        final_text = ""
        # 以下は ADK のバージョンに合わせて調整
        for event in runner.run(
            user_id=user_id,
            session_id=session_id,
            new_message=msg,
        ):
            if getattr(event, "content", None) and event.content.parts:
                for p in event.content.parts:
                    if getattr(p, "text", None):
                        final_text = p.text
        return final_text or "(応答なし)"

Cloud API Registryの接続設定

Google CloudのCloud API Registryに登録されたMCPサーバーのリソース名(例: projects/YOUR_PROJECT_ID/locations/global/mcpServers/google-bigquery.googleapis.com-mcp)を指定し、ADKの ApiRegistry から get_toolset メソッドを呼び出すだけでエージェントにツールを割り当てています。これにより、AIエージェントは自律的にBigQueryのツール群を理解し、必要に応じてデータ取得のクエリを実行してくれます。
Cloud API Registry 連携はデプロイ対象となるエージェント用ディレクトリ内のコードに書いています。
Cloud API RegistryはMCPサーバーを統合管理するカタログサービスであるため、今後ツールが追加されたり変更されたりした場合でも、柔軟に対応できる拡張性の高い構成となっています。

サンプルコード
from google.adk.tools.api_registry import ApiRegistry

def build_bigquery_toolset(project_id: str):
    api_registry = ApiRegistry(project=project_id, location="global")
    mcp_server_name = (
        f"projects/{project_id}/locations/global/mcpServers/"
        f"google-bigquery.googleapis.com-mcp"
    )
    toolset = api_registry.get_toolset(mcp_server_name=mcp_server_name)
    if toolset is None:
        raise RuntimeError("ツールセット取得に失敗しました。Registry・IAM を確認してください。")
    return toolset

# 利用例エージェント生成時
# toolset = build_bigquery_toolset("<YOUR_PROJECT_ID>")
# app = DemoAgentApp(toolset=toolset)

実装時の注意点

IAM権限と認証の設定 クラウド側でAIエージェントを動かす際、実行環境となるサービスアカウントには適切な権限(IAMロール)を付与しておく必要があります。

また、実際にご自身の環境でCloud API RegistryのMCPサーバーを利用する際は、事前に有効化している必要があります。

構成のメリット

SAP側の実装をシンプルに保てる

AIの複雑な処理やエージェントの自律的なループはすべてクラウド側(Google側のマネージドサービスとSDK)に任せるため、SAP側(FioriとCAP)の開発負担を最小限に抑えられます。
Fioriからはリクエストを送るだけでよく、CAPは単純な橋渡し役として機能するため、特別な処理をSAP側に加えることなくAI機能をアプリに組み込むことが可能です。

Googleのマネージドサービス活用による容易さと拡張性

AIの実行環境にフルマネージドサービスであるVertex AI Agent Engineを利用しているため、インフラの構築や運用の手間を省き、手軽に検証を始められます。 また、Cloud API Registryを活用しているため、今後MCPサーバーの設定を追加したくなった場合でも、公開されているものであればすぐに追加することができます。

利用するサービス/コンポーネント開発者が行った主な作業すでに用意されている機能
(省略できること)
Vertex AI Agent EngineADK で書いたエージェントをデプロイし、HTTP API(例: :query)で起動するエージェント用の実行環境の構築・運用、スケーリング、API としての公開
Agent Development Kit(ADK)LlmAgent・Runner などで、プロンプト処理とツール呼び出しのループをコードで定義モデルによるツール選択・実行、応答生成までをつなぐ実行の枠組み
GeminiADK からモデルとして指定し、推論・回答生成に利用するLLM のホスティング、推論基盤の維持(マネージド API として利用)
Cloud API Registry登録済み MCP サーバー(例: BigQuery 用)のリソース名を指定し、ApiRegistry.get_toolset でツール群をエージェントに渡すMCP サーバー側のツール定義の集約・公開、エージェント向けツール作成・追加等

実際に作成した画面

ここまで解説した構成で、実際にアプリがどのように動くのかを動画でご紹介します。Fioriアプリから自然言語でBigQueryのデータ情報を取得しています。

動画をご覧いただくとわかるように、最初は同じようなプロンプトを入力してもAIの回答が毎回ブレてしまっています。
そこで、回答を安定させるために取得したい対象(データセット名など)を明確に指定するように入力文を変更することを試しました。

ユーザー側のプロンプトの工夫で対応も可能ですが、AIエージェントにルールを追加することでも対応できると考えています。 例えば、「SQLの提供は明確に提供の指示がある場合のみ行い、それ以外の場合はSQLの実行まで行ってください」といったルールを明確に定義しておく方法です。
プロンプトの具体化やシステムルールの設定などを活用することで、AIの回答を安定させることが可能だと思います。

まとめ

今回は、SAP FioriとGoogle Cloudを連携させ、MCPを活用して手軽にAIエージェントアプリを作る方法をご紹介しました!

「AIエージェントを使ったアプリ構築」と聞くと大掛かりになりそうですが、本構成のように手元にある環境を活用すれば、複雑なコードなしで作ることができます。SAP側(Fiori + CAP)はUIとリクエストの中継に徹するだけで済むため、実装もシンプルです。

今後は、今回の構成をベースにして、複数のMCPサーバーを使ったデータ分析や、複数のAIエージェントが連携したマルチエージェント構成などにも挑戦していきたいと考えています。

「まずは簡単な構成でAIの機能を試してみたい」という方にとって、今回の記事が参考になれば幸いです!

投稿者プロフィール

伊関 敏輝
伊関 敏輝
2023年にIT未経験で入社。
AWSを使用したシステム開発に2年間ほど携わり、現在はSAP Fioriのアプリ開発に取り組んでいます。
業務を通じて得た経験を積極的に発信していきたいと思っています!
趣味は野球観戦です。
この記事をSNSでシェア!