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.
The contract
Section titled “The contract”A lookup tool needs four things:
- 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. - 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.
- 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. - A clear answer when the person is unknown. Throw the MCP
not_founderror (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.
A worked example
Section titled “A worked example”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.
What the platform sends
Section titled “What the platform sends”- 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.
Risk classification
Section titled “Risk classification”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
writeordestructiveis 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
readorread_pii.
Side effects and idempotency
Section titled “Side effects and idempotency”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.
When something goes wrong
Section titled “When something goes wrong”The workspace’s settings surface shows the state of the lookup in plain language, including the latest outcome recorded against the designated tool:
| Outcome | Meaning |
|---|---|
resolved | Your tool answered with a customer reference. |
not_found | Your tool answered, and does not know this person. Normal. |
no_designation | No lookup is designated for this channel yet. |
tool_not_found | The designated tool is no longer offered by the connection. |
field_missing | The answer carried no value at the designated reference path. |
lookup_gated | Platform policy refused the read. Usually the tool’s risk classification: classify it read or read_pii. |
upstream_error | Your 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.