このバージョンはまだ開発中であり、まだ安定しているとは見なされていません。最新の安定バージョンについては、Spring AI 2.0.1 を使用してください!

MCP クライアント Boot スターター

Spring AI MCP(モデルコンテキストプロトコル)クライアント Boot スターターは、Spring Boot アプリケーションにおける MCP クライアント機能の自動構成を提供します。同期および非同期のクライアント実装の両方をサポートし、さまざまなトランスポートオプションに対応しています。

MCP クライアント Boot スターターは以下を提供します。

  • 複数のクライアントインスタンスの管理

  • 自動クライアント初期化 (有効な場合)

  • 複数の名前付きトランスポートのサポート (STDIO、Http/SSE、ストリーミング可能な HTTP)

  • Spring AI のツール実行フレームワークとの統合

  • 選択的なツールの包含 / 除外のためのツールフィルタリング機能

  • 名前の競合を避けるためのカスタマイズ可能なツール名プレフィックス生成

  • アプリケーションコンテキストが閉じられたときにリソースを自動的にクリーンアップする適切なライフサイクル管理

  • カスタマイザーによるカスタマイズ可能なクライアント作成

スターター

標準 MCP クライアント

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-mcp-client</artifactId>
</dependency>

標準スターターは、STDIO (インプロセス)および SSE、Streamable-HTTP、Stateless Streamable-HTTP トランスポートを介して、1 つ以上の MCP サーバーに同時に接続します。SSE および Streamable-Http トランスポートは、JDK HttpClient ベースのトランスポート実装を使用します。MCP サーバーへの接続ごとに、新しい MCP クライアントインスタンスが作成されます。MCP クライアントは SYNC または ASYNC のいずれかを選択できます(注: 同期クライアントと非同期クライアントを混在させることはできません)。本番環境のデプロイでは、WebFlux ベースの SSE および StreamableHttp 接続と spring-ai-starter-mcp-client-webflux を使用することをお勧めします。

WebFlux クライアント

WebFlux スターターは標準スターターと同様の機能を提供しますが、WebFlux ベースの Streamable-Http、Stateless Streamable-Http、および SSE トランスポート実装を使用します。

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-mcp-client-webflux</artifactId>
</dependency>

プロパティの構成

共通プロパティ

共通プロパティには spring.ai.mcp.client という接頭辞が付きます。

プロパティ 説明 デフォルト値

enabled

MCP クライアントを有効 / 無効にする

true

name

MCP クライアントインスタンスの名前

spring-ai-mcp-client

version

MCP クライアントインスタンスのバージョン

1.0.0

initialized

作成時にクライアントを初期化するかどうか

true

request-timeout

MCP クライアントリクエストのタイムアウト期間

20s

type

クライアント型(SYNC または ASYNC)。すべてのクライアントは同期または非同期のいずれかである必要があります。混在はサポートされていません

SYNC

root-change-notification

すべてのクライアントのルート変更通知を有効 / 無効にする

true

toolcallback.enabled

Spring AI のツール実行フレームワークとの MCP ツールコールバック統合を有効 / 無効にする

true

MCP アノテーションプロパティ

MCP クライアントアノテーションは、Java アノテーションを用いて MCP クライアントハンドラーを宣言的に実装する方法を提供します。クライアントの mcp-annotations プロパティには、spring.ai.mcp.client.annotation-scanner というプレフィックスが付きます。

プロパティ 説明 デフォルト値

enabled

MCP クライアントアノテーションの自動スキャンを有効 / 無効にする

true

Stdio トランスポートプロパティ

標準 I/O トランスポートのプロパティには spring.ai.mcp.client.stdio というプレフィックスが付きます。

プロパティ 説明 デフォルト値

servers-configuration

JSON 形式の MCP サーバー構成を含むリソース

-

connections

名前付き stdio 接続構成のマップ

-

connections.[name].command

MCP サーバーに対して実行するコマンド

-

connections.[name].args

コマンド引数のリスト

-

connections.[name].env

サーバープロセスの環境変数のマップ

-

構成例:

