Offendersearch
Guide · 9 min · for engineers wiring tool calls into an agent or assistant

How to add registry safety checks to an AI agent

Handing a model a search endpoint is ten minutes of work. Making sure it never states a match it cannot support is the actual engineering, and it is what separates a demo from something you can put in front of users.

Define one tool

The model needs a single, narrow tool. Resist the urge to expose every parameter — a wide schema invites the model to invent inputs.

Tool schema

{
  "name": "search_sex_offender_registry",
  "description": "Search US sex-offender registries by name, date of birth, or location. Returns scored candidate records with source citations. Does not return a verdict.",
  "input_schema": {
    "type": "object",
    "properties": {
      "firstName": { "type": "string" },
      "lastName":  { "type": "string" },
      "dob":       { "type": "string", "format": "date" },
      "state":     { "type": "string", "description": "Two-letter code" }
    },
    "required": ["lastName"]
  }
}

Write the tool description for the model, not for you

The description is a prompt. "Returns scored candidate records with source citations. Does not return a verdict." does more to prevent a confidently wrong answer than any amount of system-prompt scolding, because it tells the model what the tool is at the moment it decides how to use the result.

Ground every statement in a citation

Each record carries the registry it came from, the URL of the record page, and when it was last read. Require the model to cite these when it reports a match, and the failure mode changes from a hallucinated assertion to a checkable claim.

Pass matchConfidence and matchBasis through to the model as well. A model that can see the difference between an exact-DOB match and a name-only match will describe it, if you give it the field.

  • Return sources[].registryName and sources[].recordUrl to the model
  • Return matchConfidence and matchBasis, not just the records
  • Instruct: report the basis alongside any match
  • Instruct: never assert identity from a name-only match

Handle the empty result honestly

The most dangerous output an agent can produce here is a confident "no records found" that was actually a partial search. Check per-source status before letting the model characterise a negative, and give it distinct language for "no match across all sources" and "search incomplete".

The part people lose a week to

Models are strongly biased toward reassuring phrasing. If you do not give the agent a way to say "the search was incomplete", it will say "no records were found" instead, because that is the friendlier sentence.

Skip the glue code with MCP

If your client speaks the Model Context Protocol, the MCP server removes the tool-definition and handler layer entirely and the same grounding rules apply.

Questions this raises

How do I stop the model hallucinating a match?

Give it citations and a match basis on every record, and describe the tool as returning candidates rather than a verdict. A model that must cite a registry URL and a match basis has far less room to assert something the data does not support.

Can the agent screen someone automatically?

It can search and present evidence. Keep a human on the adverse decision — Offendersearch is not a consumer reporting agency and results are not a consumer report.

Do I need a separate integration for MCP?

No. The MCP server is an alternative transport to the same API, so the grounding and citation rules in this guide apply unchanged.

Read the API reference