The Four-Resource Schema That Makes a Ringba MCP Server Actually Answer ‘Which Publisher Drifted This Week?’

Title header on dark teal background reading about a four-resource schema for Ringba MCP publisher drift.

Share This Post

TL;DR

  • A working MCP server for Ringba call disposition reporting needs four resources, not a pile of tools: calls_enriched, publisher_performance, buyer_payouts, and disposition_drift.
  • The load-bearing decision is pre-joining call_disposition, target_disposition, and IVR digit captures inside calls_enriched. Split them across tools and Claude will hallucinate “call quality looks normal” on a fraud week.
  • The single pattern that catches soundboard fraud: target_disposition='converted' with the IVR qualification digit never pressed.
  • Pipedream’s prebuilt Ringba connector is fine for a solo buyer with one campaign. Three or more buyers with different payout tiers, dispute-defensible logs, or team OAuth access push you to a custom build.
  • Humans still own three decisions: publisher disputes, buyer chargebacks, and anything that looks like consent drift.

Questions this article answers:

If you run a pay-per-call book on Ringba, your Monday audit probably looks like this. Export the Call Log. Pivot by publisher. Eyeball connected rate against billable rate. Try to remember which publisher pushed weird traffic last Thursday. The data you need is in there. Ringba’s UI just doesn’t surface the join that matters: the one between disposition codes, IVR digit captures, and buyer payout state.

An mcp server for ringba call disposition reporting fixes that by letting Claude query the joined data in one round trip. You ask, in plain English, “which publisher’s connected rate outran their billable rate this week?” and the agent names the publisher, the call count, and the dollar exposure. No CSV. No pivot table.

The catch: the schema you expose decides whether the agent answers correctly or makes something up. This guide walks through the four-resource schema, the JOIN that catches soundboard fraud, the auth and rate-limit config, a worked audit prompt, and where humans still belong in the loop.

What Is an MCP Server and Why Build One for Ringba?

An MCP server is a small program that exposes a data source to a language model through a standard protocol, so the model can query that source as part of a conversation. Anthropic’s Model Context Protocol defines three primitives: tools (functions the model can call), resources (data the model can read), and prompts (reusable templates). Under the hood it’s JSON-RPC over stdio or HTTPS.

For Ringba specifically, the server sits between Ringba’s reporting API and Claude. You write it once. You ask questions forever.

The alternatives all fail in a specific way for pay-per-call buyers:

  • Pipedream’s prebuilt Ringba MCP works for single-buyer exploration, but its generic schema doesn’t pre-join disposition with IVR captures, and you can’t add your buyer payout logic.
  • BI dashboards (Looker, Tableau) answer questions you already knew to ask. They don’t let you interrogate a weird week in natural language.
  • Zapier flows are async and one-shot. They can’t hold a conversation across follow-up questions.

Can I Just Use the Pipedream Ringba Connector Instead?

Yes, until you can’t. The Pipedream listing gives you a working Ringba MCP in about ten minutes. For a solo buyer running one campaign with one buyer, that’s enough.

You outgrow it when any of these become true:

  • You have more than three active buyers with different payout tiers.
  • You need dispute-defensible logs (timestamp, prompt, response hash).
  • Your ops team needs shared access through OAuth, not a personal token.
  • You want to expose buyer payout rules as data the agent can reason over.

If two of those are true today, build the custom server. If you’re earlier in the stack and still picking a platform, our Ringba vs TrackDrive comparison covers when each is the right substrate for this kind of automation.

Portrait process-flow infographic in teal and green showing MCP server steps for Ringba call disposition reporting.
The mcp server for ringba call disposition reporting process, step by step.

The Four-Resource Schema: calls_enriched, publisher_performance, buyer_payouts, and disposition_drift

Key Concept: A resource in MCP is read-only data the model can pull into context. A tool is a function the model calls and waits on. For high-volume reporting data, resources are cheaper in tokens and more deterministic in answers. Use resources for the data, tools only for actions.

Here is the four-resource schema. Build these. Skip the rest until you need them.