spring:
  ai:
    mcp:
      client:
        stdio:
          root-change-notification: true
          connections:
            server1:
              command: /path/to/server
              args:
                - --port=8080
                - --mode=production
              env:
                API_KEY: your-api-key
                DEBUG: "true"

あるいは、Claude デスクトップ形式 (英語) を使用して外部 JSON ファイルを使用して stdio 接続を構成することもできます。

spring:
  ai:
    mcp:
      client:
        stdio:
          servers-configuration: classpath:mcp-servers.json

Claude デスクトップ形式は次のようになります。

{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-filesystem",
        "/Users/username/Desktop",
        "/Users/username/Downloads"
      ]
    }
  }
}

Windows STDIO 構成

Windows では、npx、npm、node などのコマンドはネイティブ実行ファイルではなく、バッチファイル(.cmd)として実装されています。Java の ProcessBuilder はバッチファイルを直接実行することができず、cmd.exe /c ラッパーが必要です。

Windows に特別な処理が必要な理由

Java の ProcessBuilder (StdioClientTransport によって内部的に使用される) が Windows 上でプロセスを生成しようとすると、次のものしか実行できません。

  • ネイティブ実行ファイル (.exe ファイル)

  • cmd.exe で利用可能なシステムコマンド

npx.cmd、npm.cmd、さらには python.cmd (Microsoft Store から) などの Windows バッチファイルを実行するには、cmd.exe シェルが必要です。

ソリューション: cmd.exe ラッパー

バッチファイルコマンドを cmd.exe /c で囲みます:

Windows 構成:

{
  "mcpServers": {
    "filesystem": {
      "command": "cmd.exe",
      "args": [
        "/c",
        "npx",
        "-y",
        "@modelcontextprotocol/server-filesystem",
        "C:\\Users\\username\\Desktop"
      ]
    }
  }
}

Linux/macOS 構成:

{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-filesystem",
        "/Users/username/Desktop"
      ]
    }
  }
}

クロスプラットフォームのプログラムによる構成

個別の構成ファイルを使用せずにプラットフォーム間で動作する必要があるアプリケーションの場合は、Spring Boot アプリケーションで OS 検出を使用します。

@Bean(destroyMethod = "close")
@ConditionalOnMissingBean(McpSyncClient.class)
public McpSyncClient mcpClient() {
    ServerParameters stdioParams;

    if (isWindows()) {
        // Windows: cmd.exe /c npx approach
        var winArgs = new ArrayList<>(Arrays.asList(
            "/c", "npx", "-y", "@modelcontextprotocol/server-filesystem", "target"));
        stdioParams = ServerParameters.builder("cmd.exe")
                .args(winArgs)
                .build();
    } else {
        // Linux/Mac: direct npx approach
        stdioParams = ServerParameters.builder("npx")
                .args("-y", "@modelcontextprotocol/server-filesystem", "target")
                .build();
    }

    return McpClient.sync(new StdioClientTransport(stdioParams, McpJsonDefaults.getMapper()))
            .requestTimeout(Duration.ofSeconds(10))
            .build()
            .initialize();
}

private static boolean isWindows() {
    return System.getProperty("os.name").toLowerCase().contains("win");
}
@Bean でプログラムによる構成を使用する場合は、JSON ファイルからの自動構成との競合を避けるために @ConditionalOnMissingBean(McpSyncClient.class) を追加します。

パスの考慮事項

相対パス(携帯性重視ならおすすめ):

{
  "command": "cmd.exe",
  "args": ["/c", "npx", "-y", "@modelcontextprotocol/server-filesystem", "target"]
}

MCP サーバーは、アプリケーションの作業ディレクトリに基づいて相対パスを解決します。

絶対パス (Windows ではバックスラッシュまたはエスケープされたスラッシュが必要です):

{
  "command": "cmd.exe",
  "args": ["/c", "npx", "-y", "@modelcontextprotocol/server-filesystem", "C:\\Users\\username\\project\\target"]
}

cmd.exe を必要とする一般的な Windows バッチファイル

  • npx.cmd, npm.cmd - Node パッケージマネージャー

  • python.cmd - Python (Microsoft Store のインストール)

  • pip.cmd - Python パッケージマネージャー

  • mvn.cmd - Maven ラッパー

  • gradle.cmd - Gradle ラッパー

  • カスタム .cmd または .bat スクリプト

