Slide 1

Slide 1 text

みんなのPython 勉強会 in 長野 #4 MCP とエージェント 2025‑04‑26 さとうきよし @stealthinu 1

Slide 2

Slide 2 text

自己紹介 さとう きよし 白馬村在住でジーワークスという小さな会社をやってます ここ1 年半くらい:LLM を利用した社内システムのPoC, 研究開発 その前の1 年半くらい:VR メタバース内での音声変換(VC) とニューラル圧縮 以前は迷惑メール対策とかよくやってました 2

Slide 3

Slide 3 text

本日の流れ (45  分) 前半がMCP についての概念の説明で後半がハンズオン的な解説 セクション 時間 オープニング 2 分 Claude Desktop デモ 6 分 MCP 概要 10 分 JSON‑RPC を手で叩くデモ 6 分 MCP サーバ実装解説 10 分 MCP ホスト(Google Agent SDK) 実装解説 10 分 まとめ 1 分 3

Slide 4

Slide 4 text

MCP はなにをするものか LLM に実世界への橋渡しをする窓口 それがMCP 4

Slide 5

Slide 5 text

Claude Desktop デモ 実際に Claude Desktop でMCP でどんなことができるようになるかを見る 今日の天気図の画像をWebから取得してファイルに出力して 5

Slide 6

Slide 6 text

MCP とは? Model Context Protocol の略称 Anthropic 社が提唱した LLM ⇆ 外部ツール 接続の 共通インタフェース 「USB‑C 端子」 に例えられる どの機器でも同じケーブルで繋 がる世界 6

Slide 7

Slide 7 text

MCP が生まれた背景 ツール連携のボトルネック Function Calling 時代:アプリ× ツールごとに個別実装 多様な実世界アクセスツール ( 検索 / ファイル操作 / Web 操作など) が増えた エージェントの台頭 LLM がエージェントとして十分な性能を持つようになった LLM が「自分で判断→ 情報取得→ 行動」を行う エージェント が主流に エージェントは多様なツールを呼び出して実世界へアクセスが必要 7

Slide 8

Slide 8 text

なぜ今 MCP が注目されているのか? ツール呼び出し標準化 により再利用・共有が容易になった 多様なMCP サーバー が提供されるようになった 対応するMCP ホストが増えた エージェント構築フレームワーク のMCP サポート OpenAI やGoogle もSDK に採用するなどデファクト化したといえる 8

Slide 9

Slide 9 text

MCP の構成 LLM ホスト Claude Desktop 等のMCP サーバ 利用できるアプリ MCP クライアント MCP サーバと通信部分だがLLM ホストの意味で使われる場合も MCP サーバ 外部サービスとのやり取りを行 う部分で単にMCP というとMCP サーバを指している場合も MCP サーバというがいわゆる 「サーバ」でなくてよい 9

Slide 10

Slide 10 text

MCP の通信方法 プロトコル層 データ形式: JSON-RPC JSON を利用したリモートプロシジャーコール コマンド: initialize, tools/list, tools/call などちょっとだけ トランスポート層 STDIO: 標準入出力で現状はほとんどこちらが使われてる リモート接続 Streamable HTTP Transport: 2025-3-26 の仕様変更で今後はこちらに HTTP-SSE: クライアントと接続したまま随時データを送れるプロトコル SDK Python / TypeScript / Java / Kotlin / C# 10

Slide 11

Slide 11 text

機能カテゴリ tool LLM が実際によびだす関数でここがメインの機能 resource 読み取り専用のデータリソースでtool で生成したドキュメントなども prompt LLM へ渡すためのプロンプトテンプレートなど 11

Slide 12

Slide 12 text

2025-03-26 の仕様変更点 OAuth2.1 認証の追加 リモート接続方法の変更 HTTP-SSE から Streamable HTTP Transport に変更 JSON-RPC バッチ通信対応 Major changes - https://modelcontextprotocol.io/specification/2025-03-26/changelog ここはMCP の夜明けまえ - https://speakerdeck.com/nwiizo/kokohamcpnoye-ming- kemae 12

Slide 13

Slide 13 text

MCP サーバ 例 fetch - Web ページの取得 brave-search - Web の検索 filesystem - ファイルの読み取りや作成 git - git の操作 Playwright - ブラウザ操作 GitHub - github の各種操作や情報取得 Perplexity - Perplexity での情報調査 Notion - Nortion での情報取得や編集 Blender - 3D モデリング AWS MCP - AWS の各種操作を行う 13

Slide 14

