All Build Notes
AI & MCP 8 min read

Why I Built AdPilot MCP Instead of Another Apple Ads Dashboard

The product thesis, safety model, and Laravel stack behind an agent-native way to analyze Apple Ads and RevenueCat data.

By @kovsmakesapps

I spent $183 on Apple Ads and came away with more questions than answers.

The amount was small, but that was exactly the point. As an indie developer, I do not have a giant acquisition budget that can absorb vague decisions. Every keyword, bid, and campaign needs a reason to exist.

Apple Ads could show me what happened inside the ad account. But the questions I actually wanted to ask crossed several boundaries:

  • Which search terms are spending money without producing useful outcomes?
  • Is a campaign underperforming, or is it still too early to judge?
  • Are installs turning into revenue?
  • What changed since the previous period?
  • Which action is worth taking next—and what evidence supports it?

Answering those questions meant moving between Apple Ads, RevenueCat, notes about each app, spreadsheets, and my own memory. The problem was not a lack of dashboards. It was a lack of connected context.

That became the starting point for AdPilot MCP.

The real problem was the decision loop

Most advertising software is built around navigation.

Open a dashboard. Choose an account. Set a date range. Find the campaign. Add filters. Compare a few numbers. Export something. Open another product to understand revenue. Then decide what to do.

That interface is useful when I already know exactly where to look. It is less useful when I am trying to investigate a question.

An AI assistant is naturally good at that second kind of work. I can ask:

Review the last 30 complete days for this app. Find wasted search-term spend, check whether the result is distorted by missing data, and explain the safest next step.

The assistant can reason through the task, but reasoning is not enough. Without authenticated tools, it cannot see my current campaigns. Without durable product context, it does not know the app’s business model or protected brand terms. Without enforced limits, it should not be allowed to change anything.

I did not want a chatbot that guessed. I wanted a controlled bridge between an AI assistant and the real systems behind the decision.

Why MCP instead of another primary dashboard

Model Context Protocol makes it possible to expose structured tools, resources, and prompts to compatible AI clients.

That changed the product shape.

Instead of building another interface that asks users to reproduce their analysis workflow inside AdPilot, I could let them work in the AI client they already use—such as ChatGPT, Claude, Cursor, or Codex—and give that client a well-defined AdPilot toolset.

The MCP server becomes the product interface for questions and operations:

  • read app, campaign, ad-group, keyword, and search-term performance;
  • compare complete periods;
  • combine Apple Ads spend with mapped RevenueCat proceeds;
  • identify data-quality and campaign-mapping problems;
  • find wasted spend and under-delivery;
  • create or update keywords, negatives, bids, campaigns, and ad groups;
  • inspect action history and roll back eligible operations.

The web application still matters. It is the control plane for workspaces, apps, provider connections, team roles, operating limits, MCP clients, built-in skills, scheduled reports, and audit history.

So the thesis is not “dashboards are dead.” It is more specific:

A dashboard is excellent for setup, inspection, and control. An agent is often better for investigation and multi-step work.

AdPilot uses both surfaces for the jobs they handle best.

Connecting Apple Ads to business context

Apple Ads data can tell me about impressions, taps, installs, spend, bids, and search terms. It cannot answer every profitability question on its own.

AdPilot can also connect RevenueCat and map its app-level proceeds to the relevant app. This gives the assistant more useful context when discussing acquisition cost and value recovery.

There is an important boundary here: AdPilot does not pretend that blended app-level RevenueCat proceeds are deterministic campaign-level attribution. Missing, stale, or unmapped data is reported as unknown instead of silently becoming zero.

That distinction matters. An AI-generated answer can sound confident even when its inputs are incomplete. The system has to make uncertainty visible before the model starts explaining the numbers.

Giving an agent tools without giving it unlimited power

The hardest part of an operational MCP product is not registering a tool. It is deciding what the model should be allowed to do—and making sure those rules live outside the model.

AdPilot is designed around a simple principle: an AI request is never its own permission. Actions still have to pass normal application authorization, validation, and configurable operating controls. Changes remain traceable, and supported operations can be reviewed from the product’s history.

That separation is deliberate. Natural-language instructions are flexible. Safety rules should be deterministic.

