Mikalai SiliukMS Development
All articles
Article··8 min read

MCP for Mobile App Analytics: A Live Case Study

Four mobile app analytics tools and still no fast answer to why revenue dipped. What an MCP layer changed on a 1,000-DAU app, and what it did not.

analyticsAIarchitecture

Most funded mobile apps end up with four or five analytics tools wired in before anyone asks whether that's too many. Amplitude for behavior. Stripe for revenue. AppsFlyer for attribution. BigQuery for the exports nothing else covers. Each one answers its own question well. None of them answers the question a founder actually asks out loud: why did revenue dip last week. This is a case study in closing that gap with MCP — mobile app analytics you can actually ask questions of, on a production app rather than a demo.

I ran into this on a real-time communication platform I've led mobile delivery on for the past year — 1,000+ daily active users, 3,000+ audio and video calls a month, all under NDA. The stack was already solid: Amplitude, Customer.io, AppsFlyer, and BigQuery, each doing its job. The gap wasn't data. It was the cross-referencing of four exports before anyone could trust an answer.

The full architecture behind those numbers is in the real-time communication platform case study. This piece is about one layer on top of it.

What MCP is, in one paragraph

Model Context Protocol is a standard way to give an AI assistant direct, permissioned access to a system — a database, an API, an analytics tool — so it can query live data instead of guessing from whatever it was trained on. In practice it is a small server — one you can write yourself — that sits between the assistant and your own backend and translates a question into the query your schema understands. Nothing about your data leaves your infrastructure. Nothing gets a new dashboard. The assistant just gains the ability to read what you already have.

That is the whole idea, and the reason it matters here is narrow: the bottleneck in most mobile app analytics stacks is not collection, and not storage. It is the human in the middle, assembling.

The problem MCP actually solves in a mobile app analytics stack

The business had shipped three monetization models in sequence — token-based billing, then tiered subscriptions with daily limits, then moment packs — with thousands of existing users still on each one, which means all three now run in parallel. Revenue grew 40% in the 90 days after the third version launched. Good news, but the honest follow-up question — which of the three models is driving that, and which one is quietly dragging it down — didn't have a fast answer. It lived across a Stripe export, an Amplitude cohort, and a spreadsheet someone updated by hand.

So I wrote our own MCP server — against our backend, not against the vendors. Everything the product knows about itself already lives in that database: subscription state, billing events, call records, usage, the operator panel's own collections. What it lacked was any way to ask it a question without hand-writing a query and post-processing the result in code — and on a document store there is no join and no ad-hoc aggregation across collections, so the interesting questions are precisely the ones a single query cannot express. The server made the whole of it queryable in plain language, which matters more than it sounds: the useful questions rarely sit inside one collection, and a connector wired to a single vendor can only ever answer the part that vendor happens to hold. "Which pricing version is underperforming this week" stopped being a Tuesday-afternoon investigation. It became a question typed into a chat window, answered against live data, not a stale export from Monday.

Worth being precise about what changed, because it is easy to oversell. Nothing about the mobile app analytics itself improved — the data was always there. The queries were always writable. What went away was the assembly step — pulling three sources, lining them up on matching date ranges and user cohorts, and hoping nothing shifted between the first export and the third. That step is where the delay lived, and it is also where the errors lived, because a hand-aligned spreadsheet is a hand-aligned spreadsheet.

Running several pricing models at once is what makes this acute. One model is a single number you can read off a dashboard. Three overlapping cohorts on three different billing mechanics is a join, and joins are exactly what nobody wants to do by hand on a Tuesday. The architectural side of keeping those models separable is a different problem, argued in why payment provider abstraction belongs on day one.

Getting vendor data into a database you own

The obvious objection: most of that data lives in Amplitude and Stripe, not in your own store. It does — and every one of those vendors documents a way out.

  • Amplitude exports event data via its Export API (gzipped JSON, 4 GB per request, so hourly windows for large ranges), via a scheduled Amazon S3 export available even on free plans, or straight into Snowflake, BigQuery or Redshift as a warehouse destination.
  • Stripe Data Pipeline syncs to Snowflake, Redshift, Databricks, S3 or GCS with a refresh every few hours, and carries report-level metrics the plain REST API does not expose.
  • AppsFlyer Data Locker drops raw, user-level attribution data into a bucket you own — S3, GCS, BigQuery or Snowflake — with the Pull API for on-demand slices.
  • Customer.io has a warehouse sync that lands parquet files for deliveries, metrics and people in your S3 or GCS bucket, plus reporting webhooks for real-time events.

None of this is exotic; it is the standard "get your own data out" path each vendor already supports. The work is landing it on a schedule and giving it a schema your MCP server can reason about. That is the actual build — the assistant part is comparatively trivial once the data has a home.

A second example: call reliability

The same pattern showed up on the product side. Calls are the core of the product, and a single dropped call can lose a paying user for good. The platform runs a heartbeat watchdog that monitors every active call server-side and auto-terminates when balance runs out, with a grace period under 60 seconds. Call completion sits above 97% across 3,000+ monthly calls.

That number is easy to state and hard to interrogate. Is 97% stable, or is it drifting? Is the drop concentrated in one region, or one type of device? Before the MCP layer, answering that meant pulling call records out of the backend by hand, lining them up against session data, and a fair amount of squinting. After, it's one query against live call data.

The difference is not that the answer became available. It is that the answer became cheap enough to ask casually. A question that has to be assembled first gets asked once something is already visibly wrong. A question you can simply type gets asked while it is still a two-point drift — which is the only point at which a two-point drift is fixable.

What your mobile app analytics needs first

This does not work on a messy stack, and it is worth saying so before anyone treats it as a shortcut.

Your events have to mean something. This is the one prerequisite that decides whether the whole layer is trustworthy. An assistant querying paywall_shown, paywall_view, and paywall_displayed across three tools will confidently give you three different answers. The naming discipline that makes this layer trustworthy is the same one that makes your own dashboards trustworthy, and it is cheap in week one and expensive in month six — see the day-one event taxonomy most founders skip.

Read access has to be scoped deliberately. The server sits on the database holding your revenue and user data, which is exactly why it gets read-only keys, scoped to the collections and date ranges that answer business questions and nothing else — pointed at a reporting replica rather than the primary, if you have one. This is a normal access-control decision, not a novel one, but it is the decision people skip when they are excited about the demo.

Someone has to still know what the numbers mean. The layer removes the assembly work. It does not remove the judgment. "Revenue is up 40%" and "revenue is up 40% because one cohort's annual renewals landed in the same week" are different sentences, and only one of them is a strategy.

What this changes, practically

It didn't replace the mobile app analytics dashboards — Amplitude, Stripe, and BigQuery still exist for what they're built for. Scheduled reports, alerting, the charts a supervisor keeps open all day: those stay. It replaced the manual assembly step in between: the part where a founder or a supervisor pulls three sources, lines them up, and hopes nothing shifted in the meantime.

This is what AI-augmented delivery looks like once the novelty wears off — not code written faster, but questions answered faster by the person who already knows the system. The delivery model behind that is the same one that shipped the platform in the first place.

This isn't a one-time build. It's the kind of thing that keeps paying off as a product's data surface grows — every new integration is another collection the MCP layer can already read, not another dashboard someone has to remember to check. The stack that started as Amplitude and Stripe is now five tools deep, and the marginal cost of the sixth is a connector rather than a new tab in someone's browser and a new place to forget to look.

If your app already has the mobile app analytics stack and the questions are still taking longer to answer than they should, that's usually not a data problem. It's worth a conversation before it's worth another tool — tell me what you're trying to answer, or see how I work with teams already running in production.