IBM BobのMCP機能を使い、既存のJavaシステムを自然言語で使う
AI に社内資料を読ませて質問へ答えさせる取り組みは増えています。しかし実務で欲しくなるのは、説明だけではありません。既存の業務システムから最新情報を取得し、業務ルールに沿って処理することです。
この記事では、IBM WebSphere Application Server Liberty(以降、WAS Liberty)で稼働する Java アプリケーションのメソッドを MCP Tool として公開し、IBM Bob から呼び出す構成を紹介します。匿名化した会社員Aの交通費精算を題材に、Bob → MCP → WAS Liberty → Java 業務ロジックの流れを確認します。
この記事でできること
- WAS Liberty の Java メソッドを MCP Tool として公開する
- IBM Bob に Streamable HTTP の MCP サーバーとして接続する
- Bob から自然言語で Tool を実行し、Java 側の結果を受け取る
前提
| 必要なもの | 用途 |
|---|---|
| Java 17 以降 | WAS Liberty とアプリケーションの実行 |
| WAS Liberty 26.0.0.9 以降 |
mcp-1.0 を有効にする対象ランタイム |
| Maven | サンプルのビルドと起動 |
| IBM Bob | MCP Client として Tool を呼び出す |
このサンプルの通信経路は次のとおりです。
Bob → MCP Tool 呼び出し → WAS Liberty → CDI Bean の Java メソッド
Bob ← 結果の説明 ← MCP 応答 ← Java メソッドの実行結果
「社員ID EMP-A001(会社員A)の交通費精算状況を教えて」
「未精算の交通費と承認待ち件数を教えて」
「差戻しの明細があるか確認して」
こうした質問に答えるには、最新データを取得し、既存の業務ルールに従って処理する必要があります。
WAS Liberty の mcp-1.0 は、既存 Java アプリケーションの業務ロジックを MCP Tool として公開するための機能です。
mcp-1.0 は 26.0.0.9(2026年9月8日)で GA(正式提供)になりました。WAS Liberty 26.0.0.9 も同日に提供されています。ベータ版では機能名が mcpServer-1.0、設定要素が <mcpServer> でしたが、GA 版では mcp-1.0 と <mcp> を使用します。この記事のサンプルは GA 版の表記です。
ここでいう Tool は、AI が必要に応じて呼び出せる、名前と説明付きのアプリケーション機能です。AI が Java プログラムを直接実行するわけではありません。AI が MCP Tool を呼び出し、WAS Liberty がその Tool に対応する Java メソッドを実行します。AI は業務ルールそのものを実装するのではなく、「利用者の依頼を理解する」「使う Tool を選ぶ」「結果を人に伝える」役を担います。
最小の Tool を作る
コード上の役割
既存の Java アプリケーションには、すでに「顧客を調べる」「在庫を確認する」「金額を計算する」といった処理があります。MCP Tool 化は、その処理を AI に全部開放することではありません。AI が呼んでよい機能に、名前と説明を付けて専用の窓口を作ることです。
| コード上の名前 | 役割 | たとえ |
|---|---|---|
ExpenseService などの既存 Service |
DB や社内 API を呼び、業務ルールを実行する | 社内の専門部署 |
@Tool を付けたメソッド |
AI が呼べるようにする、限定された入口 | その部署への受付窓口 |
@ToolArg |
AI が渡す情報の名前と意味を示す | 受付票の入力欄 |
| Bob | 依頼内容を理解し、どの窓口へ行くか決め、結果を説明する | 受付係と案内役 |
Bob が Java プログラムを自由に操作するわけではありません。開発者が @Tool を付けて公開した窓口だけを、MCP 経由で呼び出せます。
以下の3ファイルで動かせます。匿名化した会社員Aの交通費精算を返すので、外部APIやDBを準備せずに、MCP の接続・Tool 選択・応答を一度に確認できます。サンプルの EMP-A001 はダミーの社員IDです。
pom.xml
この最小サンプルは再現しやすさのため Open Liberty の Maven runtime を使います。WAS Liberty では、同じ Java コードと server.xml を、社内で標準化されている WAS Liberty 26.0.0.9 以降のビルド・デプロイ方法に載せ替えてください。WAS Liberty は Open Liberty を基盤としており、ほとんどの Liberty 機能と構成を共有しています。
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>io.openliberty.samples</groupId>
<artifactId>mcp-expense</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<maven.compiler.release>17</maven.compiler.release>
</properties>
<dependencies>
<dependency>
<groupId>org.mcpjava</groupId>
<artifactId>mcp-server-api</artifactId>
<version>1.0.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.openliberty.api</groupId>
<artifactId>io.openliberty.mcp</artifactId>
<version>1.0.117</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jakarta.enterprise</groupId>
<artifactId>jakarta.enterprise.cdi-api</artifactId>
<version>4.1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<finalName>mcp-expense</finalName>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.14.1</version>
<configuration>
<release>${maven.compiler.release}</release>
</configuration>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.4.0</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
<plugin>
<groupId>io.openliberty.tools</groupId>
<artifactId>liberty-maven-plugin</artifactId>
<version>3.12.0</version>
<configuration>
<serverName>mcp-expense</serverName>
<runtimeArtifact>
<groupId>io.openliberty</groupId>
<artifactId>openliberty-runtime</artifactId>
<version>26.0.0.9</version>
<type>zip</type>
</runtimeArtifact>
</configuration>
</plugin>
</plugins>
</build>
</project>
src/main/java/io/openliberty/samples/mcp/ExpenseTools.java
CDI Bean のメソッドに @Tool と @ToolArg を付けます。
package io.openliberty.samples.mcp;
import java.util.Map;
import jakarta.enterprise.context.ApplicationScoped;
import org.mcpjava.server.tools.Tool;
import org.mcpjava.server.tools.ToolArg;
@ApplicationScoped
public class ExpenseTools {
// 接続確認用の匿名化したサンプルデータ。実業務では Service / Repository を呼ぶ。
private static final Map<String, ExpenseSummary> SAMPLE_SUMMARIES = Map.of(
"EMP-A001", new ExpenseSummary("EMP-A001", "会社員A", 12000, 2, 0));
@Tool(
name = "getExpenseSummary",
description = "Get unsettled travel expenses, pending approval count, and returned count for an employee. "
+ "The sample accepts EMP-A001 for fictional employee 会社員A."
)
public ExpenseSummary getExpenseSummary(
@ToolArg(name = "employeeId", description = "Employee ID. The sample accepts EMP-A001.") String employeeId) {
ExpenseSummary summary = SAMPLE_SUMMARIES.get(employeeId);
if (summary == null) {
throw new IllegalArgumentException("Unknown employee ID: " + employeeId);
}
return summary;
}
public record ExpenseSummary(String employeeId, String employeeName,
int unsettledTravelExpense, int pendingApprovalCount, int returnedCount) {}
}
MCP Tool はどこに追加するか
既存の業務Serviceそのものへ @Tool を付けるより、同じWAS Libertyアプリケーション内にMCP専用のToolクラスを追加するのが基本です。MCP対応は既存のWeb画面やREST APIを置き換えません。既存の入口は残したまま、Bob向けの ExpenseTools を並行して追加します。
既存の利用者 IBM Bob
↓ ↓
Web画面 / REST API MCP
↓ ↓
ExpenseResource ExpenseTools ← 新規追加
└───────────────┬───────────────┘
↓
ExpenseService ← 既存の業務ロジック
↓
ExpenseRepository / DB
既存の利用者は従来どおり画面やAPIを使い、Bobからの利用者だけがMCP経由で同じ業務ロジックを使います。ExpenseTools は AI 向けの入口だけを担い、既存の ExpenseService、Repository、DBアクセスは従来どおり利用します。
実業務では、サンプルの固定値を次のように既存Service呼び出しへ置き換えます。
@ApplicationScoped
public class ExpenseTools {
@Inject
ExpenseService expenseService;
@Tool(name = "getExpenseSummary",
description = "社員の未精算交通費と承認状況を返す")
public ExpenseSummary getExpenseSummary(
@ToolArg(name = "employeeId", description = "社員ID") String employeeId) {
// この先で ExpenseService が Repository を呼び、DBを検索・集計する。
return expenseService.findExpenseSummary(employeeId);
}
}
この @Tool メソッド自体に SQL を書く必要はありません。MCP Tool は Bob からの入口、ExpenseService は業務ルール、Repository はDB検索という責務分担にします。例えば findExpenseSummary(employeeId) の内部で、社員IDを条件に未精算交通費を SUM し、承認待ち・差戻しを COUNT して ExpenseSummary を返します。具体的なSQL例は次の記事で扱います。
| 追加方法 | 向く状況 | 判断 |
|---|---|---|
| 同じWAS LibertyアプリにToolクラスを追加 | 既存アプリを変更できる | 基本はこちら。業務ルール、認可、監査をそのまま使える。 |
| 別のWAS LibertyアプリをMCPゲートウェイとして追加 | 本体を変更できない、チームや認可境界を分けたい | 既存システムのREST APIなどを呼ぶ。 |
| 別サーバーからDBを直接読む | 既存APIがなく、限定した参照用途だけが必要 | 原則おすすめしない。認可や業務ルールを迂回しやすい。 |
別アプリにする場合も、DBを直接読むより既存システムのAPIを呼ぶほうが安全です。更新系Toolは特に、既存アプリケーションと同じ認可・入力検証・監査の境界で実行します。
src/main/liberty/config/server.xml
mcp-1.0 を有効にし、アプリケーション配下の MCP パスを指定します。
<server description="WAS Liberty MCP expense sample">
<featureManager>
<feature>mcp-1.0</feature>
</featureManager>
<httpEndpoint id="defaultHttpEndpoint" host="*" httpPort="9081" httpsPort="-1" />
<application location="mcp-expense.war" type="war">
<mcp path="/mcp" />
</application>
</server>
起動します。
mvn liberty:run
アプリケーションを起動すると、Liberty のログに MCP エンドポイントが出力されます。
CWMCM0008I: The MCP server endpoint: http://localhost:9081/mcp-expense/mcp
Bob から呼び出す
Bob の MCP 設定に、Streamable HTTP の接続先を追加します。
{
"mcpServers": {
"liberty-expense": {
"type": "streamable-http",
"url": "http://localhost:9081/mcp-expense/mcp"
}
}
}
設定後、Bob の MCP 画面で liberty-expense が「接続済み」になれば、WAS Liberty の MCP エンドポイントへの接続は成功です。
Bob で新しい会話を始めて「社員ID EMP-A001(会社員A)の交通費精算状況を教えて」と聞くと、Bob は getExpenseSummary を呼び出します。WAS Liberty が未精算交通費・承認待ち件数・差戻し件数を返します。Bob の応答に Tool 実行が表示され、結果が説明されれば成功です。
なぜ WAS Liberty で MCP を使うのか
MCP サーバーは Node.js、Python、Go など、他の言語でも実装できます。AI が Tool を選び、外部システムの結果を説明するという仕組みは言語共通です。
WAS Liberty の価値は、既存 Java アプリケーションの CDI Bean、サービス層、Jakarta Security、運用監視を生かしながら、薄い追加実装で MCP の入口を作れることにあります。新しい AI 用バックエンドを別に作るのではなく、すでに動いている業務処理を安全に公開する選択肢になります。
WAS Liberty を使う実務上の利点
| 既存の WAS Liberty 資産 | MCP Tool 化で生かせること |
|---|---|
| CDI Bean |
@ApplicationScoped などの CDI スコープを持つ Bean の、@Tool を付けたメソッドを WAS Liberty が検出する。既存の Service や依存性注入をそのまま利用できる。 |
| Jakarta Security |
@RolesAllowed、@PermitAll、@DenyAll を Tool のクラスまたはメソッドへ指定できる。呼び出し元のロールに応じて、利用可能な Tool だけを公開できる。 |
| WAS Liberty の運用基盤 | 起動時には MCP エンドポイントが WAS Liberty のメッセージログへ出る。monitor-1.0 を追加すれば、Tool 呼び出しの時間やエラーを既存のメトリクス基盤で観測できる。 |
たとえば、管理者だけが実行できる Tool は、通常の Jakarta Security のアノテーションで保護できます。
@ApplicationScoped
@RolesAllowed("Admins")
public class CustomerAdminTools {
@Tool(
name = "disableCustomer",
description = "Disable a customer account."
)
public String disableCustomer(
@ToolArg(name = "customerId", description = "Customer ID") String customerId
) {
return customerService.disable(customerId);
}
}
これは AI が安全性を保証するという意味ではありません。認可、入力検証、業務ルール、監査ログは、従来どおり WAS Liberty アプリケーション側で保証します。最初の導入では、更新しない参照系 Tool から始めるのが安全です。
WAS Liberty の MCP を選ぶ判断
MCP のためだけに Java や WAS Liberty を新規採用する、という話ではありません。すでに WAS Liberty または Jakarta EE の業務アプリケーションを運用していて、その機能を AI から使わせたい場合に特に適しています。
| 状況 | 選びやすい理由 |
|---|---|
| 既存の WAS Liberty アプリに、経費精算・在庫照会・社内検索などの機能がある | 既存の Service と認可を生かし、薄い Tool 層を追加できる。 |
| AI に最新の業務データを参照させたい | RAG の文書だけではなく、既存アプリケーションの処理結果を返せる。 |
| 更新操作にも将来対応したい | Jakarta Security、入力検証、監査ログと同じ境界で Tool を守れる。 |
| 運用チームが WAS Liberty のログ・監視基盤を使っている | MCP の障害や遅延を、別の新規サーバーではなく既存の運用方法で追える。 |
一方、単発のローカル自動化だけが目的なら、Node.js や Python の stdio 型 MCP サーバーのほうが小さく始めやすい場合があります。既存の Java 業務アプリを AI とつなぐことが目的なら、WAS Liberty の mcp-1.0 は自然な選択肢になります。
なぜ業務 Tool がうれしいのか
このサンプルはダミーの会社員Aを返します。本番で価値が出るのは、WAS Liberty で動いている既存の経費精算機能を Tool として公開し、認可済みの実データを返すことです。
実業務では、サンプルの固定値を ExpenseService や Repository 呼び出しに置き換えます。AI がユーザーの「会社員Aの交通費精算状況を教えて」という依頼を理解し、WAS Liberty 上の Tool を呼び出します。アプリケーションは認可済みの範囲で最新情報を返し、AI はそれを読みやすい文章にします。
ユーザー: 会社員Aの交通費精算状況を教えて
AI:
- 未精算の交通費は 12,000 円です
- 申請済みで承認待ちの明細は 2 件です
- 差戻しの明細はありません
AI が情報を創作しているのではなく、業務システムが返した最新結果を説明している点が重要です。
| 担当 | 役割 |
|---|---|
| AI | 質問の理解、Tool の選択、結果の要約・説明 |
| WAS Liberty アプリケーション | データ取得、業務ルール、認可、入力検証、監査 |
この役割分担なら、既存アプリケーションを置き換えずに、自然言語で使える入口を追加できます。
最初に向くのは「参照系」
導入初期は、データを変更しない Tool が現実的です。
getExpenseSummary(employeeId)getOrderDeliveryStatus(orderId)searchKnowledgeBase(query)getServiceHealth(serviceName)getRecentErrorSummary(serviceName, duration)
たとえば運用チームなら、「決済サービスで昨日から何が起きている?」という質問に対して、Tool がログ・メトリクス・デプロイ情報を必要な範囲で集約し、AI が状況と次の確認事項を説明できます。
人は複数の運用画面を横断する代わりに、会話から入れます。一方で、実データの取得や集計は既存の Java コードと運用基盤が担います。
更新系 Tool は、便利だからこそ慎重にする
注文の登録、在庫の引当、ユーザーの無効化のような更新処理も Tool にできます。ただし、AI が自然言語を解釈して実行する以上、参照系より厳格な設計が必要です。
-
@RolesAllowedなどで実行者の権限を制御する - Java 側で入力値と業務ルールを必ず検証する
- 破壊的操作には明確な確認フローを入れる
- 実行者、入力、結果を監査ログに残す
- 可能なら最初は「変更案の作成」までに留め、人が確定する
MCP の Tool メタデータには、読み取り専用か、破壊的な可能性があるか、といったヒントも設定できます。ただし、これはあくまでクライアントへのヒントです。安全性は必ず認可と業務ロジック側で担保します。
REST API を置き換えるものではない
MCP Tool は REST API の代替ではありません。
REST API はシステム同士を確定的に連携させるインターフェースです。一方 MCP Tool は、AI が目的に合わせて「いつ、どの機能を呼ぶか」を選べるようにするインターフェースです。
既存の REST API、サービス層、DB アクセスを生かしつつ、その上に AI 向けの業務単位の入口を作る、という関係が扱いやすいでしょう。
まとめ
WAS Liberty の MCP 対応によって、既存 Java アプリの業務ロジックを AI の会話から呼び出せます。
価値があるのは、AI に業務処理を丸投げすることではありません。AI は依頼の理解、適切な Tool の選択、結果の説明を担い、正確な処理、認可、検証、監査は WAS Liberty アプリケーションが担う。この役割分担が、既存の業務システムを AI 時代の実用的な基盤へ変えます。
次の記事
MCP Tool が返す明細をどう絞り、LLMへ渡す情報量を抑えるかは、次の記事で解説します。
【IBM Bob × WAS Liberty】LLMに渡す明細を減らすMCP Tool設計
Java 25 移行済みの既存アプリを取得し、実際に MCP Tool を追加して Bob から呼び出す手順は、こちらです。
【IBM Bob × Liberty】既存Java 25アプリにMCP Toolを追加するハンズオン
参考: Expose your Liberty business logic as AI tools - a guide to the MCP feature

