Pattern
How to let an agent call the enrichment API safely
Expose Triguna over MCP, write the four rules an agent needs to call it correctly, cap spend with a credit ceiling, and make it report provenance.
An agent calling an enrichment API has two failure modes a normal client does not: it can invent fields that do not exist, and it can spend money in a loop. Both are avoidable, and neither is solved by a better prompt alone.
Expose the tools
npx triguna mcp --stdio
The MCP server exposes exactly two tools, mirroring the two endpoints:
| Tool | Argument | Returns |
|---|---|---|
triguna.people.profile | profile_id (slug) | A person record |
triguna.companies.details | company_id (slug or numeric id) | A company record |
The key comes from the environment, never from a tool argument, so it cannot end up in a transcript. Full setup: agents and MCP.
Write the four rules down
Agents do far better with the conventions in the repo than inferred from the tool schema. These four cover the failures that actually appear in transcripts:
# Triguna
Use `triguna.people.profile` for a profile URL slug and
`triguna.companies.details` for a company URL slug.
- Slugs, never display names. "Acme Corporation" always 404s.
- `experience[0].positions[0].title` is the current job title.
`experience[0].title` does not exist.
- Every field is nullable. Say "not returned", never invent a value.
- Always report `source` and `fetched_at` back to the user.
Rule two matters more than it looks. An agent that reads a tool schema and reaches for
experience[0].title gets undefined, and a fluent model will often fill that gap with something
plausible rather than reporting nothing.
Give it a resolution step, not a search step
There is no search endpoint. An agent asked to “find the CTO of Northwind” cannot do it with these
tools. It can only resolve identifiers it already has. Make that explicit in the task, or the
agent will attempt increasingly creative slug guesses and burn 404s.
Good task shape:
Here are 42 company URLs. For each, call
triguna.companies.detailswith the slug and report headcount, primary industry, and funding stage. If a field is not returned, say so.
Bad task shape:
Find the headcount of our top 42 accounts.
The second one has an unstated resolution problem inside it, and the agent will improvise.
Read a trace with provenance
tool triguna.people.profile { profile_id: "williamhgates" }
↳ urn:li:member:251749025 Bill Gates · Chair, Gates Foundation
X-Data-Source: store · X-Fetched-At 2026-07-29T22:03:41Z
tool triguna.companies.details { company_id: "microsoft" }
↳ 1035 Microsoft · 221,000 staff · Redmond, US
X-Data-Source: live · X-Fetched-At 2026-07-31T14:02:11Z
The two fetched_at values differ by two days. An answer that says “Northwind has 184 staff” is a
stronger claim than the data supports; “184 staff, retrieved 31 July” is exactly as strong as the
data supports. That is what rule four is for.
Bound the loop
- Concurrency. Cap parallel tool calls. Forty simultaneous lookups is how you meet
429. - Attempts. Retry only
429, and only a bounded number of times.404and402are terminal; an agent retrying them will not stop on its own. - Scope. Pass the agent an explicit list of identifiers rather than a database it can widen.
Evaluating the loop
Before trusting an agent workflow, run it against a fixture set with known answers and check three
things: it used slugs rather than names, it reported nulls as “not returned” instead of filling
them, and it attached source and fetched_at. Those three failing is not a model problem. It
is a missing skill file.
Next
- Agents and MCP: server setup and exposed tools.
- Provenance: what the agent should be reporting.
- Handling partial records: why nulls are the normal case.