Docs
MCP

Layers Growth MCP

One MCP server that onboards your product, installs Layers measurement, and connects Meta to launch ads, from your repository. Setting it up is one paste into your coding agent, which installs the Layers CLI and runs setup for you. Prices, resources, and skills are on this page.

View as Markdown

Layers Growth MCP is one MCP server that a coding agent uses to run paid growth for your product on the Layers platform. First run is the ten-step paste below. Onboarding saves your product's brief and binds the repository to one Layers organization and project. Layers measurement is the Layers SDK in your app: install_growth_measurement returns the dependency, the app id and the init snippet, and its verify action reports when the first real event arrives. Then the person states a daily ad cap, which set_spend_cap records, and opens the signed Meta connect link on layers://workspace. The agent launches the first Meta campaign with launch_ads, and it calls one named outcome per job.

launch_ads launches in one call. It checks the app's daily spend cap first, runs Meta's validate-only check on every object, creates the campaign, ad sets and ads paused, reads each ad's live text, link and Page back from Meta, and turns them on only when every read-back matches. An app with a store listing gets an App Promotion campaign for installs, a product sold on its website gets a Sales campaign for purchases, and a waitlist or sign-up site gets a Leads campaign on its lead event, such as Lead or CompleteRegistration. halt with the project or organization scope pauses every Meta campaign a launch built, and the kill switch stops every turn-on. Trial cancellation is a preview-then-confirm call.

An Instagram account connects, satisfies onboarding, syncs, and is measured, and its own posts can be remixed. Discovery, delivery, and managed accounts run on TikTok today. No paid lane is certified yet: plan_paid_campaign refuses every platform until the Paid Growth lane ledger records a live-certified row for that lane.

Install

Set up Layers for this product: onboard it, install Layers measurement, then connect Meta and launch ads.
1. Install the CLI: run `npm install -g @layers/cli`.
2. Check that the README opens with a plain sentence saying what this product is, and write one if it does not. Setup sends that single line as the product brief, and it stops with exit code 1 when it cannot find one.
3. Set it up: run `layers setup` from this repository. It prints one line, "Send this to the person: <link> (code <code>)". Send me that link and code; I tap the link, check the code matches, and tap Allow. It also opens a browser on this machine when there is one, and either way finishes the sign-in. The link works for 15 minutes, and running `layers setup` again after a restart resumes the same link. It writes the `.mcp.json` entry and the Layers skill into the repo and stores the session in the OS credential store, so nothing secret lands in the repo. On a machine with no OS credential store, such as a Linux cloud computer, run `layers setup --allow-file-credentials` instead, which keeps the session in a private 0600 file. If it asks for the product's public URL, which is its website, its App Store page, or its Google Play page, pass that question to me. Setup also onboards the product: Layers saves the README line and the public URL as this product's brief.
4. Check the organization: when setup creates the project, its summary names the organization the project is in and says how to put the project in another one. Send me that organization line. If I name another organization, follow those instructions.
5. Read the skill at `.agents/skills/layers/SKILL.md`. If this session cannot load the Layers MCP server, as in a headless run, call a tool with `layers call <tool> '<json>'` and read a resource with `layers call layers://<resource>`; both reach the same tools and resources.
6. Install Layers measurement: call install_growth_measurement with action spec. For an Expo, React Native or Flutter app, send platforms with that framework, such as ["expo"]; the response lists the platforms the spec covers. When the product has a website to promote, send webDomain set to its host name, such as example.com. It returns the SDK dependency, the app id and the init snippet for this app. Add them to the app, run the app once on a simulator, a device or in a browser, then call install_growth_measurement with action verify until it answers reporting.
7. Set the daily cap before any launch: ask me "What is the most you want to spend on ads per day, in US dollars?" and set my answer with set_spend_cap. The cap is a 7-day average, so one day over it is fine.
8. Connect Meta: read layers://workspace. The meta-ads row of paidReadiness.providers carries a signed connect link. Send me that link; I open it and choose the ad account, the Facebook Page the ads run as and, for an app with a store listing, its Meta app. Every Meta ad runs as a Facebook Page. If I have none, the page links to where I create one; when I tell you the Page is ready, send me a new connect link. Wait until that row reads configured.
9. Make the ads: write the primary text and headline and make the images for each market, in that market's language and sized for Meta placements. Save each image inside this repository: launch_ads takes it as media with source local_file and the file's path, and the layers CLI uploads it. An image already at an https address goes as source image_url with that url. Show me the copy and the images before you launch.
10. Launch: call launch_ads with action launch, a dailyBudget within the cap in the ad account's currency, currency, markets and the creatives. An app with a live App Store or Google Play listing gets an App Promotion campaign for installs. A website product, such as a web app, a SaaS, a store or an info product, gets a campaign whose ads link to the website and optimize the conversion its Meta Pixel received in the last 28 days: a Sales campaign for Purchase, else a Leads campaign for a lead event such as Lead or CompleteRegistration from a waitlist or sign-up form. An app with no store listing yet launches only through its website, or waits for the listing. launch_ads returns each blocker with its fix; do the fix and call it again. While Meta reviews the ads, the launch answers status running; call launch_ads with action status and its jobId until it finishes.
Let me know when it is ready.

