MCP_understanding について
MCP_understanding は、MCP サーバーと Google の Agent-to-Agent フレームワークを扱う実装・検証スイートです。AI エージェントを構築・連携する開発者向けに、データベース、Web サービス、グラフ処理、複数エージェントの調整例をまとめています。
主な機能
- 0120 以上の MCP サーバー実装
- 02Google ADK との連携
- 03A2A プロトコル対応
- 04Stdio と SSE のトランスポート
- 05複数エージェントの連携
- 06データベースとグラフの例
活用シーン
- 01さまざまなサービス向け MCP サーバーの構築
- 02A2A によるエージェント連携
- 03Neo4j GraphRAG ワークフローの検証
- 04エージェントとデータベースツールの接続
MCP 対応
通貨、天気、検索、YouTube、データベース、Neo4j などのツールやリソースを提供する MCP サーバーを実装しています。Stdio と SSE のトランスポート、およびエージェントから MCP サーバーへの接続例も含みます。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
このサーバーのパッケージやリモートエンドポイントはまだ取得できていません。プロジェクトの README の手順に従ってください。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
MCP_understanding
MCP サーバーと A2A ユーティリティ - 詳細な解説
目次
- 概要
- プロジェクトアーキテクチャの概要
- Model Context Protocol(MCP)の解説
- コアコンポーネントと実装
- 技術スタック
- MCP サーバーの実装
- A2A(エージェント間)連携
- 高度な実装
- デプロイと設定
- ユースケースと例
- ベストプラクティスと学んだ教訓
概要
このプロジェクトは、Model Context Protocol(MCP)とGoogle の Agent-to-Agent(A2A)フレームワークを組み合わせた、包括的な調査・実装スイートです。複数の専門ツールやサービスを備えた AI エージェントを構築、オーケストレーション、デプロイする方法を紹介します。
主な特長:
- 20 以上の MCP サーバー実装(FastMCP、各種ドメイン固有サーバー)
- Google ADK(Agent Development Kit)との完全な連携
- 複雑なエージェントのオーケストレーションに対応する A2A プロトコル
- 実世界の例:通貨換算、天気、YouTube の文字起こし抽出、Neo4j GraphRAG
- SSE(Server-Sent Events)および Stdio トランスポートプロトコル
- マルチエージェントの連携パターン
- エラー処理と可観測性を備えた、本番環境対応のパターン
プロジェクトアーキテクチャの概要
高レベルアーキテクチャ
┌─────────────────────────────────────────────────────────────────┐
│ Client Applications │
│ (Claude Desktop, Custom Clients, UIs) │
└────────────────────────────────────────────────────────────────┐
│
┌───────────┴───────────┐
│ │
┌──────▼──────┐ ┌──────▼──────┐
│ MCP Servers │ │ A2A Agents │
│ (SPIs) │ │ (Agentic) │
└──────┬──────┘ └──────┬──────┘
│ │
┌──────▼──────────────────────▼──────┐
│ Transport Layer │
│ (Stdio, SSE, JSON-RPC 2.0) │
└──────┬──────────────────────┬──────┘
│ │
┌───────────▼──────┐ ┌──────────▼──────────┐
│ External APIs │ │ Data Sources │
│ - Web Search │ │ - Neo4j Graph DB │
│ - Exchange Rates│ │ - BigQuery │
│ - Crypto Prices │ │ - PostgreSQL │
│ - Weather │ │ - MySQL │
│ - YouTube │ │ - Snowflake │
└──────────────────┘ └────────────────────┘
プロジェクト構成
MCP_servers_and_a2a_utils/
├── Core Entry Points
│ ├── agent.py # Multi-server MCP agent orchestration
│ ├── call_tool.py # Tool invocation wrapper
│ ├── list_tools.py # Tool discovery & introspection
│ └── debug_tools.py # Debugging utilities
│
├── MCP Servers (20+ implementations)
│ ├── mcp_weather_server/ # FastMCP weather service
│ ├── mcp_tavily_search/ # Web search integration
│ ├── mcp_math_server/ # Mathematical operations
│ ├── mcp_youtube_extraction_server/ # YouTube transcript extraction
│ ├── mcp_database_server/ # Database operations
│ ├── mysql_mcp_server/ # MySQL-specific server
│ ├── mcp_server_aws/ # AWS integration
│ ├── mcp_snowflake/ # Snowflake data warehouse
│ ├── neo4j-mcp-workspace-template/ # Graph database (5 specialized servers)
│ └── [15+ other specialized servers]
│
├── A2A Integration Layer
│ ├── a2a_src/ # A2A protocol implementation
│ ├── agno_agentic_mcp/ # Agno + Agentic framework
│ ├── google_adk_agent_mcp/ # Google ADK agents
│ │ ├── currency_agent.py # Live A2A agent example
│ │ └── test_client.py # A2A client test harness
│ └── [Multiple agentic frameworks]
│
├── Framework & Adapter Layer
│ ├── mcp_adapaters_clients/ # MCP client adapters
│ ├── fastmcp_fastapi/ # FastMCP + FastAPI bridge
│ ├── langchain_mcp_server_client/ # LangChain integration
│ └── firebase/storage/remote/ # Remote storage backends
│
├── Documentation & Configuration
│ ├── README.md # Project overview
│ ├── MCP_Readme.md # MCP-specific details
│ ├── MCP_A2A_SSE_Studio.md # SSE & A2A protocols
│ ├── MCP_INspect_TEST.md # MCP Inspector usage
│ ├── claude_config.json # Claude Desktop config
│ └── copilot-instructions.md # Copilot integration
│
└── Configuration & Environment
├── pyproject.toml # Python project definition
├── requirements.txt # Core dependencies
└── [Virtual environment configs]
Model Context Protocol(MCP)の解説
MCP とは?
Model Context Protocolは、AI モデル(Claude など)を外部ツール、データソース、コンテキストプロバイダーに接続するための、標準化されたオープンプロトコルです。モデルは次のことができます。
- アクションを実行するためのツールへのアクセス
- リソース(ファイル、ドキュメント、データ)の読み取り
- 構造化されたやり取りのためのプロンプトの呼び出し
- サンプリングのリクエスト(実験的機能)
MCP アーキテクチャ
┌─────────────────┐ ┌──────────────────┐
│ MCP Client │◄──JSON-RPC 2.0─────► MCP Server │
│ (e.g., Claude) │ (Stdio/SSE) (Tool Provider) │
└─────────────────┘ └──────────────────┘
│
Uses:
│
├─ Tools: Execute tasks
├─ Resources: Access data
├─ Prompts: Structured requests
└─ Sampling: LLM interactions
主な概念
1. ツール
クライアントが呼び出せる、サーバーが公開する関数です。例:
@mcp.tool()
def get_exchange_rate(from_currency: str, to_currency: str) -> str:
"""Get current exchange rate between two currencies."""
# Implementation
return rate_data
特性:
- Pydantic モデルによる強い型付け
- 説明とアノテーションを含む
- 非同期処理に対応
- 構造化データを返す
2. リソース
クライアントが読み取れるデータソースです。例:
@mcp.resource("papers://folders")
def get_available_folders() -> str:
"""List available paper folders."""
return folder_listing
種類:
- テキストベース(ドキュメント、ログ)
- バイナリ(画像、PDF)
- 階層型(フォルダー構造)
3. プロンプト
パラメーターを指定できる再利用可能なプロンプトテンプレートです。
@mcp.prompt()
def generate_search_prompt(topic: str, num_papers: int = 5) -> str:
"""Generate a prompt for finding academic papers."""
return f"Find {num_papers} papers about {topic}..."
4. ツールのアノテーション
クライアントがツールの動作を理解するのに役立つメタデータです。
annotations=ToolAnnotations(
title="Chunk Lexical Graph",
readOnlyHint=False, # Can modify data
destructiveHint=False, # Won't delete critical data
idempotentHint=False, # May have side effects
openWorldHint=False, # Operates on closed knowledge
)
トランスポートプロトコル
Stdio トランスポート
- 用途: Unix パイプ/stdin/stdout
- 最適な用途: デスクトップアプリ、claude-desktop-config.json
- 特性: 同期リクエスト/レスポンス、低レイテンシ
- 設定:
{ "command": "python", "args": ["server.py"], "transport": "stdio" }
SSE トランスポート(Server-Sent Events)
- 用途: EventStream を使用した HTTP
- 最適な用途: Web サービス、マイクロサービス、クラウドデプロイ
- 特性: 非同期、双方向ストリーミング
- 例:
mcp = FastMCP("currency", port=7080) await mcp.run_sse_async(host="0.0.0.0", port=7080)
MCP プロトコルのフロー
Client Server
│ │
├─ Initialize │
│ {"jsonrpc": "2.0", "id": 1, │
│ "method": "initialize", ...}──────►
│ ┌─┤
│ ◄────────┤─ {"result": {"serverInfo": ...}}
│ └─┤
│
├─ List Tools │
│ {"jsonrpc": "2.0", "id": 2, │
│ "method": "tools/list"}───────────►
│ ┌──────────┤
│ ◄────────┤ {"tools": [...]}
│ └──────────┤
│
├─ Call Tool │
│ {"jsonrpc": "2.0", "id": 3, │
│ "method": "tools/call", │
│ "params": {...}}─────────────────►
│ ┌────────────────┤
│ ◄───────┤ {"result": "..."}
│ └────────────────┤
ツールの結果の種類
MCP ツールは構造化された結果を返します。
# Success Result
{
"type": "text",
"text": "The exchange rate is 1.3794 CAD per USD"
}
# Tool Error
{
"type": "text",
"text": "Error: Invalid currency code",
"isError": true
}
# Multi-part Result (images, formatted content)
{
"type": "image",
"data": "base64-encoded-image-data",
"mimeType": "image/png"
}
コアコンポーネントと実装
1. FastMCP フレームワーク
FastMCP は、このプロジェクトで MCP サーバーの構築に使用する主要なフレームワークです。
利点:
- ボイラープレートが最小限
- ツール登録を自動化
- 非同期処理を標準でサポート
- SSE と Stdio のトランスポートを内蔵
- 型安全性のための Pydantic 連携
基本構成:
from mcp.server.fastmcp import FastMCP
# Create server instance
mcp = FastMCP("MyServer", port=8000)
# Register tools
@mcp.tool()
async def my_tool(param: str) -> str:
return f"Result: {param}"
# Register resources
@mcp.resource("docs://{path}")
def get_docs(path: str) -> str:
return read_file(path)
# Run server
if __name__ == "__main__":
mcp.run(transport='sse') # or 'stdio'
2. LangChain MCP アダプター
MCP サーバーと LangChain エージェントを橋渡しします。
from langchain_mcp_adapters.client import MultiServerMCPClient
async with MultiServerMCPClient({
"tavily": {
"command": "python",
"args": ["servers/tavily.py"],
"transport": "stdio"
}
}) as client:
tools = client.get_tools()
agent = create_react_agent(model, tools)
response = await agent.ainvoke({"messages": [...]})
3. MCP Inspector
MCP サーバーのテストとデバッグに使う、ブラウザベースのツールです。
npx @modelcontextprotocol/inspector
# Starts on http://127.0.0.1:6274
# Test tools, resources, and prompts in real-time
機能:
- ツール/リソースのビジュアルエクスプローラー
- ツールのリアルタイム呼び出し
- パラメーターの検証
- レスポンスの確認
- エラーの診断
技術スタック
コア依存関係
FastMCP 2.14.1 # MCP server framework
mcp # Official MCP protocol library
httpx # Async HTTP client
pydantic # Type validation & schemas
Optional Integrations:
- langchain-core # LangChain framework
- langchain-mcp-adapters # MCP-LangChain bridge
- langchain-openai # OpenAI integration
- langgraph # Agent orchestration
- google.adk # Google Agent Development Kit
- neo4j # Graph database driver
- pymupdf # PDF processing
- docling # Document parsing
- pandas # Data manipulation
- requests # HTTP library
- beautifulsoup4 # HTML parsing
Python エコシステムとの統合
Python 3.11+
├─ Async/Await (asyncio, aiohttp)
├─ Type Hints (typing, pydantic)
├─ JSON-RPC 2.0 Protocol
├─ Environment Management (.zprofile, os.environ)
└─ Package Management (pip, uv)
MCP サーバーの実装
1. 通貨・為替サーバー
場所: google_adk_agent_mcp/
# Server: Provides exchange rate and crypto price tools
@mcp.tool()
def get_exchange_rate(currency_from: str, currency_to: str) -> dict:
"""Get real-time exchange rates via ExchangeRate-API."""
@mcp.tool()
def get_crypto_prices(symbols: str, vs_currency: str) -> dict:
"""Get cryptocurrency prices via CoinGecko API."""
使用パターン:
User Query: "How much is 100 USD in GBP?"
↓
Agent calls get_exchange_rate("USD", "GBP")
↓
Returns: {"rate": 0.7479, "conversion": 74.79}
↓
Agent formats response: "100 USD = 74.79 GBP"
2. 天気サーバー
場所: mcp_weather_server/
@mcp.tool()
async def get_weather(city: str, country_code: str = "") -> dict:
"""Get current weather for any city using OpenWeatherMap API."""
# Returns: temperature, conditions, humidity, wind speed, etc.
3. ウェブ検索サーバー
場所: mcp_tavily_search/
@mcp.tool()
async def tavily_search(query: str, max_results: int = 5) -> list:
"""Search the web using Tavily AI search engine."""
# Returns structured search results with summaries
4. YouTube 字幕抽出ツール
場所: mcp_youtube_extraction_server/
@mcp.tool()
def extract_transcript(video_url: str) -> str:
"""Extract and return transcript from YouTube videos."""
# Uses youtube-transcript-api
# Returns full transcript with timestamps
5. 数学演算サーバー
場所: mcp_math_server/
@mcp.tool()
def calculate(expression: str) -> str:
"""Evaluate mathematical expressions safely."""
# Supports complex math with numexpr library
6. Neo4j グラフデータベースサーバー
場所: neo4j-mcp-workspace-template/
グラフナレッジ管理用の、専門分野に特化した 5 つの MCP サーバー:
A. データモデリング(neo4j-data-modeling)
- グラフスキーマを定義する
- オントロジーを作成する
- エンティティタイプとリレーションシップを管理する
B. インジェスト(neo4j-ingest)
- ファイル(CSV、JSON)からデータを読み込む
- 構造化/非構造化ドキュメントを解析する
- ノードとリレーションシップを作成する
C. レキシカルグラフ(neo4j-lexical-graph)
このプロジェクトで最も複雑な実装
@mcp.tool()
async def create_lexical_graph(path: str) -> str:
"""
Create a complete lexical graph from PDFs:
1. Parse PDFs (docling, pymupdf)
2. Extract elements (tables, images, text)
3. Create nodes in Neo4j
4. Build reading order chains
"""
# Strategies: token_window, structured, by_section, by_page
# Supports parallel processing via ProcessPoolExecutor
# Includes VLM-based element description generation
詳細なツールセット:
create_lexical_graph- PDF を構造化グラフとして取り込むcheck_processing_status- バックグラウンドジョブを監視するcancel_processing- 実行中のジョブを停止するchunk_lexical_graph- ドキュメントを意味的なチャンクに分割するassign_section_hierarchy- ドキュメントのアウトライン構造を作成するgenerate_chunk_descriptions- LLM を使用してチャンクを説明するembed_chunks- 埋め込みを生成して保存するverify_lexical_graph- グラフの整合性を検証するreconstruct_document- グラフを Markdown に戻してエクスポートする
D. エンティティグラフ(neo4j-entity-graph)
- 名前付きエンティティを抽出する
- エンティティのリレーションシップを作成する
- セマンティックネットワークを構築する
E. GraphRAG(neo4j-graphrag)
- RAG(検索拡張生成)を実装する
- グラフを検索してコンテキストを取得する
- グラフデータから AI の応答を生成する
7. データベースサーバー
MySQL サーバー
@mcp.tool()
async def execute_query(database: str, query: str) -> dict:
"""Execute SQL queries against MySQL database."""
@mcp.tool()
async def list_tables(database: str) -> list:
"""List all tables in a database."""
Snowflake 統合
@mcp.tool()
async def query_snowflake(sql: str) -> dict:
"""Execute queries on Snowflake data warehouse."""
AWS 統合
@mcp.tool()
async def list_s3_objects(bucket: str) -> list:
"""List objects in AWS S3 bucket."""
@mcp.tool()
async def get_rds_databases() -> list:
"""List RDS database instances."""
A2A(エージェント間)統合
A2A とは?
エージェント間(A2A)プロトコルにより、複数のエージェントが連携して動作するオーケストレーションが可能になります。これは Google のエージェントエコシステムの一部です。
A2A アーキテクチャ
┌──────────────┐
│ Client Apps │
└────────┬─────┘
│ A2A Protocol (JSON-RPC)
┌────▼──────────────────────────┐
│ A2A Agent Executor │
│ (Runs on port 10030) │
│ │
│ ┌─────────────────────────┐ │
│ │ Root Agent │ │
│ │ - Orchestrates tasks │ │
│ │ - Routes to sub-agents │ │
│ │ - Manages context │ │
│ └──────────────┬──────────┘ │
│ │ │
│ ┌──────────────▼───────┐ │
│ │ MCP Tools │ │
│ │ (Currency, Weather, │ │
│ │ Search, etc.) │ │
│ └──────────────────────┘ │
└───────────────────────────────┘
│
┌────▼────────────────────────────┐
│ External Services │
│ (APIs, Databases, LLMs) │
└─────────────────────────────────┘
A2A の実装例
ファイル: google_adk_agent_mcp/currency_agent.py
from google.adk import agent as agent_lib
from google.adk.a2a.utils.agent_to_a2a import to_a2a
from mcp_toolset import MCPToolset
# Step 1: Load MCP tools
mcp_tools = MCPToolset(
server_url="http://localhost:7080/mcp"
).get_tools()
# Step 2: Define root agent
root_agent = agent_lib.Agent(
instructions="Help users with currency conversion and financial queries",
tools=[*mcp_tools, *other_tools],
model="models/gemini-2.0-flash"
)
# Step 3: Convert to A2A
a2a_app = to_a2a(root_agent, port=10030)
# Step 4: Run server
if __name__ == "__main__":
a2a_app.run()
A2A クライアント通信
ファイル: google_adk_agent_mcp/test_client.py
from google.adk.a2a.client import A2AClient
import json
# Connect to A2A agent
client = A2AClient("http://localhost:10030")
# Single-turn request
response = client.query(
message="What is 100 USD in CAD?",
context_id="session-123"
)
# Multi-turn conversation
context_id = "session-456"
# First turn
response1 = client.query("How much is 100 USD?", context_id)
# Agent: "Please specify target currency"
# Second turn (history is maintained)
response2 = client.query("in GBP", context_id)
# Agent: "100 USD = 74.79 GBP"
# Response structure:
{
"id": "task-id",
"status": "completed",
"artifacts": [
{
"name": "conversion_result",
"parts": [{"kind": "text", "text": "..."}]
}
],
"history": [
{"role": "user", "text": "..."},
{"role": "agent", "text": "..."}
]
}
マルチエージェントのオーケストレーション
A2A により、複雑なワークフローを実現できます:
Task: Comprehensive financial analysis
1. Currency Converter Agent
- Converts amounts between currencies
- Calls: get_exchange_rate()
2. Crypto Analyst Agent
- Analyzes cryptocurrency trends
- Calls: get_crypto_prices()
3. Summary Agent
- Combines insights
- Calls: tavily_search() for market news
Client Request
│
├─► A2A Router
│ │
│ ├─► Sub-Agent 1 (Currency) ──► MCP Currency Server
│ │
│ ├─► Sub-Agent 2 (Crypto) ────► MCP Crypto Server
│ │
│ └─► Sub-Agent 3 (Summary) ───► MCP Search Server
│ │
├─ Aggregate Results
└─► Return to Client
高度な実装
1. レキシカルグラフ処理パイプライン
Neo4j レキシカルグラフサーバーは、高度な MCP パターンを示しています:
処理フロー
Input PDF Files
│
├─ Pre-Flight Phase
│ ├── Count files and pages
│ ├── Estimate processing time
│ └── Request user confirmation
│
├─ Parse Phase (Async, Parallel)
│ ├── docling (modern, multi-format)
│ ├── pymupdf (fast, structured)
│ ├── text_only (fallback)
│ └── vlm_blocks (vision-based)
│
├─ Element Extraction
│ ├── Text blocks
│ ├── Tables (preserved as structured data)
│ ├── Images (base64 encoded)
│ ├── Headings (hierarchical)
│ └── Metadata
│
├─ Neo4j Graph Creation
│ ├── Create Document node
│ ├── Create Page nodes
│ ├── Create Element nodes
│ ├── Link with relationships
│ └── Build reading order NEXT chains
│
├─ Chunking Phase
│ ├── token_window (overlapping)
│ ├── structured (by elements)
│ ├── by_section (uses hierarchy)
│ └── by_page (page-aware)
│
├─ Enrichment Phase
│ ├── Create section hierarchy
│ ├── Generate descriptions (LLM)
│ ├── Create embeddings
│ └── Index for full-text search
│
├─ Verification Phase
│ ├── Check orphan nodes
│ ├── Validate NEXT chains
│ ├── Count statistics
│ └── Reconstruct as Markdown
│
└─ Output
├── Success report
├── Processing logs
├── Reconstruction files
└── Graph statistics
ジョブ管理パターン
class Job:
job_id: str
status: JobStatus # PENDING, RUNNING, COMPLETE, FAILED
progress: float # 0.0 to 1.0
elapsed: timedelta
files_completed: int
files_total: int
def to_status_dict(self) -> dict:
return {
"job_id": self.job_id,
"status": self.status.value,
"progress_percentage": self.progress * 100,
"elapsed_seconds": self.elapsed.total_seconds(),
"files": f"{self.files_completed}/{self.files_total}",
"eta_seconds": self.estimate_remaining()
}
非同期処理パターン
@mcp.tool()
async def create_lexical_graph(path: str) -> str:
# Create background job
job = Job(job_id=uuid4(), status=JobStatus.PENDING)
_job_manager.add_job(job)
# Start processing in background
asyncio.create_task(_process_async(job))
# Return immediately with job ID
return json.dumps({
"status": "processing",
"job_id": job.job_id,
"message": "Processing started. Check status with check_processing_status()"
})
async def _process_async(job: Job):
try:
job.status = JobStatus.RUNNING
# Count files
pdf_files = list(path.glob("*.pdf"))
job.files_total = len(pdf_files)
# Process each file
for i, pdf in enumerate(pdf_files):
await process_pdf(pdf, neo4j_driver, database)
job.files_completed = i + 1
job.progress = (i + 1) / job.files_total
job.status = JobStatus.COMPLETE
except Exception as e:
job.status = JobStatus.FAILED
job.error = str(e)
2. ドキュメントの再構築
グラフからドキュメントを再構築する機能は、グラフの整合性を示しています:
async def reconstruct_document(document_id: str, output_dir: str) -> str:
"""
Reconstructs original document structure:
From Graph:
Document {id} ──HAS_PAGE──► Page {pageNumber}
──HAS_ELEMENT─► Element {type, text, position}
Creates reading-order chain via NEXT relationships
Outputs:
1. Element-based reconstruction (reading order)
2. Chunk-based reconstruction (if chunks exist)
3. Both as .md files for comparison
"""
# Restore from graph
elements = await get_elements_in_order(document_id)
# Group by page
pages = {}
for element in elements:
page_num = element.page_number
if page_num not in pages:
pages[page_num] = []
pages[page_num].append(element)
# Generate Markdown
md_lines = []
for page_num in sorted(pages.keys()):
md_lines.append(f"# Page {page_num + 1}")
for elem in pages[page_num]:
if elem.type == "heading":
md_lines.append(f"{'#' * (elem.level + 1)} {elem.text}")
elif elem.type == "table":
md_lines.append(f"\n**[TABLE]**\n{elem.text}\n")
else:
md_lines.append(elem.text)
# Write output
output_file.write_text("\n".join(md_lines))
return f"Reconstruction saved to {output_file}"
3. 複数フレームワークの統合
このプロジェクトでは、複数の AI フレームワークとの統合を示しています:
┌──────────────────────────────────────────────────────┐
│ Integration Points │
├──────────────────────────────────────────────────────┤
│ │
│ LangChain ◄────► MCP Servers │
│ (via MultiServerMCPClient) │
│ │
│ Google ADK ◄──► A2A Protocol ◄─────► MCP Servers │
│ (via MCPToolset) │
│ │
│ FastAPI ◄─────► FastMCP ◄─────► Transport │
│ (SSE bridge) (Stdio/SSE) │
│ │
│ Claude Desktop ◄── Stdio ──► MCP Servers │
│ (stdio.json) │
│ │
└──────────────────────────────────────────────────────┘
デプロイと設定
1. ローカル開発環境のセットアップ
インストール
# Clone or navigate to project
cd MCP_servers_and_a2a_utils
# Create virtual environment
python3.11 -m venv venv
source venv/bin/activate
# Install dependencies
pip install -r requirements.txt
pip install fastmcp mcp httpx
# For specific features:
pip install python-dotenv neo4j pymupdf docling-core
pip install google-cloud-aiplatform # For Google ADK
pip install langchain langchain-mcp-adapters # For LangChain integration
環境のセットアップ
# Create .zprofile or .env with:
export OPENAI_API_KEY="sk-..."
export TAVILY_API_KEY="tvly-..."
export OPENWEATHERMAP_API_KEY="..."
export NEO4J_URI="neo4j://localhost:7687"
export NEO4J_USERNAME="neo4j"
export NEO4J_PASSWORD="password"
export GOOGLE_APPLICATION_CREDENTIALS="/path/to/credentials.json"
2. 個別サーバーの実行
FastMCP 通貨サーバー
cd google_adk_agent_mcp
python -m uvicorn currency_agent:app --host 0.0.0.0 --port 7080
# Server starts with SSE at http://0.0.0.0:7080/sse
Neo4j レキシカルグラフサーバー
cd neo4j-mcp-workspace-template/mcp-neo4j-lexical-graph
# Stdio transport (for Claude Desktop)
python -m mcp_neo4j_lexical_graph.server --transport stdio
# SSE transport (for HTTP clients)
python -m mcp_neo4j_lexical_graph.server --transport sse --host 0.0.0.0 --port 8002
天気サーバー
cd mcp_weather_server
python weather.py # Starts on port 8000
3. Claude Desktop の設定
ファイル: claude_config.json
{
"mcpServers": {
"currency": {
"command": "python",
"args": ["google_adk_agent_mcp/currency_agent.py"],
"transport": "stdio"
},
"weather": {
"command": "python",
"args": ["mcp_weather_server/weather.py"],
"transport": "stdio"
},
"neo4j_lexical": {
"command": "python",
"args": ["neo4j-mcp-workspace-template/mcp-neo4j-lexical-graph/src/mcp_neo4j_lexical_graph/server.py"],
"env": {
"NEO4J_URI": "neo4j://localhost:7687",
"NEO4J_USERNAME": "neo4j",
"NEO4J_PASSWORD": "password"
}
}
}
}
Claude Desktop での使用方法:
claude_config.jsonを~/.claude/resources/mcp.jsonにコピーします- Claude Desktop を再起動します
- すべてのサーバーのツールを Claude で利用できます
4. MCP Inspector によるデバッグ
# Start inspector
npx @modelcontextprotocol/inspector
# Open in browser
http://127.0.0.1:6274/?MCP_PROXY_AUTH_TOKEN=<token>
# Test tools:
# - Select server
# - List available tools
# - Invoke with parameters
# - View results and errors
5. A2A エージェントの実行
# Start A2A server
cd google_adk_agent_mcp
python currency_agent.py
# Server runs on port 10030
# Logs show connection status
# In another terminal, run client
python test_client.py
# Creates conversation with agent
ユースケースと例
1. 通貨換算ワークフロー
User: "How much is 100 USD in GBP?"
│
▼
Claude/Agent processes query
│
├─ Recognizes: Currency conversion needed
├─ Identifies: Source=USD, Target=GBP, Amount=100
│
▼
Calls MCP Tool: get_exchange_rate("USD", "GBP")
│
▼
A2A Agent (or Claude) receives tool result:
{
"rate": 0.7479,
"from": "USD",
"to": "GBP",
"conversion": 100 * 0.7479 = 74.79
}
│
▼
Formats response: "100 USD equals approximately 74.79 GBP"
│
▼
Returns to user
使用するコンポーネント:
- 通貨換算サーバー(MCP)
- A2A プロトコルレイヤー(任意)
- ツール呼び出しエンジン
- レスポンスのフォーマット処理
2. ドキュメントの取り込みと RAG
Process: Upload Research Papers → Build Knowledge Graph → Query with RAG
Step 1: Ingest Document
┌──────────────────────────┐
│ User uploads: paper.pdf │
└──────────────┬───────────┘
│
▼
┌────────────────────┐
│ Neo4j Lexical │
│ create_lexical_ │
│ graph(pdf_path) │
└────────┬───────────┘
│
Processing in background
│
┌────────▼──────────────┐
│ Job Status │
│ - Parse PDF │
│ - Extract elements │
│ - Create nodes/edges │
│ - Build reading order │
└────────┬──────────────┘
│
Complete
│
┌────────▼──────────────┐
│ Document Graph │
│ - Document node │
│ - Page nodes │
│ - Element nodes │
│ - Chunk nodes │
│ - Relationship indexes│
└──────────────────────┘
Step 2: Query with RAG
┌──────────────────────┐
│ User Query: Explain │
│ the paper's main │
│ contribution │
└──────────┬───────────┘
│
▼
┌──────────────────────┐
│ GraphRAG Server │
│ query_with_rag(...) │
└──────────┬───────────┘
│
┌──────────▼──────────────────┐
│ 1. Vector search in embeddings
│ 2. Retrieve context chunks │
│ 3. Extract entity paths │
│ 4. Build prompt with context │
└──────────┬──────────────────┘
│
▼
┌──────────────────────┐
│ LLM (Claude) │
│ Generate answer │
└──────────┬───────────┘
│
▼
Return RAG-augmented response
3. マルチエージェント連携
Task: Comprehensive Travel Planning
User Request: "Plan a trip to Japan with $5000 budget"
│
▼
A2A Router decides:
│
├─► Currency Agent
│ "Convert $5000 to JPY"
│ Calls: get_exchange_rate("USD", "JPY")
│ Returns: ≈750,000 JPY estimate
│
├─► Search Agent
│ "Find flights and hotels in Japan"
│ Calls: tavily_search("Japan flights hotels")
│ Returns: Recent deals and recommendations
│
├─► Weather Agent
│ "Check Japan climate for travel dates"
│ Calls: get_weather("Tokyo", "JP")
│ Returns: Seasonal weather patterns
│
└─► Aggregator Agent
Combines all information:
- Budget in local currency
- Available options
- Best seasons
Returns: Comprehensive travel plan
Response to User:
"With $5000 (≈750,000 JPY), you can:
- Stay 10-14 days
- Visit 2-3 cities
- Best season: Spring/Fall
- Current flight deals available..."
4. リアルタイムデータアプリケーション
暗号資産ポートフォリオトラッカー
# Runs as A2A agent
@tool
async def get_portfolio_summary(portfolio_dict: dict) -> str:
"""
Tracks cryptocurrency holdings and provides real-time analysis
portfolio_dict = {
"bitcoin": 0.5,
"ethereum": 5.0,
"cardano": 1000.0
}
"""
prices = {}
total_value = 0
for symbol, amount in portfolio_dict.items():
price = await get_crypto_prices(symbol, "usd")
value = amount * price
prices[symbol] = {
"amount": amount,
"price_per_unit": price,
"total_value": value
}
total_value += value
return format_portfolio_report(prices, total_value)
ベストプラクティスと得られた教訓
1. MCP サーバーの設計
✅ 推奨事項
- Pydantic モデルを使って、厳密な型ヒントを指定します
- すべてのツールに詳細な docstring を記述します
- クライアントが理解しやすいよう、ツールアノテーションを含めます
- ToolError を使って、エラーを適切に処理します
- 非同期処理をサポートします
- 入力パラメーターを検証します
- 構造化され、解析可能な結果を返します
❌ 避けるべき事項
- クライアント側でエラー処理が行われると決めつけないでください
- システムの実装詳細を公開しないでください
- 大がかりなセットアップが必要なツールを作成しないでください
- 未加工の例外メッセージをユーザーに返さないでください
- タイムアウトを設けずにブロッキング処理を行わないでください
- ツールの説明に機密性の高い認証情報を公開しないでください
例:適切なツール設計
from pydantic import Field
from mcp.types import ToolError
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("ExampleServer")
@mcp.tool()
async def safe_operation(
parameter: str = Field(
...,
description="Clear description of what this parameter does",
json_schema_extra={"example": "good_value"}
),
timeout: int = Field(
30,
description="Maximum seconds to wait for operation"
)
) -> dict:
"""
Descriptive tool docstring explaining:
- What the tool does
- When to use it
- What it returns
- Possible error conditions
"""
try:
# Validate input
if not parameter:
raise ToolError("Parameter cannot be empty")
if timeout < 1 or timeout > 300:
raise ToolError("Timeout must be between 1 and 300 seconds")
# Perform operation
result = await perform_operation(parameter, timeout=timeout)
# Return structured result
return {
"status": "success",
"result": result,
"metadata": {"operation": "safe_operation"}
}
except ToolError:
# Re-raise known errors
raise
except Exception as e:
# Log and convert unknown errors
logger.error(f"Operation failed: {e}")
raise ToolError(f"Operation failed: {str(e)}")
2. A2A エージェントのオーケストレーション
エージェント設計パターン
# Pattern 1: Hierarchical Agents
root_agent
├── currency_sub_agent
│ └── Tools: exchange_rate, crypto_prices
├── search_sub_agent
│ └── Tools: web_search, news
└── analysis_sub_agent
└── Tools: sentiment_analysis, trend_detection
# Pattern 2: Tool-Sharing Agents
agent_a ─┬─► shared_tool_1
├─► shared_tool_2
agent_b ─┘ (reduces duplication)
# Pattern 3: Fan-Out-Fan-In
root_agent
├─ Task 1 → agent_1 → task_1a, task_1b (parallel)
├─ Task 2 → agent_2 → task_2a, task_2b (parallel)
└─ Combine results
3. エラー処理パターン
# Pattern 1: Graceful Degradation
@mcp.tool()
async def get_data_with_fallback(primary_source: str) -> dict:
try:
return await fetch_from_primary(primary_source)
except ConnectionError:
logger.warning(f"Primary source {primary_source} unavailable")
return await fetch_from_fallback()
except TimeoutError:
logger.warning("Operation timed out, returning cached data")
return get_cached_data()
# Pattern 2: Structured Error Responses
@mcp.tool()
async def safe_tool(param: str) -> dict:
try:
result = await process(param)
return {
"status": "success",
"data": result
}
except ValidationError as e:
raise ToolError(f"Invalid input: {e.message}")
except PermissionError as e:
raise ToolError(f"Permission denied: {e.message}")
except Exception as e:
logger.error(f"Unexpected error: {e}", exc_info=True)
raise ToolError(f"Internal error occurred")
4. パフォーマンスの最適化
非同期/並行処理パターン
# ❌ Slow: Sequential processing
for pdf_file in pdf_files:
await process_pdf(pdf_file) # Processes one at a time
# ✅ Fast: Parallel processing
tasks = [process_pdf(pdf) for pdf in pdf_files]
results = await asyncio.gather(*tasks, return_exceptions=True)
# ✅ Better: Bounded concurrency
semaphore = asyncio.Semaphore(max_workers)
async def process_bounded(pdf):
async with semaphore:
return await process_pdf(pdf)
tasks = [process_bounded(pdf) for pdf in pdf_files]
results = await asyncio.gather(*tasks)
# ✅ Best for CPU-bound: Process pool
from concurrent.futures import ProcessPoolExecutor
with ProcessPoolExecutor(max_workers=4) as pool:
results = await asyncio.get_event_loop().run_in_executor(
pool, cpu_intensive_function, argument
)
データベース接続プーリング
# Neo4j connection pooling (automatic)
from neo4j import AsyncGraphDatabase
driver = AsyncGraphDatabase.driver(
"neo4j://localhost:7687",
auth=("neo4j", "password"),
max_connection_pool_size=100,
connection_timeout=30.0
)
# Properly close when shutting down
await driver.close()
5. MCP サーバーのテスト
# Test tool invocation
@pytest.mark.asyncio
async def test_get_exchange_rate():
mcp = create_mcp_server()
result = await mcp._tools["get_exchange_rate"].fn(
currency_from="USD",
currency_to="GBP"
)
assert result["status"] == "success"
assert "rate" in result
assert result["rate"] > 0
# Test error handling
@pytest.mark.asyncio
async def test_invalid_currency():
mcp = create_mcp_server()
with pytest.raises(ToolError):
await mcp._tools["get_exchange_rate"].fn(
currency_from="INVALID",
currency_to="GBP"
)
# Integration test with MCP Inspector
def test_server_startup():
server = subprocess.Popen(
["python", "server.py"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
time.sleep(2) # Wait for server
response = requests.get("http://localhost:8000/mcp")
assert response.status_code == 200
server.terminate()
6. ドキュメント作成のベストプラクティス
各ツールには、以下の内容を記載してください。
@mcp.tool()
async def comprehensive_tool(
required_param: str = Field(
...,
description="What this parameter does"
),
optional_param: int = Field(
42,
description="What this controls",
ge=1, le=100 # Validation
)
) -> dict:
"""
[1-2 sentence summary]
[Detailed explanation of functionality]
Parameters:
- required_param: [Description with examples]
- optional_param: [Description with range/options]
Returns:
{
"status": "success" or "error",
"data": [Actual return data structure],
"metadata": [Optional metadata]
}
Raises:
- ToolError: When [specific condition]
Examples:
>>> result = await comprehensive_tool("value", optional_param=50)
>>> print(result["data"])
"""
高度なトピック
1. カスタムトランスポートプロトコル
Stdio と SSE は標準ですが、カスタムトランスポートを実装できます。
from mcp.server import Server
from mcp.server.base import *
class CustomTransport(ServerTransport):
"""Custom transport implementation."""
async def read(self) -> ServerMessage:
"""Read message from source."""
pass
async def write(self, message: ServerMessage) -> None:
"""Write message to destination."""
pass
# Use custom transport
await mcp_server.run(CustomTransport())
2. リソースのストリーミング
大きなリソースには、ストリーミングを実装します。
@mcp.resource("data://large-dataset/{id}")
async def stream_dataset(id: str):
# Stream data in chunks instead of loading all at once
async def generate():
async for chunk in fetch_chunks(id):
yield chunk
return {
"uri": f"data://large-dataset/{id}",
"mimeType": "application/octet-stream",
"contents": [
{"type": "text", "text": chunk} async for chunk in generate()
]
}
3. LLM サンプリング(実験的)
MCP 仕様には、テキスト生成のためのサンプリング機能が含まれています。
@server.sampling()
async def sample_text(
messages: list,
model: str = "claude-3-sonnet",
max_tokens: int = 1024
) -> SamplingMessage:
"""Use Claude to generate text within MCP context."""
# Implementation uses Claude API
4. モニタリングと可観測性
import logging
from functools import wraps
logger = logging.getLogger(__name__)
def with_metrics(func):
"""Decorator to track tool execution metrics."""
@wraps(func)
async def wrapper(*args, **kwargs):
import time
start = time.time()
try:
result = await func(*args, **kwargs)
duration = time.time() - start
logger.info(
"Tool executed",
extra={
"tool": func.__name__,
"duration_ms": duration * 1000,
"status": "success"
}
)
return result
except Exception as e:
duration = time.time() - start
logger.error(
"Tool failed",
extra={
"tool": func.__name__,
"duration_ms": duration * 1000,
"error": str(e)
}
)
raise
return wrapper
@mcp.tool()
@with_metrics
async def monitored_tool():
"""Tool with automatic metrics collection."""
pass
トラブルシューティングガイド
よくある問題と解決策
| 問題 | 原因 | 解決策 |
|---|---|---|
| Inspector で「Connection refused」と表示される | サーバーが起動していない | まず python server.py でサーバーを起動します |
| ツールが一覧に表示されない | インポートエラー、またはデコレーターが適用されていない | @mcp.tool() デコレーターを確認し、インポートを検証します |
| A2A が「Input required」状態になる | エージェントが確認を待機している | クライアントからフォローアップメッセージを送信します |
| Neo4j 接続がタイムアウトする | データベースに接続できない | NEO4J_URI、ユーザー名、パスワードを確認します |
| PDF 処理中にメモリ不足になる | 大きな PDF を並行して処理しすぎている | max_parallel パラメーターを小さくします |
| SSE ストリームが予期せず閉じる | ネットワークのタイムアウト、またはサーバーのクラッシュ | サーバーログを確認し、タイムアウト設定を増やします |
| ツールの結果をシリアライズできない | JSON と互換性のないデータ型 | 文字列または構造化形式に変換します |
まとめ
このプロジェクトは、AI エージェントを構築するための包括的で、本番環境に対応したエコシステムを実現します。
- 柔軟なツール統合 - 20 以上の特化型 MCP サーバー
- 複数のフレームワークに対応 - LangChain、Google ADK、FastAPI
- 高度なオーケストレーション - エージェント間の連携を実現する A2A プロトコル
- 高度な処理 - ドキュメント理解のための ML パイプライン
- 実世界のサンプル - 通貨、天気、検索、RAG システム
このアーキテクチャは、標準化されたプロトコルを通じてAI モデルと外部機能を連携させる方法を示しています。関心事を適切に分離し、明確な抽象化を維持しながら、複雑な複数ステップのワークフローを実現できます。
主なポイント:
- MCP はプロトコルに依存しません - あらゆる AI モデル/クライアントで動作します
- 非同期/並行処理パターンは不可欠です - パフォーマンスとスケーラビリティのために必要です
- 型安全性は重要です - Pydantic による検証で、エラーを早期に防止できます
- ドキュメントは不可欠です - ツールの説明により、モデルがより適切な判断を下せます
- エラー処理は信頼性を高めます - 適切な縮退動作により、信頼性が向上します
- 可観測性によりデバッグが可能になります - ロギングとモニタリングは不可欠です
このプロジェクトは、ツール利用、RAG、マルチエージェントオーケストレーションを活用した AI 搭載システムを構築するすべての人にとって、優れたリファレンス実装となります。
インストール手順
- pip install uv
- uv init MCP_servers_and_a2a_utils
- uv run mcp install main.py
- uv run mcp
参考資料
- https://medium.com/data-and-beyond/the-model-context-protocol-mcp-the-ultimate-guide-c40539e2a8e7
- https://github.com/coleam00/ottomator-agents/blob/main/nba-agent/nba_agent.py
- https://www.youtube.com/watch?v=v_6EXt6T83I
- https://modelcontextprotocol.io/introduction
- https://github.com/coleam00/ottomator-agents/tree/main/pydantic-ai-mcp-agent
サンプルの参考資料
- https://www.dremio.com/blog/building-a-basic-mcp-server-with-python/
- https://github.com/HeetVekariya/Linear-Regression-MCP
- https://github.com/singlestore-labs/mcp-server-singlestore
- https://github.com/jlowin/fastmcp
- https://github.com/awslabs/mcp/blob/main/src/aws-documentation-mcp-server/awslabs/aws_documentation_mcp_server/server.py
MCP ワークショップはこちら
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。