リファレンス実装

OS を自動的に検出し、クライアントを適切に構成する完全なクロスプラットフォーム MCP クライアント実装については、Spring AI の例 - ファイルシステム [GitHub] (英語) を参照してください。

ストリーミング可能な HTTP トランスポートプロパティ

Streamable-HTTP および Stateless Streamable-HTTP MCP サーバーに接続するために使用されます。

Streamable-HTTP トランスポートのプロパティには、spring.ai.mcp.client.streamable-http という接頭辞が付きます。

プロパティ 説明 デフォルト値

connections

名前付き Streamable-HTTP 接続構成のマップ

-

connections.[name].url

MCP サーバーとの Streamable-Http 通信のベース URL エンドポイント

-

connections.[name].endpoint

接続に使用するストリーミング可能な http エンドポイント (URL サフィックスとして)

/mcp

構成例:

spring:
  ai:
    mcp:
      client:
        streamable-http:
          connections:
            server1:
              url: http://localhost:8080
            server2:
              url: http://otherserver:8081
              endpoint: /custom-sse

SSE トランスポートプロパティ

サーバー送信イベント (SSE) トランスポートのプロパティには、spring.ai.mcp.client.sse というプレフィックスが付きます。

プロパティ 説明 デフォルト値

connections

名前付き SSE 接続構成のマップ

-

connections.[name].url

MCP サーバーとの SSE 通信のベース URL エンドポイント

-

connections.[name].sse-endpoint

接続に使用する SSE エンドポイント(URL サフィックスとして)

/sse

構成例:

spring:
  ai:
    mcp:
      client:
        sse:
          connections:
            # Simple configuration using default /sse endpoint
            server1:
              url: http://localhost:8080
            # Custom SSE endpoint
            server2:
              url: http://otherserver:8081
              sse-endpoint: /custom-sse
            # Complex URL with path and token (like MCP Hub)
            mcp-hub:
              url: http://localhost:3000
              sse-endpoint: /mcp-hub/sse/cf9ec4527e3c4a2cbb149a85ea45ab01
            # SSE endpoint with query parameters
            api-server:
              url: https://api.example.com
              sse-endpoint: /v1/mcp/events?token=abc123&format=json

URL 分割ガイドライン

完全な SSE URL がある場合は、それをベース URL とエンドポイントパスに分割します。

完全 URL 構成

http://localhost:3000/mcp-hub/sse/token123

url: localhost:3000
sse-endpoint: /mcp-hub/sse/token123

https://api.service.com/v2/events?key=secret

url: api.service.com (英語)
sse-endpoint: /v2/events?key=secret

http://localhost:8080/sse

url: localhost:8080
sse-endpoint: /sse (or omit for default)

Troubleshooting SSE Connections

404 Not Found Errors:

  • Verify URL splitting: ensure the base url contains only the scheme, host, and port

  • Check the sse-endpoint starts with / and includes the full path and query parameters

  • Test the full URL directly in a browser or curl to confirm it’s accessible

Streamable Http Transport Properties

Properties for Streamable Http transport are prefixed with spring.ai.mcp.client.streamable-http:

Property Description Default Value

connections

名前付きストリーミング可能な HTTP 接続構成のマップ

-

connections.[name].url

MCP サーバーとの Streamable-Http 通信のベース URL エンドポイント

-

connections.[name].endpoint

接続に使用するストリーミング可能な http エンドポイント (URL サフィックスとして)

/mcp

構成例:

spring:
  ai:
    mcp:
      client:
        streamable-http:
          connections:
            server1:
              url: http://localhost:8080
            server2:
              url: http://otherserver:8081
              endpoint: /custom-sse

機能

同期 / 非同期クライアントの種類

スターターは 2 種類のクライアントをサポートします。

  • 同期 - デフォルトのクライアント型(spring.ai.mcp.client.type=SYNC)。ブロッキング操作を伴う従来のリクエストレスポンスパターンに適しています

NOTE : SYNC クライアントは、同期 MCP アノテーション付きメソッドのみを登録します。非同期メソッドは無視されます。

  • 非同期 - spring.ai.mcp.client.type=ASYNC を使用して構成された、ノンブロッキング操作を伴うリアクティブアプリケーションに適しています。