Slide 14 text

MCP ホスト 例 Claude Desktop - Claude のクライアントアプリ Visual Studio Code Cursor - VSCode のAI 統合版 CLINE - VSCode のエージェント機能拡張 14

Slide 15

Slide 15 text

MCP 対応エージェントフレームワーク例 Mastra – TypeScript ベースのエージェントフレームワーク Google Agent SDK – Python ベースでGoogle のエージェントフレームワーク (OpenAI Agents SDK) - まだ対応を表明しただけで現時点では未対応 15

Slide 16

Slide 16 text

JSON-RPC で直接MCP をしゃべってみる 実際にplaywright でページを表示してみる (※事前にClaude Desktop から起動したplaywright を閉じておく) 1. initialize - 初期化 2. initialized - 初期化完了宣言 3. tools/list - 利用可能ツールを確認 4. tools/call ( browser_navigate ) → ページ取得 {"jsonrpc":"2.0","id":0,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"cli","version":"0.1.0"}}} {"jsonrpc":"2.0","method":"initialized","params":{}} {"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}} {"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"browser_navigate","arguments":{"url":"https://yahoo.co.jp/"}}} 16

Slide 17

Slide 17 text

0. サーバ起動(STDIO モード) npx @playwright/mcp@latest 17

Slide 18

Slide 18 text

1. プロトコル初期化 {"jsonrpc": "2.0", "id": 0, "method": "initialize", "params":{ "protocolVersion": "2024-11-05", "capabilities": {}, "clientInfo": {"name": "cli", "version":" 0.1.0"} }} {"jsonrpc": "2.0", "id": 0, "result": { "protocolVersion": "2024-11-05", "capabilities": { "tools": {}, "resources": {} }, "serverInfo": { "name": "Playwright", "version": "0.0.14" } }} 18

Slide 19

Slide 19 text

2. 初期化完了通知 {"jsonrpc": "2.0", "method": "notifications/initialized"} 19

Slide 20

Slide 20 text

3. 利用可能なツール一覧取得 {"jsonrpc": "2.0", "id": 2, "method": "tools/list", "params": {}} {"jsonrpc": "2.0", "id": 2, "result": { "tools": [ { "name": "browser_navigate", "description": "Navigate to a URL", "inputSchema": { "type": "object", "properties": {"url": {"type": "string", "description": "The URL to navigate to"}}, "required": ["url"] } }, { "name": "browser_snapshot", "description": "Capture accessibility snapshot of the current page, this is better than screenshot", "inputSchema": { "type": "object", "properties": {} } }, ... ] }} 20

Slide 21

Slide 21 text

3.fetch 呼び出し {"jsonrpc": "2.0", "id": 3, "method": "tools/call", "params": { "name": "browser_navigate", "arguments": { "url": "https://yahoo.co.jp/" } }} {"jsonrpc": "2.0", "id": 3, "result": { "content": [{ "type": "text", "text":"- Ran Playwright code:\n```js\n// Navigate to https://yahoo.co.jp/\nawait page.goto('https://yahoo.co.jp/');\n..." }] }} 21

Slide 22

Slide 22 text

MCP サーバ開発クイックスタート https://modelcontextprotocol.io/quickstart/server 環境準備 uv init weather-mcp cd weather-mcp uv add httpx "mcp[cli]" weather.py を書く 22

Slide 23

Slide 23 text

MCP サーバ実装サンプル from typing import Any from mcp.server.fastmcp import FastMCP mcp = FastMCP() @mcp.tool() async def get_forecast(latitude: float, longitude: float) -> str: """Get the weather forecast for the given latitude and longitude. Args: latitude (float): Latitude of the location. longitude (float): Longitude of the location. """ forecast = f""" Temperature: 10 Wind: 3m Forecast: fine """ return forecast if __name__ == "__main__": mcp.run(transport='stdio') 23

Slide 24

Slide 24 text

Claude Desktop のMCP 設定例 {"mcpServers": { "playwright": { "command": "C:\\Program Files\\nodejs\\npx.cmd", "args": ["@playwright/mcp@latest"] }, "filesystem": { "command": "C:\\Program Files\\nodejs\\npx.cmd", "args": ["-y", "@modelcontextprotocol/server-filesystem", "C:\\Users\\name\\Desktop"] }, "brave-search": { "command": "C:\\Program Files\\nodejs\\npx.cmd", "args": ["@modelcontextprotocol/server-brave-search"], "env": {"BRAVE_API_KEY": "Bxxxxxxxxxxxxxxxxxxxxxxxx"} }, "weather-mcp": { "command": "wsl.exe", "args": [ "bash", "-c", "/home/stealth/.local/bin/uv --directory /home/stealth/mcp_sample/weather-mcp run weather.py" ] } }} 24