Paste that into Claude Code, Codex, Cursor, or any coding agent working in your repository: the agent runs the commands and the tool calls. A person taps the sign-in link, answers the daily ad cap question, and opens the Meta connect link.

Setup prints a sign-in link and code for the person to open, and opens a browser when the machine has one. It stores the session in the operating system credential store, or with --allow-file-credentials in a private 0600 file on the machine, so no token, key, or header is written into the repository or into your agent's configuration. layers mcp and layers call are the credential's only readers.

MCP clients read .mcp.json when they start, so the entry setup writes reaches the client on its next start or after /mcp. In the session where setup just ran, layers call <tool> calls the same tools over the same sign-in. Claude Code holds a new repository server pending until you approve that entry once; setup reports project_config_pending_approval and names the exact entry to approve.

Manual setup

If you would rather run the commands in a shell:

npm install -g @layers/cli
layers setup

What setup writes

PathContentsSecret
.layers/project.jsonpublic project ID, public organization ID, environment, issuer, setup versionNo
.mcp.json{ "command": "layers", "args": ["mcp"] } merged under server name layersNo
.agents/skills/layers/SKILL.mdthin pointer to the server-owned skill indexNo
.claude/skills/layersrelative symlink to the canonical skill where symlinks are supportedNo

Every file above is safe to commit. Setup is idempotent: running it again repairs Layers-owned entries, leaves every other MCP server entry byte for byte as it was, and creates no second project. For a client that does not read the repository .mcp.json, setup registers the server through that client's own command, such as codex mcp add layers -- layers mcp.

The tools

Twenty-seven outcomes make up the catalog. Prices are in credits and every charge is quoted before the work runs. The Credits column lists each charged action; anything not listed there is free. tools/list in your session is the authority on what your agent can call: a tool is there because it ships, and a tool Layers withdraws is deleted from the catalog by a release rather than switched off under you.

Three profiles, and a project has to have a profile enabled before its tools admit a call. Growth is the default.

Growth

ToolWhat it doesCredits
select_projectLists your usable projects and current selection, or binds this sign-in to a project so later requests need no selector headers. A person with one project is bound to it on the first request, and tools/list lists every tool before a project is bound. Available to signed-in people0
create_appCreates a Layers app from a name and platform: ios needs iosBundleId, android needs androidPackage, and both needs both identifiers. Returns its App ID and project. Existing apps sharing an identifier must match every requested identifier; exact matches return the oldest app with created: false, and missing or different identifiers are refused. Needs a signed-in organization owner or admin. Works before a project is bound; pass organizationId for an organization where you are an owner or admin0
list_appsLists your organization's live native Layers apps with their App IDs, iOS bundle IDs, Android packages, last event times and ingest (accepted, or revoked after revoke_app_key), one page of 50 at a time. Defaults to the bound organization, or the organization joined first before binding. An MMA API key needs mma:read and sees only apps in its organization and project scope. Works before a project is bound0
get_appReads one app by exactly one of appId or projectId: its identities, store links, store listings, ingest (accepted, or revoked after revoke_app_key) and SDK issuance and revocation state. A signed-in person can read any app they can access. An MMA API key needs mma:read and can read only apps in its organization and project scope. Works before a project is bound0
revoke_app_keyRevokes an app's public App ID, chosen by exactly one of appId or projectId, so Layers stops accepting its SDK events. Event capture refuses the App ID within about two minutes, for builds already shipped too. Events it admitted before that reach every store. Tracking-link clicks, SKAN postbacks and revenue webhooks are separate inputs that a revoke does not stop. Stored events and the app record are kept. The app's TikTok and Google conversion destinations are disabled. Turning the SDK off in the app directory keeps the App ID accepted. This tool refuses it at ingest. A repeat call returns the first revocation time with alreadyRevoked: true. Needs a signed-in organization owner or admin with a project of the app's organization bound. An MMA API key cannot call it0
onboard_productBinds the product, collects the facts no source can supply, writes its brief and store identity, and answers ready on the same call. It needs no social account and starts no background jobs0
manage_growth_landscapePins, removes, or rescopes the tracked accounts, and requests an explicit refresh6 forced incremental refresh; 6 full rebuild
find_growth_opportunitiesReturns the strongest current tests with source evidence, effort, and prior use0 read; 2 per creative preview produced
plan_content_experimentTurns one opportunity into an editable plan with one controlled variable, a target account, a measurement window, and a success gate6 new plan or structural revision
generate_influencerCreates one persona for the project from a gender, an age range, and an optional one-line look, and returns its id and a link to the portrait slate straight away while the portrait is drawn0
add_brand_assetPuts one of the project's own product assets into Layers from a public https URL, so a render has something of yours to composite0
render_contentRenders reviewable content from an approved plan revision or straight from a brief with no plan. One output per call25 static image; 85 slideshow; 200 video; 400 extended video
deliver_content_experimentPrepares a rights-cleared artifact, takes artifact-level approval, and delivers it to a TikTok draft inbox or posts it5 per delivered target
track_growth_experimentRegisters a post you published yourself as an experiment with its hypothesis and source lineage0
review_growth_resultsReads the evidence, records the verdict, and names the next controlled test1 forced provider read
install_growth_measurementPuts the Layers SDK in this product's own repository and confirms it reports, so installs and revenue resolve back to the post that produced them0
generate_tracking_linkMints a named tracking link as a stored row: a label and tags for your own reports, the five UTM fields for the ad network, a payload the app receives on first launch, and a destination that is either the app store or a web address with the click id appended0
archive_tracking_linkTakes one link out of the working inventory, and puts it back. The URL keeps resolving and the clicks keep recording either way0
configure_growth_measurementSets the App Store URL, the Play Store URL, the fallback URL and the clipboard switch on the product's measurement app, which is the fix for the tracking link's only refusal0
manage_bio_pagePublishes a link-in-bio page at <slug>.layers.click made of tracking links, states the buttons on it, edits the five tokens it renders with, or takes it down0
configure_conversions_forwardingPoints one ad platform's conversions destination at the product, says which conversion it counts and which traffic reaches it. It takes no access key: when the destination has none on file the result hands back a signed page a person opens to paste one0
decline_next_stepRecords the person's answer to an offer layers://next made: declined, or not before a date they name. One row per offer, and a later answer overwrites it0
research_tiktok_creatorReads one TikTok creator by handle: followers, posts, bio, bio link, verified and private flags, avatar, profile URL, and the date the account was created1 per call
research_tiktok_creator_postsReads one creator's recent posts, newest first, with views, likes, comments, shares, saves, length, cover and sound1 per call
research_tiktok_searchSearches TikTok for public posts on a topic, with the same numbers plus the poster's handle and follower count1 per call
research_tiktok_hashtagReads one hashtag: post count, total views, average views per post, its momentum against its own history, and recent posts1 per call
research_tiktok_trending_soundsReads the TikTok sound chart as it stands: title, artist, length, post count, whether anybody sings on it, a preview URL, and cover art1 per call
haltStops queued and running work in scope and returns a receipt per target0
cancel_trial_auto_renewalPreviews and confirms cancellation of the trial renewal0
send_feedbackSends a message to the Layers founders, who read every one. It works for a workspace that has run out of credits or has billing paused0