NOTE : ASYNC クライアントは、MCP アノテーションが付けられた非同期メソッドのみを登録します。同期メソッドは無視されます。

Client Scope and Session Boundaries

The auto-configured McpSyncClient and McpAsyncClient beans are application-scoped singletons. One client bean is created per configured MCP server connection, and that bean is shared by every request the application serves.

Each client represents a single MCP protocol session. The session stays attached to the client bean for its whole lifetime and is replaced only when the server terminates it (HTTP 404) or the client is closed.

The MCP session is not a per-user boundary.

Per-request credentials propagated through transportContextProvider(…​), a McpSyncHttpClientRequestCustomizer, or a WebClient ExchangeFilterFunction are applied per request and do reach the server with the calling user’s identity. The MCP protocol session underneath them is still shared by every caller of that client bean. Multi-user applications should account for the following:

  • The initialize and tools/list exchanges happen once, under whatever identity is available when the client connects, not under the identity of the user who later invokes a tool.

  • Any server-side state keyed on the MCP session alone is shared by all users of the client bean.

  • Server-initiated interactions such as sampling and elicitation arrive on a shared stream and carry no per-user attribution.

Do not treat the MCP session as a user or tenant boundary on either side of the connection.

Whether this matters depends on the MCP server you connect to. A shared client is fine against a stateless server, and against a stateful one that authorizes every request from the supplied token and keeps no user-meaningful state on the session. Consider a separate session per user or per tenant when:

  • The server filters tools/list, resources, or prompts by identity, since discovery runs once and every user then sees the first caller’s view.

  • The server keeps user-meaningful state on the session, such as a working directory, subscriptions, pagination cursors, or cached context.

  • You use sampling or elicitation and need those server-initiated requests attributed to a specific user.

  • The server audits or rate-limits by session, or your deployment requires that tenants not share a protocol session.

  • You cannot verify how a third-party server treats its sessions.

Applications that need a separate MCP protocol session per user or per tenant must manage that lifecycle themselves, creating one transport and client per principal and closing it when that principal’s work completes. The auto-configured beans are not suitable for this, and Spring AI does not provide per-user client pooling. See Spring AI の自動構成を回避する方法 for programmatic client construction.

クライアントのカスタマイズ

自動構成は、コールバックインターフェースを通じて広範なクライアント仕様のカスタマイズ機能を提供します。これらのカスタマイザーを使用すると、リクエストのタイムアウトからイベント処理やメッセージ処理まで、MCP クライアントの動作のさまざまなアスペクトを構成できます。

カスタマイズの種類

次のカスタマイズオプションが利用可能です。

  • リクエスト構成 - カスタムリクエストタイムアウトを設定する

  • カスタムサンプリングハンドラー (英語) - サーバーがクライアント経由で LLM に LLM サンプリング (completions または generations) をリクエストするための標準化された方法。このフローにより、クライアントはモデルのアクセス、選択、権限を制御しながら、サーバーが AI 機能を活用できるようになります。サーバー API キーは必要ありません。

  • ファイルシステム(ルート)アクセス (英語) - クライアントがファイルシステム roots をサーバーに公開するための標準化された方法。ルートは、ファイルシステム内でサーバーが操作できる範囲の境界を定義し、サーバーがアクセスできるディレクトリとファイルを理解できるようにします。サーバーは、サポートしているクライアントからルートのリストをリクエストし、そのリストが変更されたときに通知を受け取ることができます。

  • 誘導ハンドラー (英語) - サーバーが対話中にクライアントを通じてユーザーに追加情報をリクエストするための標準化された方法。

  • イベントハンドラー - 特定のサーバーイベントが発生したときに通知されるクライアントのハンドラー:

    • ツール変更通知 - 利用可能なサーバーツールのリストが変更されたとき

    • リソース変更通知 - 利用可能なサーバーリソースのリストが変更されたとき。

    • プロンプト変更通知 - 利用可能なサーバープロンプトのリストが変更されたとき。

    • ログハンドラー (英語) - サーバーが構造化されたログメッセージをクライアントに送信するための標準化された方法。

    • 進行状況ハンドラー (英語) - サーバーが構造化された進行状況メッセージをクライアントに送信するための標準化された方法。