Resource What it returns Why it exists
calls_enriched Per-call rows with disposition, target disposition, IVR digit array, buyer ID, and payout state joined on call_id The keystone JOIN. Prevents the model from stitching fields in prose.
publisher_performance Per-publisher aggregates: connected rate, billable rate, qualified rate, payout total Lets the agent compare publishers without scanning every call row.
buyer_payouts Buyer payout tiers, qualification rules, dispute windows Gives the agent the rules it needs to recommend tier changes.
disposition_drift Week-over-week deltas on key disposition ratios per publisher The signal-detection layer. What changed this week vs the trailing four weeks.

calls_enriched: The JOIN That Prevents Hallucination

Pre-join call_disposition, target_disposition, and the IVR digit array on the server, not in the prompt. Ringba’s Call Details Report exposes these as separate fields. A naive build wires them as separate tools (get_call_dispositions, get_ivr_captures, get_buyer_state) and asks the model to relate them in natural language. The model will confidently get it wrong.

Pre-joined, every row of calls_enriched looks roughly like this:

“` { “call_id”: “abc123”, “publisher_id”: “pub_47”, “call_disposition”: “connected”, “target_disposition”: “converted”, “ivr_digits_pressed”: [], “buyer_id”: “buyer_9”, “payout_state”: “billable”, “payout_amount”: 42.00, “duration_seconds”: 118 } “`

That empty ivr_digits_pressed array next to target_disposition: "converted" is the row the agent needs to see. It can only see it if you join server-side.

publisher_performance, buyer_payouts, and disposition_drift: What Each One Answers

publisher_performance answers “who is over- or under-performing right now?” Aggregate by publisher_id over a date window. Include connected rate, billable rate, IVR-qualified rate, and total payout.

buyer_payouts answers “what are the rules?” Expose each buyer’s payout tiers, the duration or IVR threshold for billable, and the dispute window. The agent needs this to recommend tier action. Without it, it will invent rules.

disposition_drift answers “what changed?” Compute this week’s converted-without-IVR-qual rate per publisher, subtract the trailing four-week average, and expose the delta. This is the resource the agent reads first on a Monday audit.

The JOIN That Catches Soundboard Fraud: target_disposition=’converted’ AND IVR Digit Never Pressed

Operator Note: The most reliable soundboard fraud signal in pay-per-call is target_disposition='converted' paired with the buyer’s IVR qualification key never pressed. The call hit the buyer. The buyer’s IVR fired. The qualification digit was never captured, usually because there’s a recorded human on the line, not a live one.

Here’s why server-side joining matters so much for this pattern.

If you expose get_call_dispositions and get_ivr_captures as separate tools, a prompt like “audit publisher 47 for last week” forces Claude to:

  1. Call get_call_dispositions for publisher 47.
  2. Call get_ivr_captures for the same window.
  3. Hold both result sets in context.
  4. Try to relate them by call_id in natural language.

Step 4 is where it breaks. With several thousand call rows and the matching IVR rows, the model runs out of working memory before it finishes the join. So it summarizes. “Call quality looks normal this week” is a common false-clean answer in this exact failure mode.

With calls_enriched, the same prompt reads one resource. The model filters rows where target_disposition = 'converted' AND ivr_digits_pressed is empty, groups by publisher_id, and returns something like:

“Publisher 47 had 312 calls marked converted last week with no IVR qualification digit pressed, up from a trailing four-week average of 41. Dispute exposure at the $42 billable rate is roughly $13,100.”

That’s a defensible answer. The first version was a guess in a confident voice. That single architecture choice is the difference between an agent that runs your Monday audit and a demo that embarrasses you in front of a buyer.

Building the Server: Auth Scoping, Rate Limits, and the Claude Desktop Config

Auth: Service Account, Token Scope, and Account ID Strategy

Use a service account, not your personal Ringba login. Generate an API token scoped to read-only access on the specific account IDs you want the agent to see. Pass the account ID as a server config value, not as a tool argument. That keeps the model from accidentally querying the wrong account.