A creative edit changes the script, opening, caption, or tags, and it is free however many times you make it. A structural revision changes the source, hypothesis, controlled variable, format, target account, or schedule, and it costs the same 6 credits as a new plan because the server recomputes the plan. Every revision is recorded and supersedes the previous one.

One render_content call starts one generation and returns one job, so it charges one rate. Rendering more is calling again. An unusable output is refunded. Reading stored results costs nothing, and a forced refresh that causes no provider read creates no debit.

Ad spend is your own money at the provider. It never consumes credits and never hides inside a credit quote, and every campaign runs under a spend authority a human granted.

The daily spend cap is the number you state for your app, set through your agent with set_spend_cap. It is a 7-day average: one day over is fine. create_approved_campaign_draft, launch_approved_campaign and apply_approved_campaign_change are off tools/list and still callable by name.

ToolWhat it doesCredits
set_spend_capSets or changes the bound app's daily spend cap in USD and returns it with the 7-day-average rule and the app's current 7-day average. Needs a signed-in organization owner or admin with the app's project bound; an MMA API key cannot call it0
plan_paid_campaignProduces a mutation-free campaign plan from a proven source or a bounded demand brief, echoing back the caps and stop rules you stated0
start_experimentStarts an experiment from the post the Content Planner already picked: you send the daily budget, Layers supplies the post, the network and the schedule, and it answers with the same plan0
resume_paid_setupContinues the plan a setup handoff belongs to: send the handle the handoff carried, and Layers re-reads the provider and returns the same plan0
create_approved_campaign_draftBuilds the non-delivering TikTok campaign drafts one exact plan describes10 per campaign that reads back complete
launch_adsLaunches Meta ads for the bound app or website in one call: one App Promotion campaign optimizing for installs for an app with a store listing, or, for a website product, one campaign optimizing the event the project's Meta dataset received in the last 28 days: a Sales campaign for Purchase, else a Leads campaign for Lead, CompleteRegistration, SubmitApplication or Schedule. conversionEvent picks another event the dataset received. Each gets one ad set per market with the budget split equally, and one ad per creative in every market whose language it carries. The app's daily spend cap is checked first, every object passes Meta's validate-only check and is created paused, each ad's live copy is read back and must match, then everything turns on. Blockers (no Meta ad account, no Page, no store link, no Meta dataset for a website, a dataset that received none of those events, the cap) come back with their fix. A long launch returns running and a status call with its jobId. A signed-in person only0; Meta bills the ad spend to your own ad account
launch_approved_campaignPreviews or confirms delivery for one campaign, and is also how a paused campaign starts delivering again0; the provider bills the ad spend to your own ad account
apply_approved_campaign_changePreviews or confirms one bounded change to one campaign: move the daily total, or delete the campaign at the provider5 on confirm
create_campaignCreates one campaign on the project's connected Meta ad account, PAUSED, with an optional campaign budget. The engine checks the app's daily spend cap, runs Meta's validate-only check, creates it paused and reads it back. Refused until granular intents ship: under the current Meta safety rules a new campaign launches through launch_ads0
create_ad_setCreates one ad set, PAUSED, under a campaign the project holds: its targeting, budget, optimization goal, bid, schedule and promoted app or pixel. Same engine steps as create_campaign. Refused until granular intents ship: a new campaign launches through launch_ads0
upload_creativePuts one image or video from an https URL into the ad account's media library and returns Meta's imageHash or videoId, recorded in the project's creative library0
create_adCreates one ad, PAUSED, from an uploaded image or video with your primary text, headline, description and link, on the project's bound Facebook Page and its Instagram account. Meta's live copy, link and Page are read back and must match0
change_ad_objectChanges one campaign, ad set or ad: status, budget, schedule, bid, name or targeting. Status ACTIVE is the only change that starts delivery, after the kill switch, a halt, the read-back block for an MMA API key and the app's daily spend cap are checked, and Meta's state is read back0; Meta bills the ad spend to your own ad account
read_ad_objectsReads the stored campaigns, ad sets, ads and creatives with each one's read-back state: matches, mismatch with the fields that disagreed, or not read0

