Skip to main content
Glama

LeadMarina

Export leads to a destination

export_leads
Destructive

Push leads into a connected destination: 'close' (CRM — uses the account's saved field mapping), 'ghl' (GoHighLevel sub-account), 'google_sheets' (new spreadsheet, or pass spreadsheet_id for one LeadMarina created before), or a file — 'csv' | 'xlsx' | 'json' (a 7-day download link in the answer; not emailed). Exports EITHER one search's leads (pass search_id) or the whole library (set all=true). Either can be narrowed with the same filter rows as query_leads — with search_id they apply within that search. Leads go out best-ranked first (rank, then id), the order of the leads table. LIMITS PER CALL, which differ by destination because CRMs take one API call per lead: csv/xlsx 50,000 · json 25,000 · google_sheets 5,000 · close/ghl 1,000. For a big library going to a CRM, export csv and import the file instead. If more leads match than the limit, the response sets truncated=true and returns next_cursor — relay that to the user, the export was partial; to send the next batch, call export_leads again with the SAME destination, search_id or all, and filters, plus cursor=next_cursor — for google_sheets also spreadsheet_id from this response, or the next batch goes into a new spreadsheet (up to 50,000 leads a spreadsheet; past that the response has no spreadsheet_id and the next batch starts a new one, or export csv). A next_cursor with not_sent means the destination's time limit cut this batch short: the same call with that cursor sends the rest. An all=true export spread over several calls reads the library live, so a lead that a search running between calls finds again can be skipped or sent twice; for one consistent copy, export the library in a single csv/xlsx (up to 50,000 leads) or json (up to 25,000) call while no search is running. Close, GoHighLevel and a LeadMarina-created sheet passed as spreadsheet_id UPDATE previously exported leads in place (matched by Google CID), never touching the user's own CRM notes/columns — unless update_existing is false (then Close skips leads it already has, and a sheet appends every row); a file or a new sheet is a fresh copy every time — so do not repeat a call that succeeded. Or pass campaign_id instead of search_id to export one advanced search's leads.

Input Schema

NameRequiredDescriptionDefault
allNoExport the whole library instead of one search.
cursorNoContinue an export: the next_cursor a previous export_leads call returned. Pass it with the same search_id/all and filters.
filtersNoOptional query_leads-style filter rows: within the search when search_id is given, across the library with all=true.
search_idNoExport this search's leads.
campaign_idNoOnly this advanced search's leads (an id from run_advanced_search or list_advanced_searches). Not with search_id.
destinationYesWhere the leads go.
sheet_titleNogoogle_sheets without spreadsheet_id: the new spreadsheet's title (up to 100 characters).
spreadsheet_idNogoogle_sheets only: add to this existing LeadMarina-created sheet instead of a new one.
update_existingNoclose, and google_sheets with spreadsheet_id: true (default) refreshes leads already there. false: Close sends only leads it hasn't had yet (the rest are skipped, not duplicated); a sheet appends every lead as a new row.

Output Schema

NameRequiredDescriptionDefault
fileNoFile exports only: the file name.
noteNo
limitNoThe per-call limit that applied, when truncated.
outcomeYesHuman-readable result, e.g. added/updated counts.
warningNoPresent when the per-call limit or this call's time limit left leads unsent: what happened and how to send them. Leads the destination refused are not covered here — outcome counts them as failed.
exportedYesLeads sent to the destination.
not_sentNoLeads of this batch the destination's time limit did not reach.
truncatedNoTrue when more leads matched than this destination's limit — the export was PARTIAL.
next_cursorNoPresent when the per-call limit or this call's time limit left matching leads unsent: pass it as cursor, with the same destination (for google_sheets, plus the spreadsheet_id this response returned), search_id/all and filters, to send them. It does not offer again a lead the destination refused (counted as failed in outcome).
data_sourcesNoWhere the sources, licences and notices are for emails and owner names that may come from open datasets and public records. Pass it on with any of this data you share.
download_urlNoFile exports only: 7-day download link.
spreadsheet_idNoGoogle Sheets only: pass it as spreadsheet_id to send the next batch into this same spreadsheet. Absent once the spreadsheet holds 50,000 leads.
spreadsheet_urlNoGoogle Sheets only: the spreadsheet the leads went to (it does not expire).

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed2 schema fields changed
    • changedOutput schema / properties / next_cursor / description
      Previous value: -"Present when the per-call limit or this call's time limit left matching leads unsent: pass it as cursor, with the same destination, search_id/all and filters, to send them. It does not offer again a lead the destination refused (counted as failed in outcome)."New value: +"Present when the per-call limit or this call's time limit left matching leads unsent: pass it as cursor, with the same destination (for google_sheets, plus the spreadsheet_id this response returned), search_id/all and filters, to send them. It does not offer again a lead the destination refused (counted as failed in outcome)."
    • addedOutput schema / properties / spreadsheet_id
      Added value: +{
      +  "description": "Google Sheets only: pass it as spreadsheet_id to send the next batch into this same spreadsheet. Absent once the spreadsheet holds 50,000 leads.",
      +  "type": "string"
      +}
  2. Changed2 schema fields changed
    • addedInput schema / properties / sheet_title
      Added value: +{
      +  "description": "google_sheets without spreadsheet_id: the new spreadsheet's title (up to 100 characters).",
      +  "type": "string"
      +}
    • addedInput schema / properties / update_existing
      Added value: +{
      +  "description": "close, and google_sheets with spreadsheet_id: true (default) refreshes leads already there. false: Close sends only leads it hasn't had yet (the rest are skipped, not duplicated); a sheet appends every lead as a new row.",
      +  "type": "boolean"
      +}
  3. Changed1 schema field changed
    • addedOutput schema / properties / spreadsheet_url
      Added value: +{
      +  "description": "Google Sheets only: the spreadsheet the leads went to (it does not expire).",
      +  "type": "string"
      +}
  4. Changed1 schema field changed
    • addedInput schema / properties / campaign_id
      Added value: +{
      +  "description": "Only this advanced search's leads (an id from run_advanced_search or list_advanced_searches). Not with search_id.",
      +  "type": "string"
      +}
  5. Changed1 schema field changed
    • addedOutput schema / properties / data_sources
      Added value: +{
      +  "description": "Where the sources, licences and notices are for emails and owner names that may come from open datasets and public records. Pass it on with any of this data you share.",
      +  "type": "string"
      +}
  6. Changed5 schema fields changed
    • addedInput schema / properties / cursor
      Added value: +{
      +  "description": "Continue an export: the next_cursor a previous export_leads call returned. Pass it with the same search_id/all and filters.",
      +  "type": "string"
      +}
    • changedInput schema / properties / filters / description
      Previous value: -"With all=true: narrow the library using query_leads-style filter rows."New value: +"Optional query_leads-style filter rows: within the search when search_id is given, across the library with all=true."
    • addedOutput schema / properties / next_cursor
      Added value: +{
      +  "description": "Present when the per-call limit or this call's time limit left matching leads unsent: pass it as cursor, with the same destination, search_id/all and filters, to send them. It does not offer again a lead the destination refused (counted as failed in outcome).",
      +  "type": "string"
      +}
    • addedOutput schema / properties / not_sent
      Added value: +{
      +  "description": "Leads of this batch the destination's time limit did not reach.",
      +  "type": "number"
      +}
    • changedOutput schema / properties / warning / description
      Previous value: -"Present when truncated: what happened and how to get the rest."New value: +"Present when the per-call limit or this call's time limit left leads unsent: what happened and how to send them. Leads the destination refused are not covered here — outcome counts them as failed."
  7. Changed4 schema fields changed
    • changedInput schema / properties / all / description
      Previous value: -"Export the whole library instead. Exports write a file, so there is no row cap."New value: +"Export the whole library instead of one search."
    • addedOutput schema / properties / limit
      Added value: +{
      +  "description": "The per-call limit that applied, when truncated.",
      +  "type": "number"
      +}
    • addedOutput schema / properties / truncated
      Added value: +{
      +  "description": "True when more leads matched than this destination's limit — the export was PARTIAL.",
      +  "type": "boolean"
      +}
    • addedOutput schema / properties / warning
      Added value: +{
      +  "description": "Present when truncated: what happened and how to get the rest.",
      +  "type": "string"
      +}
  8. Changed1 schema field changed
    • changedInput schema / properties / all / description
      Previous value: -"Export the whole library instead (max 1000 leads)."New value: +"Export the whole library instead. Exports write a file, so there is no row cap."
  9. First observed

TDQS

A4.7/5.0
Behavior5/5

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

Goes well past the annotations: it discloses per-destination limits, truncation signals (truncated=true, next_cursor, not_sent), update-in-place semantics matched by Google CID that never touch the user's own CRM notes/columns, and the race condition when an all=true export spans calls. This is exactly the mutation/idempotency context that destructiveHint=true and idempotentHint=false cannot convey on their own.

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?

Front-loaded with the destination list, which is good, but the body is a dense single block where cursor/next_cursor rules are restated two or three times (truncated, not_sent, and the consistency note all circle the same mechanic). Everything earns its place content-wise, but the wall-of-text structure makes it harder to scan than it needs to be.

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

Completeness5/5

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

Despite an output schema existing, the description correctly explains the response signals an agent must relay to the user (truncated, next_cursor, not_sent, spreadsheet_id). Combined with the limit table and consistency caveat, nothing needed to call this correctly — or to recover from a partial export — is missing.

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

Parameters4/5

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

Schema coverage is already 100%, so the baseline is 3; the description still adds real meaning — that filters follow query_leads style and apply within the search when search_id is set, and that google_sheets must be passed the returned spreadsheet_id for the next batch or it starts a new sheet. It stops short of describing every parameter (e.g. sheet_title length is left to the schema), so not a 5.

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

Purpose5/5

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

Opens with a specific verb+resource ('Push leads into a connected destination') and enumerates every destination with concrete semantics (close/ghl/google_sheets/csv/xlsx/json). It also distinguishes scope: one search via search_id, one advanced search via campaign_id, or the whole library via all=true — an agent can pick it apart from query_leads/search_leads immediately.

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

Usage Guidelines5/5

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

Explicit alternatives and conditions: 'For a big library going to a CRM, export csv and import the file instead', single-call export recommended while no search is running for a consistent copy, and 'do not repeat a call that succeeded'. It also explains exactly how to continue a truncated export with cursor.

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.