TL;DR
- Windsurf reaches LeadOcean through one
mcp_config.jsonentry and a browser sign-in. You search for the people, then ask for each one's current work email and its status. - It takes about 15 minutes. The example run spends up to 7 of your 1,000 free records: 3 on search rows, 3 on lookups and 1 on a REST re-check.
- Counts and enum lookups cost 0. A person we hold nothing for is a 404 and costs nothing.
Prerequisites
- A LeadOcean account from app.leadocean.io. The free plan has no card, 1,000 records one-off, and needs a work email.
- Windsurf installed. The Windsurf MCP docs, October 2026, say Enterprise users must turn MCP on in settings, and team admins can allowlist servers.
- Optional, for the REST steps:
curl,jqand a key in your shell as$LEADOCEAN_API_KEY. The MCP steps need no key. The lookup needs theenrichscope, which free keys have.
export LEADOCEAN_API_KEY="paste-your-key-here"Step 1: Add the LeadOcean MCP server
Add one remote entry to Cascade's MCP config. In the Cascade panel, open the ... menu, then the Open MCP config file icon in the MCPs section. Windsurf's docs say a remote HTTP server needs a serverUrl or url field.
{
"mcpServers": {
"leadocean": {
"serverUrl": "https://api.leadocean.io/mcp"
}
}
}Do not add a headers block. LeadOcean signs you in with OAuth 2.1 in the browser, so no key is pasted. The Windsurf docs do not show the Cascade sign-in prompt, so check the server's status in the MCPs section after you save.
On the Devin Local agent, one command adds the server.
devin mcp add leadocean https://api.leadocean.io/mcpThe full setup, including the Devin file paths, is on Connect LeadOcean to Windsurf.
Step 2: Check the email filters for free
Look up the exact strings before you filter. Filters take exact values, and a guess such as "Sales" returns nothing. Ask Cascade for the email type values.
Use leadocean_list_enum_values with name email_type. List the values and say which
one means an address at the person's current employer. Do not call any tool that
spends records.The answer is work. The value work_other is a business address at a different company, usually a former employer, so ask for it deliberately.
Step 3: Count the audience
Size the people you can email before you look anyone up. The example is VP-level sales leaders in the UK with a verified work address.
Use leadocean_count_leads with jobLevel ["VP"], jobFunction ["Sales & Business
Development"], country ["GB"], emailType ["work"], emailStatus ["verified"],
facets false. Report the total and say what email filter it used.The count tool is free however often you call it. Passing emailStatus replaces its default of verified, catch_all_valid and catch_all. So this total is verified work addresses only, not everyone we hold.
Step 4: Search for three people
Search returns thin rows with email flags and no addresses. Keep limit small, because each person returned costs 1 record.
Use leadocean_search_leads with the same filters and limit 3. Show name, job title,
company, email_status and the person_id for each row. Do not call get_lead yet.The REST version is the same filters in a flat JSON body. Filters are arrays, limit runs 1 to 100, and you page with cursor.
curl -s https://api.leadocean.io/v1/people/search \
-H "x-api-key: $LEADOCEAN_API_KEY" -H "content-type: application/json" \
-d '{
"jobLevel": ["VP"],
"jobFunction": ["Sales & Business Development"],
"country": ["GB"],
"emailType": ["work"],
"emailStatus": ["verified"],
"limit": 3
}' | tee search.json | jq -r '.data[].meta.source_ids.person_id'Each row carries its id at meta.source_ids.person_id. There is no name plus domain lookup in the API, so this id is how you get from a search row to an address.
Step 5: Ask for the work email
Pick a row and enrich it with reveal_email set to true. That returns every address we hold for the person, each with a type and a status. It also returns career history when we hold it: past roles, education and certifications.
Use leadocean_get_lead with person_id <id from row 1> and reveal_email true. Give me
the work address at their current employer, its status and its type in a table.
Tell me how many records this cost.Repeat for rows 2 and 3. That is 3 records, and 6 so far with the search.
The reply lists each address with a type and a status. Pick the one whose type is work. A work_other address belongs to a former employer and is the likeliest to bounce. If the person has no work address, the table says so. Do not ask Cascade to guess one.
Keep the spend visible. Ask Cascade to stop after the three lookups and report the records used. A prompt that says "find emails for everyone you found" will keep calling the tool, one record per person.
Step 6: Re-check one lookup over REST
The REST route is one request to a documented endpoint. It returns at most one address, at the person's current employer, and only if it is verified, catch_all_valid or catch_all.
ID=$(jq -r '.data[0].meta.source_ids.person_id' search.json)
curl -s "https://api.leadocean.io/v2/people/email/work?person_id=$ID" \
-H "x-api-key: $LEADOCEAN_API_KEY"This call costs 1 record, even when data comes back null. A 404, where we hold nothing for the person, costs 0. Field detail is on Find a work email.
Step 7: Read the status before you send
Ask Cascade to flag anything weaker than verified.
For each address, say whether it is safe to send to. verified is safe.
catch_all_valid and catch_all can still bounce. Flag everything else. Do not guess
an address from a name pattern.LeadOcean gives no refund for bounces. The status is your only protection.
What you get
The Step 2 and Step 3 results below are real tool runs from 21 October 2026. Both are free. The email type lookup returned seven values.
{
"name": "email_type",
"total": 7,
"values": ["work", "work_other", "work_any", "personal", "other", "unknown", "none"],
"labels": {
"work": "Work (current employer)",
"work_other": "Work (a different company)",
"work_any": "Any work address",
"personal": "Personal",
"other": "Other",
"unknown": "Unknown",
"none": "No email"
}
}The count for VP, Sales & Business Development, country GB, emailType work, emailStatus verified returned this.
{
"total": 819,
"totalIsExact": true,
"distinctCompanies": 640,
"credits": 0,
"sample": 1,
"hasMore": true,
"source": "leadocean"
}There are 819 people in the UK, at 640 companies, who match and whose best email is a verified work address. Treat it as an upper bound: the status on each enriched address is the final word. Your number will differ as the data refreshes monthly.
The lookup in Step 6 returns this shape. It is the response shape from the API reference, with placeholder values.
{
"success": true,
"data": {
"email": "jane.doe@acme.com",
"status": "verified",
"verified_batch_date": "2026-09-14"
}
}When no address qualifies, data is null. That means none that qualify, not that the person has no work email. The whole run costs up to 7 records: 3 for the search, 3 for the Step 5 lookups and 1 for Step 6.
Troubleshooting
| Error | Cause | Fix |
|---|---|---|
| 401 | Missing, wrong or revoked key on a REST call, or the MCP sign-in was not approved | Re-copy the key from app.leadocean.io and export $LEADOCEAN_API_KEY again. For MCP, repeat the browser sign-in. |
| 429 | Above your plan's rate limit (5 a second on Free, 50 on Solo, 200 on Agency), or a fair-use window reached | Wait the Retry-After seconds and send fewer calls. |
| 402 | The 1,000 free records are spent | Free records do not reset. Check GET /v1/account, or move to Solo at $97 a month. |
| Count or search returns 0 | A filter value outside the catalogue, such as emailType: "business" | Call leadocean_list_enum_values and pass the exact string. |
data: null on a lookup | No address at the current employer is verified, catch_all_valid or catch_all | A retry will not change it. It still cost 1 record. Try a personal email or skip the person. |
400 export_limit_rows | An export limit above 50,000 rows | Split the audience by country or headcount band and run several exports. Exports need Solo or above. |
FAQ
Can Windsurf find a work email from just a name and company?
Not in one call. The API has no name plus domain lookup. Search by title and domain, pick the right row, then enrich its person_id.
How many records does one work email cost?
One per lookup. That includes a lookup that returns null. A 404 costs 0. The free plan's 1,000 records cover about 1,000 lookups. Solo is $97 a month and Agency $497 a month, each with a fair-use pace instead of credits. See pricing.
Can I find emails for a list in Windsurf?
Run it per person for a handful. For a list, use the Exports page in the app at app.leadocean.io. It has a filter builder, a column picker, the price before you start and a CSV download. Filter with emailType work and emailStatus verified. Bulk CSV export is not on Free: it starts on Solo.
Is there a skill that does this?
Yes. The Find Work Email skill wraps these steps for Claude. For another editor, see find work emails in VS Code. More recipes are in the blog hub.
Find your first work email in Windsurf, free
Free to start. No credit card. 1,000 records to spend whenever you like.
Get your free API key →