Slide 25

Slide 25 text

MCP サーバ実装デモ MCPのテストをしてるのでMCPの天気予報取得するやつで白馬の天気を教えて 25

Slide 26

Slide 26 text

MCP サーバ実装デモ1 uv run weather.py {"jsonrpc":"2.0","id":0,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"cli","version":"0.1.0"}}} {"jsonrpc":"2.0","method":"notifications/initialized"} {"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}} {"method":"tools/call","params":{"name":"get_forecast","arguments":{"latitude":36.6977,"longitude":137.8619}},"jsonrpc":"2.0","id":2} 26

Slide 27

Slide 27 text

MCP サーバ実装デモ2 {"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}} {"jsonrpc":"2.0","id":1,"result":{ "tools":[{ "name":"get_forecast", "description": "Get the weather forecast for the given latitude and longitude. Args: latitude (float): Latitude of the location. longitude (float): Longitude of the location.", "inputSchema":{ "properties":{ "latitude":{"title":"Latitude","type":"number"}, "longitude":{"title":"Longitude","type":"number"} }, "required":["latitude","longitude"], "title":"get_forecastArguments", "type":"object" } }] 27

Slide 28

Slide 28 text

MCP サーバ実装デモ3 {"jsonrpc":"2.0", "id":2, "method":"tools/call", "params":{ "name":"get_forecast", "arguments":{ "latitude":36.6977, "longitude":137.8619 } }} {"jsonrpc":"2.0","id":2,"result":{ "content":[{"type":"text","text":"\nTemperature: 10\nWind: 3m\nForecast: fine\n"}], "isError":false }} 28

Slide 29

Slide 29 text

Google Agent SDK 開発クイックスタート Google Agent SDK でMCP を呼び出すサンプルを作る https://dev.classmethod.jp/articles/google-agent-development-kit-quick-start/ 環境準備 uv init gadk-sample cd gadk-sample uv add google-adk mkdir mcp_agent mcp_agent/agent.py を書く 29

Slide 30

Slide 30 text

Google Agent SDK クライアント実装 from google.adk.agents.llm_agent import LlmAgent from google.adk.tools.mcp_tool.mcp_toolset import MCPToolset, StdioServerParameters from dotenv import load_dotenv load_dotenv('../.env') async def create_agent(): """Gets tools from MCP Server.""" tools, exit_stack = await get_tools_async() agent = LlmAgent( model='gemini-2.0-flash', name='mcp_assistant', instruction='Help user interact with using available MCP tools.', tools=tools, ) return agent, exit_stack async def get_tools_async(): """Gets tools from the MCP Server.""" tools, exit_stack = await MCPToolset.from_server( connection_params=StdioServerParameters( command='uv', args=["--directory", "/home/stealth/mcp_sample/weather-mcp", "run", "weather.py"], ) ) return tools, exit_stack root_agent = create_agent() 30

Slide 31

Slide 31 text

__init__.py from . import agent .env GOOGLE_GENAI_USE_VERTEXAI=FALSE GOOGLE_API_KEY=AIxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 31

Slide 32

Slide 32 text

Agent SDK クライアント デモ cd ~/gadk-sample uv run adk web http://localhost:8000/ 白馬の天気を教えて 32

Slide 33

Slide 33 text

LLM にMCP を作ってもらう 都市の緯度経度を返すMCP を作る Building MCP with LLMs - Model Context Protocol https://modelcontextprotocol.io/tutorials/building-mcp-with-llms 以下のテキストを渡してo3 に作ってもらう https://modelcontextprotocol.io/llms-full.txt プロンプト MCPサーバのサンプルを作ってください。 MCPサーバについての規約は添付してあります。 MCPについての勉強会のデモ用に見てもらうものなので、なるべく短く、必要なものだけがまとまっているコードが良いです。 作りたいものは、都市名を渡すと、その都市の緯度経度を返してくれるというMCPサーバです。 ただ、本当の緯度経度を取ってくる必要はなく、どんな都市名を渡されても必ず長野市の緯度経度を決め打ちで返す、にしてください。 これならコードがすごく短くなるはずなので。 33

Slide 34

Slide 34 text

o3 が書いたデモ用MCP import asyncio import mcp.types as types from mcp.server import Server from mcp.server.stdio import stdio_server # Hard‑coded coordinates for Nagano City (Japan) NAGANO_LAT = 36.6486 NAGANO_LON = 138.1948 # Create the MCP server instance app = Server("nagano-coords-server", version="0.1.0") # --------------------------------------------------------------------------- # Tool registration # --------------------------------------------------------------------------- @app.list_tools() async def list_tools() -> list[types.Tool]: """Expose a single tool that returns Nagano coordinates no matter the city.""" return [ types.Tool( name="get_coordinates", description=( "Return latitude/longitude for a given city name. " "Always responds with Nagano City’s coordinates." ), inputSchema={ "type": "object", "properties": { "city": { "type": "string", "description": "Any city name (ignored)." } }, "required": ["city"] } ) ] @app.call_tool() async def call_tool( name: str, arguments: dict ) -> list[types.TextContent]: """Handle tool invocations.""" if name != "get_coordinates": raise ValueError(f"Unknown tool: {name}") city = arguments.get("city", "(unknown)") text = f"{city}: {NAGANO_LAT}, {NAGANO_LON}" return [types.TextContent(type="text", text=text)] # --------------------------------------------------------------------------- # Entry point (stdio transport) # --------------------------------------------------------------------------- async def main() -> None: async with stdio_server() as (reader, writer): await app.run(reader, writer, app.create_initialization_options()) if __name__ == "__main__": asyncio.run(main()) 34

Slide 35

Slide 35 text

FastAPI-MCP FastAPI でつくったものをそのままMCP 化できる from fastapi import FastAPI from fastapi_mcp import FastApiMCP app = FastAPI() @app.get("/weather", operation_id="say_weather") async def weather(): """天気予報をします""" return {"message": "天気は晴れです"} mcp = FastApiMCP(app, name="天気予報をします") mcp.mount() 35

Slide 36

Slide 36 text

MCP の核心 LLM に実世界との橋渡しをする仕組みがMCP LLM はこれまで「外」に出れなかった MCP を使うことでLLM やエージェントが「外」に出れる! エージェントでこそ重要になる LLM がエージェントとして働けるだけに十分かしこくなった LLM に十分なコンテキストさえ与えられればちゃんと働けるはず LLM 自身がMCP でコンテキストを取ってくることができる 36

Slide 37

Slide 37 text

参考資料 MCP 公式 Introduction - Model Context Protocol https://modelcontextprotocol.io/introduction For Server Developers - Model Context Protocol https://modelcontextprotocol.io/quickstart/server 入門記事 MCP 入門 https://zenn.dev/mkj/articles/0ed4d02ef3439c MCP 入門 https://zenn.dev/kazuwombat/articles/d8789724f10092 MCP 入門と便利なクライアント活用術 〜Cursor やDify を例に〜 | ドクセル https://www.docswell.com/s/solaoi/KP23JX-2025-04-09-023625#p15 Part1 : Azure AI Foundry で MCP を使ってみた【深掘りと最新動向調査】 https://zenn.dev/chips0711/articles/e71b088f26f56a 37

Slide 38

Slide 38 text

MCP サーバリスト microsoft/playwright-mcp: Playwright MCP server https://github.com/microsoft/playwright-mcp ppl-ai/modelcontextprotocol: A Model Context Protocol Server connector for Perplexity API, to enable web search without leaving the MCP ecosystem. https://github.com/ppl-ai/modelcontextprotocol makenotion/notion-mcp-server: Official Notion MCP Server https://github.com/makenotion/notion-mcp-server ahujasid/blender-mcp https://github.com/ahujasid/blender-mcp servers/src/brave-search at main · modelcontextprotocol/servers https://github.com/modelcontextprotocol/servers/tree/main/src/brave-search awslabs/mcp: AWS MCP Servers — specialized MCP servers that bring AWS best practices directly to your development workflow https://github.com/awslabs/mcp 38

Slide 39

Slide 39 text

Google Agent SDK Agent Development Kit https://google.github.io/adk-docs/ MCP tools - Agent Development Kit https://google.github.io/adk-docs/tools/mcp- tools/#what-is-model-context-protocol-mcp Google のAgent Development Kit (ADK )のQuick Start をやってみた! | DevelopersIO https://dev.classmethod.jp/articles/google-agent-development-kit-quick-start/ FastAPI-MCP tadata-org/fastapi_mcp: Expose your FastAPI endpoints as Model Context Protocol (MCP) tools, with Auth! https://github.com/tadata-org/fastapi_mcp 39