Skip to main content
Glama

Exa Find People

exa_find_people
Read-only

Use AFTER companies have been identified (company-find step in the same agent, user named a target, CRM lookup, etc.) to surface specific decision-makers. Results are always LinkedIn URLs.

Before composing a search, call get_skill_guide('exa_find_people') — it owns the query vs system_prompt split that decides whether results come back useful or noisy (exclusions in query backfire; they belong in system_prompt).

results holds only people who matched your query + system_prompt; non-matches come back in rejected as {name, reason} with no URL. Put exclusions and preferences in system_prompt and act on what returns — don't re-filter the results yourself.

Pass company_domain or company_linkedin_url whenever you have one. A search carrying either is answered by a people database that filters on that identifier, so it cannot return someone at a same-named company. Without one, the search falls to a name-matched provider and everything below applies.

On that name-matched path, a search naming a company drops anyone whose indexed record places them at a differently-named employer — a check the match verdict does not perform, since it weighs the whole search intent at once and passes near-namesakes, returning a founder of 'Acmely' for an 'Acme' search. The check reads the indexed employer, not summary.current_company, which is a model's reading of profile prose and routinely echoes the company you searched for back at you; it also ignores roles known to have ended, so a job someone left is not current.

That path judges against a profile snapshot (refreshed ~weekly), not live reality, so someone who changed jobs since the last crawl can still pass. Two shapes slip through: a longer name that starts with the one you searched ("Acme" admits "Acme Robotics"), and a profile resolved to no indexed record, which falls back to the extracted name. Nothing downstream re-checks — which is why an identifier is worth passing.

Accepts a list of ExaPeopleSearch — pass one for a single-company lookup, or N for a batch, fanned out in parallel (max 5 concurrent, since the name-matched provider has shown 5xx instability under bursty load). Each search routes on its own, so one batch can be served by both providers. Each call retries once on 5xx inside the HTTP client.

An identifier-pinned search matching more people than can be returned at once comes back in its own slot as {error, query} asking you to narrow by titles (and locations, at a multinational); the rest of the batch is unaffected. Re-send that one search narrowed.

Costs 0.5 Sliq credits per search that returns without error, whichever provider served it, so an empty result set still charges (the call was made). Free on BYO Exa (a connected Exa key). Soft-fails on insufficient credits: the data is returned and the charge is capped at the remaining balance. List of per-search result dicts in input order. Each is either {results: [...], rejected: [...]} on success, or {error: '...', query: '...'} on failure (after the in-client retry). results entries are {name, url, score, summary} with url always linkedin.com and summary holding name, current_title, current_company. rejected entries are {name, reason} only.

A search pinned by company_domain / company_linkedin_url is filtered on the employer and on titles, so it returns no score, no ordering, and no seniority_level / match_reasoning — those come from the per-profile read that only the unpinned path runs, and are absent rather than guessed. Don't infer seniority from position in the list; read the titles.

