FIELD NOTE 008 / TOOL VALIDATION
How to Validate AI Agent Tool Calls with JSON Schema
A practical guide to validating AI tool arguments, enforcing business rules and authorization, and testing consequential agent actions before execution.
By Harrison Ndeke · Published August 25, 2026 · Updated August 25, 2026 · 13 min read
TOOL BOUNDARY
PROPOSE → VALIDATE → AUTHORIZE → EXECUTE
In this article
DIRECT ANSWERValidate every AI agent tool call as untrusted input before execution. Require a named tool, parse its arguments against a closed JSON Schema, enforce formats and bounds in code, then check the authenticated user's authority and current system state. Reject unknown fields, stale proposals, and unauthorized effects. Schema validation proves shape—not truth, permission, or safety.
Key takeaways
- The model proposes; code decides: never execute raw prose or a partially parsed argument object.
- Close the contract: use required fields, enums, formats, numeric bounds, and
additionalProperties: falsewhere the tool contract is meant to be closed. - Validate meaning after shape: a syntactically valid payment, email, or deletion can still be false, stale, or unauthorized.
- Bind authority at execution time: derive identity and permissions from the session, not from model-supplied arguments.
- Log decisions without leaking secrets: keep the proposal, validation result, authorization decision, tool result, and correlation ID—redacted where necessary.
Why is a model-generated tool call a security boundary?
An agent may produce a tool name and arguments that look machine-readable, but the values still came from a probabilistic model and possibly from untrusted retrieved content. A plausible object can name the wrong account, include an unexpected field, exceed an operating limit, or request an action the user never authorized.
The Model Context Protocol specification treats tool results as structured content and advises validation of tool inputs and outputs. OpenAI's structured-output guidance similarly separates schema-constrained generation from the rest of application safety. JSON Schema defines object properties and makes clear that properties are optional unless listed in required; extra properties are allowed unless a schema closes them.
Harrison's public portfolio documents AI assistants, API integrations, validation, and handoff-ready workflows. The Billson Solar AI Sales System, for example, visibly connects a plain-language need to a product recommendation and buying journey. This article presents a defensive implementation pattern. It does not claim that the published system uses the exact schema or validator shown here, nor that it has completed a formal security assessment.
What should a strict tool schema contain?
A schema should describe the smallest action the tool actually supports. Do not expose one broad execute tool when the application can offer narrower operations such as draft_email, send_approved_email, or lookup_order. Narrow tools reduce ambiguity and make authorization easier to review.
{
"type": "object",
"properties": {
"orderId": {
"type": "string",
"pattern": "^[A-Z0-9-]{6,32}$"
},
"reason": {
"type": "string",
"enum": ["customer_request", "duplicate", "fraud_review"]
}
},
"required": ["orderId", "reason"],
"additionalProperties": false
}This contract rejects missing fields, unknown reasons, malformed identifiers, and extra keys. It does not prove that the order exists, belongs to the current user, is refundable, or has not already been processed. Those checks belong in application code after schema validation.
| Control | What it proves | What it does not prove |
|---|---|---|
| type, required | expected fields have expected JSON types | values are accurate |
| enum, const | value belongs to an allowed vocabulary | the selected value is justified |
| pattern, format | value matches a declared syntax | the resource exists or is safe |
| minimum, maximum | number stays inside a technical bound | the user may spend or change that amount |
| additionalProperties: false | unknown keys are rejected | known keys cannot be abused |
How should the validation pipeline run?
- Resolve the tool from an allowlist. Reject a name that is absent, disabled, or unavailable in the current environment.
- Parse once. Treat invalid JSON as a failed proposal; do not repair it with string slicing and then execute the guess.
- Validate against the server-owned schema. The model may select a tool, but it must not supply or relax its own contract.
- Normalize only declared fields. Canonicalize dates, identifiers, and URLs with explicit rules before downstream checks.
- Run business invariants. Verify existence, state transitions, limits, ownership, and duplicate/idempotency keys.
- Authorize the effect. Use authenticated identity, tenant, role, consent, and approval state from trusted application context.
- Execute with least privilege. Give the tool only the credential and scope required for that operation.
- Validate and classify the result. Separate successful effects, safe refusals, transient failures, and ambiguous outcomes before retrying.
When validation fails, return a structured error that the agent can act on without revealing secrets. State the rejected field or policy category and whether the model may revise the proposal. A failed authorization should not become a prompt to find a different tool that reaches the same forbidden effect.
How can this pattern be applied in n8n?
Use the Structured Output Parser when an AI step needs to return a defined object, but keep a separate validation and authorization layer before any side-effect node. The parser can help constrain output shape; it does not replace checks against databases, provider state, tenant rules, or user authority.
A small production flow can use these stages:
- AI step returns a typed proposal only.
- Code or validation node applies the server-owned schema and normalization rules.
- Database/API lookup confirms the referenced resource and current state.
- Policy node evaluates user, tenant, amount, destination, and action.
- Human approval is requested when the effect is consequential.
- Side-effect node executes with an idempotency key and least-privilege credential.
- Outcome and correlation ID are recorded; errors route through an error workflow.
For implementation help, Harrison's n8n workflow development service focuses on validation, API orchestration, retries, fallbacks, and handoff-ready structure.
Which tests catch dangerous tool-call failures?
- missing every required property one at a time
- unknown top-level and nested properties
- wrong JSON types, including numeric strings and nulls
- boundary values just below and above every limit
- valid syntax naming a nonexistent or cross-tenant resource
- stale approval and changed resource state
- duplicate delivery and retry after an ambiguous timeout
- injected instructions inside retrieved documents and tool results
- an allowed tool invoked through a user who lacks authority
- result payloads with unexpected fields, secrets, or excessive size
Test the effect, not only the model response. A refusal sentence is not a security result if a tool still ran. Record whether the external action occurred, whether durable state changed, and whether a retry produced a duplicate.
What is the smallest useful implementation?
- Choose one consequential tool, not the whole agent.
- Split broad operations into the smallest useful tool names.
- Write a closed JSON Schema with required fields, enums, bounds, and no unknown keys.
- Validate arguments with a maintained schema validator in application code.
- Add resource existence, ownership, state, quota, and idempotency checks.
- Bind authenticated identity and authorization outside the model context.
- Place human approval immediately before the side effect where risk requires it.
- Log a redacted proposal, decision, outcome, and correlation ID.
- Run invalid-shape, unauthorized, stale-state, injected-content, and duplicate-delivery tests.
Ship one well-bounded tool before expanding the agent's reach. A small contract that fails closed is more useful than a flexible tool whose safety depends on the model interpreting policy correctly every time.
Executive summary
Treat an AI-generated tool call as untrusted input. Resolve the tool from an allowlist, validate its arguments against a server-owned closed schema, normalize declared fields, enforce business invariants, and authorize the specific effect from trusted identity and current state. Require approval for consequential actions, execute with least privilege and idempotency, then record the result. Structured output reduces parsing ambiguity; it does not prove truth, permission, or safety.
Related reading
- Defend RAG agents against indirect prompt injection before retrieved content can influence tool proposals.
- Decide when human approval is required for external effects.
- Preserve idempotency when a tool call is retried.
- Observe the full operation with correlation IDs and business outcomes.
About the author
Harrison Ndeke is an AI automation developer in Nairobi building documented n8n workflows, agents, chatbots, RAG systems, and API integrations. His public portfolio shows validation, explicit error paths, API orchestration, asynchronous polling, duplicate lookup, and human handoff. This guide presents a defensive pattern. It does not claim a formal security assessment or that every published project uses the exact schema shown here.
Sources, scope, and limitations
Primary sources: JSON Schema object guidance, OpenAI structured-output guidance, Model Context Protocol tool specification, and n8n Structured Output Parser documentation. Provider schema support, JSON Schema drafts, tool interfaces, and model behavior change. Verify the exact runtime, validator, supported keywords, policy engine, and provider documentation before implementation. Schema validation is one control in a broader authorization and execution boundary.