Plyto
AI that makes and runs your Google and Facebook ads from your own account, with a CRM behind it.
Connect it
Settings → Connectors → Add custom connector
URL: https://plyto.ai/api/mcpSettings → Apps & Connectors → Advanced → Developer mode
Create connector with URL: https://plyto.ai/api/mcp{
"mcpServers": {
"crm": {
"url": "https://plyto.ai/api/mcp",
"headers": {
"Authorization": "<YOUR_AUTHORIZATION>"
}
}
}
}claude mcp add --transport http crm https://plyto.ai/api/mcp --header "Authorization: <value>"{
"servers": {
"crm": {
"type": "http",
"url": "https://plyto.ai/api/mcp",
"headers": {
"Authorization": "<YOUR_AUTHORIZATION>"
}
}
}
}195 tools, verified live
memory__saveSave (or update) a durable memory: a standing preference, playbook rule, correction, or business fact that should hold across ALL future conversations. Use when the user says "remember…", "always…", "never…", "from now on…", states a lasting preference, or corrects how you did something. One distilled rule per memory, ≤500 characters. If an existing memory covers the same topic (they're listed in
memory__listread-onlyList every durable memory you hold for this business (business-wide plus the current user's personal ones), with ids and when each was last confirmed. Use before consolidating, when the user asks what you remember, or to find a memoryId to update/forget.
memory__forgetcan modifyPermanently delete a saved memory. Destructive: confirm with the user first unless they just explicitly asked you to forget exactly this. Users can also remove memories themselves under Settings → Business profile.
business__updatecan modifySave what you learn about the business the moment the owner says it: real name, website, industry, who their customers are, what sets them apart, the phone to show on pages, where an ad's click should go (clickTarget page or url, and conversionUrl: their signup, booking or checkout link), and durable facts copy may rely on (addClaims: an offer, a price, financing, a response time, a credential, in
brand__scan__waitread-onlyWait for the website scan business.update started (up to 45 seconds) and get what it read: industry, audience, value proposition, claims. Call it right after saving a website on a first draft, then build from the result. Returns what is on file even when the scan is still running or failed, with a note saying which.
account__profileread-onlyReturn the Plyto profile this connection is signed in as: an opaque id that stays the same across token refresh and reconnection, the person's name and email for display, and the business the connection manages as a label. Takes no arguments.
documents__listread-onlyList the documents the owner has given you, newest first: files attached in the chat (PDF, Word, text), long messages kept as documents, and links you read and kept. Each has an id to read it with documents.read. Use it when the owner refers to something they sent before ("the brand doc", "my course outline").
documents__readread-onlyRead a document the owner gave you (an attached PDF, Word or text file, a long message kept as a document, or a link you kept), 30,000 characters at a time; pass offset to go on. Read before you answer about it: never describe a document from memory.
brand__colors__setcan modifySave the brand colors the owner names in chat, as hex codes: the primary (what graphics build on) and, when they give one, an accent. They replace the colors on file (a website scan's guess, a logo's extraction), so pass both when the owner names both. Returns what the next graphic will use. Nothing is redrawn: pictures already on the ads keep their colors, and a campaign whose pictures are on hol
business__claims__removecan modifyTake claims off the business profile once the owner says they no longer hold: the business moved and no longer serves the old area, an offer ended, a credential lapsed. Pass each claim as it is on file (a draft's placeClaimsNote quotes it). Only on the owner's word in this conversation, never on your own judgment. Every ad, picture and page is checked against the claims, so a removed claim is neve
crm__contacts__createCreate a contact (or find-and-update if one with the same email already exists in this business). Returns the created/updated contact. Use when the user mentions adding, capturing, or tracking a new person. Email is the natural dedup key; if you have an email, always pass it.
crm__contacts__updateUpdate fields on an existing contact. Only pass fields you want to change. No-op fields are silently skipped.
crm__contacts__getread-onlyFetch a single contact by id, with where they came from: the ad campaign and search keyword that brought them (when an ad did), where they were and on what device, what they asked for on the landing page, how many forms they submitted, and whether they have created an account. Use this, not source_detail alone, to say how someone arrived. Returns null if not found in this business.
crm__contacts__listread-onlyList contacts in this business with simple filters. For free-text search use crm.contacts.search. For complex filters use crm.contacts.query (W3).
crm__contacts__searchread-onlyFree-text search across contact email, first/last name, and phone. Case-insensitive substring match. Returns up to 20 contacts by default.
crm__contacts__get_propertiesread-onlyReturn all custom property values for a contact as a {key: value} map.
crm__companies__createCreate a company (or find-and-update if one with the same domain already exists). Domain is the natural dedup key; always pass the bare domain like 'acme.com' (not the full URL).
crm__companies__updateUpdate fields on an existing company. Only pass fields you want to change.
crm__companies__getread-onlyFetch a single company by id. Returns null if not found.
crm__companies__listread-onlyList companies in this business. For text search use crm.companies.search.
crm__companies__searchread-onlyFree-text search across company name, domain, and industry. Case-insensitive substring match.
crm__companies__get_propertiesread-onlyReturn all custom property values for a company as a {key: value} map.
crm__tags__createCreate a new tag (or find one with the same name; idempotent). Tags are lightweight orthogonal categories like 'VIP', 'Newsletter-only', 'Cold'.
crm__tags__listread-onlyList all tags defined in this business.
crm__tags__add_to_contactApply a tag to a contact. Idempotent: adding an already-applied tag is a no-op.
crm__tags__remove_from_contactRemove a tag from a contact. Idempotent.
crm__tags__list_for_contactread-onlyList all tags applied to a contact.
crm__tags__add_to_companyApply a tag to a company. Idempotent.
crm__tags__remove_from_companyRemove a tag from a company. Idempotent.
crm__tags__list_for_companyread-onlyList all tags applied to a company.
crm__properties__defineDefine a new custom property on contact or company. Keys must be lowercase snake_case (e.g. 'plan_tier'). For single_select / multi_select, options is required.
crm__properties__listread-onlyList custom property definitions for an entity type. Excludes archived by default.
crm__properties__archivecan modifyArchive a custom property. Existing values are preserved but the property is hidden from UI and rejected for new value sets. To 'rename', archive + redefine.
crm__properties__set_contact_valueSet the value of a custom property on a contact. Value type must match property type. For multi_select pass an array of option values.
crm__properties__set_company_valueSet the value of a custom property on a company.
crm__properties__set_deal_valueSet the value of a custom property on a deal.
crm__properties__clear_contact_valuecan modifyRemove a custom property value from a contact.
crm__properties__clear_company_valuecan modifyRemove a custom property value from a company.
crm__properties__clear_deal_valuecan modifyRemove a custom property value from a deal.
crm__properties__get_deal_valuesread-onlyReturn all custom property values for a deal as a {key: value} map.
crm__pipelines__listread-onlyList all pipelines in this business (excludes archived by default).
crm__pipelines__list_stagesread-onlyList the ordered stages in a pipeline. Use to look up stageIds for crm.deals.move_stage.
crm__pipelines__get_defaultread-onlyGet the default pipeline for this business (the one new deals land in by default). Returns null if no default is set.
crm__deals__createCreate a deal in a pipeline. If pipelineId/stageId omitted, lands in the business's default pipeline at the first open stage. Attach to a contact and/or company for full context. valueCents is the deal size in cents (e.g. $5,000 = 500000).
crm__deals__updateUpdate fields on a deal. Use crm.deals.move_stage to change stage (it handles close events). Use crm.deals.close_won / close_lost for the won/lost transitions.
crm__deals__move_stageMove a deal to a different stage in the same pipeline. If the target stage is a won/lost stage, this auto-sets closedAt and emits the appropriate close event.
crm__deals__close_wonClose a deal as won: moves it to the won stage in its pipeline. Sets closedAt and emits deal.won.
crm__deals__close_lostcan modifyClose a deal as lost: moves it to the lost stage in its pipeline. Records lostReason and emits deal.lost.
crm__deals__getread-onlyFetch a single deal by id.
crm__deals__listread-onlyList deals with simple filters. Filter by pipeline/stage for Kanban view, or by contact/company for deal history. `open: true` returns only open-stage deals; omit for all.
crm__deals__searchread-onlyFree-text search across deal names.
crm__activities__logLog an activity: something that happened (past or scheduled). Distinguished from tasks (future intent) and notes (no structure). Use 'log a 30-min discovery call with Jane' style prompts. happenedAt defaults to now if omitted.
crm__activities__listread-onlyList activities, optionally filtered by entity (contact/company/deal) or owner. Returned in reverse chronological order by happenedAt.
crm__activities__getread-onlyFetch a single activity by id.
crm__tasks__createCreate a task: future intent ('follow up with Acme by Friday'). Distinguished from activities (past event) and notes (no structure). Auto-assigns to the calling user if assignedToUserId omitted.
crm__tasks__completeMark a task as completed. Sets completedAt to now.
crm__tasks__cancelcan modifyMark a task as cancelled (rejected, different from completed). Use when the user decides a task is no longer relevant.
crm__tasks__listread-onlyList tasks. Open tasks sort by due date (closest first). Completed tasks sort by completion (most recent first).
crm__tasks__getread-onlyFetch a single task by id.
reports__previewread-onlyRun a report config WITHOUT saving. Use it to answer analytical questions ('deals by stage', 'contacts added per month', 'email opens last 30 days') and to sanity-check a config before reports.create. Returns rows + totals. Money values are in cents.
crm__sources__performanceread-onlyMarketing-source attribution: for every source (ad campaigns, UTM-tagged traffic, forms, inbound webhook, manual, import…; the webhook also accepts POST {email, outcome: qualified|customer} at /outcome so an external system of record can report when a lead pays) the full funnel (leads acquired, deals created, deals won, won revenue) plus ad spend, CPL, CAC and ROAS where spend exists. THE tool for
reports__createSave a custom report as a live card on the user's Reports dashboard. Use when the user asks for a report or says yes to saving an analysis. The config is re-executed on every dashboard view (always live). Validates by running once; returns the saved report + current data.
reports__listread-onlyList the saved custom reports on the Reports dashboard.
crm__notes__addAdd a freeform note attached to a contact, company, deal, or any combination. Use for 'remember that Jane prefers email over phone' style facts.
crm__notes__listread-onlyList notes, optionally filtered by attached entity.
crm__lists__createCreate a contact list. Manual lists are curated by hand; dynamic lists have a filter DSL (DNF: {or:[{and:[conditions]}]}) that defines membership. For dynamic, pass `criteria`. For manual, omit it.
crm__lists__getread-onlyFetch a single list by id.
crm__lists__listread-onlyList all contact lists in this business.
crm__lists__membersread-onlyReturn the contacts that are members of a list. For manual lists this returns explicit memberships; for dynamic lists it evaluates the criteria filter against contacts (lazy recompute).
crm__lists__add_contactAdd a contact to a MANUAL list. Idempotent.
crm__lists__remove_contactRemove a contact from a manual list.
crm__lists__archivecan modifyArchive a list. Membership rows are preserved but the list is hidden from default queries.
forms__createCreate a form. Slug becomes the URL: /forms/<slug>. Fields are JSON-defined with type matching the contact property type system (text/email/url/number/date/checkbox/select/multi_select/textarea/phone). If captureToListId is set, every submission is auto-added to that list (use crm.lists.create first to get a listId).
forms__updateUpdate a form: rename it, replace its fields, change appearance (theme), button text, thank-you behavior, or the capture list. Omitted properties keep their current value; `fields` and `theme` replace wholesale when provided, so send the COMPLETE new array/object (use forms.get first). Keep existing field `key`s so past submissions and automations stay attached. Users can also do this themselves a
forms__getread-onlyFetch a form by id.
forms__listread-onlyList all forms in this business.
forms__list_submissionsread-onlyList submissions for a form, newest first.
forms__get_embed_coderead-onlyGenerate the JS embed snippet and iframe alternative for a form. Returns both; the user picks whichever fits their site.
crm__contacts__queryread-onlyQuery contacts with a structured filter DSL. Use this for complex 'show me contacts where X and Y but not Z' queries. Simpler cases prefer crm.contacts.search (free text) or crm.contacts.list (single filter). Field reference forms: email, firstName, ... = stock fields custom:<key> = custom property (v1 routes through text sidecar) tag:<name> = has-tag-with-name (op must be exists/not_exists
agency__clients__listread-onlyThe client workspaces this agency workspace runs (each client is its own workspace under the agency's brand), with white-label state, who gets the reports and when the last one went out. On a client workspace, says which agency runs it. Set up under Settings, Agency (the agency side) and Settings, Client portal (each client workspace).
agency__client_report__previewread-onlyWhat this workspace's client report would say for the last 7 or 30 days: ad spend, leads, cost per lead, revenue won, by campaign, and the recent leads. Read-only; agency.client_report.send sends it.
ads__campaign__draftCreate a draft ad campaign on Meta (Facebook and Instagram), Google, or ChatGPT (OpenAI's ChatGPT Ads), the platforms Plyto can actually launch and manage. Drafts are NOT live: they require user approval and a UI launch action before spending money. Use when the user asks to create, generate, or set up a new ad campaign.
ads__listing__readRead a property listing page (Zillow, Realtor.com, Redfin, an MLS or brokerage page): the address, beds, baths, size, price, photos (imported to the library as the ad pictures), the agent and brokerage, and what is still missing. Call it first when a real estate agent or property manager shares a listing link, then pass the returned `listing` to ads.campaign.draft.
ads__campaign__listread-onlyList ad campaigns for the active business, optionally filtered by status and/or platform. Use when the user asks to see their campaigns or get an overview. The status of a launched campaign here is what Plyto last read from the ad platform (nightly, or the last refresh); before saying whether a campaign is live, paused or running, call ads.campaign.refresh, which reads the platform right now.
ads__performance__summaryread-onlyTHE authoritative source for a campaign's spend, impressions, clicks and conversions: use this for any question about how much a campaign has spent or how it is performing. Defaults to last 7 days. Numbers are aggregated from daily snapshots written by the performance poller, and `asOf` says when those snapshots were last refreshed, so report figures as of that moment. Never compute spend by summi
ads__performance__analyzeread-onlyAnalyze recent performance for the active business: surface ads/ad sets that aren't getting impressions, ones spending without converting, and concentration patterns where a small slice drives most results. Also returns CRM attribution per campaign: leads captured (via stamped UTMs), cost per lead, deals those leads became, won revenue, and ROAS. Use when the user asks 'how are my ads doing', 'wha
ads__creative__draftCreate a draft ad creative attached to an existing ad set. Combines an uploaded image with copy + CTA + landing URL. The creative goes live with the ad set when the campaign is launched. Use after ads.campaign.draft and after the user has uploaded at least one image. PLACEMENT SIZES: a campaign needs up to 4 image sizes: 1:1 (1080x1080, REQUIRED, default/fallback for Marketplace+right column+searc
ads__creative__generate_imagesGenerate AI ad photographs from a prompt + the business's brand profile, sized for Meta placements, and save them to the creative library. For a physical business the picture is the work or the product, and a REAL photo from the library (ads.creative.compose_from_photo) comes first when one exists; generate only when nothing real is on file. Never over an ad that shows the owner's own photo, and n
ads__creative__compose_graphiccan modifyCompose a DESIGNED ad graphic deterministically: real type, the real logo, the real product image, proof from the claims on file. No AI image model; the only AI step is one quick look at the product image to pick the part to show (about a cent, free while the first campaign is set up, remembered per image and headline). To EDIT an existing designed graphic, pass revisionOf (its asset id) plus only
ads__creative__flyerMake a flyer, poster or handout the owner can download and print, post or send: their title, the facts (when, where, what is included), how to reach them, their logo and one real photo, in their brand. Returns each size with a download link. For anything that is not an ad: an event, a class, an opening, a menu, a notice. Never tell anyone to screenshot a page instead.
ads__creative__compose_from_photoTurn a REAL photo from the library into a finished ad set: the photo cropped for every placement size, the headline in real type, the real logo. No image model, no credits, nothing invented. THE FIRST CHOICE for a physical business whenever the owner has uploaded photos or the website scan saved some (ads.assets.list shows which are real): a real photo of the real place beats any generated scene.
ads__creative__edit_photoEdit one of the owner's REAL photos: take something out of it or change something in it (a coffee table, rugs, clutter, a sign, the background) while their product stays exactly as it is. The edit is checked against the original and saved as a NEW copy beside it (the original is kept); pass adCreativeIds to put the edit on those draft ads. Use it whenever the owner asks to remove or change somethi
ads__creative__generate_videocan modifyRender a short video clip (4, 6 or 8 seconds, vertical 9:16 or wide 16:9) for Reels, Stories, TikTok-style and feed placements. Use for ANY request for a video, promo clip, reel or animated ad. It renders in the background for a few minutes; the finished clip lands in Creative studio (Marketing, Creative) and the person gets a notification. The clip shows a scene, never on-screen text or logos: he
ads__creative__compose_videoTurn library clips and images into a FINISHED video ad: a hook line over the opening seconds, an optional caption per clip, and a closing brand card with the real logo and a button, at 9:16 for Reels, Stories and TikTok (or 16:9, 1:1). A raw clip from ads.creative.generate_video is footage, not an ad; call this once the clips have landed, before attaching video to a draft. Deterministic compositio
ads__ads__listread-onlyList every ad on a campaign with its ID, grouped by ad group. Run this BEFORE ads.creative.update or ads.creative.delete: those tools take the ad's id, never its headline text. Also the honest way to answer 'what ads does this campaign have'.
ads__assets__listread-onlyList the creative library (images, videos) for the active business, with what each asset IS: role 'site-capture' is the real picture of their website the scan saved (the hero for ads.creative.compose_graphic layout screenshot on software), role 'reference' is a real photo of the business, source 'upload' is something the owner added, generated=true is art Plyto made, editedFrom names the owner's p
ads__assets__deletecan modifyPermanently delete an UNUSED image or video from the creative library (the file and its record). Refused when the asset — or any of its placement-size siblings (same name, different ratio) — is attached to an ad, because launch resolves sibling sizes by name. Use for library hygiene: failed or superseded generations that nothing references, e.g. after rebinding an ad to older art.
ads__campaign__updatecan modifyEdit an existing ad campaign: name, objective, daily budget, plain-English audience, Google search keywords, or a listing campaign's property facts (listing: the price, beds, baths, size, address or open house the owner corrected). Draft campaigns are freely editable. For LIVE campaigns only the budget and the listing record can change, and a budget increase requires the user's explicit approval f
ads__campaign__locations__getread-onlyWhere a campaign's ads show: the location targeting as the ad platform itself reports it for a live or paused campaign (Google: the places plus whether only people physically there see the ads; Meta: the places on every ad set), or what the draft holds. Use before changing locations, when someone asks where the ads run, and when clicks arrive from countries the business does not serve.
ads__campaign__changesread-onlyThe change history of a campaign: every edit made through Plyto (budget, locations, keywords, bidding, status, ads), by whom and when, plus, for a live Google campaign, Google's own change log including edits made directly in Google Ads by a person. Use before explaining why results changed, before proposing a change someone may already have made, and whenever the current settings and an earlier c
ads__campaign__getread-onlyRead ONE campaign's full setup as it is on Google or Meta right now: bidding strategy and any cap or target, daily budget, what counts as a conversion and whether any have recorded in 30 days, the locations setting, networks, keyword and exclusion counts, ad approval and strength, and for Meta each ad set's optimization goal, audience and placements. Returns plain-English notes on setup problems t
ads__landing_pages__buildBuild a landing page for every ad group in a campaign (or one ad group): a Plyto-hosted page whose headline says the ad's promise back in the visitor's words, brand-grounded bullets, proof only from the claims on file, and the business's lead form. Draft campaigns: the ads' links are set to the pages and launch uses them. Live campaigns: the pages are built and nothing that is serving changes, so
ads__landing_pages__listread-onlyThe landing pages Plyto hosts for this business's ads, with their links, which campaign and ad group each belongs to, and how many people have viewed each. Use before building pages (to reuse), and when someone asks where an ad sends people.
ads__landing_pages__getread-onlyEverything on one landing page, for reading back or editing: every line of copy, the photo, the accent color, whether it collects details (form) or sends people to a link, which ad it belongs to and whether traffic is reaching it, what the owner has edited by hand. Call it before ads.landing_pages.update so you change the right field and keep the rest.
ads__landing_pages__updatecan modifyEdit one landing page: pass ONLY what changes and everything else stays. 'Change the headline to X' is headline alone; 'I don't like the color' is accent alone; 'send people to my booking link' is destination link plus ctaUrl; 'put my Calendly (or my Typeform, my HubSpot form) on the page' is destination embed plus the link or code they gave; 'put the crew photo on it' is heroImageUrl from ads.ass
ads__landing_pages__createMake ANOTHER landing page for an ad group: a second angle to test against the page ads.landing_pages.build made, a page for a new offer, a variant the owner asked for. You give the ANGLE; Plyto's copywriter writes the page from the ad's words, the brand profile and the claims on file, through the same claim checks as every page (lines the facts on file cannot back come back as Confirm asks). It is
ads__campaign__launchcan modifyLaunch a DRAFT campaign on Facebook and Instagram or Google Ads, the same way the Run it button does: checks that the ad account, payment method, Page and lead capture are in place, then starts the launch in the background. Money moves after this, so call it once WITHOUT confirmLaunch to get the exact daily budget and what will run, put that to the user, and call again with confirmLaunch: true onl
ads__campaign__status__setcan modifyPause a live campaign or resume a paused one on the ad platform, the same path as the page's pause and resume buttons (platform call, audit row, undoable). Pausing needs no confirmation and stops spend at once. Resuming restarts spend, so it needs confirmResume: true after the user asked. To pause a single ad rather than the campaign, use ads.ads.status.set if available, or tell the user the campa
ads__campaign__refreshPull the current state of launched campaigns, their ad groups and their ads straight from Google Ads and Facebook, and match Plyto's records to it: live or paused at every level, the campaign's daily budget, each ad's review state, and any delivery problem the platform reports. Plyto otherwise learns about changes made inside Google Ads or Ads Manager once a night. Call it before saying whether a
ads__destination__getread-onlyWhere this business's ad clicks go, or, when nobody has decided yet, the short numbered question to ask the owner (ask: one line per choice, their site's real pages checked live, and the pick with its reason). A draft's result already carries what to say as destinationAsk; call this when the owner wants to launch or asks what is left. Never decide it yourself: relay ask as it is, without adding to
ads__destination__setRecord where the owner wants ad clicks to go, then do what that implies: build and host the landing page (page, or an embeddable link), point the campaign's draft ads at their site or link (site, link), or mark a Facebook draft for an instant form. Call it the moment they answer the destination question, or with decidedBy agent when they said 'you pick'. Answers with what to tell them. Live ads ar
ads__funnel__summaryread-onlyThe funnel behind the ad spend, by campaign, for the last N days: spend, clicks, and every stage after the click through to a paying customer, with cost per stage. Call this BEFORE judging a campaign, proposing a budget change, or answering 'what should we change about our ads': the platform's conversion count is not the number of customers, and a signup or a form fill that never went further is n
ads__campaign__locations__setcan modifySet or replace the location targeting on a campaign, DRAFT or LIVE: plain place names, applied to every ad group, plus (Google) whether the ads reach only people physically in those places. Use when the checklist warns about missing locations, when targeting defaulted to the business's country and the user wants somewhere else, when clicks are arriving from countries the business does not serve, o
ads__creative__addAdd one ad (headline + primary text + CTA, plus a link except on a Meta leads campaign with an instant form, where the form is the destination) to a campaign's ad set. On a DRAFT it is saved and launches with the campaign. On a LIVE Google campaign it publishes a new responsive search ad into the ad group immediately, an extra variant competing alongside the existing ads, no budget change. Live Me
ads__meta__ads__publishcan modifyPut finished draft ads (copy and picture) onto Meta inside a campaign that is already launched, live or paused, in the ad set they were added to. Use after ads.creative.add (with confirmLiveEdit) and ads.creative.attach_image on a launched Meta campaign. Call once without confirmPublish to get the summary, put it to the user, then call again with confirmPublish true after they said yes. If the ad
ads__meta__ad_sets__publishcan modifyCreate ad sets that exist only in Plyto on Meta, inside a campaign that is already launched (live or paused), PAUSED, with their finished draft ads (copy and picture) inside. Use after new audiences were drafted into a running campaign. Nothing delivers until the owner turns an ad set on. Two steps: call without confirmPublish to get the summary for the user, then with it once they say yes.
ads__meta__ads__refreshcan modifyPush what an ad carries NOW (its picture set, copy, button and landing page) to the ad already on Meta, as a new creative on the same ad. Use after ads.creative.compose, ads.creative.update or a landing page change on an ad that is live or paused on Meta; without this the edit stays in Plyto and Meta keeps showing the old one. Two steps: call without confirmRefresh to get the summary for the user,
ads__ad_set__statuscan modifyTurn one ad set of a launched Meta campaign on (live) or off (paused) while the campaign keeps running. Use for 'turn on the plumbing ad set', 'pause the dental audience'. Two steps: call without confirm to get what starts or stops spending for the user, then with confirm true once they say yes. Google ad groups are not supported yet.
ads__ad_set__spend_floorSet the least a Meta campaign's shared daily budget spends on one ad set each day (a minimum spend target), so a small audience is not starved by the others in a test. Only for campaigns with a campaign-level budget. Use for 'give each audience at least $12 a day'. Two steps: call without confirm to get the sum of floors against the campaign budget for the user, then with confirm true once they sa
ads__meta__goal__setcan modifySwitch what a Meta campaign aims for: landing_page_views (people who reach the page; right for an account whose pixel has no conversions yet, or when the owner asks for visits first) or conversions (the objective's own event, a Lead on a leads campaign; switch once leads are coming in, roughly ten or more a week). Changes every published ad set on Meta and restarts Meta's learning. Two steps: call
ads__meta__pixel__setupSet up the Meta pixel on the business's connected Facebook ad account: keeps the one already chosen, adopts the account's only pixel, or creates one named after the business when the account has none (free, and it belongs to the owner's ad account). With several on the account it lists them; ask which one, then call again with pixelId. Pages Plyto builds report to the chosen pixel on their own; th
ads__creative__attach_imageAttach a creative-library image OR video clip to a draft ad (sets it as the ad's media; for image sets, launch resolves the other placement sizes by the asset's name-siblings; a video clip launches as a Meta video ad that plays in Reels, Stories and the feed). Use right after ads.creative.generate_images or once a generated clip has landed, pairing each asset with the ad whose copy it matches, one
ads__creative__detach_imageTake the picture off a DRAFT ad. The file stays in the library (ads.assets.delete removes it); the ad keeps its words and is marked as waiting for a picture, so it will not launch bare. Use it when a picture went on an ad that should have waited (the owner asked for their own photo first), or shows the wrong thing and nothing should stand in its place yet. To put a different picture on instead, ad
ads__pictures__holdPut a campaign's pictures on hold because the owner said to wait for their own photo ("don't make any imagery until I send the exterior shot", "no pictures yet, I'll send some"). While it holds, nothing draws a picture for its ads: not ads.creative.generate_images, not ads.creative.compose_graphic, not the redraws, and not the step that gives every new ad a picture before the reply goes out. The a
ads__pictures__releaseLift the picture hold on a campaign because the owner said in so many words to go ahead without their photo (or to make a placeholder after all). The ads then take pictures again the usual way. Not needed when their photo arrives: a real photo lifts the hold by itself.
ads__audience__listread-onlyList the Meta custom audiences and lookalikes on the connected ad account, with their approximate sizes. Use when the user asks what audiences they have, or before targeting or building one.
ads__audience__createcan modifyCreate a Meta audience for the business: either a custom audience from one of their Plyto contact lists, or a lookalike of an audience they already have. Use when the user wants to target their customers, or reach 'people like' their best customers. Creating an audience spends nothing and changes no running campaign, but it does send their customer list to Meta, which is not reversible by deleting
ads__audience__interestsread-onlySearch Meta's interest and behavior catalog for detailed targeting, with approximate audience sizes. Use when the user wants to target people by interest, or asks what interests they could target. Returns ids that can be attached to an ad set.
ads__search_terms__listread-onlyShow what people actually searched for before seeing the business's Google ads, with spend, clicks and conversions per term, and which terms are wasting money (spend with zero conversions). Use when asked where the ad budget is going, why costs are high, or what to block. This report is PARTIAL: Google lags and hides low-volume terms, so its spend figures are a floor and must never be reported as
ads__negative_keywords__addBlock search terms on a Google campaign by adding them as negative keywords, so the ads stop showing for that traffic. Use after finding wasteful terms. This lowers wasted spend and never raises a budget.
ads__negative_keywords__listread-onlyList the negative keywords already blocking traffic on a Google campaign. Use before adding more, so nothing is added twice.
ads__delivery__diagnoseread-onlyExplain why live campaigns are or aren't delivering: learning phase, budget too small to enter the auction, rejected ads, audience too narrow, payment problems. Use whenever the user asks why a campaign has low or zero spend, impressions, or results.
ads__google_audience__listread-onlyList the Customer Match and remarketing audiences on the connected Google Ads account, with their sizes. Use when the user asks what Google audiences they have or before targeting one.
ads__google_audience__createcan modifyTEMPORARILY UNAVAILABLE: Google approved Plyto for conversion reporting, and approval for customer list uploads is still pending, so this tool currently refuses with an explanation. When a user asks for a Google audience, say that plainly and offer keyword targeting on Google or the same audience on Meta instead. Normally: upload a Plyto contact list to Google as a Customer Match audience. Emails
ads__lead_form__listread-onlyList the Facebook instant forms (lead forms) on the connected page, with how many leads each has collected. Use when the user asks about their lead forms or before pointing a campaign at one.
ads__lead_form__createcan modifyCreate a real instant form on the business's Facebook page. It becomes a live asset on their page that collects strangers' names, emails and phone numbers, and Facebook does not let you delete forms that have submissions. Submissions land in Contacts automatically.
ads__google__conversion_tracking__repairSet up Google conversion tracking for a business that is missing it. Use when a campaign launched without conversion tracking, or when the campaign page reports that setup failed. It never changes how a campaign bids or spends: the result lists each live Google campaign's conversions in the last 30 days and whether that is enough (about 15) for conversion bidding. Relay that in words; if one is re
ads__destinations__syncPush the landing page URLs shown in Plyto to the live ads on Google, for a campaign whose destinations were changed after launch. Use when ads are sending traffic somewhere other than what the campaign page shows. Changes where clicks land; it does not change budget or spend.
ads__google__search_partners__setTurn Google Search Partners on or off for a live campaign. Partner sites deliver cheap clicks with high click-through rates and far worse conversion than Google Search, so turning them off is the standard fix when a campaign shows an implausible click-through rate and no results. Changes where ads show; it does not change budget.
ads__google__bidding__setSwitch a live Google campaign between clicks bidding and conversions bidding. Use maximize_clicks when a campaign shows zero or near-zero impressions on Google Search because it is optimizing toward conversions that never get recorded. Spends the same daily budget either way; does not raise it. This changes how a live campaign spends, so call it only after the owner has said yes to this specific c
ads__google__ads__strengthenFill every live responsive search ad in a Google campaign up to the full 15-headline / 4-description asset counts, keeping all existing lines and pins and adding brand and ad-group-themed lines. Use when Google rates the ads' Ad strength Poor: thin asset lists cap Ad strength, and Poor strength costs auctions regardless of bid. Existing copy is never removed. Honest caveats to relay: Google briefl
ads__creative__updatecan modifyEdit an existing ad's headline, description, or destination link. Drafts update in place. A live Google search ad gets a replacement version published and the old one paused, because Google does not allow editing published ad copy; destination-only changes update in place. Live Meta ads cannot be edited yet.
ads__creative__deletecan modifyDelete a DRAFT ad outright (its images stay in the library), or PAUSE a live Google search ad (published ads can't be deleted, but a paused ad stops serving immediately). Use when a pre-launch check flags an ad the user wants gone — a trademarked competitor name in a headline, off-brand copy — instead of leaving a flagged ad you cannot clear. Live Meta ads can't be changed yet.
ads__funnel__testSend a tagged test lead through a campaign's whole funnel: landing page, form, CRM contact, conversion attribution, and a dry-run Google upload check. The test lead uses an undeliverable address, is removed afterwards, and no ads or budgets change. Use when someone asks whether their tracking or funnel actually works.
ads__google__keywords__addAdd keywords to a live Google campaign's ad group, phrase match by default. Use to feed phrasing families that are converting, for example when winning search terms are not yet covered by the keyword list. Does not change budget; new keywords compete inside the existing daily cap.
ads__google__ads__add_landing_variantStart a landing page A/B test on the live Google campaign. In ad groups with room it adds a copy of the strongest ad pointing at the new URL; in groups already at Google's 3-ad cap it repoints the weakest ad instead, keeping the strongest on the incumbent page. Google's ad rotation splits the traffic and attribution records which page each signup came through. Skips ad groups that already point at
ads__query_pages__buildThe query-to-page engine: cluster what people actually searched on a live Google campaign, generate one landing page per intent cluster (headline that speaks the search back, brand-grounded copy, the business's live form embedded), and point variant ads at each page. Charges AI credits for the copy. Returns each page's URL and how many ads were routed. Use when search terms show distinct intents l
ads__google__ad_groups__addAdd a complete search ad group (keywords phrase-match by default, RSA copy) to a SPECIFIC Google campaign by id. Headlines are at most 30 characters and descriptions 90, and every offer, timeframe or proof is checked against what the owner said (the words refused most: today, same-day, free, best prices, guaranteed, any price not on file). Where its clicks go follows the owner's decision on file (
ads__google__ad_groups__removecan modifyRemove an ad group you (or the user) no longer want. Draft groups are deleted outright along with their draft ads. Groups on a LIVE campaign are PAUSED in Google instead: delivery stops immediately, history is kept, and the pause is reversible in Google Ads. Use this to clean up groups created by mistake.
ads__campaign__deletecan modifyDelete a campaign that never launched (draft or failed): the campaign, its ad groups, and its draft ads are removed permanently; images stay in the creative library. A campaign that has reached the ad platform is archived instead of deleted, and a LIVE campaign is refused until it is paused. Two-step: first call returns a summary to confirm with the user; call again with confirm:true to delete (sa
ads__google__extensions__generatecan modifyDraft sitelinks, callouts, and a structured snippet for a DRAFT Google campaign from the brand profile and the campaign's own keywords, and save them onto the draft. They are applied to Google at launch. URL VERIFICATION IS BUILT IN: sitelink destinations are chosen from the site's own sitemap and each is HEAD-checked live (HTTP 200) before saving, so NEVER refuse to run this out of doubt about UR
email__create_templateCreate a reusable email template. Body and subject are plain text and support merge tags: {{contact.firstName}}, {{contact.lastName}}, {{contact.fullName}}, {{contact.email}}, {{business.name}}, with fallbacks like {{contact.firstName|there}}.
email__list_templatesread-onlyList email templates for this business.
email__list_sendsread-onlyList recent email sends, optionally filtered to one contact or template. Shows delivery status per send.
email__get_send_statsread-onlyAggregate send counts by status (queued/sent/delivered/opened/clicked/bounced/failed), optionally for one template and/or a recent window. Use to answer 'how did that email do?'
email__domain__statusCheck the business's custom sending domain: current status, and when it is still pending, exactly which DNS records have not been found yet (record type, host name, and value to add). Calling this also asks the email provider to re-check DNS right now, so it doubles as a manual re-verify. Use whenever someone asks why their domain is pending, whether their domain is verified, or why email still se
email__signature__setSet or clear the CURRENT USER's personal email signature for this business (their Gmail-style sign-off, appended when they compose one-to-one emails from a contact page). ONE-TO-ONE ONLY: marketing campaigns and automation emails never include it, by design; their sign-off is part of the campaign content. Markdown works: bold, [links](https://url), image logos. Pass an empty string to clear back t
email__campaign__listread-onlyList email marketing campaigns with status, type, subject, and audience size. Use to answer 'what campaigns do we have' or find a campaign to edit.
email__campaign__getread-onlyGet one email campaign's full draft: subject, preview text, body, audience, schedule, A/B test setup and (once it has sent) its per-variant results and winner, plus the current eligible-recipient breakdown. Call before editing so changes are targeted, and call it to answer 'which version won'.
email__campaign__createCreate a DRAFT email marketing campaign (never sends anything). Write subject/preview/body in the brand voice; the user reviews in the composer and nothing goes out without an explicit send confirmation. Returns the campaign URL to share with the user.
email__campaign__updateEdit a draft or scheduled email campaign: name, subject, preview text, body, audience list, schedule, or A/B test. Plyto DOES support A/B testing on email campaigns: set abVariable plus the matching B-side copy and every recipient is assigned a side at send time, then the campaign page reports opens and clicks per variant and names a winner. Sent campaigns can't be edited. Changes appear instantly
automations__createCreate an automation: a trigger + a linear chain of steps. Created in DRAFT and it stays that way. Do NOT activate it as part of building it: tell the user what it does and let them ask for it to be turned on. Steps run in order; a branch step exits contacts that don't match (its false path can be rewired later via automations.connect_steps). Example: trigger form.submitted → delay 1 day → action
automations__pausePause an active automation: no new enrollments. In-flight enrollments finish their current step and then hold (W7 executor checks status).
automations__listread-onlyList automations with status and trigger.
automations__getread-onlyFetch one automation with its full step graph (ordered), for inspection or before editing.
automations__connect_stepsRewire the step graph: point a step's `next` or `branch_false` slot at another step (or null to make that path exit). Use after automations.get to see current wiring.
automations__list_enrollmentsread-onlyList enrollments (who's in an automation and where they are), filterable by automation and state.
automations__get_step_runsread-onlyStep-by-step execution log for one enrollment: what ran, when, with what outcome/error. The debugging tool for 'why didn't Jane get the email?'
automations__exit_contactcan modifyForce-exit an active enrollment: the contact stops at the next step boundary and receives nothing further from this automation. Use when someone asks to be left alone or was enrolled by mistake.
automations__retry_enrollmentSend a FAILED enrollment back to the step that failed, so the contact continues from there (nothing they already received is sent again). Use after the cause is fixed. automations.list_enrollments with state failed shows who stopped and why. Sends real email to a real person: confirm with the owner first.
automations__test_runread-onlyStatic dry-run: validates every step of an automation WITHOUT executing anything: action tools exist and accept their arguments (with templates resolved against dummy values), delays/waits are in bounds, the graph reaches an exit. Run before activate; report problems to the user.
automations__restoreRestore an archived automation. It comes back PAUSED (never auto-active). Activate it separately to resume enrolling. Previously-exited contacts are not re-enrolled.
websites__create_siteCreate a WEBSITE: the business's home on the web, multi-section, with a nav. NOT for landing pages: the page an ad sends people to is ads.landing_pages.build, under Marketing, Landing pages. HOW TO BUILD ONE. (1) Call websites.photos first; a site with no photo of the real place, work or people is the failure mode, and photos decide which variants you can use. (2) Pick the pairing and radius for t
websites__list_sitesread-onlyList this business's websites with status and URLs.
websites__get_siteread-onlyGet a site with its theme and every section (block ids, kinds, content) for editing. Call it before any edit so you change the right block, and read the current content back to the person in plain words when they ask what is on the site.
websites__update_siteChange a site's settings: name, SEO title and description, accent color, font pairing, corner radius, dark or light. Omitted settings keep their value, so 'make it darker' is dark: true and nothing else. Owners can also edit these and every section themselves under Site.
websites__update_blockEdit part of a section. Pass ONLY the fields that change; everything else in the section is kept, so 'shorten the headline' touches the headline and nothing else. Arrays (items, steps, images) are replaced whole when passed, so to change one service, pass the full items list with that one changed. Use unset to remove fields ('take the photo off the hero': unset ['image']). Shapes are per kind, as
websites__add_blockAdd a section to a site, at the end or at a position (0 is the top; later sections shift down). Same shapes and photo rules as websites.create_site. 'Add pricing' means: ask nothing if the prices are on file or in the conversation, otherwise ask for the prices first, then add it.
websites__remove_blockcan modifyRemove a section from a site. Do it the moment they ask ('take off the pricing', 'remove the gallery'): photos stay in the library, the section can be added back, and nothing is public until they publish, so never ask 'are you sure'. Confirm first only when it is unclear which section they mean.
websites__reorder_blocksReorder a site's sections ('move pricing above the FAQ'). Pass the COMPLETE list of block ids in the new top-to-bottom order (websites.get_site returns them). Partial lists are rejected so blocks can't be silently dropped.
websites__photosread-onlyWhat this business can put on a website, newest first: real photos the owner added or attached in chat (what: photo), product screenshots (product-screen), and scenes Plyto generated for ads (generated-scene, hero or about only, and only when nothing real exists). Ad graphics with headlines baked in and screenshots of their current website are left out; they never belong on a site. Call it before
websites__analyze_websiteread-onlyFetch and analyze an existing website (theirs or a competitor's). Returns title, description, headings, navigation links, and the page's visible text so YOU can rebuild it as a much better Plyto site. Keep the real business facts (services, hours, locations, offers), upgrade the copy and structure. Call this FIRST when the user wants their current site redesigned, then compose websites.create_site
websites__check_custom_domainVerify a site's custom domain DNS. If the records point at us, the domain goes active and the site serves on it (TLS is automatic).
seo__run_auditRun an SEO + GEO (generative engine optimization) audit on a URL. Fetches the page, robots.txt, sitemap.xml and llms.txt, runs ~15 deterministic checks (title, meta description, headings, alt text, structured data, FAQ content, llms.txt, mobile viewport…), stores the result, and returns the scored checklist. If no URL given, use the business profile's website.
seo__list_auditsread-onlyList recent SEO/GEO audits with scores.
seo__blog__create_draftSave a blog post draft. YOU write the post (600-1200 words of genuinely useful, non-generic content in the brand voice, markdown with ## headings) and pass it here. Include a meta description (<=155 chars) and 3-6 keywords.
seo__blog__listread-onlyList blog posts (drafts and published).
seo__blog__update_settingsConfigure the automatic blog writer: posts per week (0 disables, max 3), topic list to rotate through, and whether posts auto-publish or wait as drafts. HARD CEILING: 3 posts per week and 10 per day, enforced by the system, no exceptions. When someone asks for more ("120 a week"), do NOT attempt it and do NOT promise it. Set 3, and explain that the cap is deliberate: search engines reward steady c
booking__pages__listread-onlyList the business's booking pages with their public URLs, durations, and weekly availability. A booking page is where a lead picks a call time; a booked call automatically qualifies the lead (sales_qualified) and, when the lead came from an ad, reports that qualification back to the ad platform.
booking__pages__createCreate a booking page and return its public URL, ready to share, link from the website, or put in a form's thank-you message. Availability is weekly windows in 24h HH:MM, keyed by weekday number (0=Sunday..6=Saturday). Times are in the page timezone: pass the IANA zone where the business is (America/Phoenix for Phoenix, America/New_York for New York, Europe/London for the UK). Leaving it out means
booking__bookings__listread-onlyUpcoming booked calls: who, when, their note, and the show-up task. Use for questions like "what calls do I have" or "who booked this week".
pitches__createGenerate a branded pitch deck: a full slide presentation built from the brand kit (colors, logo, voice, approved claims) and, when a deal/company/contact id is given, grounded in that CRM record — who they are, what the deal is worth. Returns a hosted share link the user sends to their prospect. Takes one to two minutes and charges AI credits (it is a large generation). Growth plan and up. Use whe
pitches__listread-onlyList this business's pitch decks with status, share links, and view counts. The honest source for 'has anyone opened the deck'. Status 'generating' means the deck is still building; 'failed' means the build errored and it should be recreated.
pitches__edit_slideEdit one slide of an existing pitch deck with an AI rewrite that keeps the deck's design. The share link updates instantly. Use when the user wants to tweak a deck: change wording, adjust a slide's angle, fix an error. Charges a small AI credit amount.
pitches__deletecan modifyDelete a pitch deck permanently. Its share link stops working immediately. Two-step: first call returns the deck title to confirm with the user; call again with confirm:true to delete (the same two-step as deleting a deck in the UI).
Alternatives in CRM & Sales
Compare →MUMuninB
Open-source all-in-one MCP-first customer platform: KB, Conversations, CRM, CMS, Outreach, Analytics
BonderyB
Open-source personal CRM for building better bonds
GTM OttoB
Self-driving LinkedIn prospecting: it sources, warms and invites daily. You approve every message.
HMHitPay MCP ServerB
Official HitPay MCP: sales, payouts, balances; create payment links and invoices. OAuth; no refunds.
NMNevent MCPB
Talk to your live-events CRM (campaigns, analytics, paid ads, segments) in Claude and ChatGPT.
SalesTouchB
Give AI agents the LinkedIn tools to find, qualify, engage, and follow up with prospects.