On insufficient Sliq credits the batch is refused before running: it raises InsufficientCreditsError rather than returning per-search slots.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
persistNoDefault True — in an agent, matched people are saved and linked as person rows automatically (see `list_name`). Pass False only for a read-only lookup the user doesn't want on a list.
agent_idNoOptional — a specific agent to save the matched people into. Omit it to use the running agent, which is the usual case. Only a throwaway lookup outside any agent returns results without saving.
searchesYesList of `ExaPeopleSearch` objects. Each has its own `query` + optional `system_prompt`. For a single-company lookup, pass a list of one.
list_nameNoShort kebab slug naming the Output-tab list bucket (e.g. 'acme-execs'). When this runs in an agent, matched people are saved and linked as `agent_search_results` person rows automatically — deduped by profile, re-runs update in place; `list_name` names their list, and absent it they land in the 'default' list. Query them by reference with `query_search_results` instead of re-typing URLs from `results`. The `results` return is unchanged either way.
num_resultsNoCandidates Exa retrieves and ranks per search before the match filter runs. Default 10; max 100. Matches cluster at the top of Exa's ranking, so 10 usually holds the right people for a well-formed query; the returned `results` are shorter after filtering. If `results` is thin and `rejected` is long, reword the query (the reject reasons say how) rather than raising this — the tail ranks are lower-relevance anyway.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed2 schema fields changed
    • changedInput schema / properties / persist / description
      Previous value: -"Default True — in an agent, matched people are saved and linked\nas person rows automatically (see `list_name`). Pass False to return\nresults without saving, for a flow that folds these people into\nanother row instead — e.g. a company-find that nests them under each\ncompany row via `record_search_results`, where a standalone person\nlist would duplicate people already shown under their company."New value: +"Default True — in an agent, matched people are saved and linked\nas person rows automatically (see `list_name`). Pass False only for a\nread-only lookup the user doesn't want on a list."
    • addedInput schema / properties / searches / items / properties / locations
      Added value: +{
      +  "anyOf": [
      +    {
      +      "items": {
      +        "type": "string"
      +      },
      +      "type": "array"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "Places the person must be based in, by country, state or city name, e.g. ['United States'] or ['Texas', 'Colorado']. Entries are OR-ed, and the filter applies whichever provider serves the search. Spell states out: a two-letter code is read as a country, so 'CT' does not mean Connecticut. At a multinational this is what keeps overseas staff out of the results — naming a place in `query` or `system_prompt` does not filter a search pinned by `company_domain` / `company_linkedin_url`."
      +}
  2. Changed4 schema fields changed
    • addedInput schema / properties / agent_id
      Added value: +{
      +  "anyOf": [
      +    {
      +      "type": "integer"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "Optional — a specific agent to save the matched people into.\nOmit it to use the running agent, which is the usual case. Only a\nthrowaway lookup outside any agent returns results without saving."
      +}
    • changedInput schema / properties / list_name / description
      Previous value: -"Short kebab slug naming the Output-tab list bucket (e.g.\n'acme-execs'). When this runs in a task, matched people are saved\nand linked as `agent_search_results` person rows automatically —\ndeduped by profile, re-runs update in place; `list_name` names\ntheir list, and absent it they land in the 'default' list. Query\nthem by reference with `query_search_results` instead of re-typing\nURLs from `results`. The `results` return is unchanged either way."New value: +"Short kebab slug naming the Output-tab list bucket (e.g.\n'acme-execs'). When this runs in an agent, matched people are saved\nand linked as `agent_search_results` person rows automatically —\ndeduped by profile, re-runs update in place; `list_name` names\ntheir list, and absent it they land in the 'default' list. Query\nthem by reference with `query_search_results` instead of re-typing\nURLs from `results`. The `results` return is unchanged either way."
    • changedInput schema / properties / persist / description
      Previous value: -"Default True — in a task, matched people are saved and linked\nas person rows automatically (see `list_name`). Pass False to return\nresults without saving, for a flow that folds these people into\nanother row instead — e.g. a company-find that nests them under each\ncompany row via `record_search_results`, where a standalone person\nlist would duplicate people already shown under their company."New value: +"Default True — in an agent, matched people are saved and linked\nas person rows automatically (see `list_name`). Pass False to return\nresults without saving, for a flow that folds these people into\nanother row instead — e.g. a company-find that nests them under each\ncompany row via `record_search_results`, where a standalone person\nlist would duplicate people already shown under their company."
    • removedInput schema / properties / task_id
      Removed value: -{
      -  "anyOf": [
      -    {
      -      "type": "integer"
      -    },
      -    {
      -      "type": "null"
      -    }
      -  ],
      -  "default": null,
      -  "description": "Optional — a specific task to save the matched people into.\nOmit it to use the running task, which is the usual case. Only a\nthrowaway lookup outside any task returns results without saving."
      -}
  3. Changed3 schema fields changed
    • changedInput schema / properties / list_name / description
      Previous value: -"Short kebab slug naming the list bucket (e.g.\n'acme-execs'). Pass together with `task_id`. When set, the\nmatched people are also saved as `agent_search_results` person\nrows under this slug (deduped by profile, re-runs update in\nplace) — query them by reference with `query_search_results`\ninstead of re-typing URLs from `results`. The `results` return\nis unchanged either way."New value: +"Short kebab slug naming the Output-tab list bucket (e.g.\n'acme-execs'). When this runs in a task, matched people are saved\nand linked as `agent_search_results` person rows automatically —\ndeduped by profile, re-runs update in place; `list_name` names\ntheir list, and absent it they land in the 'default' list. Query\nthem by reference with `query_search_results` instead of re-typing\nURLs from `results`. The `results` return is unchanged either way."
    • addedInput schema / properties / persist
      Added value: +{
      +  "default": true,
      +  "description": "Default True — in a task, matched people are saved and linked\nas person rows automatically (see `list_name`). Pass False to return\nresults without saving, for a flow that folds these people into\nanother row instead — e.g. a company-find that nests them under each\ncompany row via `record_search_results`, where a standalone person\nlist would duplicate people already shown under their company.",
      +  "type": "boolean"
      +}
    • changedInput schema / properties / task_id / description
      Previous value: -"Pass together with `list_name` to save every matched\nperson into this task's Output-tab list. Omit both for a\nthrowaway lookup."New value: +"Optional — a specific task to save the matched people into.\nOmit it to use the running task, which is the usual case. Only a\nthrowaway lookup outside any task returns results without saving."
  4. First observed

TDQS

A4.7/5.0
Behavior5/5

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

Goes far past the readOnlyHint annotation: per-search cost (0.5 Sliq credits, charged even on empty results), BYO-Exa free path, soft-fail with capped charge on insufficient credits, in-client 5xx retry, max 5 concurrent fan-out, provider routing differences, and snapshot staleness (~weekly) that lets job-changers through. This is exactly the operational context annotations cannot carry.

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 summary tag front-loads well, but the body is very long and re-explains behavior already documented in the schema (company-name filtering vs company_domain, titles narrowing, batch semantics). Those repeated passages dilute an otherwise efficient description.

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?

Covers routing, cost, failure modes, batching, and return shapes (via the returns block) with no output schema present. The per-search success/error slot structure and the InsufficientCreditsError behavior are spelled out, leaving nothing material for correct invocation 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 100% (baseline 3), but the prose adds decision-level meaning beyond the schema: the query-vs-system_prompt split and why exclusions backfire in query, the value of passing an identifier, and batch-wide implication of one failing search. It stops short of covering every param, 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?

States a specific verb and resource ('Find people on LinkedIn') plus a precise scope ('for one or more company searches') and pins its position in a workflow ('Use AFTER companies have been identified'). An agent can distinguish it from the many other search/enrichment siblings without opening the schema.

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 when-to-use ('after companies have been identified... to surface decision-makers'), an explicit prerequisite ('call get_skill_guide before composing a search'), and explicit routing conditions (pass company_domain/company_linkedin_url whenever you have one; pass null for cross-company or alumni searches).

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