Blog • AI / JSON Schema
Why Do AI Agents Need JSON Schema? Tool Calling to Structured Output Explained
You're wiring an LLM Agent and the docs mention tools[].function.parameters, response_format.json_schema, and MCP's inputSchema—they all look like JSON, but what does each constrain and guarantee?
JSON Schema is the standard for describing JSON data structures (current mainstream: 2020-12). In AI Agent development, it's not an optional doc format—it's the contract language between models and the outside world: Tool Calling uses it for tool parameters, Structured Output for final answers, MCP for tool I/O.
This article covers:
- Where JSON Schema appears in the Agent stack
- How Tool Calling uses schema to constrain
arguments - Three Structured Output paths (JSON Mode / Function Calling / Strict Schema) compared
- How to write MCP 2020-12 tool contracts
- A copy-paste tool schema example and validation workflow
Keep this in mind: The model outputting JSON and outputting schema-conformant JSON are two different things. JSON Schema defines the latter—field names, types, required fields, enums. Below we walk through why it's needed → Tool Calling → Structured Output → MCP → how to write → how to validate.
Why Agents can't live without JSON Schema
The Agent core loop: model reasoning → decide tool call or structured answer → execute → feed result back → continue. Every I/O step in this loop should be machine-parseable, validatable, and auditable.
Plain natural language output has two fatal problems:
- Not programmatically consumable: downstream code can't reliably extract fields—only regex or a second LLM parse
- Not regression-testable: same prompt may produce different formats twice—no fixture comparison
JSON Schema solves the format contract problem: before the model generates, you declare which fields, types, and required items the output must have. This is key infrastructure for Agents going from demo to production.
The 2026 Agent stack is highly aligned: OpenAI Function Calling, Anthropic Tool Use, DeepSeek Function Calling, MCP Tools—all use JSON Schema to describe tool parameters.
Where schema appears in the Agent stack
One table to see where JSON Schema sits in Agent development:
| Layer | Schema field | Constrains | Who validates |
|---|---|---|---|
| LLM API — Tool Calling | tools[].function.parameters |
Model-generated tool_calls[].function.arguments |
Model (soft) + your code (hard validate) |
| LLM API — Structured Output | response_format.json_schema |
Model final answer JSON structure | Model (Strict hard) + your code |
| MCP Server | inputSchema / outputSchema |
Tool call params / Server structuredContent | Client SDK + your code |
| Business layer | Custom schema files | Final gate before DB / API response | ajv / jsonschema / your validate function |
Key insight: API-layer schema guides model generation; business-layer schema rejects bad data. You need both—they don't replace each other.
Tool Calling: parameters IS JSON Schema
With OpenAI-compatible APIs, you declare a tools array; each tool's function.parameters is a JSON Schema object:
{
"model": "deepseek-v4-pro",
"messages": [
{ "role": "user", "content": "查一下北京今天天气" }
],
"tools": [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get current weather for a city",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "City name, e.g. Beijing"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"default": "celsius"
}
},
"required": ["city"],
"additionalProperties": false
}
}
}
]
}
In the model's tool_calls, function.arguments is a JSON string, not a parsed object:
{
"tool_calls": [
{
"id": "call_abc123",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"city\": \"Beijing\", \"unit\": \"celsius\"}"
}
}
]
}
This means you must do two things in the business layer:
-
1
JSON.parse + try/except
argumentsmay be syntactically broken (missing quotes, trailing commas)—ensure valid JSON first. -
2
JSON Schema validate
Validate the parsed object against your declared
parametersschema—check fields, types, and enum values.
The full tool loop: request with schema → model picks tool and generates arguments → you parse and validate → execute tool → feed result as tool message → model continues. Schema quality directly affects whether the model generates correct arguments on the first try.
Three Structured Output paths compared
Besides Tool Calling, you can have the model output structured JSON as the final answer. Three common paths:
| Path | API config | Guarantees | Best for |
|---|---|---|---|
| JSON Mode | response_format: { "type": "json_object" } |
Valid JSON object output | Free-form extraction, simple classification, flat structures |
| Function Calling | tools + model returns tool_calls |
arguments roughly match parameters schema | Agent tool calls, combined with MCP |
| Strict Schema | response_format.json_schema + strict: true |
Output strictly conforms to given schema | Production, complex schemas, strict field types |
Strict Schema example (OpenAI / DeepSeek compatible):
{
"model": "deepseek-v4-pro",
"messages": [
{ "role": "user", "content": "分析这段用户反馈的情感和关键问题" }
],
"response_format": {
"type": "json_schema",
"json_schema": {
"name": "sentiment_analysis",
"strict": true,
"schema": {
"type": "object",
"properties": {
"sentiment": {
"type": "string",
"enum": ["positive", "neutral", "negative"]
},
"issues": {
"type": "array",
"items": { "type": "string" }
},
"confidence": {
"type": "number",
"minimum": 0,
"maximum": 1
}
},
"required": ["sentiment", "issues", "confidence"],
"additionalProperties": false
}
}
}
}
Best practice is defense in depth: pick Strict or Function Calling at API layer → JSON Schema validate in business logic → format / diff / schema check locally with JSONNote. See DeepSeek V4-Pro explained for the JSON output chapter.
MCP and JSON Schema 2020-12
Model Context Protocol (MCP) is the standard protocol between Agents and external services. The 2026-07-28 spec upgrades tool inputSchema and outputSchema to full JSON Schema 2020-12, supporting oneOf, anyOf, $ref and other composition features.
{
"name": "search_docs",
"description": "Search documentation by keyword",
"inputSchema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"query": { "type": "string", "minLength": 1 },
"limit": { "type": "integer", "minimum": 1, "maximum": 50, "default": 10 }
},
"required": ["query"]
},
"outputSchema": {
"type": "object",
"properties": {
"results": {
"type": "array",
"items": {
"type": "object",
"properties": {
"title": { "type": "string" },
"url": { "type": "string", "format": "uri" }
},
"required": ["title", "url"]
}
}
},
"required": ["results"]
}
}
Server structuredContent must conform to outputSchema when defined. Same engineering problem as parsing tool_calls.arguments from LLM APIs—except the data source is an MCP Server. More MCP background in AI Conference 2026 hot topics.
How to write a good tool schema
Schema quality directly affects tool calling success rate. Production-proven tips:
-
1
Write description for every property
Models read description to fill values.
cityas "City name, e.g. Beijing, Shanghai" beats a bare field name. -
2
Use enum to limit options, don't hint in description
"enum": ["low", "medium", "high"]beats writing "optional low/medium/high" in description. -
3
Set additionalProperties: false
Prevents the model from "creatively" adding undeclared fields. Strict Schema mode usually enforces this.
-
4
Use oneOf / $ref for complex params, don't flatten all combinations
E.g. "lookup by ID" vs "lookup by name" are two param shapes—oneOf is clearer than one big object.
-
5
Tool description: when to call and when NOT to call
Models use description for tool selection. "Only call when user explicitly asks about weather" reduces false triggers.
Validation workflow: from API to business layer
Recommended Agent JSON validation pipeline:
import json
from jsonschema import validate, ValidationError
TOOL_SCHEMA = {
"type": "object",
"properties": {
"city": {"type": "string"},
"unit": {"type": "string", "enum": ["celsius", "fahrenheit"]}
},
"required": ["city"],
"additionalProperties": False
}
def parse_tool_arguments(raw: str) -> dict:
try:
data = json.loads(raw)
except json.JSONDecodeError as e:
raise ValueError(f"Invalid JSON in arguments: {e}") from e
try:
validate(instance=data, schema=TOOL_SCHEMA)
except ValidationError as e:
raise ValueError(f"Schema validation failed: {e.message}") from e
return data
# 用法
args = parse_tool_arguments(tool_call["function"]["arguments"])
weather = get_weather(args["city"], args.get("unit", "celsius"))
Whether data comes from model arguments or MCP structuredContent, use the same parse → validate → business logic. During development, paste schema and actual output into JSONNote for visual validation—faster than print debugging.
Debug schema and model output with JSONNote
The slowest part of Agent development is often not writing prompts—it's debugging model JSON. JSONNote runs locally in the browser, ideal for API responses and MCP messages:
-
1
Format model output
Paste
tool_calls[].function.argumentsinto JSON Formatter to instantly see syntax errors and indentation issues. -
2
Validate tool schema
Paste tool definitions and model arguments into JSON Schema for validation.
-
3
Compare two calls
Use JSON Diff to diff structured output before and after prompt iterations for regression checks.
-
4
Share debug context
Use URL Hash sharing to embed a tool call JSON in a link—colleagues open it to reproduce, data never hits a server.
FAQ
What is the relationship between JSON Schema and Function Calling?
Function Calling's tools[].function.parameters IS JSON Schema. The model generates arguments JSON strings based on the schema; your code parses and validates conformance. They're not parallel concepts—they're the call mechanism and the parameter contract.
What is the difference between JSON Mode and Strict Schema?
JSON Mode only guarantees valid JSON object output, not field/type conformance. Strict Schema constrains token generation so output strictly conforms to the given schema. Use JSON Mode for simple extraction; Strict Schema for complex production structures.
Which JSON Schema version do MCP tool inputSchemas use?
MCP 2026-07-28 requires inputSchema and outputSchema to use JSON Schema 2020-12 with full oneOf, anyOf, and $ref support. outputSchema describes the Server's structuredContent structure.
The model already returned JSON—do I still need manual validation?
Yes. Even with Strict Schema, production code should try/except parse + JSON Schema validate. tool_calls.arguments may miss fields or have wrong types—validation is your business layer's job.
What is the difference between JSON Schema and OpenAPI?
OpenAPI is a full REST API description spec (paths, methods, auth, status codes); its request/response bodies use JSON Schema. Agent Tool Calling only needs a single function's parameter schema—use JSON Schema directly, no need for a full OpenAPI document.
Summary
The core signal of AI Agent development can be summarized as:
Agent I/O goes JSON, tool contracts go Schema, validation goes multi-layer.
JSON Schema runs through Tool Calling parameters, Structured Output response_format, and MCP inputSchema/outputSchema—it's the universal contract language between models and the outside world. Write good schemas, add business-layer validate, debug locally with JSONNote—that's the path from demo to production.