Store the token in an environment variable. Never put it in the prompt. Never let the model see it.

Rate Limits and Pagination: Chunk by Hour, Not by Day

Ringba’s Call Log API paginates. A high-volume week can easily exceed 40,000 rows. If you let the server pull a full week in one request, you’ll either hit the rate limit or time out the LLM’s context window waiting for pagination.

Chunk requests by hour. Cache the hourly results on disk for at least the current day. When the agent asks for “last week,” the server reads from cache, not from the API. Rebuild the cache nightly with a cron job.

This one design choice is the difference between a server that answers in seconds and one that times out.

Local vs Hosted: Claude Desktop Today, OAuth Tomorrow

Start local. Use the Model Context Protocol SDK (TypeScript or Python), run the server over stdio, and register it in claude_desktop_config.json:

“` { “mcpServers”: { “ringba”: { “command”: “node”, “args”: [“/path/to/ringba-mcp/dist/index.js”], “env”: { “RINGBA_API_TOKEN”: “…”, “RINGBA_ACCOUNT_ID”: “…” } } } } “`

Graduate to a hosted HTTPS server with OAuth when more than one person on your ops team needs access, or when your compliance owner wants a centralized audit log. Local stdio servers run as the logged-in user. Fine for one operator, brittle for a team.

Claude Code can scaffold most of this for you. Hand it the Ringba API docs and the four-resource schema above. A non-engineer ops lead can usually get a working local server in two or three working sessions. Production hardening (caching, error handling, logging) adds another week.

The Worked Audit Prompt: How Claude Names the Publisher, the Count, and the Dispute Exposure

Here’s the Monday audit prompt. Copy it, paste it, edit the thresholds for your book:

Audit last week’s publisher performance using the disposition_drift and calls_enriched resources. Flag any publisher whose converted rate exceeded their IVR-qualified rate by more than 15 percentage points. For each flagged publisher, return: publisher ID, total calls, converted-without-qualification count, dollar exposure at the current billable payout, and a recommended payout-tier action. Cite the specific rows you used.

The formulas the agent should use:

  • Publisher billable rate = Billable calls ÷ Total connected calls
  • Disposition drift = (This week’s converted-without-IVR-qual rate) − (Trailing four-week average)
  • Publisher margin exposure = Disputed payouts × Expected dispute win rate
  • Call qualification rate = IVR-qualified calls ÷ Total connected calls
  • Effective cost per qualified call = Total publisher payout ÷ IVR-qualified calls

Expose those formulas as a prompts primitive in the MCP server so the agent always uses the same math. Don’t let it reinvent the formula on each query.

The 9-code IVR disposition map is the upstream piece. Without disposition discipline at the buyer level, no MCP schema will save you.

Where Humans Stay in the Loop: Dispute Defensibility, Chargeback Decisions, and the Audit Trail Your CFO Will Ask For

The Three Decisions That Never Leave Human Hands

The agent flags. The human decides. Three places where this is non-negotiable:

  1. Publisher dispute decisions. The agent surfaces the drift pattern. Your ops lead pulls the recording, listens to a sample, and writes the dispute. A publisher will challenge any adjustment that traces back to “the AI told me so.” Adjustments traced to recordings and disposition logs hold up.
  2. Buyer chargeback adjustments. Financial moves on the buyer side stay manual. The agent can recommend; a human signs off and pushes the credit memo.
  3. Anything that looks like consent drift. TCPA-adjacent patterns (sudden traffic from a new source, mismatched caller IDs, unusual hour-of-day distributions) escalate to your compliance owner, not to an auto-action.

Logging Every MCP Call: The Audit Trail That Defends Disputes

Log every MCP interaction: timestamp, the prompt text, which resources were read, the row count returned, and a hash of the response. Store the logs somewhere your CFO and your compliance owner can reach without asking you for help.

When a publisher disputes a payout adjustment three weeks later, you don’t want to reconstruct the conversation from memory. You want to pull the log and show the exact rows that triggered the flag.

