Skip to content

The customer lookup contract

Before oHallo can verify a caller, link a conversation to a customer, or send a record-bound verification link, it has to find the customer in your own system. That lookup runs first, on every inbound message and every call. This page is the contract for the tool that answers it.

Your customers live in your systems, not in oHallo. oHallo reads a customer from those systems when it needs one and stores only your customer reference. The operator designates, in the workspace settings, which of your tools finds a customer, which tool input carries the email address or the phone number, and which field in the answer holds your customer reference. The platform then calls exactly what was designated, with exactly the argument name you declared, and nothing else.

A lookup tool needs four things:

  1. An input for an email address, an input for a phone number, or both. The names are yours; the operator designates them. The designation is validated against your declared inputSchema, so declare one.
  2. A stable customer reference in the response. The identifier your own systems use for this customer, at a field path the operator can designate. It must not change when the customer renews, moves, or changes contact details.
  3. A declared outputSchema. The designation surface derives the pickable fields from it. A tool without one can still be designated, but the operator has to type field paths by hand and a typo only surfaces at runtime.
  4. A clear answer when the person is unknown. Throw the MCP not_found error (or return an empty object). The platform records that as “your system does not know this person”, which is a normal outcome, not a fault.

The tool declaration:

{
"name": "find_contact",
"description": "Find a contact by email address or phone number.",
"inputSchema": {
"type": "object",
"properties": {
"email": { "type": "string" },
"phone": { "type": "string" }
}
},
"outputSchema": {
"type": "object",
"properties": {
"contact_id": { "type": "string" },
"account_id": { "type": "string" },
"name": { "type": "string" },
"email": { "type": "string" },
"phone": { "type": "string" }
},
"required": ["contact_id", "name", "email"]
}
}

What the platform sends when a new caller phones in, assuming the operator designated phone as the phone input:

{ "phone": "+4574882222", "tenantId": "...", "workspaceId": "..." }

What your tool answers:

{
"contact_id": "CON-001",
"account_id": "ACC-001",
"name": "Mikkel Andersen",
"email": "mikkel.andersen@danfoss.com",
"phone": "+45 74 88 22 22"
}

The platform reads the designated reference field (contact_id here), stores it as the contact’s external reference, and discards the rest of the payload apart from name and company fields used for the operator’s screen. The answer never reaches a language model.

  • Email: the sender address as it arrived on the channel.
  • Phone: the caller’s number as the carrier delivered it, in E.164 form, for example +4574882222.

Match tolerantly on your side: accept common phone formatting differences and compare email addresses case-insensitively. A lookup that only matches one exact byte form will miss real customers.

The operator classifies every tool’s risk in the MCP hub. A lookup tool is typically read_pii, because it returns personal data. The resolution read runs on a server-side reader lane that satisfies the assurance gate for designated tools, so a read_pii classification does not block the lookup.

Two rules follow from the lane being read-only:

  • A tool classified write or destructive is refused as a lookup. Keep the lookup a pure read.
  • A tool with no risk classification at all is treated as a write and refused too. Classify it read or read_pii.

The lookup carries no idempotency key and takes no dispatch claim, because it must be free of side effects. The platform may call it repeatedly for the same person. Do not create records, send notifications, or mutate state in a lookup tool.

The workspace’s settings surface shows the state of the lookup in plain language, including the latest outcome recorded against the designated tool:

OutcomeMeaning
resolvedYour tool answered with a customer reference.
not_foundYour tool answered, and does not know this person. Normal.
no_designationNo lookup is designated for this channel yet.
tool_not_foundThe designated tool is no longer offered by the connection.
field_missingThe answer carried no value at the designated reference path.
lookup_gatedPlatform policy refused the read. Usually the tool’s risk classification: classify it read or read_pii.
upstream_errorYour system returned an error or timed out.

Without a working lookup, the assistant cannot recognise a returning customer, cannot send a verification link to the address on your record, and cannot ask security questions bound to your data. The lookup is the foundation the rest of identity builds on.