servers / plyto

Plyto MCP server

communitystreamable_httpremotedestructive capablehealthy

A CRM powered by your agent: contacts, deals, email, ads, and reports over MCP.


01Tools · 173

How to read this: tool names here are observed from a live tools/list handshake. The Risk label is a heuristic inferred from the tool name (write/destructive verbs), not from executing the tool — a conservative guess, not a verified capability. We never escalate risk from a description. Found one that's wrong? Tell us — we fix on report.

ToolRiskSide effectsApproval
crm__contacts__update
Update fields on an existing contact. Only pass fields you want to change. No-op fields are silently skipped.
writetrueunknown
crm__deals__create
Create 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).
writetrueunknown
reports__preview
Run 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.
readfalseunknown
forms__update
Update 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 at Forms → open the form → Edit form.
writetrueunknown
crm__contacts__query
Query 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) has:open_deal | won_deal | task_open | company = relational predicates (op must be exists/not_exists) Operator availability depends on field kind: text → equals/contains/in/...; number → gt/lt/between; date → before/after/in_last_days; etc. Invalid pairings return a compile error.
readfalseunknown
ads__campaign__update
Edit an existing ad campaign: name, objective, daily budget, plain-English audience, or Google search keywords. Draft campaigns are freely editable. For LIVE campaigns only the budget can change and an increase requires the user's explicit approval first (then pass confirmSpendIncrease: true). Never launches anything. The name is the campaign's name only: never fold an ad-group or intent name into it ('Campaign · Group'); new intent groups are ads.google.ad_groups.add on the draft's id.
writetrueunknown
ads__campaign__changes
The 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 conversation seem to disagree. Describe changes in words; never show the internal action names.
readfalseunknown
ads__landing_pages__update
Edit 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.assets.list. When the owner dictates wording, use their words verbatim. Every offer, timeframe, credential, price or proof line must already be on file or in the owner's own messages in this conversation; a line the owner typed passes by definition, so put it in as written, while a promise you would be adding yourself is refused and named. What you change here counts as the owner's edit: regeneration will not rewrite it. Call ads.landing_pages.get first. Edits show on the live page immediately, so on a page that is getting traffic say so in one line.
writetrueunknown
ads__destination__set
Record 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 are never moved by this.
writetrueunknown
ads__meta__ads__publish
Put 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 set is switched off the ads are created but nothing delivers until it is turned on; say so.
writetrueunknown
ads__audience__create
Create 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 the audience afterwards.
writetrueunknown
ads__negative_keywords__add
Block 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.
writetrueunknown
ads__google_audience__create
TEMPORARILY 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 are hashed before they leave Plyto, but the upload itself cannot be taken back.
writetrueunknown
ads__creative__delete
Delete 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.
destructivetruetrue
ads__query_pages__build
The 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 landing on one generic page.
readfalseunknown
email__campaign__create
Create 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.
writetrueunknown
email__campaign__update
Edit 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 in the user's composer and are undoable from the activity log.
writetrueunknown
automations__create
Create 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 email.send (welcome) → wait_for_event email.opened (3 days) → branch (opened?) → action crm.tasks.create. WIN-BACKS: when the business takes bookings through Plyto, use trigger booking.lapsed (fires once when a contact's last confirmed booking passes 60 days with nothing upcoming); only fall back to a tag-based trigger when they don't use Plyto booking, and say plainly that someone must apply the tag. AUDIENCE CHECK before creating: the trigger defines who enters. contact.created = every new contact (ad leads, imports, form fills), NOT just signups; when the user means a narrower group, set trigger.filterCriteria (e.g. source equals signup) or lead with a branch, and tell the user exactly who will enter. SKIP TAGS MUST HAVE WRITERS: in Plyto's own house business ONLY, the platform writes these tags automatically: google-ads-connected, meta-connected, stripe-connected, imported-contacts, card-on-file, and activated (set when the person launches a campaign, activates an automation, or publishes a site). In every other business NO tag is platform-written. A skipIf on a tag nothing writes is inert until a human applies it, so either use a tag one of this business's own automations/forms writes, or tell the user plainly that they must apply your chosen tag by hand and when. NUDGE STEPS: any step whose copy assumes inaction ('still there?', 'if you haven't launched yet', 'just checking in') MUST carry a skipIf on the signal that would make it wrong (a tag like activated, a property, a won deal), and you must tell the user which signal you chose so they know what to set. A customer who already acted and still gets 'if you haven't started yet' reads it as spam. JOURNEY SHAPE: use per-step skipIf and automation-level exitCriteria so sequences respect what contacts already did (tags they gained, fields that changed): a nudge someone already acted on should skip, and a goal reached mid-sequence should end the journey.
writetrueunknown
websites__update_site
Change 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.
writetrueunknown
websites__add_block
Add 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.
writetrueunknown
booking__pages__create
Create 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 (default America/Los_Angeles). Example availability: {"1":[["09:00","17:00"]],"3":[["09:00","12:00"]]}.
writetrueunknown
crm__companies__create
Create 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).
writetrueunknown
crm__deals__close_lost
Close a deal as lost: moves it to the lost stage in its pipeline. Records lostReason and emits deal.lost.
unknownunknownunknown
crm__activities__log
Log 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.
unknownunknownunknown
forms__create
Create 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).
writetrueunknown
ads__performance__summary
THE 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 summing another report: ads.search_terms.list in particular is partial by design and its totals are a small fraction of real spend.
readfalseunknown
ads__campaign__locations__set
Set 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, or whenever the user names where ads should run. Drafts: names resolve against the platform catalog when an account is connected, otherwise they are saved as pending and resolve at launch. Live campaigns: read the current targeting with ads.campaign.locations.get first, tell the user what changes (which places stop seeing the ads), and call with confirmLiveEdit: true once they have said so; every name must resolve or nothing changes.
writetrueunknown
ads__creative__generate_images
Generate 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. If every size fails quality review, call it once more with a simpler wordless brief (the tools or materials alone, no hands, no labeled equipment) before falling back to a designed graphic. PLACEMENT SIZES: 1:1 1080x1080 (REQUIRED default/fallback: Marketplace, right column, search), 4:5 1080x1350 (Instagram feed), 9:16 1080x1920 (Stories/Reels), 16:9 1920x1080 (Facebook feed ONLY, never Marketplace or right column). Defaults to the full four-size set. Charges AI credits (~15-20¢ per image). Takes up to a minute; returns asset ids. When generating FOR a campaign's existing ads, finish the job: pair each concept with the ad whose copy it matches and attach it with ads.creative.attach_image, one call per ad. Never leave images in the library and tell the user to attach them by hand.
readfalseunknown
ads__search_terms__list
Show 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 the campaign's total spend. Get real spend from ads.performance.summary. IMPORTANT when reporting: each term is a query a stranger typed into Google. Describe it as 'someone searching for X', never as a customer, company, or signup name.
readfalseunknown
email__signature__set
Set 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 to the default sign-off. Only affects the person talking to you, never teammates. They can also edit it themselves under Settings, Email signature.
writetrueunknown
memory__list
List 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.
readfalseunknown
memory__save
Save (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 your context with ids), pass its memoryId to UPDATE it instead of creating a near-duplicate. Do NOT save one-off task details, secrets, credentials, or personal contact data. Contact facts belong on the contact (crm.notes.add).
unknownunknownunknown
memory__forget
Permanently 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.
unknownunknownunknown
business__update
Save 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 their words). A workspace created from a signup carries a placeholder name until you set the real one, and the placeholder would otherwise end up in their ads and emails. Setting a website starts a background scan that fills the brand profile (industry, audience, voice, logo, colors) and, for a workspace with nothing in it yet, stages a starter kit (lead form, welcome email, follow-up automation, all as drafts); tell the user the scan takes about a minute. Pass only the fields you actually learned.
writetrueunknown
crm__contacts__list
List contacts in this business with simple filters. For free-text search use crm.contacts.search. For complex filters use crm.contacts.query (W3).
readfalseunknown
crm__contacts__create
Create 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.
writetrueunknown
crm__contacts__get_properties
Return all custom property values for a contact as a {key: value} map.
readfalseunknown
crm__contacts__get
Fetch 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.
readfalseunknown
crm__companies__search
Free-text search across company name, domain, and industry. Case-insensitive substring match.
readfalseunknown
crm__tags__add_to_contact
Apply a tag to a contact. Idempotent: adding an already-applied tag is a no-op.
writetrueunknown
crm__tags__remove_from_company
Remove a tag from a company. Idempotent.
destructivetruetrue
crm__contacts__search
Free-text search across contact email, first/last name, and phone. Case-insensitive substring match. Returns up to 20 contacts by default.
readfalseunknown
crm__companies__get
Fetch a single company by id. Returns null if not found.
readfalseunknown
crm__tags__create
Create a new tag (or find one with the same name; idempotent). Tags are lightweight orthogonal categories like 'VIP', 'Newsletter-only', 'Cold'.
writetrueunknown
crm__companies__update
Update fields on an existing company. Only pass fields you want to change.
writetrueunknown
crm__companies__get_properties
Return all custom property values for a company as a {key: value} map.
readfalseunknown
crm__tags__remove_from_contact
Remove a tag from a contact. Idempotent.
destructivetruetrue
crm__tags__list_for_company
List all tags applied to a company.
readfalseunknown
crm__properties__set_contact_value
Set the value of a custom property on a contact. Value type must match property type. For multi_select pass an array of option values.
writetrueunknown
crm__companies__list
List companies in this business. For text search use crm.companies.search.
readfalseunknown
crm__tags__list
List all tags defined in this business.
readfalseunknown
crm__tags__add_to_company
Apply a tag to a company. Idempotent.
writetrueunknown
crm__properties__list
List custom property definitions for an entity type. Excludes archived by default.
readfalseunknown
crm__tags__list_for_contact
List all tags applied to a contact.
readfalseunknown
crm__properties__define
Define 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.
unknownunknownunknown
crm__properties__set_company_value
Set the value of a custom property on a company.
writetrueunknown
crm__properties__clear_deal_value
Remove a custom property value from a deal.
unknownunknownunknown
crm__pipelines__get_default
Get the default pipeline for this business (the one new deals land in by default). Returns null if no default is set.
readfalseunknown
crm__deals__close_won
Close a deal as won: moves it to the won stage in its pipeline. Sets closedAt and emits deal.won.
unknownunknownunknown
crm__properties__archive
Archive a custom property. Existing values are preserved but the property is hidden from UI and rejected for new value sets. To 'rename', archive + redefine.
destructivetruetrue
crm__properties__clear_contact_value
Remove a custom property value from a contact.
unknownunknownunknown
crm__pipelines__list
List all pipelines in this business (excludes archived by default).
readfalseunknown
crm__properties__set_deal_value
Set the value of a custom property on a deal.
writetrueunknown
crm__properties__clear_company_value
Remove a custom property value from a company.
unknownunknownunknown
crm__pipelines__list_stages
List the ordered stages in a pipeline. Use to look up stageIds for crm.deals.move_stage.
readfalseunknown
crm__deals__move_stage
Move 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.
writetrueunknown
crm__deals__list
List 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.
readfalseunknown
crm__activities__get
Fetch a single activity by id.
readfalseunknown
crm__tasks__list
List tasks. Open tasks sort by due date (closest first). Completed tasks sort by completion (most recent first).
readfalseunknown
crm__properties__get_deal_values
Return all custom property values for a deal as a {key: value} map.
readfalseunknown
crm__deals__update
Update 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.
writetrueunknown
crm__tasks__complete
Mark a task as completed. Sets completedAt to now.
unknownunknownunknown
crm__deals__get
Fetch a single deal by id.
readfalseunknown
crm__activities__list
List activities, optionally filtered by entity (contact/company/deal) or owner. Returned in reverse chronological order by happenedAt.
readfalseunknown
crm__tasks__cancel
Mark a task as cancelled (rejected, different from completed). Use when the user decides a task is no longer relevant.
destructivetruetrue
crm__deals__search
Free-text search across deal names.
readfalseunknown
crm__tasks__create
Create 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.
writetrueunknown
crm__tasks__get
Fetch a single task by id.
readfalseunknown
reports__list
List the saved custom reports on the Reports dashboard.
readfalseunknown
crm__lists__get
Fetch a single list by id.
readfalseunknown
crm__lists__remove_contact
Remove a contact from a manual list.
destructivetruetrue
crm__notes__add
Add a freeform note attached to a contact, company, deal, or any combination. Use for 'remember that Jane prefers email over phone' style facts.
writetrueunknown
crm__lists__list
List all contact lists in this business.
readfalseunknown
crm__lists__archive
Archive a list. Membership rows are preserved but the list is hidden from default queries.
destructivetruetrue
forms__list
List all forms in this business.
readfalseunknown
crm__sources__performance
Marketing-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 'which marketing source makes me the most money'. Sorted by won revenue; money values are in cents. Mirrors the Reports → Sources view.
readfalseunknown
crm__notes__list
List notes, optionally filtered by attached entity.
readfalseunknown
crm__lists__members
Return 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).
readfalseunknown
reports__create
Save 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.
writetrueunknown
crm__lists__create
Create 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.
writetrueunknown
crm__lists__add_contact
Add a contact to a MANUAL list. Idempotent.
writetrueunknown
forms__list_submissions
List submissions for a form, newest first.
readfalseunknown
ads__campaign__list
List 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.
readfalseunknown
forms__get_embed_code
Generate the JS embed snippet and iframe alternative for a form. Returns both; the user picks whichever fits their site.
readfalseunknown
forms__get
Fetch a form by id.
readfalseunknown
ads__campaign__draft
Create a draft ad campaign on Meta (Facebook and Instagram) or Google, the only two 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.
unknownunknownunknown
ads__creative__draft
Create 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+search), 4:5 (1080x1350, Instagram feed), 9:16 (1080x1920, Stories/Reels), 16:9 (1920x1080, Facebook feed ONLY, never Marketplace or right column). The square must always exist; omit landscape rather than crop it badly.
readfalseunknown
ads__creative__generate_video
Render 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: headline and CTA live in the ad copy. People described generically in the brief are FINE (a plumber at work, a customer smiling at her phone, a barista); do not refuse or reframe a brief because it has a person in it. What is refused: real, named people and celebrities, copyrighted characters, and a STARTING IMAGE that contains a face.
unknownunknownunknown
ads__assets__delete
Permanently 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.
destructivetruetrue
ads__creative__compose_graphic
Compose a DESIGNED ad graphic deterministically: real type, the real logo, the real product image, proof from the claims on file. No AI image model, no credits. To EDIT an existing designed graphic, pass revisionOf (its asset id) plus only the fields that change: the rest is kept, the old set is archived and the ad using it switches to the new one. Layout "complete" is the finished ad and the default for software and for any business with a product screen or site capture; "offer" is a typographic poster for a pricing or free-trial offer. For a physical business (trades, restaurants, retail, fitness, physical products) the picture is a photograph of the work or the product: their own photo through ads.creative.compose_from_photo first, ads.creative.generate_images only when they have none. Every offer, credential, timeframe and proof in the words must trace to the brand profile, the website scan, or what the person said; the tool refuses the rest. All four placement sizes by default.
unknownunknownunknown
ads__performance__analyze
Analyze 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', 'what should I cut', 'which campaign actually makes money'.
readfalseunknown
ads__creative__compose_from_photo
Turn 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. One call per photo; pass adCreativeId to attach the square to that ad. Generated images are refused here; those already are ads.
readfalseunknown
ads__creative__compose_video
Turn 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 composition, no credits, about a minute in the background; the ad lands in Creative studio with a notification and can then go on a draft with ads.creative.attach_image. Every offer or proof in the words must trace to the brand profile, the website scan or what the person said.
unknownunknownunknown
ads__ads__list
List 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'.
readfalseunknown
ads__assets__list
List 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. Use it to pick a heroAssetId, a fromAssetId, or an asset for ads.creative.attach_image.
readfalseunknown
ads__campaign__locations__get
Where 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.
readfalseunknown
ads__landing_pages__build
Build 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 show the owner the links and ask before passing repointLiveAds. Idempotent per ad group. Charges a small amount of AI credits for the copy. Use when a campaign's ads would otherwise send people to a homepage, when the owner has no website, or when Google rates ad relevance or landing page experience below average.
readfalseunknown
ads__landing_pages__list
The 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.
readfalseunknown
ads__landing_pages__get
Everything 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.
readfalseunknown
ads__campaign__refresh
Pull 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 campaign, ad group or ad is live, paused or running; when the owner says they changed something on the ad platform directly; and whenever what Plyto shows disagrees with what they see there. Reads only; nothing on the platform is changed.
unknownunknownunknown
ads__landing_pages__create
Make 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 gates as every page (nothing invented). It is a landing page (one promise, a form or a button, no navigation), never a website. Pick the conversion for what they sell: self-serve software or checkout gets destination link to the signup or buy page; a business that calls people back gets the form. The ad's own picture or the newest real photo goes on the page unless you name one from ads.assets.list. The ads keep pointing where they were unless pointDraftAds is set on a draft campaign; on a live campaign the owner moves traffic from the page's screen (Send traffic). Returns the page's link, its copy and what is still missing; show the link, read the headline back, and act on the warnings.
writetrueunknown
ads__campaign__launch
Launch 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 only after they said yes. The launch itself takes a minute or two; the campaign page shows progress and a failure posts to the conversation.
readfalseunknown
ads__campaign__status__set
Pause 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 campaign-level option.
writetrueunknown
ads__destination__get
Where this business's ad clicks go, or, when nobody has decided yet, the numbered question to ask the owner (their site's real pages checked live, a recommendation and why). A draft's result already carries this as destinationAsk; call this when you need it again or before launching. Never decide it yourself: relay the question, numbered, verbatim, and record the answer with ads.destination.set.
readfalseunknown
ads__creative__add
Add one ad (headline + primary text + CTA, plus a link except on a Meta leads campaign, where the instant form is the destination and no link is needed) 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 Meta campaigns can't take new ads yet. Write copy in the brand voice; keep Google headlines ≤30 chars and descriptions ≤90 chars; on Meta keep the primary text under 125 characters (Facebook hides the rest behind "See more") and the headline under 40. Call once per ad variation.
writetrueunknown
ads__funnel__summary
The 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 not a result. Also returns the landing-page funnel (sessions, starts, submits) by page so you can see where clicks are lost.
readfalseunknown
ads__audience__list
List 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.
readfalseunknown
ads__creative__attach_image
Attach 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 call per ad. Only draft ads; live ads change through the app.
unknownunknownunknown
ads__audience__interests
Search 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.
readfalseunknown
ads__delivery__diagnose
Explain 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.
unknownunknownunknown
ads__negative_keywords__list
List the negative keywords already blocking traffic on a Google campaign. Use before adding more, so nothing is added twice.
readfalseunknown
ads__lead_form__list
List 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.
readfalseunknown
ads__google__search_partners__set
Turn 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.
writetrueunknown
ads__google_audience__list
List 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.
readfalseunknown
ads__google__conversion_tracking__repair
Set up Google conversion tracking for a business that is missing it, and move live Google campaigns from bidding on clicks to bidding on conversions. Use when a campaign launched without conversion tracking, or when the campaign page reports that setup failed. Changes how the campaign bids; it does not change any budget.
unknownunknownunknown
ads__destinations__sync
Push 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.
unknownunknownunknown
ads__lead_form__create
Create 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.
writetrueunknown
ads__google__bidding__set
Switch 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.
writetrueunknown
ads__google__ads__strengthen
Fill 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 briefly re-reviews edited ads, the ads' learning history resets, and the Ad strength label can take hours to recompute.
readfalseunknown
ads__creative__update
Edit 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.
writetrueunknown
ads__google__ads__add_landing_variant
Start 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 that page, so it is safe to run twice. Does not change budget, bidding, or keywords.
writetrueunknown
ads__campaign__delete
Delete 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 (same as the two-step Remove in the UI).
destructivetruetrue
ads__google__extensions__generate
Draft 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 URLs, and never leave callouts empty over URL concerns (callouts have no URLs at all). Run this on every Google draft you build; a Search campaign without sitelinks and callouts loses ad real estate to competitors who have them. Re-running replaces the previous draft set. Refuses live campaigns (extensions ship at launch).
readfalseunknown
email__get_send_stats
Aggregate 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?'
writetrueunknown
ads__funnel__test
Send 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.
unknownunknownunknown
ads__google__ad_groups__add
Add a complete search ad group (keywords phrase-match by default, RSA copy) to a SPECIFIC Google campaign by id. Where its clicks go follows the owner's decision on file (a page Plyto builds for the group, or their own link); undecided, the result carries the question to ask. Pass 8-12 VARIED headlines and 3-4 distinct descriptions: launch pools them (plus title-cased keywords) into one responsive search ad, and thin or repetitive lists rate Poor on Ad strength, which loses auctions regardless of bid. On a DRAFT campaign this creates draft rows only, reviewable and launchable later; nothing reaches Google. On a LIVE campaign it writes to Google immediately and is refused unless confirmLiveEdit is true, which you may set only after the user explicitly asked to edit that live campaign. While building a new campaign, always pass the new draft's id. Errors instead of duplicating when a same-named group already exists.
writetrueunknown
ads__google__keywords__add
Add 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.
writetrueunknown
ads__google__ad_groups__remove
Remove 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.
destructivetruetrue
email__list_templates
List email templates for this business.
readfalseunknown
email__create_template
Create 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}}.
writetrueunknown
email__domain__status
Check 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 sends from the shared Plyto address. Relay the missing records concretely: name the record type and host, never just say 'check your DNS'. A background check also runs every 30 minutes and emails the owner the moment verification passes.
readfalseunknown
email__list_sends
List recent email sends, optionally filtered to one contact or template. Shows delivery status per send.
readfalseunknown
email__campaign__list
List email marketing campaigns with status, type, subject, and audience size. Use to answer 'what campaigns do we have' or find a campaign to edit.
readfalseunknown
email__campaign__get
Get 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'.
readfalseunknown
automations__pause
Pause an active automation: no new enrollments. In-flight enrollments finish their current step and then hold (W7 executor checks status).
readfalseunknown
automations__list
List automations with status and trigger.
readfalseunknown
automations__connect_steps
Rewire 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.
readfalseunknown
automations__test_run
Static 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.
writetrueunknown
automations__get
Fetch one automation with its full step graph (ordered), for inspection or before editing.
readfalseunknown
automations__exit_contact
Force-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.
unknownunknownunknown
websites__list_sites
List this business's websites with status and URLs.
readfalseunknown
automations__list_enrollments
List enrollments (who's in an automation and where they are), filterable by automation and state.
readfalseunknown
automations__restore
Restore an archived automation. It comes back PAUSED (never auto-active). Activate it separately to resume enrolling. Previously-exited contacts are not re-enrolled.
unknownunknownunknown
automations__get_step_runs
Step-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?'
readfalseunknown
websites__create_site
Create 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 the trade (a roofer is workshop and sharp, a bakery is warm and round, a bookkeeper or clinic is editorial and soft, a software company is modern and soft). (3) Compose 6 to 9 sections from the list below, writing real, specific copy in the owner's voice, never lorem ipsum, and put real photos in every slot that fits one. The standard spine: hero (split, with their best photo), services (3 to 6), about (with the owner or team photo), process (3 to 4 steps from the customer's side), then whatever they have proof for (gallery, before_after, testimonials, stats, pricing, areas), then faq (4 to 6 real questions), cta, contact. WHAT EACH SECTION IS FOR: hero: First screen. variant "photo" (one full-width picture, headline over it, the booking card floating on it) is the default: Plyto puts a scene of the place there when no real photo exists; "split" (headline left, their photo right) for a strong real photo; "centered" is the fallback with no picture at all. Headline is the promise in the customer's words, under 70 characters. services: What they sell, 3 to 6 items. "photo-cards" when each service has a photo; "cards" otherwise; "list" for many small items. One line each, no adjectives standing alone. about: Who they are, in the owner's voice, with a photo of the owner or the team. "split" with a photo; "story" for text alone. Byline is the owner's name and role. gallery: Their work. Only real photos from their library; never generated scenes here. 4 to 12. process: What happens after someone gets in touch, 3 to 4 steps from the customer's side: "We come out and photograph it", not "our team will reach out". Renders beside up to two pictures (images); Plyto fills them with scenes of the place when no real photos exist. testimonials: ONLY real quotes with real names. Omit the section entirely when none exist; never write one. team: Real people with real photos. Omit when there are none. pricing: Only prices the owner gave. Omit when none. Note carries the caveat ("from", "plus parts"). areas: Service area as a list of places. From the profile or the owner, never guessed. stats: Proof strip, ONLY from approved claims on file. Omit when there are none: an empty strip is fine, an invented one is not. cta: One band near the end repeating the main promise and the one action. contact: Form plus phone, email, address, hours: only the details actually on file. "split" puts the details beside the form. faq: 4 to 6 real questions customers ask, answered plainly. No marketing in the answers. logos: Certifications, associations, partners. Only real ones with real logos. before_after: Paired photos of the same job. Trades and cosmetic work. Omit without real pairs. hours: Opening hours, address, phone, map. Only what is on file. video: A YouTube or Vimeo link they gave. Never a generated clip here. custom: Anything else, heading and body. FACTS ONLY: never invent operational promises the owner has not made (response times, guarantees, service-area lists), never fabricate testimonials, review counts, stats or years in business, never state booking windows, scarcity, prices or hours that are not on file. Omit a section rather than fill it with an invention. The tool checks: any offer ('free'), timeframe ('same day', 'within a few days', 'one to three days'), credential ('licensed', 'certified'), waived fee, founding year, count or price that is not in the brand profile or in the owner's own messages is refused with the phrase named; drop it or ask the owner. CONTACT DETAILS: phone, email, address and hours only when the profile or the owner gave them; after creating, ask for what is missing. Never write 'call us' unless the number is on the page. The contact section is wired to the business's newest live form (one is created if none exists), so every site can convert; hero and cta buttons default to #contact. Created as a DRAFT at plyto.ai/sites/[subdomain] that only the signed-in owner and team can open until it is published; the owner publishes it. After creating, say that in one line, show the preview link, and offer the edits you would make next, in plain words: they can change anything by talking to you.
writetrueunknown
websites__update_block
Edit 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 in websites.create_site; photo urls must come from websites.photos. Call websites.get_site first for block ids and current content.
writetrueunknown
websites__photos
What 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.create_site and before any edit that adds a picture. Only urls from this list may be used.
readfalseunknown
seo__list_audits
List recent SEO/GEO audits with scores.
readfalseunknown
booking__pages__list
List 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.
readfalseunknown
websites__get_site
Get 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.
readfalseunknown
websites__remove_block
Remove 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.
destructivetruetrue
websites__check_custom_domain
Verify 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).
unknownunknownunknown
seo__blog__list
List blog posts (drafts and published).
readfalseunknown
websites__reorder_blocks
Reorder 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.
readfalseunknown
seo__run_audit
Run 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.
writetrueunknown
websites__analyze_website
Fetch 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 from what you learn plus the brand profile.
readfalseunknown
seo__blog__create_draft
Save 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.
writetrueunknown
seo__blog__update_settings
Configure 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 cadence and punish content flooding, so 3/week outperforms a burst. After changing settings, mention they can also adjust cadence and publishing mode anytime on the Blog page's Auto-writer card.
writetrueunknown
booking__bookings__list
Upcoming 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".
readfalseunknown
pitches__delete
Delete 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).
destructivetruetrue
pitches__create
Generate 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 when someone wants a pitch, proposal deck, sales presentation, or slides for a specific prospect or deal.
writetrueunknown
pitches__list
List 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.
readfalseunknown
pitches__edit_slide
Edit 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.
writetrueunknown

02Install & source
https://plyto.ai/api/mcp
remote_url

03Access granted
Search the web · writeUpdate a CRM · destructiveRead email · write

The access this server can exercise, inferred from its verified tools — not a declared OAuth scope.


05Provenance & freshness
sourcesOfficial MCP Registry [p1]
last_checked2026-09-20 10:23Z
next_check2026-09-22 04:50Z
cadenceevery 48h
verifiedtools_list:passed handshake:passed metadata:passed tools_list:passed handshake:passed metadata:passed tools_list:passed handshake:passed metadata:passed handshake:skipped
index_statusindex5 unique facts >= 5

06Badge

Add the “as seen on MCPExplorer” badge to your README. Plyto MCP — as seen on mcpexplorer.com

[![Plyto MCP — as seen on mcpexplorer.com](https://mcpexplorer.com/badge/plyto.svg)](https://mcpexplorer.com/servers/plyto)

Next step

This is one server. A loadout combines the right servers, governance, and proven plays for a whole job — assembled deliberately, not tool-dumped.

Explore loadouts →