4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Claude Agent SDKにおけるMCPサーバー接続フローとalwaysLoadパラメータについて

4
Posted at

tl;dr

  • Claude Agent SDK(TypeScript版)でMCPサーバーを接続する際、.mcp.jsonalwaysLoad: trueを設定しておくと、セッション開始時からMCPサーバーが使えるようになる
  • そのMCPサーバーを常に・必ず使ってほしい場合はtrueに設定しよう
  • コンテキスト次第で使ったり使わなかったりする場合は設定しなくて良いです

はじめに

こんにちは、ふくちです。

皆様Claude Agent SDK使っていらっしゃいますでしょうか。
私は先日、Claude Agent SDKを使用してMCPサーバーに接続した時、以下の現象が発生していました。

[INIT] Model: jp.anthropic.claude-haiku-4-5-20251001-v1:0
[INIT] Tools: 
[INIT] MCP Servers: [{"name":"aws-knowledge-mcp-server","status":"pending"}]

このようにinitメッセージでMCPサーバーのステータスが「pending」と表示されていました。

ここまでなら設定ミスかなと思ったのですが、挙動を見ているとその直後、ツールリストが空のままMCPツール(mcp__aws-knowledge-mcp-server__aws___search_documentation)が正常に呼び出され、実行結果が返ってきていました。

つまり、

  1. MCP接続状態がpendingのままで、connectedに遷移していない
  2. ツール定義がinitメッセージに含まれず、ツール一覧が空である
  3. にもかかわらずMCPツールは正常に動作している

こんな状況でした。

initメッセージ時点ではMCPサーバーが接続完了していないはずなのに、その直後のツール呼び出しが成功している。これはなんぞ??と思って、少し調べてみました。

実行環境

以下のような.mcp.jsonとエージェントコードを書いて動かしてみました。

.mcp.json
{
  "mcpServers": {
    "aws-knowledge-mcp-server": {
      "url": "https://knowledge-mcp.global.api.aws",
      "type": "http",
      "disabled": false
    }
  }
}
agent-mcp.ts
import { query } from "@anthropic-ai/claude-agent-sdk";

for await (const message of query({
  prompt: "Amazon Bedrockの料金体系について教えて",
  options: {
    settingSources: ["project"],
    tools: ["mcp__aws-knowledge-mcp-server__*"],
    allowedTools: ["mcp__aws-knowledge-mcp-server__*"],
    includePartialMessages: true,
  }
})) {
    switch (message.type) {
        // セッション開始
        case "system":
            if (message.subtype === "init") {
                console.log(`\n[INFO] Model: ${message.model}`);
                console.log(`[INFO] Tools: ${message.tools.join(", ")}`);
                console.log(`[INFO] MCP Servers: ` +
                  `${JSON.stringify(message.mcp_servers)}`);
                console.log("---");
            }
            break;

        // トークン単位のテキストストリーミング
        case "stream_event":
            if (message.event.type === "content_block_delta"
                && message.event.delta.type === "text_delta") {
                process.stdout.write(message.event.delta.text);
            }
            break;

        // ツール呼び出し(テキストは上のstream_eventで出力済み)
        case "assistant":
            for (const block of message.message.content) {
                if (block.type === "tool_use") {
                    console.log(`\n\nTool: ${block.name}`);
                    console.log(`   Input: ${JSON.stringify(block.input)}`);
                }
            }
            break;

        // ツール実行結果
        case "user":
            if (Array.isArray(message.message.content)) {
                for (const block of message.message.content) {
                    if (typeof block === "object"
                        && "type" in block
                        && block.type === "tool_result") {
                        const content = typeof block.content === "string"
                            ? block.content
                            : JSON.stringify(block.content);
                        console.log(`   Result: ${content?.slice(0, 200)}...`);
                    }
                }
            }
            break;
    }
}

Bedrockの料金について確認しているので、AWS Knowledge MCPを検索して回答を返してくれるはずです。

そこで動かしてみると…

[INIT] Model: jp.anthropic.claude-haiku-4-5-20251001-v1:0
[INIT] Tools: 
[INIT] MCP Servers: [{"name":"aws-knowledge-mcp-server","status":"pending"}]

Tool call: mcp__aws-knowledge-mcp-server__aws___search_documentation

という形になっていました。

調査フェーズ

コードベースで調査してみる

まず、Claude Agent SDK(version 0.3.201)のnode_modules/@anthropic-ai/claude-agent-sdk/sdk.d.tsを確認しました。

するとalwaysLoadという項目を発見しました。

sdk.d.ts
export declare type McpHttpServerConfig = {
    type: 'http';
    url: string;
    headers?: Record<string, string>;
    tools?: McpServerToolPolicy[];
    timeout?: number;
    /**
     * When true, all tools from this server are always included in the prompt 
     * and never deferred behind tool search. Equivalent to setting defer_loading: 
     * false on the API. Default: tools are deferred when tool search is enabled. 
     * As a side effect this also blocks startup until the server is connected 
     * (capped at the standard 5s connect timeout) even though MCP startup is 
     * otherwise non-blocking by default, since the tools must be present 
     * when the turn-1 prompt is built.
     */
    alwaysLoad?: boolean;
};

