VPoTの岩本 (iwamot) です。
このたび、ENECHANGE社内で使っているSlack botからMCPサーバーを呼び出せるようにしました。おもな背景は次の2つです。
- MCPの普及により、便利なMCPサーバーが続々と公開されている
- 社内Slack botに「外部サイトが参照できたら便利」との意見があった
今回の記事では、機能を実現するために選んだ7つのツールをご紹介します。
MCPホストツール
Collmbo
筆者が開発・公開しているSlack botアプリです。LiteLLMを組み込んでおり、100以上のLLMとチャットできます。
MCPサーバーを呼び出す機能がなかったため、次に説明するStrands Agentsを新たに組み込んで実装しました。
トランスポートについては、以下の理由でStreamable HTTPのみをサポートしています。
- stdioをサポートすると、Collmboのメンテナンスが大変になる。MCPサーバーとの結合度を低くしておきたい
- すでに非推奨となっているSSEはサポートしたくない
呼び出したいMCPサーバーのURLは、環境変数の MCP_SERVER_URL
で複数指定できるようにしました。|
で区切って並べられる仕様です。
MCP_SERVER_URL=https://example.com/mcp|https://example.org/servers/A/mcp
実装は以下のようにしています。
- Collmboの起動時、各MCPサーバーのツールリストを取得する
- 各MCPツールを、OpenAIのfunction calling形式に変換してメモリに保持する
- LLMへの問い合わせ (chat completion) 時の
tools
パラメータにツールリストを含める - LLMからMCPツール呼び出しが推奨されたら、MCPサーバーを呼び出す
下記は「各MCPサーバーのツールリストを取得し、function calling形式に変換する処理」を現状のソースコードから抜粋したものです。
# 内部的なツール名を「{MCPツール名}-{MCPサーバーのインデックス}」とする def build_mcp_tool_name(spec_name: str, server_index: int) -> str: return f"{spec_name}{MCP_TOOL_NAME_SEPARATOR}{server_index}" # MCPツールをfunction calling形式に変換する def transform_mcp_spec_to_classic_tool( *, mcp_spec: ToolSpec, server_index: int, model: str, ) -> dict: parameters = deepcopy(mcp_spec["inputSchema"]["json"]) # Remove invalid "format" property for Gemini models if model.startswith("gemini/"): for prop in parameters.get("properties", {}).values(): if "format" in prop and prop["format"] not in ("date-time", "enum"): prop.pop("format") return { "type": "function", "function": { "name": build_mcp_tool_name(mcp_spec["name"], server_index), "description": mcp_spec["description"], "parameters": parameters, }, } # 各MCPサーバーのツールリストを取得する def load_mcp_tools() -> list[dict]: result: list[dict] = [] mcp_servers = split_mcp_server_url(MCP_SERVER_URL) for idx, url in enumerate(mcp_servers): try: tools = fetch_tools_from_mcp_server(url) result.extend( transform_mcp_spec_to_classic_tool( mcp_spec=tool.tool_spec, server_index=idx, model=LITELLM_MODEL_TYPE, # 会話するモデルを環境変数で指定 ) for tool in tools ) except Exception as exc: logging.warning("Failed to load MCP tools from %s: %s", url, exc) return result
コードにある通り、内部的なツール名を {MCPツール名}-{MCPサーバーのインデックス}
という形式にしています。たとえばLLMから fetch-0
の呼び出しを推奨された場合、0番目のMCPサーバーの fetch
ツールを呼び出す寸法です。これで複数のMCPサーバーに対応できます。
MCPクライアントツール
Strands Agents
AWSが2025年5月に公開した、AIエージェントを作れるSDKです。AWS自身、Amazon Q Developerなどのサービスで使っているそうです。
しかし今回は、MCP Python SDKのラッパーとしてのみ使うことにしました。
MCPの公式SDKであるMCP Python SDKは、asyncなインターフェイスしか提供していません。そのため、syncなCollmboで使うのは難しい状況です。
# MCP Python SDKの利用例 async with streamablehttp_client("example/mcp") as ( read_stream, write_stream, _, ): async with ClientSession(read_stream, write_stream) as session: await session.initialize() # MCPツールリストの取得 (async) tools = await session.list_tools() # MCPツールの呼び出し (async) result = await session.call_tool("tool-name", arguments={"arg1": "value"})
一方Strands Agentsでは、MCP Python SDKをラップしたsyncなインターフェイスが提供されています。
# Strands Agentsの利用例 with mcp_client: # MCPツールリストの取得 (sync) tools = mcp_client.list_tools_sync() # MCPツールの呼び出し (sync) result = mcp_client.call_tool_sync( tool_use_id="tool-123", name="tool-name", arguments={"arg1": "value"} )
Strands Agentsを使うことで、syncなCollmboでもMCPクライアント機能が簡単に実装できました。MCPを扱う詳しい方法については、Strands Agentsのドキュメントをご参照ください。
MCPサーバーツール
mcp-proxy
MCPのトランスポートを変換できるプロキシツールです。これを使うと、たとえばstdioなMCPサーバーをStreamable HTTP経由で呼び出せます。
Streamable HTTPに対応したMCPサーバーは、まだ多くありません。次に説明するFetch MCP ServerやAWS Documentation MCP Serverも、現時点ではstdioのみサポートしています。
そこでmcp-proxyを使って、stdioなMCPサーバーをStreamable HTTP経由で呼び出せるようにしました。
mcp-proxy --stateless --port 8000 \ --named-server-config /path/to/named-server-config.json
named-server-config.jsonの内容は、現状では下記の通りです。
{ "mcpServers": { "fetch": { "disabled": false, "timeout": 60, "command": "uvx", "args": [ "mcp-server-fetch" ], "transportType": "stdio" }, "aws-documentation": { "disabled": false, "timeout": 60, "command": "uvx", "args": [ "awslabs.aws-documentation-mcp-server@latest" ], "env": { "FASTMCP_LOG_LEVEL": "ERROR", "AWS_DOCUMENTATION_PARTITION": "aws" }, "transportType": "stdio" } } }
Fetch MCP Server
外部サイトが参照できるMCPサーバーです。MCP公式によるリファレンス実装ですが、公式であれば信頼性が高いと判断して選びました。
導入の目的は、もちろん「外部サイトが参照できたら便利」との同僚からの意見に応えることです。他に適切そうなMCPサーバーが登場したら、乗り換えるかもしれません。
AWS Documentation MCP Server
AWSのドキュメントが参照できるMCPサーバーです。AWS公式。
複数のMCPサーバーが呼び出せることを示すため、まずは安全で便利そうなものを選びました。
運用ツール
Amazon ECS
AWSのコンテナ実行サービスです。社内Slack botの運用環境として、もともと活用しています。今回はMCPサーバーのコンテナを追加しました。
細かい話ですが、mcp-proxyはヘルスチェック用のURL /status
を用意しています。そのためECSのタスク定義で下記のチェックを指定しました。
healthCheck = { command = [ "CMD-SHELL", "wget -q --spider http://localhost/status >>/proc/1/fd/1 2>&1 || exit 1", ] }
Amazon GuardDuty
AWSの脅威検出サービスです。AWS環境での不審なアクティビティを検出してくれます。
今回はECSのランタイムモニタリングを有効化しました。外部サイトへのアクセスを許可したので、監視したほうが安全だと判断したものです。
具体的には下記の手順で進めました。
- GuardDutyのランタイムモニタリング設定を有効化
- ECSクラスターに
GuardDutyManaged = true
タグを付与 - ECSサービスを「新しいデプロイの強制」で更新 (
aws ecs update-service --cluster my-cluster --service my-service --force-new-deployment
)
3で再デプロイしているのは、GuardDutyの仕様によります。そうしないと、ECSのランタイムモニタリングが有効になりません。
構成図
ツールの関係性を分かりやすく示すため、全体の構成図をご紹介します。図中で太字になっている要素が、今回選んだ7つのツールです。
おわりに
7つのツールのおかげで、Slack botからMCPサーバーを呼び出す機能が簡単に実現できました。特にStrands Agentsとmcp-proxyは便利です。
MCP関連ツールが充実し、手軽に試せる時代になってきました。ぜひ一度お試しください。