はじめに
先月、Anthropic社よりMCP(Model Context Protocol)というプロトコルが発表されました。
www.anthropic.com
MCPはAIアシスタント(RAGシステム)と情報源やツール群をつなげるための通信規約(プロトコル)ですが、現時点で何がどこまでできるかが未知数でしたので、調査を行い、LangChainのエージェント機能で動作させました。
とりあえずは、得られた知見についてシステム構成面の切り口で考察していきたいと思います。
MCPとは
MCPの各種情報は以下にあります。
- 公式サイト
- github
- Python SDK
- servers: サーバーのリファレンス実装もある
- langchain-mcp: 上記のPython SDKを使用したLangChainへの実装。ToolkitもしくはToolの形態をしている
概要
MCPはプロトコル仕様のArchitectureにある下記の図のようにアプリケーションがMCPのクライアントとなり、ローカルやリモートに位置するMCPのサーバーと通信して、情報を取得したり、ツールを動作させたりします。
アプリケーションにはデスクトップアプリやSaaSサービスが想定されます。
そして、MCP自体は以下のようなプロトコルのフローやメッセージの中身が規定されています。
認証の不在
プロトコルの規定の中で気になったのは、現時点では認証に対応しておらず、今後議論していくように書かれていました。
認証が存在しない以上、インターネットを介しての通信は難しいかもしれません。
Auth
Authentication and authorization are not currently part of the core MCP specification, but we are considering ways to introduce them in future. Join us in GitHub Discussions to help shape the future of the protocol!
Clients and servers MAY negotiate their own custom authentication and authorization strategies.
2つのトランスポート
プロトコル仕様のTransportsによると、MCPには以下の2つのトランスポートがあるそうです。
後者のSSEタイプはhttpsを介した通信なのでMCPのサーバーはローカルとリモートを問わずに適用できます。
一方で、前者のstdioタイプはMCPのクライアントがMCPのサーバーとなるプロセスを起動して、パイプ機能による標準入出力(stdio)を介して通信するため、stdioタイプはローカル内でしか動作しないです。
SDKとリファレンスサーバー群
MCPの公式githubにはPython SDKとTypeScript SDKが整備されており、これらを使用したリファレンスやサードパーティのサーバー群も提供されています。
SDKは前述した2つのトランスポートの両方に対応しているのですが、リファレンスサーバー群のほとんどはstdioタイプで作られているため、リモートで動作するものはないです。
LangChainへの実装
Python SDKを使用してLangChainへ実装したlangchain-mcpというライブラリもありますが、stdioタイプを前提としているため、ローカル内でのみ動作します(=リモートでは動作しません)。
langchain-mcpはTool
コンポーネントのMCPTool
もしくはToolkit
コンポーネントのMCPToolkit
という形態で提供されるため、LangChainのエージェント機能で使う形になります。
このlangchain-mcpはasync with
構文でトランスポートのクライアント(下記の例ではstdio_client
)を起動した状態で実行する必要があるため、チェインの構成と実行を近接して行う必要があります。
async with stdio_client(server_params) as (read, write): async with ClientSession(read, write) as session: toolkit = MCPToolkit(session=session) await toolkit.initialize() (toolkitを使用してrunする)
HEROZ ASKはチェインの構成と実行のタイミングが離れているので、langchain-mcpが適用しづらく、組み込みについては一旦は断念することにしました。
システム構成
MCPの動作についてシステム構成面で図を交えて考察していきます。
Claude Desktopでのシステム構成
Anthropic社はMCPの発表とともに応用例としてデスクトップ版Claude(Claude Desktop)からのデスクトップ検索を提示しています。
これが「デスクトップ検索が便利だ」や「デスクトップを覗かれるのは危険だ」みたいな感想とともに強調されてしまい、「MCP=デスクトップ検索」や「MCP=Claude Desktop」みたいな勘違いが発生しています。
MCPはあくまで通信プロトコルであって、Claude Desktopやデスクトップ検索は直接的には関係なく、単なる応用例の一つに過ぎません。
Claude Desktopでのシステム構成を図にすると、以下になります。
Claude DesktopはMCPクライアントとして位置し、必要なMCPサーバーを自ら起動して、stdioタイプのトランスポートで接続します。
そして、起動したMCPサーバーのプロセスからデスクトップのファイルにアクセスしています。
起動するMCPサーバーの種類やアクセス先は設定ファイルのjsonにてClaude Desktopに渡しますが、任意のプログラムが起動できたり、ローカルのリソースに自由にアクセスできるという点で、安全とは言えない代物です。
SaaSシステムでの目指したいシステム構成
HEROZ ASKのようなSaaS型のAIアシスタントサービスにMCPを組み込む場合には、以下のような2つのパターンのシステム構成があると思います。
a.はSaaSサービスがMCPクライアントとなるパターンで、ユーザーからの質問に応じて、AIアシスタントがリモートサーバーにある情報を取得したり、ツールで何か実行したりします。
b.はSaaSサービスがMCPサーバーとなるパターンで、SaaSサービスが持っているリソースに対して、ユーザのAIアシスタントアプリや、別のSaaSサービスのAIアシスタントからのアクセスを受け付けます。
こちらはSaaSサービスが持つリソースが重要となるので、どちらかと言うとコンテンツプロバイダー的な位置付けになります。
HEROZ ASKは独自のリソースを持つわけではないので、a.のパターンを狙うことになります。
また、HEROZ ASKのようなエンタープライズ向けのサービスの場合には、リモートサーバーはお客様の情報やツールが入ったサーバーになることが想定されます。
現状のシステム構成
前述のようにAIアシスタントのSaaSサービスはa.のようなMCPクライアントとして、リモートサーバーへのアクセスを望む場合が多いですが、現状はlangchain-mcpがstdioタイプのトランスポートにしか対応していないため、下記のようなシステム構成にならざるをえません。
すなわち、ユーザから質問を受け取ると、MCPサーバーとなるプロセスを起動するとともに、SaaSサービスが動作しているサーバーのリソースにアクセスします。
これは、セキュリティ的にも問題が多いので、HTTP with SSEの対応が待たれます。
SaaSシステムでの問題点
仮にlangchain-mcpがHTTP with SSEタイプのトランスポートに対応したとしても、お客様のサーバーに情報を取りに行ったり、ツールを実行しに行ったりする場合には以下のような問題があります。
これらを図示すると以下となります。
LangChainのエージェント機能で動かしてみた
langchain-mcpのREADMEにはエージェント機能を使わない例が載っていますが、せっかくなのでエージェント機能を使って動作させてみました。
/doc
というディレクトリと/doc/test.txt
というファイルを作成してから、「/docには何のファイルがありますか?」という質問でディレクトリ内のファイル一覧を取得させています。
コードを見る
!pip install langchain langchain-openai langchain-mcp langchain-community==0.3.12 langchain-core==0.3.25 !mkdir -p /doc !touch /doc/test.txt import os import asyncio from langchain_openai import ChatOpenAI from langchain import hub from langchain.agents import AgentExecutor, create_structured_chat_agent from mcp import ClientSession, StdioServerParameters from mcp.client.stdio import stdio_client from langchain_mcp import MCPToolkit os.environ["OPENAI_API_KEY"] = "(OpenAIのAPIキー)" server_params = StdioServerParameters( command="npx", args=["-y", "@modelcontextprotocol/server-filesystem", "/doc"], ) from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder from langchain.agents.structured_chat.prompt import FORMAT_INSTRUCTIONS, PREFIX, SUFFIX HUMAN_MESSAGE_TEMPLATE = "{input}\n\n{agent_scratchpad}" prompt = ChatPromptTemplate.from_messages( [ ("system", "\n\n".join([PREFIX, "{tools}", FORMAT_INSTRUCTIONS, SUFFIX])), MessagesPlaceholder("chat_history", optional=True), ("human", HUMAN_MESSAGE_TEMPLATE), ] ) async def main(message): async with stdio_client(server_params) as (read, write): async with ClientSession(read, write) as session: toolkit = MCPToolkit(session=session) await toolkit.initialize() model = ChatOpenAI(model_name="gpt-4o") tools = toolkit.get_tools() agent = create_structured_chat_agent(model, tools, prompt) agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True) await agent_executor.ainvoke({"input": message}) asyncio.run(main("/docには何のファイルがありますか?"))
無事にtest.txt
があるという回答を得ることができましたが、langchain-community
とlangchain-core
をバージョン固定にしないとうまく動きませんでした。
おわりに
新しく登場したMCPは外部の情報やツールを活用できるので、期待の技術と思っていたのですが、以下の理由によりまだまだ時期尚早のように思いました。
- プロトコルの仕様に認証機能が搭載されていないため、インターネット経由の接続が難しい
- リファレンスサーバーやlangchain-mcpのトランスポートがstdioタイプなので、ローカル内でしか実行できない(リモートサーバーへの接続ができない)
- Python SDKは
async with
構文の中でしか実行できないので、セッションの確立(チェインの作成)と実際の動作(チェインの実行)を分離することができない
とは言え、これらの技術課題が解決されれば、大規模言語モデル(LLM)を用いたエンタープライズサーチの実現も夢が広がります。こうしたOSSへのコントリビュートについても一緒にやってくれる仲間を募集しています。