クライアントは最小ログレベルを設定することでログの詳細度を制御できる

クライアントのカスタマイズ例

アプリケーションのニーズに応じて、同期クライアントには McpCustomizer<McpClient.SyncSpec> を、非同期クライアントには McpCustomizer<McpClient.AsyncSpec> を実装できます。

  • 同期化

  • 非同期

@Component
public class CustomMcpSyncClientCustomizer implements McpClientCustomizer<McpClient.SyncSpec> {
    @Override
    public void customize(String serverConfigurationName, McpClient.SyncSpec spec) {

        // Customize the request timeout configuration
        spec.requestTimeout(Duration.ofSeconds(30));

        // Sets the root URIs that this client can access.
        spec.roots(roots);

        // Sets a custom sampling handler for processing message creation requests.
        spec.sampling((CreateMessageRequest messageRequest) -> {
            // Handle sampling
            CreateMessageResult result = ...
            return result;
        });

        // Sets a custom elicitation handler for processing elicitation requests.
        spec.elicitation((ElicitRequest request) -> {
          // handle elicitation
          return new ElicitResult(ElicitResult.Action.ACCEPT, Map.of("message", request.message()));
        });

        // Adds a consumer to be notified when progress notifications are received.
        spec.progressConsumer((ProgressNotification progress) -> {
         // Handle progress notifications
        });

        // Adds a consumer to be notified when the available tools change, such as tools
        // being added or removed.
        spec.toolsChangeConsumer((List<McpSchema.Tool> tools) -> {
            // Handle tools change
        });

        // Adds a consumer to be notified when the available resources change, such as resources
        // being added or removed.
        spec.resourcesChangeConsumer((List<McpSchema.Resource> resources) -> {
            // Handle resources change
        });

        // Adds a consumer to be notified when the available prompts change, such as prompts
        // being added or removed.
        spec.promptsChangeConsumer((List<McpSchema.Prompt> prompts) -> {
            // Handle prompts change
        });

        // Adds a consumer to be notified when logging messages are received from the server.
        spec.loggingConsumer((McpSchema.LoggingMessageNotification log) -> {
            // Handle log messages
        });
    }
}
@Component
public class CustomMcpAsyncClientCustomizer implements McpClientCustomizer<McpClient.AsyncSpec> {
    @Override
    public void customize(String serverConfigurationName, McpClient.AsyncSpec spec) {
        // Customize the async client configuration
        spec.requestTimeout(Duration.ofSeconds(30));
    }
}

serverConfigurationName パラメーターは、カスタマイザが適用され、MCP クライアントが作成されるサーバー構成の名前です。

MCP クライアントの自動構成は、アプリケーションコンテキストで見つかったカスタマイザーを自動的に検出して適用します。

輸送サポート

自動構成では、複数のトランスポート型がサポートされます。

  • 標準 I/O (スタジオ) (spring-ai-starter-mcp-client と spring-ai-starter-mcp-client-webflux によって活性化される)

  • (HttpClient) HTTP/SSE と Streamable-HTTP (spring-ai-starter-mcp-client によって活性化される)

  • (WebFlux) HTTP/SSE と Streamable-HTTP (spring-ai-starter-mcp-client-webflux によって活性化される)

ツールフィルタリング

MCP クライアント Boot スターターは、McpToolFilter インターフェースを介して検出されたツールのフィルタリングをサポートしています。これにより、MCP 接続情報やツールプロパティなどのカスタム条件に基づいて、ツールを選択的に含めたり除外したりできます。

ツールフィルタリングを実装するには、McpToolFilter インターフェースを実装する Bean を作成します。

@Component
public class CustomMcpToolFilter implements McpToolFilter {

    @Override
    public boolean test(McpConnectionInfo connectionInfo, McpSchema.Tool tool) {
        // Filter logic based on connection information and tool properties
        // Return true to include the tool, false to exclude it

        // Example: Exclude tools from a specific client
        if (connectionInfo.clientInfo().name().equals("restricted-client")) {
            return false;
        }

        // Example: Only include tools with specific names
        if (tool.name().startsWith("allowed_")) {
            return true;
        }

        // Example: Filter based on tool description or other properties
        if (tool.description() != null &&
            tool.description().contains("experimental")) {
            return false;
        }

        return true; // Include all other tools by default
    }
}

