MCP Toolを実装するとき、inputSchemaは比較的分かりやすい機能です。Toolへ、
{
"query": "RTX 5070",
"limit": 10
}
のような引数を渡すため、その入力形式をinputSchemaで定義します。inputSchema自体の書き方はMCPツールのinputSchemaはどう書く?で解説しています。一方、Toolの戻り値には、
outputSchema structuredContent content
という似た名前の仕組みがあり、違いが分かりにくいところです。
結論から言えば、outputSchemaは必須ではありません。文章を返すだけの単純なToolなら、contentだけでも実装できます。しかし、Toolの結果をMCP Client側のプログラムから、
temperature userId items total status
のような値として確実に扱いたいなら、outputSchemaとstructuredContentを利用する価値があります。
outputSchemaは「このToolはどのような構造のデータを返すのか」という契約です。structuredContentは、実際のTool実行結果として返される構造化データです。そしてcontentは、テキストや画像など、主にモデルが利用するContent Blockです。MCP Python SDKの現行ドキュメントでも、contentはモデル向け、structured_contentはClient Application向け、output_schemaは両者をつなぐ事前の契約として説明されています。
この記事では、MCP ToolのoutputSchemaとstructuredContentの違い、どのようなToolで必要になるのか、contentと両方返す理由、JSON Schemaの実例まで解説します。
- outputSchemaはToolの「戻り値の型」を定義する
- structuredContentは実際に返ってきたデータ
- contentはstructuredContentとは役割が違う
- なぜ同じ結果をcontentとstructuredContentの両方で返すのか
- outputSchemaは必須ではない
- outputSchemaが向いているのはプログラムから結果を使うTool
- outputSchemaがあると戻り値の破壊的変更を検出しやすい
- TypeScript SDKではoutputSchemaとstructuredContentをセットで返す
- Python SDKなら戻り値の型から自動生成できる
- Python SDKではスカラーもStructured Outputにできる
- 2026-07-28ではoutputSchemaのRootはObject限定ではない
- 2025-11-25以前との互換性には注意する
- outputSchemaではoneOfや$refも使える
- Tool ErrorではstructuredContentを信用しない
- contentだけでよいToolもある
- 検索結果やAPIレスポンスにはoutputSchemaが向いている
- 「JSON文字列」とstructuredContentは同じではない
- structuredContentだけ返せばcontentはいらない?
- outputSchemaと実装を二重管理しない
- outputSchemaを付けるならValidationまで行う
- outputSchemaを巨大にしすぎない
- MCPツールのoutputSchemaに関するよくある質問
- MCPツールのoutputSchemaは「必要なときだけ使う」でよい
outputSchemaはToolの「戻り値の型」を定義する
inputSchemaがToolへ渡すArgumentsを定義するのに対して、outputSchemaはToolから返ってくる構造化データを定義します。たとえば天気を取得するToolがあるとします。
{
"name": "get_weather",
"description": "指定した都市の現在の天気を取得します",
"inputSchema": {
"type": "object",
"properties": {
"city": {
"type": "string"
}
},
"required": [
"city"
]
},
"outputSchema": {
"type": "object",
"properties": {
"temperature": {
"type": "number"
},
"condition": {
"type": "string"
},
"humidity": {
"type": "integer"
}
},
"required": [
"temperature",
"condition",
"humidity"
]
}
}
このTool Definitionを見ればMCP Clientは、Toolを実行する前から、temperatureはnumber、conditionはstring、humidityはintegerという出力形式を理解できます。現在のMCP TypeScript SDKでも、outputSchemaはToolがCallToolResult.structuredContentとして返すデータの構造を記述するOptionalなJSON Schemaとして定義されています。つまりoutputSchemaは実際の結果ではありません。「結果はこの形になる」という事前定義です。
structuredContentは実際に返ってきたデータ
一方のstructuredContentは、tools/callを実行した結果に含まれる実データです。先ほどの天気Toolなら、実行結果は概念的に次のようになります。
{
"content": [
{
"type": "text",
"text": "東京は24.5℃、晴れ、湿度58%です。"
}
],
"structuredContent": {
"temperature": 24.5,
"condition": "sunny",
"humidity": 58
}
}
outputSchemaはtemperatureがnumber、conditionがstring、humidityがintegerという構造を宣言します。structuredContentには、その型に従った実際の値が入ります。MCP Clientは、ToolがoutputSchemaを公開している場合、返されたstructuredContentをそのSchemaに対してValidationできます。現在のTypeScript SDKではClient側でStructured Outputを自動Validationする機能も実装されています。
contentはstructuredContentとは役割が違う
さらにcontentがあります。MCPのTool ResultにおけるcontentはContent Blockの配列です。たとえばTextなら、
{
"type": "text",
"text": "東京は24.5℃です。"
}
です。ほかにもImage、Audio、Embedded Resource、Resource Linkなどを返せます。Python SDKでは、contentは主にモデルが読む情報、structured_contentはClient Applicationがプログラムとして扱うデータという役割で説明されています。つまり、
content → AIモデルが理解しやすい情報 structuredContent → アプリケーションが処理しやすいJSON outputSchema → structuredContentの構造定義
と考えると分かりやすくなります。
なぜ同じ結果をcontentとstructuredContentの両方で返すのか
天気が24.5℃なら{"temperature": 24.5}だけ返せば十分に見えるかもしれません。しかしモデル側では、「temperatureという値が24.5」だけより、「東京の現在気温は24.5℃です。」というText Contentのほうがそのまま回答へ利用しやすい場合があります。一方、Client Applicationでは文章を解析して24.5を取り出したくありません。そのため、Structured Dataも欲しくなります。
MCPではこの2種類を同時に返せます。
{
"content": [
{
"type": "text",
"text": "東京の現在気温は24.5℃です。"
}
],
"structuredContent": {
"temperature": 24.5
}
}
この設計ならモデルにもApplicationにも使いやすくなります。MCP SDKのドキュメントでも、Structured Contentを返すToolは互換性のために同じデータをSerialized JSONなどのTextContentでも提供することが推奨されています。古いClientやStructured Contentを利用しないClientでも結果を取得できるためです。
outputSchemaは必須ではない
すべてのMCP ToolへoutputSchemaを付ける必要はありません。たとえば「今日のシステム状況を人間向けの文章で説明する」Toolを考えます。結果が「APIとデータベースは正常です。バックグラウンドジョブが2件遅延しています。」というHuman-readable Textだけで十分なら、Structured Outputを用意する必要はありません。
Python SDKなら、
from mcp.server import MCPServer
mcp = MCPServer("Status")
@mcp.tool(structured_output=False)
def system_report() -> str:
return (
"APIとデータベースは正常です。"
"バックグラウンドジョブが2件遅延しています。"
)
のようにStructured Outputを無効にできます。この場合はoutput_schemaも生成されず、structured_contentも返されません。contentだけが返されます。したがって「MCP Toolには必ずoutputSchemaを書く」という理解は正しくありません。
outputSchemaが向いているのはプログラムから結果を使うTool
逆に、結果を後続処理で利用したいToolではoutputSchemaが便利です。たとえば商品検索Toolが「RTX 5070搭載PCが3件見つかりました。」という文章だけを返すとします。Client Applicationが商品一覧をUIへ表示したい場合、文章から商品名や価格を解析しなければなりません。
Structured Outputなら、
{
"items": [
{
"id": "pc-001",
"name": "Gaming PC A",
"price": 189800
},
{
"id": "pc-002",
"name": "Gaming PC B",
"price": 199800
}
],
"total": 2
}
と返せます。そしてoutputSchemaを、
{
"type": "object",
"properties": {
"items": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"price": {
"type": "integer"
}
},
"required": [
"id",
"name",
"price"
]
}
},
"total": {
"type": "integer"
}
},
"required": [
"items",
"total"
]
}
とします。これならClientは文章解析をせず、items・total・priceへ直接アクセスできます。
outputSchemaがあると戻り値の破壊的変更を検出しやすい
Structured Outputには、Application IntegrationだけでなくAPI Contractとしてのメリットもあります。たとえば最初は{"userId": "123", "name": "Taro"}を返していたToolが、実装変更によって{"id": 123, "displayName": "Taro"}を返すようになったとします。
Schemaがなければ、JSONとしてはどちらも正常です。しかしClient側ではuserIdがないため壊れる可能性があります。outputSchemaを、
{
"type": "object",
"properties": {
"userId": {
"type": "string"
},
"name": {
"type": "string"
}
},
"required": [
"userId",
"name"
]
}
としておけば、戻り値が契約から外れたことをValidationで検出できます。MCPのStructured Outputでは、Schemaを宣言したServerはStructured ResultをそのSchemaへ適合させる必要があり、Client側もValidationすることが推奨されています。
TypeScript SDKではoutputSchemaとstructuredContentをセットで返す
TypeScript SDKでは、たとえば次のように実装できます。
server.registerTool(
"measure",
{
description: "文字列の長さを取得します",
inputSchema: {
name: z.string()
},
outputSchema: {
name: z.string(),
length: z.number()
}
},
async ({ name }) => {
const output = {
name,
length: name.length
};
return {
content: [
{
type: "text",
text: JSON.stringify(output)
}
],
structuredContent: output
};
}
);
ここではoutputSchemaが期待する構造を定義し、structuredContentへ実データを入れています。現在のTypeScript SDK v2では、利用するSchema LibraryからoutputSchemaを生成でき、Serverが結果を返す前にstructuredContentをSchemaへValidationできます。inputSchemaと同様、Zod SchemaからJSON Schemaを導出する仕組みです。
Python SDKなら戻り値の型から自動生成できる
Python SDKのHigh-level APIでは、手動でoutputSchemaを書く必要がないケースもあります。たとえば、
from pydantic import BaseModel, Field
from mcp.server import MCPServer
mcp = MCPServer("Weather")
class WeatherData(BaseModel):
temperature: float = Field(
description="気温。攝氏"
)
condition: str
humidity: int
@mcp.tool()
def get_weather(
city: str
) -> WeatherData:
return WeatherData(
temperature=24.5,
condition="sunny",
humidity=58
)
とします。現在のMCP Python SDKでは戻り値のType Annotationからoutput_schemaを生成し、Tool Definitionとしてtools/listへ公開できます。Toolを呼ぶとSDKがcontent・structured_contentの両方を生成し、返されたPython値をSchemaに対してValidationします。つまり単純なHigh-level Toolなら、outputSchemaを手書きするより、戻り値の型を正しく定義するほうがHandlerとSchemaの不一致を防ぎやすくなります。
Python SDKではスカラーもStructured Outputにできる
たとえば気温だけを返すToolです。
@mcp.tool()
def get_temperature(
city: str
) -> int:
return 24
intはObjectではありません。現在のPython SDKのHigh-level APIでは、このようなScalar Returnを{"result": 24}というObjectへ自動的にWrapします。生成されるoutput_schemaは概念的に、
{
"type": "object",
"properties": {
"result": {
"type": "integer"
}
},
"required": [
"result"
]
}
となります。実行結果は、contentが"24"、structured_contentが{"result": 24}となります。ここは「MCP Protocol自体の制限」と「Python SDKのHigh-level APIの便利な変換」を分けて理解する必要があります。
2026-07-28ではoutputSchemaのRootはObject限定ではない
現在の2026-07-28 MCPでは、inputSchemaのRootは引き続きObjectでなければなりません。一方、outputSchemaにはこの制限がありません。2026-07-28でTool SchemaがFull JSON Schema 2020-12へ拡張され、outputSchemaのRootにはObjectだけでなくArray、String、Number、oneOfなども使用できるようになりました。同時にstructuredContentもObjectだけではなく、任意のJSON Valueを返せるようになっています。
たとえばArrayを直接返すSchemaも書けます。
{
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
}
},
"required": [
"id",
"name"
]
}
}
structuredContentには、
[
{
"id": "1",
"name": "Alice"
},
{
"id": "2",
"name": "Bob"
}
]
を返せます。
2025-11-25以前との互換性には注意する
ここは古いMCP Clientもサポートする場合に重要です。2025-11-25世代ではoutputSchemaとstructuredContentはObject Shapeを前提としていました。2026-07-28でこの制限が解除されています。
そのため、[{"id": 1}, {"id": 2}]というBare ArrayをStructured Contentとして返すToolは、2026-07-28対応Clientなら扱えても古いClientでは問題になる可能性があります。幅広いClientをサポートしたいなら、
{
"items": [
{
"id": 1
},
{
"id": 2
}
]
}
のようにObjectへ包む設計が互換性を確保しやすくなります。SDKやそのバージョンによっては、Object以外のRootを持つoutputSchema自体を正規化・無効化する実装もあるため、古いClientや古いSDKも対象にする場合は、Object Rootを前提にした設計のほうが安全です。
outputSchemaではoneOfや$refも使える
2026-07-28ではFull JSON Schema 2020-12になったため、出力側でも複雑なSchemaを定義できます。たとえば成功時と失敗時で構造を分けるなら、
{
"oneOf": [
{
"type": "object",
"properties": {
"success": {
"const": true
},
"data": {
"type": "object"
}
},
"required": [
"success",
"data"
]
},
{
"type": "object",
"properties": {
"success": {
"const": false
},
"message": {
"type": "string"
}
},
"required": [
"success",
"message"
]
}
]
}
のように書くこともProtocol上は可能です。$defsと$refで共通構造を再利用することもできます。ただしTool ErrorについてはMCPにisErrorがあるため、単純な失敗まで何でも独自のsuccess: false Schemaへ詰め込む必要はありません。
Tool ErrorではstructuredContentを信用しない
MCPのTool ResultにはisErrorがあります。Toolが正常に実行できなかった場合、isError = trueとして返せます。Python SDKのClient Documentationでも、Tool Errorの場合には通常contentへエラー内容が入り、structured_contentはNoneになります。Client側ではStructured Contentを利用する前にis_errorを確認することが推奨されています。
たとえば、
result = await client.call_tool(
"lookup_book",
{
"title": "Solaris"
}
)
if result.is_error:
handle_error(result.content)
else:
process(result.structured_content)
という形です。outputSchemaは主に正常なTool Resultの契約として考えると分かりやすいでしょう。
contentだけでよいToolもある
たとえば「READMEを要約する」Toolがあるとします。戻り値が「このプロジェクトはFastAPIを使用したAPIサーバーです。開発環境ではPostgreSQLを利用します。」という文章だけなら、Applicationが項目ごとに値を利用する必要がないかもしれません。この場合、outputSchemaなし・structuredContentなし・contentのみでも十分です。
画像生成ToolならImageContent、音声ToolならAudioContentを中心に返す設計もあります。Python SDKではContent BlockやImage、Audioなどを返すToolについて、Structured Outputの自動生成を行わない構成があります。つまり、Structured Outputを使わないことが古い設計というわけではありません。Toolの用途に合わせて選びます。
検索結果やAPIレスポンスにはoutputSchemaが向いている
たとえば検索Toolが「3件見つかりました。1. Product A 10000円 2. Product B 12000円 3. Product C 15000円」というTextだけを返すと、モデルは理解できます。しかしUIへ商品カードを表示したいClientでは不便です。
Structured Outputなら、
{
"items": [
{
"id": "a",
"name": "Product A",
"price": 10000
},
{
"id": "b",
"name": "Product B",
"price": 12000
}
],
"total": 2
}
と返せます。MCP ClientはoutputSchemaを見て事前に型を把握でき、実際の結果ではstructuredContent.itemsをそのままUIへ渡せます。検索API、Database Query、Metrics取得、商品情報、ユーザー情報など、後続処理へ使うデータではStructured Outputのメリットが大きくなります。
「JSON文字列」とstructuredContentは同じではない
次のTool Resultを考えます。
{
"content": [
{
"type": "text",
"text": "{\"temperature\":24.5,\"condition\":\"sunny\"}"
}
]
}
見た目はJSONですが、MCP Protocol上はTextContentです。Clientは文字列として受け取ります。値として利用するには、Clientの言語でJSONをParseしなければなりません。Structured Contentなら、
{
"structuredContent": {
"temperature": 24.5,
"condition": "sunny"
}
}
となります。Clientは文字列Parseをする必要がありません。さらにoutputSchemaがあるため、その構造を事前に知りValidationできます。つまり「contentにJSON文字列を書く」ことと「structuredContentを返す」ことは同じではありません。
structuredContentだけ返せばcontentはいらない?
最新Protocolだけを前提にした自前Clientなら、structuredContentだけでも目的を達成できるケースがあります。しかし互換性を重視するなら、contentも返すほうが安全です。MCPのStructured Outputでは、Structured Contentを返すToolは後方互換性のためにSerialized JSONなどをTextContentにも含めることが推奨されています。
たとえば、
{
"content": [
{
"type": "text",
"text": "{\"temperature\":24.5,\"condition\":\"sunny\"}"
}
],
"structuredContent": {
"temperature": 24.5,
"condition": "sunny"
}
}
という構成です。High-level SDKでは、この二重化を自動的に行ってくれる場合があります。
outputSchemaと実装を二重管理しない
Low-level MCP Serverでは、自分でSchemaとResultを組み立てます。たとえばPythonなら、
SEARCH_BOOKS = Tool(
name="search_books",
input_schema={
"type": "object",
"properties": {
"query": {
"type": "string"
}
},
"required": [
"query"
]
},
output_schema={
"type": "object",
"properties": {
"matches": {
"type": "integer"
},
"query": {
"type": "string"
}
},
"required": [
"matches",
"query"
]
}
)
とします。Tool Resultでは、
return CallToolResult(
content=[
TextContent(
type="text",
text="3 books found"
)
],
structured_content={
"matches": 3,
"query": query
}
)
のようにします。Low-level APIではoutput_schemaの宣言もstructured_contentの生成も開発者側の責任になります。そのためSchemaではmatchesとしているのにResultでcountを返すといった不一致が起きないよう注意が必要です。High-level SDKで型から自動生成できるなら、その方法を利用するほうが管理しやすい場合があります。
outputSchemaを付けるならValidationまで行う
outputSchemaを書くだけで満足すると、実装変更によって実際のResultがSchemaからずれる可能性があります。重要なのは、Schemaを宣言するだけでなく、返却時にSchemaへ適合していることを検証することです。
TypeScript SDK v2では、ClientのcallTool()がTool Definitionを取得済みならStructured OutputをoutputSchemaに対してValidationできます。またServer側でも利用するSchema Libraryに応じたValidationが行われます。SchemaをAPI Contractとして使うなら、Testでも実際のTool ResultがSchemaに一致することを確認すると安全です。
outputSchemaを巨大にしすぎない
inputSchemaと同様、JSON Schemaは複雑にしようと思えばかなり複雑にできます。たとえば巨大なoneOf・anyOf・allOf・$defs・$refを組み合わせることもできます。しかしTool Resultを利用するClientにとって、本当にその複雑さが必要なのか考えたほうがよいでしょう。
たとえば1つのToolが検索結果・統計・エラー・認証情報・デバッグ情報・UI設定をすべて別形式で返すより、責務を分けたほうが扱いやすい場合があります。Structured Outputの目的は、複雑なSchemaを書くことではありません。Clientが結果を安定して利用できる契約を作ることです。
MCPツールのoutputSchemaに関するよくある質問
QoutputSchemaはすべてのToolに必要ですか
A必要ありません。モデルが読む文章だけを返すToolならcontentだけで十分です。Tool ResultをClient側のプログラムから値として利用したい場合にoutputSchemaとstructuredContentを追加する価値があります。
QstructuredContentとcontentのJSON文字列は同じ意味ですか
A違います。contentへJSON文字列をTextとして書いても、Clientから見ればただの文字列でありParseが必要です。structuredContentはJSON値として直接返され、outputSchemaがあれば事前に構造を検証できます。
QoutputSchemaのRootはinputSchemaと同じくobjectにする必要がありますか
A2026-07-28仕様では制限が異なります。inputSchemaのRootは引き続きobjectである必要がありますが、outputSchemaはarray・string・number・oneOfなどもRootに使えます。ただし古いClientやSDKの中にはobject以外のoutputSchemaを想定していないものもあるため、幅広い互換性が必要ならobjectで包む設計が無難です。
QPython SDKで整数や文字列だけを返すToolでもStructured Outputになりますか
Aなります。High-level APIでは戻り値の型注釈がint やstrなどのScalarの場合、{“result”: 値}という形のObjectへ自動的にラップされ、それに対応するoutput_schemaが生成されます。
QTool Errorのときstructured_contentは使えますか
A通常はNoneになります。Tool Errorの場合はcontentにエラー内容が入り、structured_contentは提供されません。Client側ではまずis_error(またはisError)を確認し、エラーでない場合にのみstructured_contentを利用するようにしてください。
MCPツールのoutputSchemaは「必要なときだけ使う」でよい
MCP ToolのoutputSchemaは必須ではありません。モデルに読ませるHuman-readable Textを返すだけなら、contentだけでも十分です。一方、Tool ResultをClient Applicationからプログラムとして利用したい場合は、Structured Outputを使う価値があります。その場合、outputSchemaで結果の構造を宣言し、structuredContentへ実際のJSON Dataを返します。モデルにも結果を分かりやすく伝えたい場合や古いClientとの互換性を考えるなら、contentにもTextまたはSerialized JSONを含めます。
整理すると、outputSchemaはStructured Resultの契約、structuredContentは契約に従った実際の結果、contentはモデルが利用するText・ImageなどのContent Block、という違いです。
2026-07-28 MCPではoutputSchemaがFull JSON Schema 2020-12へ拡張され、Object以外にもArray、String、Number、oneOfなどをRootとして利用できるようになりました。structuredContentも任意のJSON Valueを返せます。ただし2025-11-25世代ではObject Shapeが前提だったため、古いClientもサポートするなら{"items": [...]}のようなObject Envelopeを維持する設計も検討するとよいでしょう。
MCP ToolでoutputSchemaを使うか迷ったら、「この結果をモデルが文章として読むだけなのか、それともClientのコードが値として利用するのか」を基準にすると判断しやすくなります。モデルが読むだけならcontentで十分です。Applicationも利用するなら、outputSchemaとstructuredContentを追加するのがおすすめです。inputSchemaの書き方はMCPツールのinputSchemaはどう書く?もあわせて参照してください。
