TL;DR: Ask Claude Code about your campaign through the FirstSales MCP analytics, progress and events tools, but force every answer to show its denominator, its sample size and the raw field names it read. The model is fast at summarizing numbers and bad at knowing which numbers deserve trust, so you supply the rules.
#The angle: questions with denominators
"How is my campaign doing?" is a question that invites a pleasant, useless answer. A model will say the campaign is "performing well" or "needs improvement", and neither phrase carries information.
A good analytics question has a denominator. It asks for replies out of how many delivered messages, bounces out of how many sent, positive replies out of how many replies. A number with no denominator is a mood.
This guide is about training yourself, and your agent, to ask questions that have denominators, to say how big the sample is and to refuse metrics that flatter without informing.
FirstSales is an AI SDR and cold email product. Its MCP server exposes read tools for campaign analytics, progress and events, according to the tool list of a connected session.
The CLI has matching commands: campaigns analytics, campaigns progress and campaigns events. As of October 2026, this post was written without running any command against a live account.
Because the README does not publish the fields those tools return, this guide never names one. Instead, it teaches you to make the model list the fields first, which protects you from a model that describes a metric the tool never returned.
If you have not connected the server yet, follow the five-minute MCP setup. To build the campaign you will measure, use the campaign build guide.
#What you need first
You need five things.
- The
firstsales-productMCP server connected and authenticated. - A saved tool list showing that campaign analytics, progress and events are available. Your list is per account and per grant, so check it.
- The CLI installed for a second view, with
FIRSTSALES_API_KEYset in your shell and never typed into a prompt. - A campaign that has sent at least a few messages. Analytics on a campaign with no sends is an empty exercise.
- A written definition of success, made before you look at any number.
That last item deserves a minute. Decide in advance what result would make you continue, change or stop. Without a prior definition, you will interpret every number as supporting what you already believed.
These questions only read data. Nothing in this guide starts, pauses or changes a campaign.
If a number worries you, the next step is a human decision, and the CLI commands firstsales campaigns pause and firstsales campaigns resume exist for it. The guide to starting and pausing campaigns from the CLI covers them.
The Model Context Protocol specification describes how clients discover and call tools, and the Claude Code MCP guide shows how to inspect what a server returns. Remember the safety lines that apply to every FirstSales workflow. Run campaigns readiness and campaigns send-test-email before campaigns start, never paste an API key into a prompt, and treat deletes as permanent.
#The three read tools and their CLI twins
The confirmed MCP session showed three read tools that matter here. The CLI gives you a twin for each, which is useful for cross-checking.
| Question type | MCP tool | CLI twin | Best for |
|---|---|---|---|
| How is it doing overall? | Campaign analytics | firstsales campaigns analytics --campaign <id> | Aggregate results ✓ |
| Where is it in the run? | Campaign progress | firstsales campaigns progress --campaign <id> | Sent versus remaining ✓ |
| What just happened? | Campaign events | firstsales campaigns events --campaign <id> | Individual events, recent first ✓ |
| Which leads are in it? | Not on the confirmed list | firstsales campaigns leads --campaign <id> | Lead-level detail ✗ via MCP |
Use the CLI twin when you want a file you can keep. Redirect the JSON to a folder, and you have a dated record of what the system said.
bashfirstsales campaigns analytics --campaign <campaign-id> --org org_123 --workspace ws_123 --json \ | jq -S . > reports/$(date +%F)-analytics.json
Replace org_123 and ws_123 with identifiers from firstsales orgs list and firstsales workspaces list. The date call is a shell feature that stamps the file name.
Keep a folder of these snapshots. Trends appear when you compare today's file with last week's, and a model can compare two files faster than you can.
flowchart TD A[Question with a denominator] --> B[MCP read tool] B --> C[Model lists field names] C --> D[Model quotes raw values] D --> E{Sample big enough?} E -->|no| F[Report as direction only] E -->|yes| G[Compute rates with stated denominator] G --> H[Compare with CLI snapshot] H --> I[Human decides: continue, change or pause] F --> I
The final box matters. The model reports, and you decide.
#Step 1: make Claude list the fields it received
Open a session where the MCP server is connected. Before any question about performance, ask for a map of the data.
Call the campaign analytics tool for campaign <campaign-id>. List every field name in the result, with its value. Do not calculate anything yet. Do not describe the campaign's performance.
Read the field list as a vocabulary lesson. You learn what the system counts, and you spot names that differ from the terms you use in your head.
Repeat for the progress and events tools.
Call the campaign progress tool and list every field name with its value. Then call the campaign events tool for the last 20 events and list the fields that appear on an event. Do not interpret anything.
Why start here? Because a model that describes data it has not seen listed will fill gaps with plausible language. If the tool returns no field for "meetings booked", the model should not give you a meetings number, and you can only catch it if you know what the tool returned.
Save the field list in a notes file. It becomes your data dictionary, and you can paste it into future sessions so the model starts with the right vocabulary.
When a field name is ambiguous, ask. Does "sent" count attempts or accepted messages? Does "replied" include automatic out-of-office responses?
The tool description in your tool list may answer. If it does not, treat the definition as unknown and say so in your notes.
#Step 2: ask for counts before rates
Counts come first, and rates follow. A rate is a ratio of two counts, and you need both to judge it.
From the analytics result, report these as raw counts with the exact field names you used: messages sent, messages delivered if present, bounces, replies, and unsubscribes if present. If a field is missing, say it is missing. Do not estimate.
The instruction about missing fields is the safeguard. Models are helpful, and a helpful model will estimate to satisfy you. An estimate in a report becomes a fact in a meeting.
Compare the counts with the CLI snapshot.
bashfirstsales campaigns progress --campaign <campaign-id> --org org_123 --workspace ws_123 --pretty
If the MCP answer and the CLI output disagree, stop. Check that both point at the same organization and workspace with firstsales whoami --json, and check the timing, since counts change as sends continue.
Write the counts in a table with the date. The table beats any narrative.
| Date | Sent | Bounced | Replied | Unsubscribed |
|---|---|---|---|---|
| Day 1 | 40 | 2 | 0 | 0 |
| Day 2 | 85 | 3 | 2 | 0 |
The numbers above are an invented example of a format. Your own counts replace them.
The guide to email open rates as a dead metric explains why this table leaves out opens. Mail clients can load tracking pixels automatically, so opens say more about software than about people.
#Step 3: demand the denominator
Now compute rates, and require the model to show its work.
Calculate reply rate and bounce rate. For each, show the formula with the two raw counts and the field names. State which denominator you used and why. If two denominators are plausible, show both.
Denominators matter more than most people realize. A reply rate over messages sent differs from a reply rate over messages delivered, and a rate over people differs from a rate over messages. A campaign with three steps sends several messages to one person, so "replies per message" and "replies per person" tell different stories.
Pick the denominator that matches your decision. If you want to know how a first email performs, use people who received a first email. If you want to know how a program performs, use people who entered the campaign.
Ask the model to flag any rate where the denominator is small, and to refuse a rate when a count is zero.
If any denominator is under 100, label the rate "too early to judge". If a denominator is zero, say "not computable" and do not report a rate.
This habit prevents the most common error in outbound reporting: a headline rate built on a handful of messages. The post on cold email benchmarks and the guide to reply rate benchmarks for 2026 show reference ranges with sources, which are only useful when your own denominator is large enough to compare.
#Step 4: judge the sample size
A small sample can produce any number. Before you celebrate or panic, ask how much uncertainty the sample carries.
Here is a hypothetical example, with invented numbers, to show the scale. Imagine a campaign that sent 200 messages and received 5 replies. The point estimate is 2.5%.
A Wilson score interval at 95% confidence for 5 replies in 200 messages runs from about 1.1% to about 5.7%. That calculation uses the formula published by Edwin B. Wilson in 1927, and it is a standard method for proportions. The range tells you the true rate could plausibly be half of your estimate or more than double it.
Now imagine 1 reply in 20 messages. The point estimate is 5%, which looks excellent. The same method gives an interval from about 0.9% to about 23.6%, which is nearly useless for a decision.
These are hypothetical figures that illustrate the method, and they are not benchmarks. I computed them with the Wilson formula, and you can reproduce them in a few lines of code.
Ask Claude Code to do the arithmetic and show its steps.
For replies out of messages delivered, compute a 95% Wilson score interval. Show the formula, the inputs and the result. Then say, in one sentence, what range of true reply rates this sample allows.
Verify the output yourself on the first few tries. Models make arithmetic mistakes, and a confidence interval from a model deserves a second look. A short script is more reliable than mental math.
pythonimport math def wilson(k, n, z=1.96): p = k / n d = 1 + z*z/n c = (p + z*z/(2*n)) / d m = z * math.sqrt(p*(1-p)/n + z*z/(4*n*n)) / d return round((c-m)*100, 1), round((c+m)*100, 1) print(wilson(5, 200))
The script prints the lower and upper bounds as percentages. Keep it in your repo, and ask the model to run it instead of calculating by hand.
The practical rule is simple. Treat early numbers as direction, and make no decision from a sample with a wide interval. Wait for more sends, or run the next test at a larger scale.
#Step 5: refuse vanity metrics
Some numbers feel good and guide badly. Tell the model which ones to refuse.
Opens. Mail clients can fetch tracking pixels automatically, so an open may reflect software and not a person. The post on bot clicks and fake engagement shows the same problem for link clicks.
Clicks. Security scanners often follow links before a human reads the message. Treat click counts with suspicion.
Total sends. Volume describes your activity, not your results.
"Engagement" scores. A blended score hides what you need to see. Ask for the components.
Averages across campaigns. A good campaign and a bad one average into a mediocre number that describes neither.
Put the refusal in your standing instructions.
Analytics rules for this project - Quote raw field names and values before you interpret. - Show the denominator for every rate. - If a denominator is under 100, say "too early to judge". - Never report opens or clicks as evidence of interest. - Never estimate a missing field. Say it is missing. - Never recommend a change. Describe the data and stop.
The last rule may surprise you. A model that recommends changes from thin data pushes you toward action that the data does not support. Ask for description first, and ask for options as a separate step.
Replies are the better signal, and positive replies are better still. A reply, even a negative one, tells you a human read the message. Sorting replies by intent takes judgment, so read them yourself. The reply handling playbook describes categories and response times.
#Tripwires for deliverability
Analytics should also warn you before a reputation problem grows. Set tripwires, and write them down before launch.
Google's email sender guidelines and its FAQ for senders give two numbers worth knowing. They ask senders to keep the spam rate reported in Postmaster Tools below 0.10% and to avoid ever reaching 0.30%. As of October 2026, those thresholds apply to senders who deliver to Gmail accounts, and the guidelines define a bulk sender as one that sends close to 5,000 or more messages to Gmail accounts in a day.
FirstSales analytics will not show your Postmaster Tools spam rate, so those numbers come from Google's own dashboard. Pair the two views each week: campaign counts from FirstSales and the spam rate from Postmaster Tools.
Unsubscribe handling is part of the same picture, since RFC 8058 defines the one-click mechanism that Google requires for bulk senders. Add tripwires that you can see in campaign data.
- Bounces. A sudden rise in bounces usually means a bad list or a broken domain setup. Pause first, investigate second.
- Unsubscribes. A rise after a copy change tells you the new copy annoys people.
- Replies that complain. Read angry replies on the day they arrive.
- Sends without delivery. If progress shows sends but events show failures, stop and look.
Write the rules as thresholds, such as "pause and review if bounces exceed a level we agree on". Pick your own levels from your list quality and your history, since the README gives no universal bounce limit. The guides on spam complaint rate thresholds and Google bulk sender rules for 2026 explain the context.
When a tripwire fires, a human acts. The model can tell you which tripwire fired and show the events, and you decide whether to run firstsales campaigns pause.
Authentication belongs on this list too. If bounces rise suddenly, check firstsales email-auth status and the SPF, DKIM and DMARC setup guide. A broken record can look like a copy problem when it is a domain problem.
#A daily and weekly question set
Consistency makes numbers readable. Ask the same questions at the same times, and save the answers.
Daily, five minutes.
For campaign <campaign-id>: list the raw counts for sent, bounced and replied. Show the change since yesterday's snapshot in reports/. List any events in the last 24 hours that look like failures. Describe only. Do not recommend.
Weekly, twenty minutes.
Compare this week's analytics snapshot with last week's. For each rate, show the formula, the denominator and the sample-size label. List the three replies I should read first, with the event ids. Then list questions the data cannot answer.
The last line of the weekly prompt is the most valuable. A model that lists what the data cannot answer keeps you honest about what you know.
For a ready-made routine, the later post on a daily outbound standup prompt packages this idea, and the guide to weekly campaign reports with cron and the CLI shows how to schedule the CLI half.
Save every answer. A folder of dated reports lets you answer "when did this start?" with evidence.
Tell the model the date in each session. It does not know your calendar unless you say so, and it may compare the wrong days.
#Reading events without fooling yourself
The events tool returns individual events, which makes it the most detailed and the easiest to misread.
Ask for a table of the last twenty events with the fields exactly as returned, and look at them with your own eyes. A pattern often jumps out that no summary would mention: a cluster of failures at one domain, a run of replies from one segment, a repeated error message.
List the last 50 events as a table with the raw field names as columns. Then group them by event type and show counts. Do not interpret. I will read the table myself.
Group by type, then by recipient domain if the data allows. A bounce cluster at one company's domain tells a different story than bounces scattered everywhere.
Be careful with causation. If replies rose after you changed step two, the change may be the cause, or the audience may differ, or the week may be unusual. The model can list candidates, and only a controlled test can separate them. The guide to the segment validation test shows how to compare groups fairly.
Watch for automatic replies. Out-of-office messages are not interest, and a reply count that includes them overstates engagement. Read a sample of replies before you quote a rate.
When you cite an event in a report, include its identifier so a colleague can find it. A claim with an id behind it can be checked, and a claim without one cannot.
#Turning numbers into decisions
Numbers matter when they change what you do. Use a simple decision table, written before you look.
| Observation | Sample status | Action |
|---|---|---|
| Bounces above your tripwire | Any size | Pause, check list and domain setup ✓ |
| Replies low, sample under 100 | Too early | Wait and keep sending ✗ no change |
| Replies low, sample large, copy unchanged | Enough | Test one change to the offer or subject ✓ |
| Unsubscribes jumped after an edit | Enough | Review the edit, consider reverting ✓ |
| Replies high, mostly negative | Enough | Read replies, revisit audience and claims ✓ |
The table is a template. Replace the actions with your own thresholds and commit it to the repo.
Link each action to a command you control. Pausing is firstsales campaigns pause. Changing copy is the loop in editing a campaign workflow with Claude. Changing the audience is a list question, covered in the terminal import guide.
Separate observation from decision in the conversation. First ask what the data shows. Then, in a new message, ask for two or three options with risks. Last, choose yourself.
For the bigger picture of quality control, the post on automated pre-send checks and the guide to human-in-the-loop cold email both argue for the same split: machines gather, people decide.
#A worked weekly review with invented numbers
Everything in this section is hypothetical. The campaign, the counts and the decisions are made up to show the shape of a review, and none of it came from a real account.
Picture a campaign in its second week. The Monday snapshot shows 600 messages sent in total, 18 bounces and 14 replies. The previous Monday showed 210 sent, 5 bounces and 3 replies.
Ask Claude Code for the week's change, and require counts first. This week added 390 sends, 13 bounces and 11 replies. The weekly bounce count rose from 5 on 210 to 13 on 390, which is about 2.4% against 3.3% of sends. Both are rough, and the model should label them as direction only because the earlier week has a small denominator.
The model then lists three replies to read first. You open them. Two are interested, one is an out-of-office message. So the true reply count for the week is closer to 10 than 11, and one reply is a negative with a request to stop.
You add the opt-out to your suppression list, and you check it with firstsales suppression check. The step takes a minute and protects the person's trust.
Next the model lists what the data cannot answer. It cannot say whether the replies came from the new subject line, since two things changed. It cannot say how many meetings resulted, since that field is not in the tool result. It cannot say whether Gmail users saw the mail in spam, since that lives in Postmaster Tools.
You finish with a short note in the reports folder: three facts, two open questions and one decision. The decision is to keep sending at the same volume for another week and to change nothing, because the sample is too small to justify a change.
Notice what the model did and did not do. It gathered, calculated and organized. It did not choose.
#Connecting the numbers to your list
Analytics often points back at the list. A bounce cluster, a run of wrong-person replies or a spike in unsubscribes can all trace to how the leads were chosen and cleaned.
When you see a pattern, ask the model to group events by recipient domain and, if the data supports it, by company size or title. Then compare the group against your original criteria. The guide to defining an ideal customer profile helps you test whether the audience still matches the plan.
Bounces point at verification. Revisit email verification before sending and catch-all email addresses, and consider whether the file was old. The post on B2B data decay explains how quickly contact data goes stale.
Wrong-person replies point at targeting. If many replies say "not my area", the title filter may be too loose.
Unsubscribes and complaints point at relevance and frequency. Reread the copy with a stranger's eyes, and consider whether the follow-up gaps are too short.
Fix list problems at the source, in the import step, using the habits in the terminal import guide. Adjusting copy to compensate for a bad list wastes effort.
#Keeping a reports folder
A reports folder turns one-off questions into a record.
Name files by date and campaign, such as 2026-10-12-pilot-analytics.json. Keep the raw CLI output and a short markdown note beside it. The raw file is evidence, and the note holds your reading of it.
Ask Claude Code to compare two snapshots and to quote the field names it used. If a field appears in one file and not the other, the model should say so instead of filling the gap.
Commit the folder to git, and keep it free of secrets. Reports contain counts and ids, and they never need a key.
After a month, the folder answers questions you cannot answer today: when bounces started rising, which edit preceded a drop in unsubscribes and how long replies take to arrive.
#Common pitfalls when an AI reads your numbers
The narrative pitfall. Models like a story. Given a rise in replies and a recent copy change, a model will connect them confidently. Ask for alternative explanations every time.
The rounding pitfall. A model may round 2.46% to 2.5% and later compare it to 2.5%. Ask for unrounded values in calculations.
The mixed-window pitfall. Counts from different time windows get combined without a flag. Ask the model to state the window for each number.
The survivor pitfall. Analyzing only campaigns that finished ignores those you stopped. Include paused and stopped campaigns.
The proxy pitfall. A model may treat "delivered" as "read". Delivery means a message reached a mailbox, not that anyone looked at it.
The stale-data pitfall. A model that read the analytics an hour ago may reuse the old numbers. Ask for a fresh call each time you need a current figure.
The invented benchmark pitfall. Asked whether a rate is "good", a model may quote a benchmark from memory. Require a named source, or ask it to say it does not know. The unsupervised-agent risk described in unsupervised AI outbound starts with small fabrications like this.
The over-trust pitfall. After a few good answers, you stop checking. Keep spot-checking against the CLI, and re-run the first-day verification when your tool list changes.
The post on guardrails for email-sending agents and the guide to MCP security for outbound explain why you keep verification habits even when everything seems fine.
#FAQs
#Which MCP tools show campaign performance?
The confirmed session had campaign analytics, progress and events tools. Check your own tool list, since it varies by account and grant.
#What are the CLI equivalents?
firstsales campaigns analytics, firstsales campaigns progress and firstsales campaigns events. They are useful for saving snapshots and cross-checking.
#What fields does the analytics tool return?
This post does not name any, because the README does not publish them. Ask Claude Code to list the field names it received.
#Why list the fields first?
It stops the model from describing a metric the tool never returned. It also builds a data dictionary for later sessions.
#What is a denominator and why does it matter?
It is the count a rate is divided by. A reply rate over messages sent differs from one over messages delivered, so a rate without a stated denominator is ambiguous.
#How many sends do I need before judging a campaign?
There is no universal number. A rule of thumb in this post is to label any rate with a denominator under 100 as too early to judge, and to use an interval for borderline cases.
#What is a Wilson score interval?
It is a standard method for estimating the plausible range of a true proportion from a sample. This post used it for hypothetical examples.
#Are the confidence figures in this post real data?
No. The 200-message and 20-message examples are hypothetical, and the intervals come from the Wilson formula.
#Should I track open rates?
Treat them with suspicion. Mail clients can load tracking pixels automatically, so opens often reflect software.
#Are clicks any better?
Not by much. Security scanners can follow links before a person reads the message.
#What spam rate should I stay under?
Google's sender guidelines ask for a rate below 0.10% in Postmaster Tools and say to avoid reaching 0.30%.
#Does FirstSales show my Postmaster Tools spam rate?
This post does not claim it does. Read the spam rate in Google's Postmaster Tools and compare it with your campaign counts.
#What bounce rate should trigger a pause?
The README gives no universal limit. Choose a threshold from your list quality and history, write it down before launch and pause when you cross it.
#Can Claude Code pause a campaign for me?
The CLI has firstsales campaigns pause, but keep the decision with a person. Let the model report, and run the command yourself.
#How do I stop the model from inventing benchmarks?
Add a rule that every benchmark needs a named source, and ask it to say it does not know when it has none.
#How often should I check analytics?
Check briefly each day and review properly each week. Save a dated snapshot each time.
#Can I compare two campaigns?
Yes, but compare like with like. Different audiences and dates can explain a difference that has nothing to do with copy.
#What about meetings booked or revenue?
If your tools do not return those fields, the model cannot know them. Track them in your CRM or inbox and bring them into the report yourself.
#Does this work with the inbox commands?
The CLI has inbox commands for threads and drafts, which help with reading replies. Keep the same approval habits there.
#What should I read next?
Read the daily outbound standup prompt for a ready routine, and the campaign build guide if you are starting a new campaign.
#Conclusion
Analytics from an AI agent are only as good as the questions you put to it. A question with a denominator, a stated sample size and a list of raw fields gets a useful answer. A vague one gets a pleasant story.
Remember three rules. List the fields before you interpret, show the denominator for every rate, and refuse vanity metrics. Keep the model in the describing role, and make the decisions yourself, including whether to run firstsales campaigns pause.
Build a small habit: a dated snapshot, a short question set and a written threshold for each tripwire. In a month you will own a record that answers questions your memory cannot.
Ready to try it? Connect the server with the setup guide, save today's snapshot with firstsales campaigns analytics, and ask your first question with a denominator in it.