Skip to main content
Glama

waterfall_email_act

Destructive

Run the email waterfall over a TABLE's rows, on the server — op update_rows. Nothing personal goes through this call, and nothing found comes back: name the rows and the columns once, oto reads each row, runs the same cascade as waterfall_email and writes the find into the row.

Cheaper than one call per row: only rows whose status_column is empty are taken, and each gets found (its provider in the status comment), no_match or failed — so a row is never paid twice; call again with the same arguments until remaining is 0 (clear a status to retry that row). no_match is written only when a provider answered without finding and none failed: a row whose steps failed or never ran stays empty, its code in errors. Rows with the same inputs share ONE lookup. Up to 8 rows run in parallel; a call that runs out of time says stopped: "time_budget" and leaves the rest pending. ⚠️ The asynchronous steps (dropcontact, fullenrich, lemlist, pipecorn) are left out here — they would answer after the row is written; the one-contact tool collects them. The answer is counts plus errors: [{row_id, code}]; dry_run reads the rows, counts the lookups and returns the first one's plan, calling nothing. From a hosted agent, a step whose tool the agent may not call is skipped and its rows stay pending (tool_not_in_job, not a quota): the answer then names them (missing_tools) with the owner's one-click fix.

Tool call template

Replace each placeholder with a value matching the input schema. Only required parameters are included; add optional parameters as needed.

{
  "id": 1,
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "arguments": {
      "op": "<op>",
      "datastore": "<datastore>",
      "inputs": "<inputs>",
      "output": "<output>",
      "status_column": "<status_column>"
    },
    "name": "waterfall_email_act"
  }
}

Input Schema

NameRequiredDescriptionDefault
opYes`update_rows`.
_orgNoOrg (id) de CET APPEL. `oto_list_orgs()`.
rolesNo
_groupNoÉquipe (id) de CET APPEL, sous son org parente.
filterNodata_rows filter grammar; `{}` = every row not yet treated.
inputsYes{input: column} — inputs are `first_name`, `last_name`, `full_name`, `domain`, `company_name`, `linkedin_url`. Map every column you have: more inputs open more (and cheaper) steps.
outputYes{field of the find: column} — `email`, `status`, `all`, or `provider`.
_run_idNoOBLIGATOIRE à chaque appel dès `run_start` ou `data_claim_next` : sans lui, l'écriture sur une ligne réservée est refusée. Hérité seulement si le serveur tient un run actif — n'y compte pas.
dry_runNoread and plan only — nothing called, nothing written.
qualifyNo
row_idsNothe rows to run (at most 50). Exclusive with `filter`.
_projectNoProjet (id) de CET APPEL — jeton PRIMAIRE. `oto_project(op='list')`.
_instanceNoInstance de connecteur PRÉCISE (un credential exact). `oto_instance(op='list')`.
datastoreYesthe table, by name or number.
providersNothe steps to try, in order, for these rows (see `waterfall_email`).
batch_sizeNorows per call with `filter` (1-50, default 25).
qualify_minNo
technologiesNo
apify_max_usdNo
status_columnYeswhere found | no_match | failed is written.
max_paid_stepsNo
people_per_rowNo

Schema Changelog

Changes observed during successful MCP inspections.

No schema history has been recorded yet.

TDQS

A4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the destructive/openWorld annotations: it discloses that no personal data transits the call, that findings are written into `status_column` as found/no_match/failed, the precise no_match guard condition, that identical inputs share one lookup, that up to 8 rows run in parallel, and that a timeout yields `stopped: "time_budget"`. It also flags the excluded async steps (dropcontact, fullenrich, lemlist, pipecorn) and the hosted-agent `tool_not_in_job` / `missing_tools` path — none of which the annotations convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The purpose is front-loaded, which is right, but the body is a dense wall of nested clauses and backticked fragments ('a row whose steps failed or never ran stays empty, its code in errors'). The final hosted-agent paragraph describes a narrow edge case at a length disproportionate to its frequency.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description usefully documents the return shape (counts plus `errors: [{row_id, code}]`, `remaining`, `stopped`), the retry loop, and the dry_run plan — exactly the gaps a caller would otherwise hit. It falls short only on the long tail of tuning parameters, leaving an agent to guess at `providers`, `max_paid_steps`, and `qualify`.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 68% schema coverage the schema already carries much of the meaning, and the description mostly reinforces it (status_column lifecycle, dry_run). Many of the 22 parameters — providers ordering, qualify/qualify_min, technologies, max_paid_steps, people_per_row, batch_size, the _org/_group/_project scoping params — get no treatment in the description, so the coverage gap is not compensated.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb and resource ('Run the email waterfall over a TABLE's rows, on the server') and pins the op to `update_rows`. It distinguishes itself from the single-contact path ('the one-contact tool collects them'), though it never names `waterfall_email` outright as the alternative, so the routing contrast is inferable rather than explicit.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives concrete operating rules: only rows with an empty `status_column` are taken, call again with the same arguments until `remaining` is 0, clear a status to retry a single row, `dry_run` plans without calling. It also explains the filter/row_ids exclusion. What's missing is a direct statement of when to prefer `waterfall_email` or `waterfall_person_act` instead.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.

Resources