The six granular tools take a network field, meta today, with each network's own fields as its arm of the input. A create is always paused. A project with no connected Meta ad account answers PROVIDER_NOT_READY with a connect link, and a write that outlives the call answers pending; the same call with the same idempotencyKey reads the outcome.

set_daily_budget moves one campaign's daily total. delete_campaign removes the campaign at the provider, including one that is delivering right now, and a deleted campaign cannot be resumed. Both preview for free, both cost 5 credits on confirm, and both report success only after the provider reads the change back.

Managed distribution

A Layers-operated fleet is billed in dollars from the organization's cash wallet, at $150 per account per month. That is separate money from credits.

ToolWhat it doesCredits
plan_managed_distributionQuotes a fleet of Layers-operated TikTok accounts. Quoting reserves nothing and holds nothing0
provision_approved_managed_accountsOrders the exact fleet one plan quoted. This is the call the cash wallet is charged on, at the monthly rate above0
release_managed_accountsPreviews or confirms giving managed accounts back, with what money comes back and what the current period keeps0

MMA (Mobile Measurement Agent)

A studio that measures its app in MMA gets the same numbers in its coding agent. Run npm i -g @layers/cli && layers setup in the app's repository. Setup binds the repository to one organization and one project; in a studio with several apps, layers setup --project prj_<id> names the app. The agent then reads the app's MMA screens as resources (listed under Free resources) and records the product experiments it runs, which show on MMA's Experiments page. Every read and write uses your own sign-in and MMA's own rule: studio membership and access to the app. Approving a recommendation stays a click in MMA.

An agent that runs unattended (a scheduled Claude Code or Codex run, a GitHub Action) signs in with an MMA API key instead. Create one on MMA's API Keys page with Read MMA over MCP and the app it reads, then send it as Authorization: Bearer <key> together with the x-layers-organization-id (org_<uuid>) and x-layers-project-id (prj_<uuid>) headers. For that app the key reads the layers://mma resources, list_mma_experiments, get_mma_experiment, list_mma_reviews, get_mma_ratings, get_mma_cohorts, get_mma_retention, get_mma_insights and get_mma_pockets, and marks its own inbox read with mark_mma_inbox_read. get_mma_studio_brief and run_events_sql also need only Read MMA over MCP (mma:read). get_mma_studio_brief takes no input. An app-scoped key receives only its bound app's brief, without studio-wide decisions or alerts; an org-wide key or a signed-in person receives every app in the studio. The result states scope as app or studio, and mmaUrl opens the studio Brief page. Each write tool below needs one more permission on the key: Manage experiments (experiments:write) for register_mma_experiment and update_mma_experiment, Request decisions (decisions:write) for file_mma_decision and withdraw_mma_decision, and Write Shipyard records (shipyard:write) for the Shipyard tools. Prototype gates are set by a person; a key proposes a change with file_mma_decision.

Each wake-up starts at layers://mma/inbox: what changed for the app since the agent last marked it read (experiment reads due, answers to its asks, spend against the daily cap, broken signals, next steps). Reading it marks nothing; mark_mma_inbox_read with the read's readAt does. The layers-status prompt runs the whole check-in, and hosts that do not show MCP prompts use the layers-status skill.

