「MCP is all you need」とは何か:講演の背景
2026年4月、Pydanticの作者Samuel ColvinがAI Engineerカンファレンスで行った15分間の講演「MCP is all you need」がX上で大きな注目を集めた。
Pydanticは月3.6億ダウンロード(1秒あたり140回)という規模で使われているPythonデータバリデーションライブラリだ。
Colvinは2023年にPydanticを会社化し、現在は次の3つのプロダクトを展開している:
| プロダクト | 概要 |
|---|---|
| Pydantic | Python向けデータバリデーションライブラリ(OSS) |
| PydanticAI | Pydanticの設計原則で作られたPythonエージェントフレームワーク |
| Pydantic Logfire | AIアプリ向けオブザーバビリティプラットフォーム(商用) |
加えて、ColvinはMCP Python SDKのco-maintainerでもある。つまり、今回の講演はMCPの設計者に近い立場からの「正しい使い方」の解説だ。
タイトルはJakub Löwit氏の過去講演「Pydantic is all you need」「Pydantic is still all you need」をオマージュしたものであり、核心にある主張は同じだ:「みんなが複雑にしすぎている。シンプルな道具で十分なことが多い。」
MCPの3つのプリミティブと「自律エージェント」での使い分け
MCPには3つの基本プリミティブがある:
(プロンプトテンプレート)"] A --> C["Resources
(ファイル・データ)"] A --> D["Tools
(関数呼び出し)"] B -->|"主な対象"| E["Cursor / Claude Desktop
型のコーディングエージェント"] C -->|"主な対象"| E D -->|"主な対象"| F["自律エージェント
(Pythonコード)"]
ColvinがこのトークでスコープにしているのはCursorやClaude Desktopのような「コーディングエージェント」ではなく、自分でコードを書いて動かす自律エージェントだ。
この文脈では、PromptとResourcesはあまり関係せず、Tool calling(ツール呼び出し)が圧倒的に重要になる。
なぜOpenAPIではなくMCPか?
よく聞かれる質問に「MCPって結局OpenAPIじゃダメなの?」がある。Colvinが挙げた理由:
1. Dynamic tools:エージェント実行中にツールが動的に増減できる
2. Logging:ツール実行中に途中経過をクライアントへ返せる
3. Sampling:MCP サーバーからクライアント経由でLLMを呼べる
4. Stdio transport:サブプロセスとして起動しstdin/stdoutで通信できる
中でもSamplingは最も強力で最も誤解されやすい機能だとColvinは強調している。
最重要機能「Sampling」の仕組みを完全理解する
Samplingは「MCP界で最も命名が混乱している機能」とColvin自身が認めている。 しかし、理解すれば自律エージェントのアーキテクチャが根本的に変わる。
Samplingなしの問題点
MCPなしの典型的なマルチエージェント構成では、すべてのエージェントが個別にLLMアクセスを必要とする:
(LLM: GPT-4o)"] -->|"ツール呼び出し"| B["サブエージェントA
(LLM: 別途必要)"] A -->|"ツール呼び出し"| C["サブエージェントB
(LLM: 別途必要)"] B -->|"さらに呼び出し"| D["ツール群"] C -->|"さらに呼び出し"| D style B fill:#f9a,stroke:#f00 style C fill:#f9a,stroke:#f00
問題は3つある:
- リモートMCPサーバーがLLMを使うとコスト管理が困難
- 各サブエージェントのAPIキー設定が必要
- LLMプロバイダーが増えると認証・課金が複雑化
SamplingでLLM呼び出しを委譲する
Samplingは「MCPサーバーがクライアント経由でLLMを使う仕組み」だ:
MCPサーバー(ツール)が自身のLLMを持たなくても、メインエージェントのLLMを「間借り」できる。
PydanticAIはこのSamplingをクライアントとしてもサーバーとしてもサポートしている(講演時点ではPRマージ直前)。
PydanticAI + FastMCPの実装デモ:PyPIダウンロード統計エージェント
ColvinはPydanticAI + FastMCPを使ったデモを紹介した。BigQueryのPyPI公開データセットからパッケージのダウンロード数を調べるリサーチエージェントだ。
MCPサーバー側:FastMCPでツール定義
# pypi_mcp_server.py
from mcp.server.fastmcp import FastMCP
from pydantic_ai import Agent
from pydantic_ai.models.openai import OpenAIModel
from google.cloud import bigquery
mcp = FastMCP("pypi-stats-server")
@mcp.tool()
async def pypi_downloads(
ctx: MCPContext,
question: str,
) -> str:
"""PyPIパッケージのダウンロード統計をBigQueryで照会する。
ユーザーの自然言語の質問をBigQuery SQLに変換し、
PyPI公開データセットを照会してダウンロード数を返す。
"""
# MCPコンテキスト経由でログ送信(ツール実行中にクライアントへ返る)
await ctx.log("info", f"BigQuery照会を開始: {question}")
# 内部でPydanticAIエージェントを動かす(Samplingを使用)
result = await _run_query_agent(ctx, question)
return result
async def _run_query_agent(ctx: MCPContext, question: str) -> str:
"""内部エージェント:クライアントのLLMをSampling経由で使用"""
agent = Agent(
model=ctx.sampling, # メインエージェントのLLMを借用
system_prompt=BIGQUERY_SYSTEM_PROMPT,
result_type=QueryResult,
result_validator=validate_and_run_query,
)
result = await agent.run(question)
return format_as_xml(result.data)
if __name__ == "__main__":
mcp.run() # デフォルトはstdio transport
OutputValidatorでSQLエラーを自動リトライ
Colvinのデモで最も注目すべきポイントは「エラー時の自動リトライ」だ。
from pydantic_ai import ModelRetry
async def validate_and_run_query(
ctx: RunContext[MCPContext],
result: str
) -> str:
"""生成されたSQLを検証・実行。失敗時はModelRetryでLLMに再生成を依頼"""
# LLMがmarkdownコードブロックで囲んだ場合は除去
sql = strip_markdown_fences(result)
# テーブル名の検証
if WRONG_TABLE in sql:
raise ModelRetry(
f"テーブル名が間違っています。正しくは: {CORRECT_TABLE}"
)
# BigQueryでSQLを実際に実行
client = bigquery.Client()
try:
rows = list(client.query(sql).result())
return format_rows_as_xml(rows)
except Exception as e:
# 実行失敗時は自動リトライ
raise ModelRetry(f"SQLエラー: {e}\n再度試してください。")
ModelRetryをraiseするだけで、PydanticAIがLLMに「やり直し」を指示する。これはPydanticのバリデーション設計思想をエージェントに応用したものだ。
メインエージェント側:MCPサーバーをツールとして登録
# main_agent.py
from pydantic_ai import Agent
from pydantic_ai.mcp import MCPServerStdio
from datetime import date
# MCPサーバーをサブプロセスとして起動・登録
research_agent = Agent(
model="openai:gpt-4o",
mcp_servers=[
MCPServerStdio("python", ["pypi_mcp_server.py"])
],
system_prompt=f"""
あなたはPyPIパッケージの調査エージェントです。
今日の日付: {date.today()}
""",
)
# 実行
result = await research_agent.run(
"Pydanticは今年何回ダウンロードされましたか?"
)
print(result.data)
# → "Pydantic は 2026年に約 1.6 billion 回ダウンロードされています。"
コンテキストウィンドウ最適化:ツール内推論パターン
Colvinが強調したもう一つの重要ポイントが「ツール内でLLM推論を実行することでメインエージェントのコンテキストを節約する」設計だ。
BigQueryのスキーマ情報・SQL生成ルール・テーブル定義をすべてメインエージェントのシステムプロンプトに含めると、そのツールを使わない場面でも常にコンテキストを消費し続ける。
推奨パターンとアンチパターンの比較:
| アンチパターン | 推奨パターン | |
|---|---|---|
| SQLスキーマ情報 | メインエージェントのプロンプトに含める | MCPサーバー内部に隠蔽 |
| SQL生成ロジック | ツールの説明文に詰め込む | サーバー内エージェントが担当 |
| エラーハンドリング | メインエージェントが判断 | ModelRetryで自動処理 |
| コンテキスト消費 | ツール呼び出しの有無に関わらず消費 | 実際の呼び出し時のみ消費 |
「ツール説明文にたくさんの情報を詰め込むと、モデルはあまり好まない。それ以上に、常にコンテキストウィンドウを無駄遣いする」 — Samuel Colvin
MCPサーバー内でSamplingを使って内部エージェントを動かすことで、メインエージェントは「自然言語でツールに質問する」だけでよくなる。
MCPのLogging機能:ツール実行中のリアルタイム進捗
MCPにはctx.log()というLogging機能がある。これはツール実行が完了する前にクライアントへ情報を送れる仕組みだ。
@mcp.tool()
async def long_running_research(ctx: MCPContext, query: str) -> str:
await ctx.log("info", "データソースを検索中...")
results_a = await search_source_a(query)
await ctx.log("info", f"ソースAから{len(results_a)}件取得。分析中...")
analysis = await analyze(results_a)
# progressノーティフィケーションも使える
await ctx.report_progress(current=50, total=100)
await ctx.log("info", "最終レポートを生成中...")
return generate_report(analysis)
元々はCursorのようなUIで「まだ処理中ですよ」と伝えるために設計されたが、Webアプリケーションでのストリーミング更新にも活用できる。数分かかる処理でも、ユーザーに進捗を見せながら実行できる。
Pydantic Logfireでのオブザーバビリティ:MCP呼び出しの可視化
ColvinはPydantic Logfireを使ったトレーシングのデモも見せた。エージェント実行の全フローが可視化される:
(GPT-4o呼び出し)"] -->|"ツール呼び出し判断"| B["MCPクライアント処理"] B -->|"pypi_downloads実行"| C["MCPサーバー"] C -->|"Sampling: SQL生成"| D["内部エージェント
(クライアント経由でLLM)"] D -->|"BigQuery実行"| E["クエリ結果(XML)"] E -->|"ツール結果返却"| A A -->|"最終回答生成"| F["ユーザーへの回答"]
Logfireのダッシュボードでは:
- どのレイヤーでLLM呼び出しが起きたか
- 実際に生成されたSQLクエリ
- 各ステップのレイテンシ
- Samplingのクライアント⇔サーバー往復
…がすべてトレースとして記録される。MCPのオブザーバビリティはMCPサーバーの作り方2026年完全ガイドでも触れているが、Logfireと組み合わせることで特に強力になる。
まとめ:Colvinが示したMCPの正しい設計原則
Colvinの講演から抽出できる設計原則をまとめる:
1. ツール内に推論を閉じ込める:メインエージェントのコンテキストを汚染しない
2. Samplingでコスト集約:すべてのLLM呼び出しをメインクライアント経由に集約
3. ModelRetryでエラー自動回復:バリデーションとリトライをLLMに委ねる
4. Loggingで進捗をストリーミング:長時間処理でもユーザー体験を損なわない
MCPを単なる「ツール呼び出しプロトコル」として使うのは勿体ない。Samplingを活用したマルチエージェント設計は、コスト・複雑性・コンテキスト効率の3点で従来のアーキテクチャを凌駕する。
AIエージェントフレームワーク比較2026年版でもPydanticAIは注目フレームワークの一つとして取り上げているが、MCP+Sampling対応が整った今、実用プロジェクトへの導入を検討する価値がある。