← Back to Payloads
tutorial

Validate Everything: JSON Schema Patterns for Robust AI Tool Integrations

JSON Schema isn't just for APIs. Learn how to use it as a first-class pattern in your AI agent tool pipelines to catch bad data before it breaks your workflow.
Quick Access
Install command
$ mrt install json-schema
Browse related skills

Validate Everything: JSON Schema Patterns for Robust AI Tool Integrations

When you're wiring up AI agents to external tools, the gap between "what the model thought it sent" and "what the tool actually expects" will bite you. Every. Single. Time.

The fix isn't prompting discipline — it's validation at the boundary. And the most practical tool for that job is JSON Schema.

Why JSON Schema, Why Now

Most AI agent tutorials hand-wave input validation or skip it entirely. That works until a model decides to pass `{"count": "five"}` instead of `{"count": 5}` — and your downstream tool chrashes at 2am.

JSON Schema gives you:

  • **Declarative contracts** you can version, share, and test
  • **Built-in generators** for Python (Pydantic), TypeScript (Zod/Zod-like), Go, and Rust
  • **Self-documenting behavior** — your schema _is_ your docs
  • **Runtime + compile-time** safety in typed languages

The Core Pattern: Tool Input Schemas

Every tool your agent calls should declare its input schema. Here's a practical example:

{

"type": "object",

"properties": {

"query": {

"type": "string",

"description": "Search query, max 200 chars",

"maxLength": 200

},

"limit": {

"type": "integer",

"description": "Number of results, 1-50",

"minimum": 1,

"maximum": 50,

"default": 10

},

"filters": {

"type": "object",

"properties": {

"source": {"type": "string", "enum": ["web", "news", "images"]},

"date_range": {

"type": "string",

"pattern": "^\\d{4}-\\d{2}-\\d{2}$",

"description": "ISO date, e.g. 2024-01-15"

}

},

"additionalProperties": false

}

},

"required": ["query"],

"additionalProperties": false

}

Key moves here:

  • `required` marks non-optional fields so missing params fail fast
  • `additionalProperties: false` catches typos in parameter names
  • `pattern` on date strings prevents garbage dates like `yesterday`
  • `enum` constrains categorical values to known valid options

Validating in Python with Draft-7

from jsonschema import validate, ValidationError

import jsonschema

Use Draft-7 (widely supported, stable)

Validator = jsonschema.Draft7Validator

def validate_tool_input(schema: dict, payload: dict) -> list[str]:

"""Returns list of validation errors, empty if valid."""

validator = Validator(schema)

errors = [e.message for e in validator.iter_errors(payload)]

return errors

In your tool dispatch

errors = validate_tool_input(tool_schema, agent_output)

if errors:

raise ToolInputError(f"Invalid input: {'; '.join(errors)}")

Auto-Generating Schemas from Pydantic

Don't hand-write schemas for complex objects — derive them:

from pydantic import BaseModel, Field

import json

class SearchRequest(BaseModel):

query: str = Field(..., max_length=200)

limit: int = Field(default=10, ge=1, le=50)

filters: dict | None = None

One line to schema

schema = SearchRequest.model_json_schema()

print(json.dumps(schema, indent=2))

This gives you validation _and_ a shareable schema for your agent's system prompt.

The Validation Sandwich

A robust tool integration validates at three points:

1. **Before tool dispatch** — catch bad output from the model before it reaches the tool

2. **At the tool boundary** — re-validate in the tool adapter (models can hallucinate tool call payloads)

3. **At the tool response** — validate what the tool returns before passing it back to the model

Middle layer: tool adapter

class ToolAdapter:

def __init__(self, tool_schema: dict):

self.validator = jsonschema.Draft7Validator(tool_schema)

def dispatch(self, validated_input: dict) -> dict:

errors = [e.message for e in self.validator.iter_errors(validated_input)]

if errors:

raise ValidationError(f"Schema violation: {errors}")

return self._execute(validated_input)

Common Pitfalls

  • **Forgetting `additionalProperties: false`** — allows extra garbage fields to sneak through
  • **`null` vs missing** — use `type: ["string", "null"]` if null is a valid value, not absence
  • **Dates as strings** — always validate format with `pattern` or `$ref` to date-time formats
  • **Number coercion** — JSON numbers and Python integers are safe; strings pretending to be numbers need explicit `pattern` or `format` checks

Related Resources

  • [JSON Schema Core](https://json-schema.org/understanding-json-schema/) — official spec and tutorial
  • [jsonschema Python library](https://python-jsonschema.readthedocs.io/) — full Draft-7/2019-09/2020-12 support
  • [Zod](https://zod.dev/) — TypeScript-first schema validation with inference
  • [Pydantic](https://docs.pydantic.dev/) — Python validation with JSON Schema generation

Next Steps

  • Add JSON Schema validation to one tool in your agent pipeline today
  • Generate schemas from your existing Pydantic/TypeScript types
  • Write a schema for your agent's most failure-prone tool call