The useful lesson is the design principle: treat the model as an interface to carefully defined application capabilities, not as the security boundary.

The stack: Laravel as the control plane

AdPilot is built with Laravel 13, with the web application, MCP server, authentication, scheduled work, and product APIs living in one codebase.

Laravel is a strong fit because this product is much more than an AI prompt. It needs conventional application infrastructure:

  • users, workspaces, roles, and authorization;
  • secure provider connections;
  • authentication for remote MCP clients;
  • queues and scheduled synchronization;
  • rate limiting and validation;
  • action history and product limits;
  • scheduled reports and subscription boundaries;
  • tests around every boundary that can spend money or change a campaign.

The backend uses Laravel MCP for the remote tool server and the Laravel AI SDK for AI workflows owned by the application.

The product interface uses Inertia, React, TypeScript, and Tailwind CSS. That gives me a Laravel backend with a modern client-side experience without splitting the product into separate applications too early.

Laravel MCP: tools as application code

Laravel MCP lets me define tools, resources, and prompts as regular application code. They can use the same dependency injection, authorization policies, validation, services, and tests as the rest of the Laravel product.

That is important for AdPilot. An MCP tool should not become a shortcut around the product’s business rules. It should be another interface to the same trusted application layer used elsewhere.

The package also supports metadata that helps an AI client understand whether a capability is read-only or potentially destructive. That improves the client experience, while the application continues to enforce its own rules.

The official Laravel MCP documentation covers the server, client, authentication, tool, resource, prompt, and testing primitives behind this approach.

The Laravel AI SDK: agents with boundaries

AdPilot uses the first-party Laravel AI SDK for AI work that belongs inside the application itself.

One example is scheduled performance reporting. A useful report needs to work from approved product data, produce a predictable structure, respect application limits, and clearly distinguish facts from recommendations.

The SDK makes it possible to express that workflow as an agent class with tools and structured output instead of scattering prompt strings throughout the codebase. AdPilot also uses it for strategy assistance grounded in the information supplied for an app.

The boundary is straightforward: reporting workflows are designed for analysis and recommendations, while operational capabilities remain separately controlled by the application.

This is where I find the Laravel AI SDK most useful: not as a shortcut for sending a prompt, but as an application framework for AI behavior.

At a high level, it gives the codebase:

  • dedicated agent classes;
  • typed tool contracts;
  • JSON-schema structured output;
  • configurable providers and models;
  • queueing, streaming, and testing support;
  • a consistent interface across supported AI providers.

Laravel’s official AI SDK documentation describes agents as the fundamental building block and supports tools, structured output, provider options, embeddings, files, and MCP tools through the same first-party package.

Testing the unexciting parts

The product only becomes useful when the boring boundaries are reliable.

AdPilot uses automated application, static-analysis, formatting, and frontend checks. The most valuable tests are not the ones proving that a page renders. They are the ones covering broad boundaries such as authorization, data isolation, incomplete inputs, operating limits, and the separation between analytical and operational capabilities.

AI makes the interface more flexible. That increases the importance of deterministic tests underneath it.

What I learned from changing the interface

Building AdPilot changed how I think about small SaaS products.

The traditional instinct is to start with pages: dashboard, reports, settings, tables, filters. MCP starts with a different question:

What context and actions must the system expose so another intelligent interface can do useful work safely?

That pushes product design toward clear contracts, truthful metadata, explicit permissions, predictable errors, and auditable operations. Those qualities are valuable even if the AI interface changes later.

The result is still a SaaS product. It still needs onboarding, billing, support, security, and a control plane. But the center of gravity moves away from “How many screens should this have?” and toward “What should the user be able to accomplish?”

The next experiment is distribution

The first version of AdPilot exists because I wanted a better way to reason about my own Apple Ads experiments.

Now the bigger question is whether other indie developers and small app teams want the same workflow: their real acquisition and revenue context available inside the AI assistant they already use, with hard limits and a complete history around every operation.

Building the tools was one experiment. Earning trust is the next one.

That is the part I will keep sharing at @kovsmakesapps: what works, what fails, what the numbers say, and how the product changes when reality disagrees with the original idea.