McpConnectionInfo レコードは、次のものへのアクセスを提供します。

  • clientCapabilities - MCP クライアントの機能

  • clientInfo - MCP クライアントに関する情報 (名前とバージョン)

  • initializeResult - MCP サーバーからの初期化結果

フィルターは自動的に検出され、同期および非同期の MCP ツールコールバックプロバイダーに適用されます。カスタムフィルターが指定されていない場合は、検出されたすべてのツールがデフォルトで含まれます。

メモ: アプリケーションコンテキストでは、McpToolFilter または Bean を 1 つだけ定義してください。複数のフィルターが必要な場合は、1 つの複合フィルター実装に統合してください。

ツール名プレフィックスの生成

MCP クライアント Boot スターターは、McpToolNamePrefixGenerator インターフェースを介してカスタマイズ可能なツール名プレフィックス生成をサポートしています。この機能により、複数の MCP サーバーのツールを統合する際の名前の競合を回避できます。ツール名に固有のプレフィックスを追加することで、この問題を解決できます。

デフォルトでは、カスタム McpToolNamePrefixGenerator Bean が指定されていない場合、スターターは DefaultMcpToolNamePrefixGenerator を使用します。これにより、すべての MCP クライアント接続で一意のツール名が確保されます。デフォルトのジェネレーターは次のとおりです。

  • 既存の接続とツール名をすべて追跡して一意性を確保します

  • 英数字以外の文字をアンダースコアに置き換えてツール名をフォーマットします (たとえば、my-tool は my_tool になります)

  • 異なる接続間で重複したツール名が検出されると、カウンタープレフィックスが追加されます (例: alt_1_toolName、alt_2_toolName)

  • スレッドセーフであり、べき等性を維持します。クライアント、サーバー、ツールの同じ組み合わせは常に同じ一意の名前を取得します。

  • 最終的な名前が 64 文字を超えないようにします (必要に応じて先頭から切り捨てる)

次に例を示します: * ツール search の最初の出現 → search * 異なる接続からのツール search の 2 番目の出現 → alt_1_search * 特殊文字を含むツール my-special-tool → my_special_tool

独自の実装を提供することで、この動作をカスタマイズできます。

@Component
public class CustomToolNamePrefixGenerator implements McpToolNamePrefixGenerator {

    @Override
    public String prefixedToolName(McpConnectionInfo connectionInfo, Tool tool) {
        // Custom logic to generate prefixed tool names

        // Example: Use server name and version as prefix
        String serverName = connectionInfo.initializeResult().serverInfo().name();
        String serverVersion = connectionInfo.initializeResult().serverInfo().version();
        return serverName + "_v" + serverVersion.replace(".", "_") + "_" + tool.name();
    }
}

McpConnectionInfo レコードは、MCP 接続に関する包括的な情報を提供します。

  • clientCapabilities - MCP クライアントの機能

  • clientInfo - MCP クライアントに関する情報 (名前、タイトル、バージョン)

  • initializeResult - MCP サーバーからの初期化結果(サーバー情報を含む)

組み込みプレフィックスジェネレーター

フレームワークには、いくつかの組み込みプレフィックスジェネレーターが用意されています。

  • DefaultMcpToolNamePrefixGenerator - 重複を追跡し、必要に応じてカウンタープレフィックスを追加することで、ツール名の一意性を確保します。(カスタム Bean が提供されていない場合はデフォルトで使用される)

  • McpToolNamePrefixGenerator.noPrefix() - プレフィックスなしでツール名を返します (複数のサーバーが同じ名前のツールを提供する場合、競合が発生する可能性があります)

プレフィックスを完全に無効にして生のツール名を使用するには (複数の MCP サーバーを使用している場合は推奨されません)、プレフィックスなしジェネレーターを Bean として登録します。

@Configuration
public class McpConfiguration {

