Skip to main content

Input & Output Controls

Tool Validation

tool-validation limits which tools a client may offer to the model. A request that declares a tool outside your allow list is blocked. It also checks that the JSON schemas you configure for your tools compile, and can ask an external validator model for a second opinion.

It does not check the arguments that the model generates against those schemas. Validate arguments and permissions in your tool executor.

Configuration​

policy-config.yaml
pack:
  name: tool-validation-example-1
  version: "1.0.0"
  enabled: true

policies:
  chain:
    - tool-validation

policy:
  tool-validation:
    declared_tools:
      - web_search
      - database_query
    allow_undeclared: false

Verify the allow list​

Save this JSON test next to policy-config.yaml. The tools go in input.request:

tests/undeclared-tool.json
{
  "name": "blocks-undeclared-tool",
  "input": {
    "messages": [
      {
        "role": "user",
        "content": "Search the documentation."
      }
    ],
    "request": {
      "tools": [
        {
          "type": "function",
          "function": {
            "name": "delete_database"
          }
        }
      ]
    }
  },
  "expected": {
    "verdict": "block",
    "reason_code": "tool-validation.invalid"
  }
}
verdictan policy lint --file policy-config.yaml
verdictan policy test --json

The test passes. Copy it, change the tool name to web_search and the expected result to allow and ok. That test passes too, with a nested tool-validation.ok.

Fields​

FieldTypeDefaultDescription
declared_toolsstring[][]Allowed tool names. An empty list allows every name.
schemasobject{}JSON Schema objects by tool name. Lint and the gateway compile each as Draft 7.
allow_undeclaredbooleanfalseWith false, a name outside declared_tools blocks. With true, it is allowed and recorded.
semantic_validation.enabledbooleanfalseTurns on the external validator call
semantic_validation.endpointstringOpenAI-compatible Chat Completions URL of the validator. Required when enabled.
semantic_validation.modelstring"judge"Model name in the validator request
semantic_validation.secret_key_ref{ env: string }Variable with the validator bearer token
semantic_validation.timeout_msinteger3000Timeout of the validator request

How it works​

  1. The gateway reads each tool name from tools[*].function.name, or from tools[*].name.
  2. With a non-empty declared_tools, names outside the list are undeclared.
  3. Each entry in schemas is compiled as Draft 7. Schemas that do not compile are listed.
  4. A schema that does not compile, or an undeclared tool with allow_undeclared: false, blocks with tool-validation.invalid.
  5. If those checks pass and semantic validation is on, the gateway asks the validator. See Semantic validation. An error or valid: false blocks with tool-validation.invalid.
  6. Otherwise, the request is allowed with tool-validation.ok.
  7. The details record requested_tools, undeclared_tools, invalid_schemas, semantic_validated, and semantic_reason.

Semantic validation​

This optional step sends your tool definitions to another model. Turn it on after the allow list works:

Inside policy-config.yaml
policy:
  tool-validation:
    declared_tools: [web_search, database_query]
    allow_undeclared: false
    semantic_validation:
      enabled: true
      endpoint: https://replace-with-validator-host/v1/chat/completions
      model: replace-with-validator-model
      secret_key_ref:
        env: VERDICTAN_VALIDATOR_API_KEY
      timeout_ms: 3000

The gateway sends a Chat Completions request with the configured model, one user message, and a response_format for a JSON object with valid and reason. The message is a JSON string with declared_tools, schemas, and request_tools.

It reads the result from:

  1. A top-level valid boolean, with an optional reason, or else
  2. A JSON object with valid and an optional reason in choices[0].message.content.

A response without valid, a non-2xx status, a timeout, or invalid JSON counts as a failed validation, and blocks. The cause is in semantic_reason.

Phase and verdicts​

ItemValue
Input phaseThe declared tools, before dispatch. The result reports the phase as pre_request.
Output phaseNot checked
Verdictsallow, block
Passedtool-validation.ok
Failedtool-validation.invalid

Examples​

Allow list only​

Inside policy-config.yaml
policy:
  tool-validation:
    declared_tools:
      - search

Record undeclared tools without a block​

Inside policy-config.yaml
policy:
  tool-validation:
    declared_tools:
      - web_search
    allow_undeclared: true

Limits and failure behavior​

  • Schemas are compiled, not applied to tool call arguments.
  • An empty declared_tools allows every tool. Set the list before you rely on the block.
  • Names must match exactly, including case.
  • Lint rejects a schema that is not valid Draft 7.
  • The validator runs only when the local checks pass. A validator error always blocks. There is no fail-open setting.
  • The validator sees the declared tools, the schemas, and the request tools, not the messages.
  • For pattern and entity checks on the whole request, use Tool Security.

Next steps​