ToolWhat it doesCredits
record_mma_shipyardRecords one Shipyard record: a playtest (vendor, study, testers planned and done, cost, status, build, scores, "play tomorrow" counts), a survey (questions, shown and answered counts, answer counts by option), a release (version, platform, track, rollout, store review state) or a dated change on an experiment. An optional externalKey makes a repeat update the same record (upserted: true); a release updated this way also dates each rollout or track change. An MMA API key needs shipyard:write0
update_mma_shipyardChanges a playtest, a survey or a logged experiment change by id; a release is append-only, so record a new one instead. An MMA API key needs shipyard:write0
create_mma_attachment_uploadRequests an upload for one screenshot, short video or PDF on an experiment or Shipyard record, and returns a signed PUT URL with the exact headers to send. The agent PUTs the bytes itself, then finalizes. Images up to 30 MB, video 200 MB, PDF 10 MB. An optional externalKey makes a repeat return the same attachment. An MMA API key needs shipyard:write0
finalize_mma_attachmentChecks the uploaded file's size and type against the request and publishes it with a short-lived signed read URL. A key finalizes only its own uploads. An MMA API key needs shipyard:write0
exclude_mma_installTakes one QA or test install out of the app's numbers: send the installId the SDK sent from the test device and a reason. MMA records who excluded it and why, marks the install's stored and future events in MMA as test data, and stops counting it in installs, sessions, cohorts, retention and SDK revenue. It has no undo. A repeat returns the stored record with alreadyExcluded: true; an install MMA has never counted, or whose first day is more than 35 days old, is refused. An MMA API key needs shipyard:write0
set_mma_prototype_gatesReplaces the app's prototype gates: each gate's criteria on playtest scores, read against the newest done playtest recorded for it. A signed-in person only: an MMA API key is refused and files an MMA decision with file_mma_decision to propose a change0
list_mma_experimentsLists the app's experiments in MMA, newest first, filtered by status, with a cursor to page0
get_mma_experimentReads one experiment by its mexp_ id or by the key it was registered under, with MMA's per-arm read: installs exposed per arm, conversions on the primary metric with a 95% interval, spend and cost per conversion, network-claimed installs and the proof rate (proven installs ÷ installs the network reports), the leading arm and whether its interval separates it, and readDue once the read date passes0
register_mma_experimentRecords a new experiment: key, title, hypothesis, arms with traffic shares and the mapping MMA reads them by (SDK event property values or landing pages, and the campaigns or ad sets whose spend counts), primary metric, decision rule, guardrails, planned read date, a link, and status. A key already on file returns that experiment unchanged0
update_mma_experimentMoves an experiment's status (planned, running, paused, reading, decided, stopped) and records its result: winner, effect, confidence interval, units per arm, and a note0
list_mma_reviewsLists the bound app's deduped store reviews, newest first. Filter by store, inclusive minRating and maxRating (1 to 5), version and since (ISO date-time with offset or UTC day). limit is 1 to 50, default 25; send nextCursor back as cursor to page. App Store reviews come from RSS and App Store Connect; Google Play reviews come from the Play API. A review in another language also carries titleEn and bodyEn (its English translation), detectedLanguage (ISO 639-1) and translationModel0
get_mma_ratingsReads daily displayed ratings and rating counts aggregated over storefronts for each store, with per-version statistics, release markers and model definitions. days is 7 to 365, default 30. App Store version statistics count ratings received while the version was current; Google Play version statistics count written reviews on the version0
get_mma_studio_briefReads the morning brief: yesterday and trailing seven-day spend against caps, proven installs, revenue by source, ratings, alerts, experiment reads due, open decisions, releases and day-over-day changes. Takes no input. People and org-wide keys read the studio; app-scoped keys read only the bound app. Every figure carries its n or source, with low-n marked below 30 observations. mmaUrl opens the Brief page0
run_events_sqlRuns one read-only SELECT or WITH statement over the studio's apps in ClickHouse. Read layers://events/sql-guide first. Use events.seat_events, events.seat_events_final for exact counts and events.seat_events_by_install for per-install timelines; these views drop identifier and contact property paths. A query has a 60-second limit and a 100,000-row server cap. maxRows is 1 to 10,000, default 1,000, and truncated is true when more rows exist. The result carries column names and types, rows, the query id, elapsed time, and rows and bytes read. organizationId defaults to the bound organization, and only studio organizations can run it. An MMA API key needs mma:read0
get_mma_cohortsReads install-day cohorts for the bound app: installs per install day and in total, proven installs with their network and attribution method, organic installs, the installs the ad networks claim, and returners on day 1, 3, 7, 14 and 30. from and to are install days (at most 92) in the app reporting timezone. Optional filters: campaignId, adSetId, network, country, platform and appVersion. Emulators, store test devices and excluded installs are absent, as on every MMA page. A day N that has not ended yet reports mature: false with null counts. Totals carry each rate's 95% Wilson interval and say whether every install day has reached day N. basis names what the installs hold (proven, proven_and_organic or organic); claimed installs stay a separate figure. Send nextCursor back as cursor for the following install days0
get_mma_retentionReads the bound app's daily retention baseline, discovered dimensions and selected slices, with D1, D3, D7, D14 and D30 returners, heavy-player share, D7 revenue intervals and attributable cost. dimension defaults to builtin:all; use builtin:<key>, property:<key>, day0_event:<key> or cross:<key> to select slices. computedOn selects a snapshot date and defaults to latest; sdkAppId selects among the returned sdkAppIds. Each metric uses 28 fully aged local install days. Rates carry 95% Wilson intervals; D1 and D7 differences use Newcombe against the rest of the app, with Holm correction across the app's slice tests that day. lowN flags fewer than 100 eligible D7 installs (D1 when the app has no eligible D7 installs), or a missing D1 interval or one wider than 10 percentage points. Low-n slices produce no insights. Cost is present only where the spend report carries the slice's keys; unavailable cost or currencies that cannot be combined give null0
get_mma_insightsReads stored pocket findings, slice outliers, trend shifts and experiment observations, newest day first, then score, with sample sizes, values and intervals. scope defaults to app; studio includes only authorized apps. Optional sdkAppId and computedOn filter the feed; limit is 1 to 30, default 20. Send nextCursor back as cursor with the same filters. Slice findings use 95% Wilson rates, Newcombe differences against the rest of the app in the same 28 fully aged local install days, and Holm-corrected D1 and D7 tests. Low-n slices produce no findings. Pocket cost appears only where the spend report carries its keys. The findings describe associations0
get_mma_pocketsReads healthy acquisition pockets, weak cut candidates and behavioral product pockets from each authorized app's latest daily snapshot. scope defaults to app; studio includes only authorized apps. Optional filters: sdkAppId, computedOn and verdict (healthy_pocket, weak_pocket or product_pocket). limit is 1 to 30, default 20; send nextCursor back as cursor with the same filters. Rows carry retention with 95% Wilson intervals, D1 and D7 Newcombe differences against the rest of the app and Holm-corrected tests, heavy-player share and D7 revenue with a seeded bootstrap interval. Low-n slices receive no pocket verdict. Pockets rank by retained players per day, then cost per D7 player within each source currency. Spend, CPI and cost per D7 player are present only where the spend report carries the pocket's keys; unavailable cost or currencies that cannot be combined give null, not zero. Pockets overlap and describe associations, so do not sum them or infer causation0
file_mma_decisionAsks a studio member a question on MMA's Decisions page: title, ask, recommendation, options (default approve and deny), cost in US dollars and a due date. It opens pending; the answer arrives on layers://mma/decisions and in the inbox, with chosenOption verbatim. The same title again while your first ask is pending returns that ask with created: false. An ask filed with an MMA API key carries the key's name. An MMA API key needs decisions:write0
withdraw_mma_decisionTakes a pending decision back by its mdec_ id or bare uuid. An answered decision keeps its answer and is refused; a repeat returns it with alreadyWithdrawn: true. You withdraw only the asks you filed. An MMA API key needs decisions:write0
mark_mma_inbox_readMarks the agent's MMA inbox read up to the readAt of the read it acted on; the marker is the agent's own and only moves forward0