    @Bean
    public McpToolNamePrefixGenerator mcpToolNamePrefixGenerator() {
        return McpToolNamePrefixGenerator.noPrefix();
    }
}

プレフィックスジェネレーターは、Spring の ObjectProvider メカニズムを通じて自動的に検出され、同期および非同期の MCP ツールコールバックプロバイダに適用されます。カスタムジェネレーター Bean が提供されていない場合は、DefaultMcpToolNamePrefixGenerator が自動的に使用されます。

複数の MCP サーバーで McpToolNamePrefixGenerator.noPrefix() を使用する場合、ツール名が重複すると IllegalStateException が発生します。デフォルトの DefaultMcpToolNamePrefixGenerator では、重複するツール名に自動的に固有のプレフィックスを追加することで、この問題を防止します。
This generator only de-duplicates names across MCP connections; it has no visibility into local @Tool methods. See Combining Local and MCP Tools for the local/remote collision case and which call paths actually guard against it.

ツールコンテキストから MCP メタコンバーターへ

MCP クライアント Boot スターターは、Spring AI の ToolContext を ToolContextToMcpMetaConverter インターフェースを介して MCP ツール呼び出しメタデータに変換するカスタマイズ可能な機能をサポートしています。この機能により、LLM が生成する呼び出し引数とともに、追加のコンテキスト情報(ユーザー ID、シークレットトークンなど)をメタデータとして渡すことができます。

たとえば、ツールコンテキストで MCP progressToken を MCP 進捗フロー (英語) に渡して、長時間実行される操作の進行状況を追跡できます。

ChatModel chatModel = ...

String response = ChatClient.create(chatModel)
        .prompt("Tell me more about the customer with ID 42")
        .toolContext(Map.of("progressToken", "my-progress-token"))
        .call()
        .content();

デフォルトでは、カスタムコンバーター Bean が提供されていない場合、スターターは次の ToolContextToMcpMetaConverter.defaultConverter() を使用します。

  • MCP 交換キーを除外する (McpToolUtils.TOOL_CONTEXT_MCP_EXCHANGE_KEY)

  • NULL 値のエントリを除外します

  • 他のすべてのコンテキストエントリをメタデータとして渡す

独自の実装を提供することで、この動作をカスタマイズできます。

@Component
public class CustomToolContextToMcpMetaConverter implements ToolContextToMcpMetaConverter {

    @Override
    public Map<String, Object> convert(ToolContext toolContext) {
        if (toolContext == null || toolContext.getContext() == null) {
            return Map.of();
        }

        // Custom logic to convert tool context to MCP metadata
        Map<String, Object> metadata = new HashMap<>();

        // Example: Add custom prefix to all keys
        for (Map.Entry<String, Object> entry : toolContext.getContext().entrySet()) {
            if (entry.getValue() != null) {
                metadata.put("app_" + entry.getKey(), entry.getValue());
            }
        }

        // Example: Add additional metadata
        metadata.put("timestamp", System.currentTimeMillis());
        metadata.put("source", "spring-ai");

        return metadata;
    }
}

内蔵コンバーター

フレームワークには組み込みコンバーターが用意されています。

  • ToolContextToMcpMetaConverter.defaultConverter() - MCP 交換キーと null 値を除外します (カスタム Bean が提供されていない場合はデフォルトで使用される)

  • ToolContextToMcpMetaConverter.noOp() - 空のマップを返し、コンテキストからメタデータへの変換を事実上無効にします。

コンテキストからメタデータへの変換を完全に無効にするには:

@Configuration
public class McpConfiguration {

    @Bean
    public ToolContextToMcpMetaConverter toolContextToMcpMetaConverter() {
        return ToolContextToMcpMetaConverter.noOp();
    }
}

コンバーターは Spring の ObjectProvider メカニズムを通じて自動的に検出され、同期および非同期の MCP ツールコールバックに適用されます。カスタムコンバーター Bean が指定されていない場合は、デフォルトのコンバーターが自動的に使用されます。

MCP ToolCallback の自動構成を無効にする

MCP ToolCallback 自動構成はデフォルトで有効になっていますが、spring.ai.mcp.client.toolcallback.enabled=false プロパティを使用して無効にすることができます。

