これは、なにをしたくて書いたもの?
MCP(Model Context Protocol)というものを、ちょっと勉強してみようかなということで。
MCP(Model Context Protocol)
MCP(Model Context Protocol)は、Anthropic社がオープンソースとして公開したプロトコルです。
Introducing the Model Context Protocol \ Anthropic
MCPは開発者がデータソースとAIツールの間で、セキュアに双方向接続を構築できるようにするオープンスタンダードだと
されています。
Model Context Protocol · GitHub
ドキュメントはこちら。
Introduction - Model Context Protocol
仕様書はこちら。
Specification – Model Context Protocol Specification
仕様書は、現時点で以下の2つのリビジョンがあるみたいですね。
- Model Context Protocol specification / Revision 2025-03-26
- Model Context Protocol specification / Revision 2024-11-05
Revision 2025-03-26は出たばかりですね。
MCPのドキュメントのイントロダクションを読む
まずはドキュメントのイントロダクションを見て、MCPの概要を掴んでみましょう。
Introduction - Model Context Protocol
MCPは、アプリケーションがLLMにコンテキストを提供する方法を標準化する、オープンプロトコルです。
MCP is an open protocol that standardizes how applications provide context to LLMs.
MCPはAIアプリケーションのUSB-Cのようなものに相当し、USB-Cが様々な周辺機器やアクセサリーに接続するための
標準化された方法を提供するのと同じように、MCPはAIモデルを様々なデータソースやツールに接続するための標準化された
方法を提供します。
Think of MCP like a USB-C port for AI applications. Just as USB-C provides a standardized way to connect your devices to various peripherals and accessories, MCP provides a standardized way to connect AI models to different data sources and tools.
MCPが提供するのは、次の機能です。
- LLMが直接接続できる、構築済みインテグレーション
- LLMプロバイダーとベンダーを切り替える柔軟性
- インフラストラクチャー内でデータを保護するためのベストプラクティス
アーキテクチャーはこちら。
Introduction / Why MCP? / General architecture
登場する要素は以下になります。
- MCPホスト … Claude Desktop、IDEまたはMCPを介してデータにアクセスするAIツールなどのプログラム
- MCPクライアント … サーバーと1対1の接続を維持するプロトコルクライアント
- MCPサーバー … 標準化されたModel Context Protocolを通じて特定の機能を公開する軽量なプログラム
- ローカルデータソース … MCPサーバーが安全にアクセスできるコンピューターのファイル、データベース、サービス
- リモートサービス … MCPサーバーが接続できるインターネット経由(API経由など)で利用可能な外部システム
LangChain MCP Adapters
LangChainには、LangChain MCP AdaptersというMCPのラッパーがあるようです。
GitHub - langchain-ai/langchain-mcp-adapters
現時点でまだ0.0.7ですが、機能としては以下のようです。
LangChain MCP Adapters / Features
LangChain MCP AdaptersはMCPのPython SDKを使っています。
MCPのドキュメントにもQuickstartはあるのですが、Anthropicが前提になりがちのようなので今回は
このLangChain MCP Adapters、それからOllamaを使ってMCPを試してみたいと思います。
環境
今回の環境はこちら。
$ python3 --version Python 3.12.3 $ uv --version uv 0.6.12
Ollama。
$ bin/ollama serve $ bin/ollama --version ollama version is 0.6.4
準備
uvでプロジェクトを作成します。
$ uv init --vcs none langchain-mcp-adapters-getting-started $ cd langchain-mcp-adapters-getting-started $ rm main.py
依存ライブラリーを追加。今回のポイントはlangchain-mcp-adaptersですね。
$ uv add langchain-mcp-adapters langgraph langchain-ollama
mypyとRuffも追加しておきます。
$ uv add --dev mypy ruff
インストールされた依存関係の一覧。
$ uv pip list Package Version ---------------------- --------- annotated-types 0.7.0 anyio 4.9.0 certifi 2025.1.31 charset-normalizer 3.4.1 click 8.1.8 h11 0.14.0 httpcore 1.0.7 httpx 0.28.1 httpx-sse 0.4.0 idna 3.10 jsonpatch 1.33 jsonpointer 3.0.0 langchain-core 0.3.51 langchain-mcp-adapters 0.0.7 langchain-ollama 0.3.0 langgraph 0.3.25 langgraph-checkpoint 2.0.24 langgraph-prebuilt 0.1.8 langgraph-sdk 0.1.61 langsmith 0.3.24 mcp 1.6.0 mypy 1.15.0 mypy-extensions 1.0.0 ollama 0.4.7 orjson 3.10.16 ormsgpack 1.9.1 packaging 24.2 pydantic 2.11.2 pydantic-core 2.33.1 pydantic-settings 2.8.1 python-dotenv 1.1.0 pyyaml 6.0.2 requests 2.32.3 requests-toolbelt 1.0.0 ruff 0.11.4 sniffio 1.3.1 sse-starlette 2.2.1 starlette 0.46.1 tenacity 9.1.2 typing-extensions 4.13.1 typing-inspection 0.4.0 urllib3 2.3.0 uvicorn 0.34.0 xxhash 3.5.0 zstandard 0.23.0
pyproject.toml
[project]
name = "langchain-mcp-adapters-getting-started"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
"langchain-mcp-adapters>=0.0.7",
"langchain-ollama>=0.3.0",
"langgraph>=0.3.25",
]
[dependency-groups]
dev = [
"mypy>=1.15.0",
"ruff>=0.11.4",
]
[tool.mypy]
strict = true
disallow_any_unimported = true
#disallow_any_expr = true
disallow_any_explicit = true
warn_unreachable = true
pretty = true
LangChain MCP AdaptersのQuickstartをやってみる
それでは、LangChain MCP AdaptersのQuickstartをやってみます。
LangChain MCP Adapters / Quickstart
サーバーの作成
まずはMCPサーバーを作成します。
math_server.py
from mcp.server.fastmcp import FastMCP mcp = FastMCP("Math") @mcp.tool() def add(a: int, b: int) -> int: """Add two numbers""" return a + b @mcp.tool() def multiply(a: int, b: int) -> int: """Multiply two numbers""" return a * b if __name__ == "__main__": mcp.run(transport="stdio")
足し算、掛け算ができるサーバー、ということはわかるのですが、MCPまわりがよくわかりませんね。
MCPのPython SDKのドキュメントを見てみましょう。
MCP Python SDK / Core Concepts / Server
FastMCPというのが、MCPプロトコルのインターフェースになるようです。接続の管理やプロトコルの準拠、ルーティングの
処理などを行うようです。
The FastMCP server is your core interface to the MCP protocol. It handles connection management, protocol compliance, and message routing:
この部分ですが、クライアントとサーバー間の通信に標準入出力を使うことを示しています。
mcp.run(transport="stdio")
MCPでは、トランスポートに標準入出力(ローカルプロセス)とHTTP+SSE(リモート)が使えるようです。
Core architecture / Core components / Transport layer
そして@mcp.toolは?というところですが。
@mcp.tool() def add(a: int, b: int) -> int:
これは、LLMがMCPサーバー経由でToolを実行できる機能のようですね。
Tools - Model Context Protocol
今回はToolのみを扱いますが、MCPサーバーでは他にもResource、PromptをLLM向けに提供できるようです。
Resources - Model Context Protocol
Prompts - Model Context Protocol
クライアントの作成
次はMCPクライアントを作成します。
参考にしているのはこちらです。
LangChain MCP Adapters / Quickstart / Client
client.py
import asyncio from mcp import ClientSession, StdioServerParameters from mcp.client.stdio import stdio_client from langchain_mcp_adapters.tools import load_mcp_tools from langgraph.prebuilt import create_react_agent from langchain_ollama import ChatOllama async def run_client() -> None: model = ChatOllama( model="llama3.2:3b", temperature=0, base_url="http://localhost:11434", ) server_params = StdioServerParameters( command="python3", args=["math_server.py"], ) async with stdio_client(server_params) as (read, write): async with ClientSession(read, write) as session: await session.initialize() tools = await load_mcp_tools(session) agent = create_react_agent(model, tools) agent_response = await agent.ainvoke({"messages": "what's (3 + 5) x 12?"}) print() print("response:") print(agent_response) print() print("messages:") for message in agent_response["messages"]: print(f" {message}") if __name__ == "__main__": asyncio.run(run_client())
MCPのPython SDKで、MCPクライアントについて書かれているのはこちらですね。
MCP Python SDK / Writing MCP Clients
こちらで、先ほど作成したMCPサーバーを起動するコマンドを設定します。トランスポートに標準入出力を使うことが名前から
わかりますね。
server_params = StdioServerParameters(
command="python3",
args=["math_server.py"],
)
あとはMCPクライアントのセッションを作成し、Agentを呼び出します。
async with stdio_client(server_params) as (read, write): async with ClientSession(read, write) as session: await session.initialize() tools = await load_mcp_tools(session) agent = create_react_agent(model, tools) agent_response = await agent.ainvoke({"messages": "what's (3 + 5) x 12?"})
ここでいうAgentは、LangGraphのAgentですね。
質問は、「(3 + 5) x 12は?」です。
agent_response = await agent.ainvoke({"messages": "what's (3 + 5) x 12?"})
ここまでのコードから予想がつくように、使用するChat modelがToolをサポートしている必要があるので、Ollamaで使う
モデルにはllama3.2:3bを選択しています。
model = ChatOllama(
model="llama3.2:3b",
temperature=0,
base_url="http://localhost:11434",
)
動作確認
では、実行してみます。
$ uv run client.py
最初にこんな表示が出ます。
Processing request of type ListToolsRequest Processing request of type CallToolRequest
次に、最初にprintした結果。Agentからのレスポンスです。
response:
{'messages': [HumanMessage(content="what's (3 + 5) x 12?", additional_kwargs={}, response_metadata={}, id='4a2a09ff-943c-4e6f-b23a-c0fb5af74e7b'), AIMessage(content='', additional_kwargs={}, response_metadata={'model': 'llama3.2:3b', 'created_at': '2025-04-05T12:31:02.502805806Z', 'done': True, 'done_reason': 'stop', 'total_duration': 9099840386, 'load_duration': 1803031734, 'prompt_eval_count': 222, 'prompt_eval_duration': 5740068389, 'eval_count': 22, 'eval_duration': 1554403441, 'message': Message(role='assistant', content='', images=None, tool_calls=None)}, id='run-f9a1efd9-ca24-4d32-91b9-e6da51b747c7-0', tool_calls=[{'name': 'multiply', 'args': {'a': '8', 'b': '12'}, 'id': 'ec89504b-9e78-406a-973f-ddb60d12b731', 'type': 'tool_call'}], usage_metadata={'input_tokens': 222, 'output_tokens': 22, 'total_tokens': 244}), ToolMessage(content='96', name='multiply', id='4d32f271-1fe5-4a19-ab86-4b130e9f9a86', tool_call_id='ec89504b-9e78-406a-973f-ddb60d12b731'), AIMessage(content='The result of the calculation is 96.', additional_kwargs={}, response_metadata={'model': 'llama3.2:3b', 'created_at': '2025-04-05T12:31:04.439189052Z', 'done': True, 'done_reason': 'stop', 'total_duration': 1925453797, 'load_duration': 14696953, 'prompt_eval_count': 99, 'prompt_eval_duration': 1241347320, 'eval_count': 10, 'eval_duration': 668408146, 'message': Message(role='assistant', content='The result of the calculation is 96.', images=None, tool_calls=None)}, id='run-36fd0772-41d1-4970-b9d3-0478c5f7da28-0', usage_metadata={'input_tokens': 99, 'output_tokens': 10, 'total_tokens': 109})]}
HumanMessage → AIMessage → ToolMessage → AIMessageの順にメッセージが続いています。
messagesの部分を抜き出してprintしたのがこちら。
messages:
content="what's (3 + 5) x 12?" additional_kwargs={} response_metadata={} id='4a2a09ff-943c-4e6f-b23a-c0fb5af74e7b'
content='' additional_kwargs={} response_metadata={'model': 'llama3.2:3b', 'created_at': '2025-04-05T12:31:02.502805806Z', 'done': True, 'done_reason': 'stop', 'total_duration': 9099840386, 'load_duration': 1803031734, 'prompt_eval_count': 222, 'prompt_eval_duration': 5740068389, 'eval_count': 22, 'eval_duration': 1554403441, 'message': Message(role='assistant', content='', images=None, tool_calls=None)} id='run-f9a1efd9-ca24-4d32-91b9-e6da51b747c7-0' tool_calls=[{'name': 'multiply', 'args': {'a': '8', 'b': '12'}, 'id': 'ec89504b-9e78-406a-973f-ddb60d12b731', 'type': 'tool_call'}] usage_metadata={'input_tokens': 222, 'output_tokens': 22, 'total_tokens': 244}
content='96' name='multiply' id='4d32f271-1fe5-4a19-ab86-4b130e9f9a86' tool_call_id='ec89504b-9e78-406a-973f-ddb60d12b731'
content='The result of the calculation is 96.' additional_kwargs={} response_metadata={'model': 'llama3.2:3b', 'created_at': '2025-04-05T12:31:04.439189052Z', 'done': True, 'done_reason': 'stop', 'total_duration': 1925453797, 'load_duration': 14696953, 'prompt_eval_count': 99, 'prompt_eval_duration': 1241347320, 'eval_count': 10, 'eval_duration': 668408146, 'message': Message(role='assistant', content='The result of the calculation is 96.', images=None, tool_calls=None)} id='run-36fd0772-41d1-4970-b9d3-0478c5f7da28-0' usage_metadata={'input_tokens': 99, 'output_tokens': 10, 'total_tokens': 109}
HumanMessage、AIMessage、ToolMessage、AIMessageのcontentの部分、もしくはtool_callsの部分を抜き出してみます。
what's (3 + 5) x 12?
tool_calls=[{'name': 'multiply', 'args': {'a': '8', 'b': '12'}, 'id': 'ec89504b-9e78-406a-973f-ddb60d12b731', 'type': 'tool_call'}]
96
The result of the calculation is 96.'
ちゃんと計算できていますね。そしてToolの呼び出しも行っています。よさそうです。
複数のMCPサーバーを呼び出す
せっかくなので、こちらもやってみましょう。
LangChain MCP Adapters / Multiple MCP Servers
MCPサーバーを追加。
weather_server.py
from mcp.server import FastMCP mcp = FastMCP("Weather") @mcp.tool() async def get_weather(location: str) -> str: """Get weather for location.""" return "It's always sunny in New York" if __name__ == "__main__": mcp.run(transport="sse")
地域を指定して天気を聞かれるわけですが、常に「ニューヨークはいつも晴れです」と答えるMCPサーバーです…。
こちらはトランスポートがSSEになります。
multiple_client.py
import asyncio from langchain_mcp_adapters.client import MultiServerMCPClient from langgraph.prebuilt import create_react_agent from langchain_ollama import ChatOllama async def run_client() -> None: model = ChatOllama( model="llama3.2:3b", temperature=0, base_url="http://localhost:11434", ) async with MultiServerMCPClient( { "math": { "command": "python3", "args": ["math_server.py"], }, "weather": { "url": "http://localhost:8000/sse", "transport": "sse", }, } ) as client: agent = create_react_agent(model, client.get_tools()) math_response = await agent.ainvoke({"messages": "what's (3 + 5) x 12?"}) weather_response = await agent.ainvoke( {"messages": "what is the weather in nyc?"} ) print() print("math_response:") print(math_response) print() print("math_messages:") for message in math_response["messages"]: print(f" {message}") print() print("weather_response:") print(weather_response) print() print("weather_messages:") for message in weather_response["messages"]: print(f" {message}") if __name__ == "__main__": asyncio.run(run_client())
MultiServerMCPClientという、複数のMCPサーバーを扱うクラスがあるみたいですね。
async with MultiServerMCPClient( { "math": { "command": "python3", "args": ["math_server.py"], }, "weather": { "url": "http://localhost:8000/sse", "transport": "sse", }, } ) as client:
math_server.pyは標準入出力をトランスポートに使い、もうひとつの方はSSEで接続することがわかります。
では試してみましょう。
weather_server.pyを起動。
$ uv run weather_server.py
Uvicornで起動するようです。
INFO: Started server process [34008] INFO: Waiting for application startup. INFO: Application startup complete. INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
MCPクライアントを実行。
$ uv run multiple_client.py
先ほどと同じように、こんな感じの出力が出た後に
Processing request of type ListToolsRequest Processing request of type CallToolRequest
math_server.pyを使った結果、
math_response:
{'messages': [HumanMessage(content="what's (3 + 5) x 12?", additional_kwargs={}, response_metadata={}, id='7f8ae0ff-2b0a-4493-ba74-cc58a0cc39bf'), AIMessage(content='', additional_kwargs={}, response_metadata={'model': 'llama3.2:3b', 'created_at': '2025-04-05T12:54:21.623032101Z', 'done': True, 'done_reason': 'stop', 'total_duration': 6918013472, 'load_duration': 15727122, 'prompt_eval_count': 264, 'prompt_eval_duration': 5408887494, 'eval_count': 22, 'eval_duration': 1492631940, 'message': Message(role='assistant', content='', images=None, tool_calls=None)}, id='run-bc05333e-53b3-4042-bf87-4e6fa4ab63fc-0', tool_calls=[{'name': 'multiply', 'args': {'a': '8', 'b': '12'}, 'id': 'eac7c461-87b8-4ad0-a5a0-bff31fd64baa', 'type': 'tool_call'}], usage_metadata={'input_tokens': 264, 'output_tokens': 22, 'total_tokens': 286}), ToolMessage(content='96', name='multiply', id='a2402fe7-b320-4468-8966-4015fcecbf71', tool_call_id='eac7c461-87b8-4ad0-a5a0-bff31fd64baa'), AIMessage(content='The result of the calculation is 96.', additional_kwargs={}, response_metadata={'model': 'llama3.2:3b', 'created_at': '2025-04-05T12:54:23.489100401Z', 'done': True, 'done_reason': 'stop', 'total_duration': 1859462907, 'load_duration': 18925810, 'prompt_eval_count': 99, 'prompt_eval_duration': 1223402128, 'eval_count': 10, 'eval_duration': 615606945, 'message': Message(role='assistant', content='The result of the calculation is 96.', images=None, tool_calls=None)}, id='run-bf5006d3-2faf-46f5-bfcc-b8538569e1d5-0', usage_metadata={'input_tokens': 99, 'output_tokens': 10, 'total_tokens': 109})]}
math_messages:
content="what's (3 + 5) x 12?" additional_kwargs={} response_metadata={} id='7f8ae0ff-2b0a-4493-ba74-cc58a0cc39bf'
content='' additional_kwargs={} response_metadata={'model': 'llama3.2:3b', 'created_at': '2025-04-05T12:54:21.623032101Z', 'done': True, 'done_reason': 'stop', 'total_duration': 6918013472, 'load_duration': 15727122, 'prompt_eval_count': 264, 'prompt_eval_duration': 5408887494, 'eval_count': 22, 'eval_duration': 1492631940, 'message': Message(role='assistant', content='', images=None, tool_calls=None)} id='run-bc05333e-53b3-4042-bf87-4e6fa4ab63fc-0' tool_calls=[{'name': 'multiply', 'args': {'a': '8', 'b': '12'}, 'id': 'eac7c461-87b8-4ad0-a5a0-bff31fd64baa', 'type': 'tool_call'}] usage_metadata={'input_tokens': 264, 'output_tokens': 22, 'total_tokens': 286}
content='96' name='multiply' id='a2402fe7-b320-4468-8966-4015fcecbf71' tool_call_id='eac7c461-87b8-4ad0-a5a0-bff31fd64baa'
content='The result of the calculation is 96.' additional_kwargs={} response_metadata={'model': 'llama3.2:3b', 'created_at': '2025-04-05T12:54:23.489100401Z', 'done': True, 'done_reason': 'stop', 'total_duration': 1859462907, 'load_duration': 18925810, 'prompt_eval_count': 99, 'prompt_eval_duration': 1223402128, 'eval_count': 10, 'eval_duration': 615606945, 'message': Message(role='assistant', content='The result of the calculation is 96.', images=None, tool_calls=None)} id='run-bf5006d3-2faf-46f5-bfcc-b8538569e1d5-0' usage_metadata={'input_tokens': 99, 'output_tokens': 10, 'total_tokens': 109}
weather_server.pyを使った結果がそれぞれ続きます。
weather_response:
{'messages': [HumanMessage(content='what is the weather in nyc?', additional_kwargs={}, response_metadata={}, id='03d3a378-9f1c-4cc4-933f-496ec48a6742'), AIMessage(content='', additional_kwargs={}, response_metadata={'model': 'llama3.2:3b', 'created_at': '2025-04-05T12:54:30.020484601Z', 'done': True, 'done_reason': 'stop', 'total_duration': 6527211089, 'load_duration': 13308135, 'prompt_eval_count': 260, 'prompt_eval_duration': 5271246975, 'eval_count': 18, 'eval_duration': 1241845825, 'message': Message(role='assistant', content='', images=None, tool_calls=None)}, id='run-11526265-dff8-468d-9aaf-a76e4579e9cb-0', tool_calls=[{'name': 'get_weather', 'args': {'location': 'nyc'}, 'id': 'd063807d-a5e9-4794-91d1-41c40d3d9df6', 'type': 'tool_call'}], usage_metadata={'input_tokens': 260, 'output_tokens': 18, 'total_tokens': 278}), ToolMessage(content="It's always sunny in New York", name='get_weather', id='3c712174-b744-4850-8401-eac2d84f54e7', tool_call_id='d063807d-a5e9-4794-91d1-41c40d3d9df6'), AIMessage(content="That's not accurate! According to the current weather conditions, it's actually partly cloudy with a high of 68°F (20°C) and a low of 48°F (9°C). The current time is 2:30 PM EST. Would you like more detailed information or up-to-date forecasts?", additional_kwargs={}, response_metadata={'model': 'llama3.2:3b', 'created_at': '2025-04-05T12:54:35.650385936Z', 'done': True, 'done_reason': 'stop', 'total_duration': 5618734329, 'load_duration': 13826259, 'prompt_eval_count': 99, 'prompt_eval_duration': 1199320268, 'eval_count': 63, 'eval_duration': 4404416590, 'message': Message(role='assistant', content="That's not accurate! According to the current weather conditions, it's actually partly cloudy with a high of 68°F (20°C) and a low of 48°F (9°C). The current time is 2:30 PM EST. Would you like more detailed information or up-to-date forecasts?", images=None, tool_calls=None)}, id='run-6c0b0b8e-74a3-4fbe-9734-eb0e6fdf51f4-0', usage_metadata={'input_tokens': 99, 'output_tokens': 63, 'total_tokens': 162})]}
weather_messages:
content='what is the weather in nyc?' additional_kwargs={} response_metadata={} id='03d3a378-9f1c-4cc4-933f-496ec48a6742'
content='' additional_kwargs={} response_metadata={'model': 'llama3.2:3b', 'created_at': '2025-04-05T12:54:30.020484601Z', 'done': True, 'done_reason': 'stop', 'total_duration': 6527211089, 'load_duration': 13308135, 'prompt_eval_count': 260, 'prompt_eval_duration': 5271246975, 'eval_count': 18, 'eval_duration': 1241845825, 'message': Message(role='assistant', content='', images=None, tool_calls=None)} id='run-11526265-dff8-468d-9aaf-a76e4579e9cb-0' tool_calls=[{'name': 'get_weather', 'args': {'location': 'nyc'}, 'id': 'd063807d-a5e9-4794-91d1-41c40d3d9df6', 'type': 'tool_call'}] usage_metadata={'input_tokens': 260, 'output_tokens': 18, 'total_tokens': 278}
content="It's always sunny in New York" name='get_weather' id='3c712174-b744-4850-8401-eac2d84f54e7' tool_call_id='d063807d-a5e9-4794-91d1-41c40d3d9df6'
content="That's not accurate! According to the current weather conditions, it's actually partly cloudy with a high of 68°F (20°C) and a low of 48°F (9°C). The current time is 2:30 PM EST. Would you like more detailed information or up-to-date forecasts?" additional_kwargs={} response_metadata={'model': 'llama3.2:3b', 'created_at': '2025-04-05T12:54:35.650385936Z', 'done': True, 'done_reason': 'stop', 'total_duration': 5618734329, 'load_duration': 13826259, 'prompt_eval_count': 99, 'prompt_eval_duration': 1199320268, 'eval_count': 63, 'eval_duration': 4404416590, 'message': Message(role='assistant', content="That's not accurate! According to the current weather conditions, it's actually partly cloudy with a high of 68°F (20°C) and a low of 48°F (9°C). The current time is 2:30 PM EST. Would you like more detailed information or up-to-date forecasts?", images=None, tool_calls=None)} id='run-6c0b0b8e-74a3-4fbe-9734-eb0e6fdf51f4-0' usage_metadata={'input_tokens': 99, 'output_tokens': 63, 'total_tokens': 162}
math_server.pyの方は変わらないので、今回はweather_server.pyを使った結果の方を見てみましょう。
こちらもHumanMessage → AIMessage → ToolMessage → AIMessageの順にメッセージが続いています。
contentの部分、もしくはtool_callsの部分を抜き出してみましょう。
what is the weather in nyc?
tool_calls=[{'name': 'get_weather', 'args': {'location': 'nyc'}, 'id': 'd063807d-a5e9-4794-91d1-41c40d3d9df6', 'type': 'tool_call'}],
It's always sunny in New York
That's not accurate! According to the current weather conditions, it's actually partly cloudy with a high of 68°F (20°C) and a low of 48°F (9°C). The current time is 2:30 PM EST. Would you like more detailed information or up-to-date forecasts?
最後、どこからその答えになった?というメッセージになっている気はしますがひとまずMCPサーバーを呼び出せていることは
わかったのでよしとしましょう…。
ちなみに、weather_server.py側に記録されるアクセスログはこんな感じです。
INFO: 127.0.0.1:38980 - "GET /sse HTTP/1.1" 200 OK INFO: 127.0.0.1:38996 - "POST /messages/?session_id=dbfb4909800e43f8b3c879131204bd7b HTTP/1.1" 202 Accepted INFO: 127.0.0.1:38996 - "POST /messages/?session_id=dbfb4909800e43f8b3c879131204bd7b HTTP/1.1" 202 Accepted INFO: 127.0.0.1:38996 - "POST /messages/?session_id=dbfb4909800e43f8b3c879131204bd7b HTTP/1.1" 202 Accepted Processing request of type ListToolsRequest INFO: 127.0.0.1:41512 - "POST /messages/?session_id=dbfb4909800e43f8b3c879131204bd7b HTTP/1.1" 202 Accepted Processing request of type CallToolRequest
今回はスキップするもの
LangGraph API Serverとの組み合わせは、そもそもLangGraph API Serverを使ったことがないので今回は
スキップすることにします。
LangChain MCP Adaptersj / Using with LangGraph API Server
おわりに
MCPを、LangChain MCP AdaptersとOllamaを使って試してみました。
MCPについては名前こそ見かけていたものの、ちゃんと調べたことがなかったので学ぶいいきっかけになりました。
これで概念も少しは押さえられましたしね。
このプロトコルを使うと、確かにいろいろできそうですね。