What onboarding sends

Your agent reads the repository on your machine and submits a short product brief: name, one-line description, category, target users, the problem, the conversion goal, seed keywords, known social handles, and store identities. Layers never receives your source code. No file, path, diff, or excerpt is sent. The request carries the brief fields, one digest, and a closed list of evidence classes such as package_manifest and readme.

Onboarding writes the brief and the store identity and finishes on the same call. It needs no social account and starts no background jobs. The calls after it are create_app, which registers the app's iOS bundle id or Android package and issues its App ID on the bound project, and install_growth_measurement, which puts the Layers SDK in the app and confirms it reports.

A project onboarded from an App Store or Google Play listing also gets its mobile app layer, its store listing record and its bundle id at the same moment, which is what lights the App Store Optimization surface in the app.

It creates no schedule, campaign, managed account, standing automation, provider mutation, or charge.

Free resources

Resources read stored state. They are free, they never trigger a provider read or a model call, and each one reports when its data was observed and which tool refreshes it.

ResourceWhat it holds
layers://nextthe one move this project is at and the rows that follow it: a tool to call now with complete arguments and its price, a link to hand a person, a purchase that funds the move already chosen, or a wait with the time to come back. Beside it, the presence tier the decision table branched on and the inputs that decided it, every row of the table with what happened to it, and the answers already given to an offer. The same step rides every tool result in the envelope's next field, without the rows that follow
layers://accountidentity, plan or trial, credit balances, reserved credits, profile availability, active offers, and a human billing link. layers://account/credit-events pages every balance change
layers://workspaceproduct brief, growth goal, connected accounts, measurement readiness, and posting policy
layers://landscaperanked tracked accounts, pins, exclusions, scope, freshness, and source evidence
layers://opportunitiesthe standing ranked queue, with full source evidence per opportunity
layers://experimentsexperiment summaries, the current projection per experiment, and the append-only event ledger
layers://influencersthe project's personas, each with the look it was generated from, its portrait, and whether it is still being drawn, plus slateUrl, a page you can hand to a person who wants to see the faces
layers://brand-assetsthe project's own product media a render composes: app screenshots, demo videos and end cards, each with a stable id render_content accepts
layers://musicthe curated tracks a render can be scored with: title, artist, length, whether anybody sings on it, and a preview URL to play a person
layers://measurementwhat the project spent beside what Layers recognized over one window: ad spend per platform with how much of it is settled, recognized revenue per channel, the frozen D7, D30 and D90 cohort figures, and installs as observed, proven and claimed, with the arbitration between them. It names every figure that is unknown rather than zero
layers://jobsactive and recent jobs with state, receipts, errors, and recovery steps
layers://artifacts/<id>one rendered artifact by the cnt_ id its job named: whether it is ready, whether it is video, slideshow or image, the addresses to look at, the measured bytes with dimensions and duration, and the job and experiment it came out of
layers://tracking-linksevery link this project has minted, newest first, with its label, its tags, its UTM fields and what it did over the last 30 days: clicks, store taps, installs attributed to one of its clicks, and the revenue that followed. Filter by tag and by the surface that minted it; read one at layers://tracking-links/<id>
layers://clicks/<click id>one tap: when it happened, the platform it routed to, the link it came from, its UTM fields, the install it produced with the match method and confidence tier, and the revenue that followed
layers://eventsthe product events the SDK reported over a window: every event name with its count, its distinct people, when it was first and last seen, and a country rollup. Never a single event row
layers://revenuewhat the product earned from its own billing: a daily series per source, the monthly and annual run rate, subscribers, trials, churn and lifetime value, the trial forecast, and each source stated as ready, degraded or unavailable
layers://attributionwhich installs Layers could tie to a click and by what evidence: installs by method and rung, the resolve funnel with its five outcomes, the SKAdNetwork postbacks received, decoded and relayed on, and the residual with its causes
layers://sdk-healthwhether the SDK in the field is reporting at all: the versions in use with the installs behind each, the newest beacon and event, the events accepted, delivered and dropped with reasons, and whether the build is behind the current release
layers://conversionswhere the product's conversions are forwarded, per ad platform: whether it is on, which destination is bound and what class it is, what it counts, the delivery counts over 30 days (including conversions unsent because the access token was refused), whether it needs a reconnect, and the circuit breaker. Never an access key
layers://bio-pagethe hosted page at <slug>.layers.click: whether it is published, the icon, name and tagline it leads with, the five tokens it renders with, its buttons in order with the tracking link behind each one and what that link did, and how many people and how many crawlers opened the page each day
layers://mma/overviewthe app's MMA Overview figures over a window (?from=YYYY-MM-DD&to=YYYY-MM-DD, default the last 30 days): spend, installs, paid installs, CPI, D1 and D7 retention, trials, new payers, gross and net revenue with the split by store (App Store, Google Play, web), MRR, cohort ROAS from D7 to D180, payback day, and a daily series, each beside the previous window. Installs are first recorded SDK production installs on the UTC install day; D1 and D7 retention are the share of each install day's installs with any production event exactly 1 or 7 UTC days later. Ad revenue is not ingested and the body says so
layers://mma/retentionthe install-day retention matrix from MMA's Cohorts screen (up to 31 install days): each cohort's size and, for day 0 through 30, day 60 and day 90, the share active on exactly that UTC day and the share active on it or later. A null cell is a day that has not ended
layers://mma/spendspend by campaign per ad network over a window: spend, impressions, clicks, the network's claimed installs, the installs Layers proved to the campaign, trials, payers, revenue from those installs, CPI, and revenue over spend, with organic installs beside them
layers://mma/cohortsthe Cohorts screen's read over install days you choose (?from&to, default 30 days): installs per install day, revenue and conversions at each age, spend and projection ratios, from which ROAS, LTV per install and payback follow
layers://mma/funnelsthe saved funnels, newest first, up to 10, each computed over a window (?from&to, default 7 days, at most 31)
layers://mma/eventsthe event taxonomy over a window: each production event name with its counts, where it is forwarded, and whether it is live, quiet or missing
layers://mma/realtimethe Realtime screen: active devices, events per minute, installs and revenue today, and the last 30 minutes
layers://mma/deliveriesconversion deliveries per ad network destination over a window, with health and the delivery log (?cursor pages)
layers://mma/matchesinstalls matched to an ad click, store referrer or URL parameter, newest first, with the match rate (?cursor pages)
layers://mma/activitythe change log: every change to the app's ad accounts and campaigns and who made it (?cursor pages)
layers://mma/decisionsthe app's decisions from MMA's Decisions list (?cursor pages)
layers://mma/shipyardthe app's Shipyard: the newest playtests, surveys, releases and changes logged on its experiments, each prototype gate with its verdict and the first gate not yet passed, and playtest spend by vendor
layers://mma/data-notesdated notes on changes in how MMA derives its numbers (?cursor pages)
layers://mma/portfoliothe app's Portfolio row: today, 7-day and 30-day figures and the alerts
layers://mma/ladderthe app's row of the viability ladder, as the Ladder section on its MMA Overview shows it: the stage, every playbook gate with its value, benchmark, the app's own target and a verdict, and the keep, iterate or kill suggestion with the rule behind it
layers://mma/recommendationswhat MMA is asking a person to act on: the ad optimizer's open approval queue with each proposed change, its rationale and projected outcome, and the measurement-health problems (an ad sign-in in error or expiring, spend with no installs, installs from a network whose spend is not connected, figures that stopped refreshing). Each row carries a link to the MMA screen where a person approves, dismisses or fixes it
layers://skills/v1the skill index and each skill body

