Leadspicker A/B Testing (MCP)
Splits all contacts from a source project into N equal random batches and distributes them across N target projects — one batch per project. Use this for A/B (or A/B/C/…) testing of outreach sequences, messaging variants, or campaign strategies.
Two modes:
- Auto-create mode — target projects don't exist yet. The skill creates them as
{source_name}_version_a,_version_b, … then deletes the original source project once the data is fully redistributed and verified. - Existing-projects mode — the user already has the targets. The skill copies N − 1 batches into them; the source project keeps the Nth batch (others deleted from it), becoming one of the test groups itself.
MCP tools used
| MCP tool | Purpose |
|---|---|
mcp__leadspicker__list_projects |
Resolve project by name or list recent |
mcp__leadspicker__get_project |
Fetch source project name + timezone |
mcp__leadspicker__create_project |
Create a new versioned project (name, timezone) |
mcp__leadspicker__list_contacts |
Page contacts (page_size=100) and verify counts (page_size=1 to read count) |
mcp__leadspicker__copy_contacts |
Copy a batch of contacts to a target project (project_id, target_project_id, person_ids, copy_mode="copy") |
mcp__leadspicker__delete_contacts |
Mass-delete contacts from the source project after copying (project_id, person_ids) |
mcp__leadspicker__manage_project |
action="delete" to delete the source project (auto-create mode only) |
User input
| Parameter | Description | Example |
|---|---|---|
source_project_id |
Source Leadspicker project (resolved by name) | 29953 |
num_splits |
How many equal groups to create | 2, 3, 4 |
projects_exist |
Are the target projects already created? | yes / no |
Project resolution
Display format: always render projects as {name} (#{id}).
- User named a project →
mcp__leadspicker__list_projects(search_query="{name}", limit=5). Confirm; if multiple, ask which one. - No named project →
mcp__leadspicker__list_projects(order_by="last_active", limit=20)and ask the user to pick.
Apply the same resolution for each target project when projects_exist=yes.
projects_exist=yes: resolvenum_splits − 1target projects (the source project becomes the final group). Example for a 3-way split: resolve 2 targets; source project = group C.projects_exist=no: ask fortimezonefor the new projects, or inherit from the source (mcp__leadspicker__get_project(project_id=source_project_id)→timezone).
Mode A — auto-create projects
1) Fetch source project details
mcp__leadspicker__get_project(project_id=<source_project_id>)
Extract name and timezone.
2) Create target projects
For each split (a, b, c, …) up to num_splits:
mcp__leadspicker__create_project(
name=f"{source_name}_version_a",
timezone=source_timezone,
)
Record the returned project id for each.
Letter sequence: a, b, c, d, e, f, … (up to 26 splits, practically 2–4).
3) Split and copy
See Split logic and Copy execution below.
4) Delete the original source project
After all batches are individually verified:
mcp__leadspicker__manage_project(project_id=<source_project_id>, action="delete")
The original is no longer needed — all its data is redistributed.
Mode B — existing projects
1) Validate target projects
For each target project the user named, resolve to an id and verify with
mcp__leadspicker__get_project(project_id=X). Confirm the name back to the user.
2) Split and copy
Copy N − 1 batches to the N − 1 target projects. The source project keeps the final batch.
3) Clean up source project
After all copies are verified, mass-delete the contacts that were copied out:
mcp__leadspicker__delete_contacts(
project_id=<source_project_id>,
person_ids=[<all copied contact IDs>],
)
The source project keeps exactly one batch; each target project has exactly one batch.
Split logic
Fetch all contacts (paginated)
mcp__leadspicker__list_contacts(project_id=<source_project_id>, page=1, page_size=100)
Repeat with page=2, 3, … until the returned items array is shorter than page_size,
or total_fetched >= count. Collect all id values.
Divide into batches
total = len(all_ids)
base = total // num_splits
remainder = total % num_splits
# Shuffle randomly (no fixed seed)
random.shuffle(all_ids)
batches = []
cursor = 0
for i in range(num_splits):
size = base + (1 if i < remainder else 0)
batches.append(all_ids[cursor:cursor + size])
cursor += size
Remainder contacts (when total doesn't divide evenly) go one each into the first batches. Example: 335 contacts, 3 splits → batches of 112, 112, 111.
Show the plan before executing
Present this to the user and get explicit approval:
Source project: {source_name} (#{source_id}) — {total} contacts
Split plan:
Group A → {target_name_a} (#{id_a}) — {size_a} contacts
Group B → {target_name_b} (#{id_b}) — {size_b} contacts
…
After copy:
[Auto-create] The source project (#{source_id}) will be DELETED
[Existing] {size_n} contacts will be DELETED from the source project
(source keeps group {last_letter} with {size_n} contacts)
Proceed? (yes/no)
Copy execution
For each batch (except the last batch in existing-projects mode, which stays in source):
mcp__leadspicker__copy_contacts(
project_id=<source_project_id>,
target_project_id=<target_id>,
person_ids=[<batch_ids>],
copy_mode="copy",
)
After each copy, verify the target project count before moving to the next batch:
mcp__leadspicker__list_contacts(project_id=<target_id>, page=1, page_size=1)
Use the returned count.
The copy is asynchronous — poll with a 3–5-second delay and retry up to 5 times until
count matches the expected batch size. If it never matches, stop and alert the user
before proceeding to the next batch or deleting the source project.
Critical: never delete (or mass-delete from) the source project until ALL batch copies have been individually verified.
Workflow
Step 1 — collect input
Resolve the source project (see Project resolution) and collect num_splits and
whether target projects already exist.
Step 2 — fetch source
mcp__leadspicker__get_project(project_id=<source_id>)— name, timezone.mcp__leadspicker__list_contacts(project_id=<source_id>, page=1, page_size=1)— totalcount.
Step 3 — set up target projects
- Auto-create: create all
num_splitsprojects viamcp__leadspicker__create_project. Record their IDs. - Existing: resolve
num_splits − 1targets by name; verify each withmcp__leadspicker__get_project.
Step 4 — calculate split and show plan
Shuffle, divide into batches, show the full plan (names, IDs, counts, cleanup action).
Step 5 — get user approval
Do not execute anything until the user explicitly confirms.
Step 6 — copy all batches
For each batch:
mcp__leadspicker__copy_contacts(...).- Poll target count every 3–5 s, up to 5 attempts, until
countequals expected batch size. - Only proceed to the next batch once confirmed.
- If a copy fails to verify after 5 attempts, stop and alert the user — do not proceed.
Report each confirmed copy: ✓ Group A → {name} (#{id}): {count} contacts.
Step 7 — verify all target projects
Before any deletion, re-check count on every target project one final time. If anything
looks off, stop and alert the user.
Do not proceed to Step 8 until every target project is confirmed.
Step 8 — cleanup (only after Step 7 passes)
- Auto-create:
mcp__leadspicker__manage_project(project_id=<source_id>, action="delete"). - Existing:
mcp__leadspicker__delete_contacts(project_id=<source_id>, person_ids=[<all copied IDs>]). Then verify the source's remainingcountequals one batch.
Step 9 — report summary
A/B split complete ✓
| Group | Project name | Project ID | Contacts |
|-------|---------------------|------------|----------|
| A | {name}_version_a | {id} | {count} |
| B | {name}_version_b | {id} | {count} |
| … | … | … | … |
Original project: DELETED (auto-create mode)
{count} contacts retained as Group {X} (existing-projects mode)
Common errors
| Symptom | Likely cause | Fix |
|---|---|---|
Tool returns 404 |
Wrong project | Re-list and reconfirm |
Tool returns 422 on copy |
Required field missing | copy_contacts needs target_project_id and person_ids |
Tool returns 409 on create |
Project name already exists | Append _2 to the version name or ask user for a different base name |
Tool returns 429 |
Rate limit | Add 1–2 s delay between calls |
Safety
- Always show the full plan (including cleanup / deletion) and get explicit approval before executing.
- Project deletion is irreversible — verify all batches first.
- Never delete or mass-delete from the source project until every target batch is individually verified.