無効にすると、使用可能な MCP ツールから ToolCallbackProvider Bean は作成されません。

MCP クライアントアノテーション

MCP クライアント Boot スターターは、さまざまな MCP クライアント操作を処理するためのアノテーション付きメソッドを自動的に検出し、登録します。

  • @McpLogging - MCP サーバーからのログメッセージ通知を処理します

  • @McpSampling - LLM 補完のための MCP サーバーからのサンプリングリクエストを処理します

  • @McpElicitation - ユーザーから追加情報を収集するための情報収集リクエストを処理します

  • @McpProgress - 長時間実行される操作の進行状況通知を処理します

  • @McpToolListChanged - サーバーのツールリストが変更されたときに通知を処理します

  • @McpResourceListChanged - サーバーのリソースリストが変更されたときに通知を処理します

  • @McpPromptListChanged - サーバーのプロンプトリストが変更されたときに通知を処理します

使用例:

@Component
public class McpClientHandlers {

    @McpLogging(clients = "server1")
    public void handleLoggingMessage(LoggingMessageNotification notification) {
        System.out.println("Received log: " + notification.level() +
                          " - " + notification.data());
    }

    @McpSampling(clients = "server1")
    public CreateMessageResult handleSamplingRequest(CreateMessageRequest request) {
        // Process the request and generate a response
        String response = generateLLMResponse(request);

        return CreateMessageResult.builder(Role.ASSISTANT, response, "gpt-4")
            .build();
    }

    @McpProgress(clients = "server1")
    public void handleProgressNotification(ProgressNotification notification) {
        double percentage = notification.progress() * 100;
        System.out.println(String.format("Progress: %.2f%% - %s",
            percentage, notification.message()));
    }

    @McpToolListChanged(clients = "server1")
    public void handleToolListChanged(List<McpSchema.Tool> updatedTools) {
        System.out.println("Tool list updated: " + updatedTools.size() + " tools available");
        // Update local tool registry
        toolRegistry.updateTools(updatedTools);
    }
}

アノテーションは同期実装と非同期実装の両方をサポートしており、clients パラメーターを使用して特定のクライアント用に構成できます。

@McpLogging(clients = "server1")
public void handleServer1Logs(LoggingMessageNotification notification) {
    // Handle logs from specific server
    logToFile("server1.log", notification);
}

@McpSampling(clients = "server1")
public Mono<CreateMessageResult> handleAsyncSampling(CreateMessageRequest request) {
    return Mono.fromCallable(() -> {
        String response = generateLLMResponse(request);
        return CreateMessageResult.builder(Role.ASSISTANT, response, "gpt-4")
            .build();
    }).subscribeOn(Schedulers.boundedElastic());
}

利用可能なすべてのアノテーションとその使用パターンの詳細については、MCP クライアントアノテーションのドキュメントを参照してください。

使用例

適切なスターター依存関係をプロジェクトに追加し、application.properties または application.yml でクライアントを構成します。

spring:
  ai:
    mcp:
      client:
        enabled: true
        name: my-mcp-client
        version: 1.0.0
        request-timeout: 30s
        type: SYNC  # or ASYNC for reactive applications
        sse:
          connections:
            server1:
              url: http://localhost:8080
            server2:
              url: http://otherserver:8081
        streamable-http:
          connections:
            server3:
              url: http://localhost:8083
              endpoint: /mcp
        stdio:
          root-change-notification: false
          connections:
            server1:
              command: /path/to/server
              args:
                - --port=8080
                - --mode=production
              env:
                API_KEY: your-api-key
                DEBUG: "true"

MCP クライアント Bean は自動的に構成され、注入に使用できるようになります。

@Autowired
private List<McpSyncClient> mcpSyncClients;  // For sync client

// OR

@Autowired
private List<McpAsyncClient> mcpAsyncClients;  // For async client

ツールコールバックが有効になっている場合 (デフォルトの動作)、すべての MCP クライアントに登録された MCP ツールは ToolCallbackProvider インスタンスとして提供されます。

@Autowired
private SyncMcpToolCallbackProvider toolCallbackProvider;
ToolCallback[] toolCallbacks = toolCallbackProvider.getToolCallbacks();

アプリケーション例