A client without MCP resource support gets one extra read-only tool, read_layers_state, which returns the same data and makes the same authorization decision. It reaches every resource above except layers://campaigns, so a paid-media projection needs a resource-capable client.

Skills

The server owns the skill bodies and setup installs one thin pointer at .agents/skills/layers/SKILL.md. The pointer names the server, the project binding rule, and the pinned major version. Skills carry judgment about when to use an outcome and how to read the result. They hold no credentials, no prices, and no tool of their own.

SkillProfileJob
niche-mapgrowthBuild and curate the standing map of direct, adjacent, and inspirational accounts
what-to-postgrowthTake one opportunity through a plan, an optional render, approval, and delivery
growth-reviewgrowthRead early or final evidence, state the uncertainty, and pick the next controlled test
outcome-loggrowthRegister work you posted yourself and keep the hypothesis, result, and next decision together
paid-growthpaid mediaPromote an owned post under exact spend authority
managed-distributionmanaged distributionPlan, approve, monitor, and release a disclosed managed fleet

Pricing

Credits pay for the work the agent asks for. One organization holds one credit balance, and the same operation costs the same number of credits on every plan.

PlanPriceCredits
Pay as you go$0 per monthnone included
Pro monthly$49 per month5,000 per month
Pro annual$468 per year, $39 per month5,000 each month
Ultra monthly$199 per month25,000 per month
Ultra annual$1,908 per year, $159 per month25,000 each month