Cap the server to read-only Ringba scope. The agent should never be able to change a payout, pause a campaign, or edit a buyer rule. Those are human actions executed in the Ringba UI, after the human has read the agent’s recommendation.

What This Replaces, What It Doesn’t, and When to Talk to Someone

A well-scoped Ringba MCP server replaces the weekly CSV export, the ad-hoc Looker query, and the Slack thread that starts with “can you pull me last week’s connected rate by publisher.” That’s real time back for a media buyer.

It doesn’t replace a warehouse for trend analysis longer than 90 days. Ringba’s API isn’t the right substrate for that. It doesn’t replace buyer-side attribution modeling. It doesn’t replace your judgment on which publishers to test next.

It also doesn’t replace operational discipline upstream. If your buffer time settings are wrong, or your buyer payout tiers aren’t ranked by EV per call, no agent will save you from the structural problem.

One note on the broader market context. Google’s rollout of unified measurement through Meridian means Smart Bidding increasingly trains on signals deeper in the funnel than the click. For pay-per-call buyers, that makes disposition cleanliness a paid-media problem, not just an ops problem. The cleaner your billable-call signal, the better Smart Bidding optimizes against it.

Frequently Asked Questions

What is an MCP server and why build one for Ringba?

An MCP server is a small program that exposes a data source to a language model through Anthropic’s Model Context Protocol, so the model can read or query that source during a conversation. For Ringba, it lets Claude pull call dispositions, IVR captures, and buyer payouts directly without you exporting CSVs. The reason to build one is interrogation speed. Questions you couldn’t reasonably ask a BI dashboard become a single prompt.

Can I just use the Pipedream Ringba connector instead?

Yes, until you need multi-buyer payout logic, dispute-defensible logs, or team OAuth access. Pipedream’s prebuilt connector is the right starting point for a solo buyer with one campaign. Once you have three or more active buyers with different payout tiers, the generic schema starts producing thin answers and you’ll want a custom build.

Why does Claude keep saying call quality looks normal when it isn’t?

Because your schema probably exposes call disposition and IVR captures as separate tools, forcing the model to relate them in natural language across thousands of rows. It runs out of working memory and falls back to a generic summary. The fix is to pre-join disposition, target disposition, and IVR digits inside a single calls_enriched resource so the model never has to stitch the relationship in prose.

How long does it take to build this if I am not an engineer?

A working local MCP server, with Claude Code doing most of the scaffolding, is realistic in two or three focused sessions for a non-engineer ops lead. Production hardening (caching, rate-limit handling, logging, error states) adds another week of part-time work. If you’re paying an engineer, plan on roughly 30 to 50 hours total for the four-resource schema and a hosted deployment.

Should buyer payout rules live in the server or the prompt?

Put them in the server as a buyer_payouts resource the agent reads. Hard-coding rules in the prompt means every audit prompt repeats them, which burns tokens and lets the rules drift when you forget to update one of the prompts. As a resource, the rules are one source of truth and the agent pulls them only when relevant.

When do I graduate from a local MCP server to a hosted one?

Graduate when more than one person on your ops team needs access, or when your compliance owner asks for a centralized audit log. Local stdio servers run as the logged-in user, which is fine for one operator but brittle for a team. A hosted HTTPS server with OAuth gives you per-user authentication, shared logs, and the ability to revoke access without a laptop reset.


We’re media buyers and ops practitioners sharing what we see in the field. This isn’t legal advice. TCPA and lead-compliance rules vary by state and vertical. Talk to an actual attorney before changing your consent flows or vendor contracts.

If you’re spending $25k or more a month on pay-per-call and you want a second set of eyes on the schema before you ship, or you want help designing the broader AI workflow around it, book a free consultation with Elevarus. We’ll walk through your current Ringba setup, the audits you’d want the agent to run on Monday mornings, and where the human-review handoffs need to live.



Ready to put this into action?

Picture of SHANE MCINTYRE

SHANE MCINTYRE

Founder & Executive with a Background in Marketing and Technology | Director of Growth Marketing.