この注釈を日本語訳すると下記のようになります。

この設定を「true」にすると、このサーバーにあるすべてのツールが常にプロンプトに含まれるようになり、ツール検索によって読み込みが後回しにされることはありません。これは、APIで defer_loading: false を設定するのと同等です。
デフォルトでは、ツール検索が有効な場合、ツールの読み込みは後回し(defer)にされます。

また、この設定の副次的な影響として、サーバーに接続されるまで起動プロセスがブロックされます(標準の接続タイムアウトである5秒が上限です)。
MCPの起動は通常、非ブロッキングで行われますが、この設定を有効にすると、最初のプロンプトを作成する時点でツールが揃っている必要があるため、接続を待機するようになります。

この注釈から、デフォルトではMCP起動が非ブロッキング(non-blocking)であると明らかになりました。

…で、非ブロッキングって何?そもそもこのパラメータ何???となったので追加で調査しました。

ドキュメントを調査してみる

下記ドキュメントにまとまっていました。

サーバーのツールを、検索の手間をかけずに常にClaudeから利用可能な状態にしておきたい場合は、そのサーバー設定で alwaysLoadtrue に設定してください。

これにより、ENABLE_TOOL_SEARCH の設定に関わらず、そのサーバーのすべてのツールがセッション開始時にコンテキストへ読み込まれます。

ただし、事前に読み込まれたツールは、本来会話に使えるはずのコンテキスト容量を消費します。そのため、この設定はClaudeがすべてのターンで必要とするような、少数のツールに限定して使用することをお勧めします。

alwaysLoad: true を設定すると、サーバーが接続されるまで起動処理がブロックされます。ただし、これには標準で 5 秒間の接続タイムアウト制限が設けられています。
通常、MCP の起動は非ブロッキング(並列処理)で行われますが、この設定が有効な場合は例外となります。これは、最初のプロンプトが生成される時点で、該当するツールが必ず利用可能な状態でなければならないためです。なお、他のサーバーについては、通常通りバックグラウンドで接続処理が継続されます。

つまり、デフォルトではMCPツール定義は遅延ロードされ、initメッセージには含まれないようになっているようです。具体的には以下の流れです。

T0: query()が呼び出される
    MCP接続開始(バックグラウンド) → status: pending
    
T1: system init メッセージ発火
    status: pending のまま
    ツール検索が有効な場合、MCPツール定義は含まれていない
    
T2-T3: MCPサーバー接続が進行(バックグラウンド)
    status: pending → connected
    
T4: Claude理由付けとツール呼び出し実行
    この時点では既にMCPサーバーが接続完了している
    
T5: MCPツール呼び出し成功

冒頭のように、init時点ではpendingステータスだったのに気づいたらMCPサーバーを使えるようになっていた、というのはこういう流れがあったからでした。

解決策

それを防ぎ、会話の最初からMCPサーバーを有効化しておきたい場合にalwaysLoadを設定します。
具体的には、.mcp.jsonファイルでalwaysLoadオプションをtrueに設定します。

.mcp.json
{
  "mcpServers": {
    "aws-knowledge-mcp-server": {
      "type": "http",
      "url": "https://knowledge-mcp.global.api.aws",
+     "alwaysLoad": true     
    }
  }
}

この状態で実行すると、init時点で最初からツールが読み込まれており、ステータスもconnectedになっていました。

[INIT] Model: jp.anthropic.claude-haiku-4-5-20251001-v1:0
[INIT] Tools: mcp__aws-knowledge-mcp-server__aws___get_regional_availability, mcp__aws-knowledge-mcp-server__aws___list_regions, mcp__aws-knowledge-mcp-server__aws___read_documentation, mcp__aws-knowledge-mcp-server__aws___retrieve_skill, mcp__aws-knowledge-mcp-server__aws___search_documentation
[INIT] MCP Servers: [{"name":"aws-knowledge-mcp-server","status":"connected"}]

余談:Claude Code側のアップデートに伴うパラメータだったらしい

下記サーバーワークスさんのブログでわかりやすく解説されていました。

tool-search deferral は MCP ツールの数が増えるとコンテキスト消費が膨らむ問題を解決するために導入された仕組みで、Claude Code は通常、必要になったツールをその都度サーチしてロードする遅延ロード方式で動作します。

alwaysLoad: true を設定すると、そのサーバーのツール一式は遅延ロードを経由せず、ENABLE_TOOL_SEARCH 設定の値にかかわらずセッション開始時から常駐します。

毎ターン必ず Claude が叩く社内 API ツール群や、コーディング作業の各ステップで参照するドキュメント検索系サーバー(例: 最新ドキュメントを引く Context7 のようなサーバー)など、ToolSearch のオーバーヘッドを避けたい少数のツールを抱えるサーバーに有効です。

よくよく見るとさっきの公式ドキュメントもClaude Agent SDKのドキュメントではなく、Claude Codeのドキュメントでした。

Claude Codeの挙動含め、勉強になりました!

4
0
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
4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?