Pay as you go costs nothing a month and includes no credits. It needs a card, and credits are bought in packs at 2 cents each. It is the way in for a workspace that wants to pay for exactly the work it asks for.

The trial is the first week: 7 days, $9 today, a card required, and 1,000 credits. The first landscape build is included, so the trial can reach opportunities without spending them. The trial converts to Pro monthly at $49 unless it is cancelled first, with the $9 credited toward the first month.

Subscriptions auto-renew until a human cancels them. Your agent can cancel the trial renewal for you with cancel_trial_auto_renewal: the first call previews the trial end, the effective date, what you keep, and what you lose, and returns a link. Cancellation itself takes your click on that Layers page. No MCP tool can complete a checkout, start a plan, or change a renewal on its own.

One-time packs add credits to the same balance and do not expire. There are two sets of prices, and a workspace buys from the one its plan puts it on.

PackCreditsOn a planOn pay as you go
Crawl1,000$9$20
Walk4,000$29$80
Run10,000$69$200
Scale20,000$129$400

layers://account reports which set applies to you, at creditPacks.eligibility.observed.packAudience, and every pack price it lists is the price your card is charged. A checkout link for the other set is refused.

Ad spend and managed-account fees are separate money. They never consume credits and never hide inside a credit quote.

Available today

Verified against the server source on 2026-09-02. tools/list in your session is the authority: every tool in the tables above is in the catalog, and a bound project can call it.

Every profile is on for a bound project, so paid media and managed distribution need no separate enablement, and neither adds a network-prefixed or provider-prefixed tool.

A few of the growth outcomes carry detail the table has no room for.

  • manage_growth_landscape charges only for a refresh. A full rebuild costs the same six credits as a forced incremental one and runs the same discovery crawl.
  • find_growth_opportunities reads the stored queue. The default read starts no vendor call, no model call, and no charge. includeCreativePreview: "generate" makes the creative analysis for the returned cards that have none yet, at two credits for each preview actually produced and nothing for a card it could not analyze; each one is cached, so a later read of the same card is free. quoteOnly returns the same cards and that price without producing anything.
  • generate_influencer is free. layers://influencers is where the persona is read back once its portrait lands, and slateUrl on both surfaces opens a page of the project's portraits for a person to look at.
  • render_content renders one output a call. A remix reads video or slideshow off the post it adapts and charges the matching rate; layers://brand-assets and layers://music are where the screens and the track it can be directed with are read.
  • The five research_tiktok_* reads each cost one credit a call whatever the row count, charged on the call. research_tiktok_trending_sounds and layers://music answer different questions: the chart is what TikTok is playing, and the resource is what a render may legally be scored with.
  • review_growth_results reads stored evidence for nothing and pays one credit only for a forced provider sync.
  • halt covers one job, one experiment, one social account, one paid campaign, one managed account, or the whole project. On a campaign it pauses provider delivery and withdraws the approvals that campaign holds.

Two earlier surfaces were retired on 2026-08-30 with no bridge and no compatibility shim: the npm package @layers/mcp-server, including the keyless onboarding mode it started in without a key, and the growth MCP that served the protocol at growth.layers.com. Do not install or call either one. That hostname now serves the landing site for this server and no protocol. The Growth page covers the retired growth MCP. The product contract for this server, including where the outcome of every retired tool went, is docs/specs/layers-mcp-product.md in the Layers repository: section 15.2 for the 26 growth tools and section 15.3 for the 52 API-backed tools and the five keyless tools. The REST routes those tools mirrored are unchanged.

Support

Ask in the in-app chat at app.layers.com, or email support@layers.com. For a security report, email security@layers.com.

Layers also has a public REST API for building against the platform directly. See API.

On this page