Servidor MCP

AfterLaunch: the agentic growth marketing engine

io.afterlaunch/agentic-growth-marketing

Qué hace este MCP

Runs growth-marketing workflows covering SEO, AI-search visibility, competitor analysis, content planning, distribution channels, experiments, and performance measurement.

accept_move
Accept a move only after the founder says yes. This records one durable preparation attempt and may start the configured worker only when launch_won is true. A repeat never starts another worker. Free; requires the 'act' scope.
Esquema de entrada
{'type': 'object', 'required': ['move_id', 'target'], 'properties': {'note': {'type': ['string', 'null'], 'maxLength': 2000}, 'target': {'enum': ['agent_pull', 'share', 'open', 'claude_cloud', 'cursor', 'codex'], 'type': 'string'}, 'move_id': {'type': 'string', 'description': 'Move id (uuid).'}, 'operation': {'enum': ['accept', 'retry'], 'type': 'string', 'description': 'Defaults to accept. Retry requires expected_attempt_id; use null only with the exact legacy state and updated_at.'}, 'expected_attempt_id': {'type': ['string', 'null'], 'description': 'Required for retry. Pass the exact managed attempt, or null for a legacy job.'}, 'expected_legacy_state': {'type': ['string', 'null'], 'description': 'get_move: prepared_result.legacy_state ?? state.'}, 'expected_legacy_updated_at': {'type': ['string', 'null']}}, 'additionalProperties': False}
archive_move
Archive a growth move: a lighter dismissal than skip, with no verdict recorded. Free; requires the 'act' scope. Idempotent on an already-archived move.
Esquema de entrada
{'type': 'object', 'required': ['move_id'], 'properties': {'move_id': {'type': 'string', 'description': 'Move id (uuid), from list_feed.'}}, 'additionalProperties': False}
create_checkout
Create a Founder-tier checkout link for THIS product run, the way to unlock the Founder-only growth controls and more metered marketing work. Returns a checkout_url the founder opens to pay; the upgrade lands automatically once payment succeeds. Reachable on a free trial because it is the path TO Founder. Requires the 'act' scope, and it is always bound to your own enrollment.
Esquema de entrada
{'type': 'object', 'properties': {}, 'additionalProperties': False}
create_topup
Create a credit top-up checkout link for THIS product run, to refill the credits that pay for metered growth marketing work. Pass pack_id: small, medium or large. Returns a checkout_url the founder opens to pay; the credits land automatically once payment succeeds. Requires the 'act' scope and the Founder plan (on a free trial use create_checkout first). Always bound to your own enrollment.
Esquema de entrada
{'type': 'object', 'required': ['pack_id'], 'properties': {'pack_id': {'enum': ['small', 'medium', 'large'], 'type': 'string', 'description': 'The refill pack size: small, medium or large. The founder sees the price on the checkout page.'}}, 'additionalProperties': False}
disconnect_connection
Disconnect a growth data source or distribution channel and delete the credential stored for it (for Google it is also revoked at Google). Idempotent: disconnecting something that was never connected changes nothing. It narrows what the growth engine can measure and where it can distribute, so confirm with the founder first. Free.
Esquema de entrada
{'type': 'object', 'required': ['provider'], 'properties': {'provider': {'type': 'string', 'description': 'Which connector to disconnect: ga4, gsc, gbp, linkedin or reddit.'}}, 'additionalProperties': False}
dismiss_gap
Set aside one AI visibility (GEO) gap the founder is not going to act on: a tracked question where rivals get named and this product does not. The same verdict as skip_move, on the AI visibility surface, and it resolves the gap in ONE place: it stops being re-proposed here AND on the growth Feed, and the reason improves what gets ranked next. Free; requires the 'act' scope, and available on every plan because telling the agent "not this one" is never a paid feature. Idempotent: a gap already shipped or archived is left as it is.
Esquema de entrada
{'type': 'object', 'required': ['prompt_id', 'prompt_text'], 'properties': {'reason': {'enum': ['not_relevant', 'wrong_voice', 'wrong_angle', 'wrong_timing', 'low_quality', 'duplicate', 'other'], 'type': 'string', 'description': 'Why it is being set aside. Closed vocabulary; unknown keys are ignored by the learning loop.'}, 'prompt_id': {'type': 'string', 'description': 'The tracked question id, from get_visibility.'}, 'prompt_text': {'type': 'string', 'description': 'The tracked question text, from get_visibility. Both fields are required: together they identify the gap.'}}, 'additionalProperties': False}
get_activity
The product timeline: what the growth agent and the founder already did and why (drafts, ships, skips, scans, observations, decisions with their rationale), newest first. Read before acting so you never redo recent work. Read-only, free.
Solo lectura
Esquema de entrada
{'type': 'object', 'properties': {'limit': {'type': 'integer', 'maximum': 200, 'minimum': 1, 'description': 'How many entries to return (1 to 200, default 50).'}}, 'additionalProperties': False}
get_business_context
Structured business positioning, audience, ICP, pricing, features and competitors, plus growth_strategy: the latest saved stage, bottleneck, bets and non-goals with version, source and date. Read before planning or writing. Strategy is dated judgement, not measured evidence or proof of results; check it against current founder intent. Missing facts or strategy are null. Read-only and free; never generates or revises a strategy.
Solo lectura
Esquema de entrada
{'type': 'object', 'properties': {}, 'additionalProperties': False}
get_claims
The claim library: the measured numbers this founder will stand behind in public, for replies, posts and any marketing writing. Each carries the claim in one sentence, the number with its unit, keywords saying when it is relevant, and a caveat stated against the founder's own interest. READ THIS BEFORE CITING ANY NUMBER about this product, and never quote a claim without its caveat: the caveat is what makes the number safe to say. A claim marked held is NOT for use. An empty library is an answer, not an error. Read-only, free.
Solo lectura
Esquema de entrada
{'type': 'object', 'properties': {}, 'additionalProperties': False}
get_competitors
The competitor roster with the measured stat battery for you and each rival (performance, SEO, Core Web Vitals, authority, G2 and Product Hunt presence, content freshness), plus the founder's own edits. Read before any competitor or outreach work so a rival is never treated as a pitch target. Read-only, free.
Solo lectura
Esquema de entrada
{'type': 'object', 'properties': {}, 'additionalProperties': False}
get_content_calendar
Growth content calendar, source drafts, current Feed state and X production switch. Read-only. Check linkage and calendar_sync; saved words are not publication proof.
Solo lectura
Esquema de entrada
{'type': 'object', 'properties': {}, 'additionalProperties': False}
get_enrollment
The product run summary for this growth engine: product_url, tier, trial_ends_at, timezone, whether autonomous work is active, and delivery settings. Credits once metering is live. Read-only, free.
Solo lectura
Esquema de entrada
{'type': 'object', 'properties': {}, 'additionalProperties': False}
get_experiments
Growth content experiments already run, newest first, with scoped evidence. Read-only; never runs one. Each is an observation, not a rate.
Solo lectura
Esquema de entrada
{'type': 'object', 'properties': {'limit': {'type': 'integer', 'maximum': 50, 'minimum': 1}, 'idea_id': {'type': 'string', 'format': 'uuid'}, 'experiment_id': {'type': 'string', 'format': 'uuid'}}, 'additionalProperties': False}
get_kb_page
One Memory page by slug, with its full markdown body: the record the growth marketing engine drafts from. Slugs come from list_kb_pages. Read-only, free.
Solo lectura
Esquema de entrada
{'type': 'object', 'required': ['slug'], 'properties': {'slug': {'type': 'string', 'description': 'The page slug, from list_kb_pages.'}}, 'additionalProperties': False}
get_loop_status
The automated growth marketing loops provisioned for this product (AI visibility, competitors, channel distribution) with their autonomy level, plus runnable_loop_types, what run_loop accepts. A runnable type only runs once a loop of that type is provisioned and enabled here.
Solo lectura
Esquema de entrada
{'type': 'object', 'properties': {'loop_type': {'type': 'string', 'description': 'Optional loop type, e.g. daily_brief or linkedin_post.'}}, 'additionalProperties': False}
get_move
One growth move: evidence, source material, instructions and prepared_result. linked_article is earlier work to reuse, not a completed revision. Ready means awaiting review, not published. Closed post-trial access withholds bodies without asserting absence. tracked_link_state explains a null link (no_link, unavailable, withheld); null clicks means unreadable. Read-only, free.
Solo lectura
Esquema de entrada
{'type': 'object', 'required': ['move_id'], 'properties': {'move_id': {'type': 'string', 'description': 'Move id (uuid), from list_feed or get_standup.'}}, 'additionalProperties': False}
get_outcomes
What the shipped growth moves earned: tracked-link clicks per move, shipped counters, the weekly movement scoreboard, and whether GA4 and Search Console are connected. Call it after ship_move. Read-only, free.
Solo lectura
Esquema de entrada
{'type': 'object', 'properties': {}, 'additionalProperties': False}
get_output
Read a queue draft by id. SEO linked_article {id,title,content} adds the full Markdown article. redraft_output edits the queue draft only.
Solo lectura
Esquema de entrada
{'type': 'object', 'required': ['output_id'], 'properties': {'output_id': {'type': 'string', 'description': 'The output id (uuid).'}}, 'additionalProperties': False}
get_scoreboard
Did the growth work move anything? The proof read for a period: AI visibility (GEO) at the START and the END of the window, the moves shipped between them, the scans that ran, and the receipts with what was verified live and the clicks each earned. ALWAYS read like_for_like before reporting a change: true means both scans asked the same tracked questions so the movement is real, false means the question set changed inside the window so it is a new baseline rather than a rise or a fall, and null means it cannot be proven either way. Never present a delta as a result when like_for_like is not true. Read-only, free.
Solo lectura
Esquema de entrada
{'type': 'object', 'properties': {'window_days': {'type': 'integer', 'maximum': 90, 'minimum': 7, 'description': 'How many days the scoreboard covers (7 to 90, default 14). Out-of-range values are clamped, never rejected.'}}, 'additionalProperties': False}
get_seo
The site-wide SEO audit: issue groups with severity and affected pages, the weekly score trend, page performance, links and authority, and day-0 search ranks. Read before any SEO work of your own; the Feed seo_fix moves are minted from it. Read-only, free. Pass include_pages for the per-page detail.
Solo lectura
Esquema de entrada
{'type': 'object', 'properties': {'include_pages': {'type': 'boolean', 'description': 'Include the per-page audit detail. Default false: the grouped issues only.'}}, 'additionalProperties': False}
get_setup_snippet
The paste-able 'Growth (AfterLaunch)' section for this repository's CLAUDE.md or AGENTS.md: how a coding agent should use AfterLaunch for growth, marketing, SEO, AI visibility (GEO), competitor and distribution work, and which tools cost money. Free, read-only. Show it to the founder and add it with their say-so.
Solo lectura
Esquema de entrada
{'type': 'object', 'properties': {}, 'additionalProperties': False}
get_snapshot
The Growth Snapshot this product run started from: positioning, the discoverability score, the prioritised leverage actions, the competitor set, and the day-0 SEO and AI visibility baselines. The stable business context; for live signal data use get_visibility and get_seo. Read-only, free.
Solo lectura
Esquema de entrada
{'type': 'object', 'properties': {}, 'additionalProperties': False}
get_standup
The daily growth marketing standup in one call: what recently shipped and what AfterLaunch verified about it (receipts), the top ranked moves shippable now (ready; rank is the full-board position, so gaps mean those ranks are not shippable now), what the engine did on its own in the last 7 days (while_you_were_gone; capped at the account's age), and whether the deep scan is still running. Call this at the START of a session, before list_feed, and relay the message field. Read-only, free.
Solo lectura
Esquema de entrada
{'type': 'object', 'properties': {}, 'additionalProperties': False}
get_visibility
The measured AI visibility (GEO) results: how ChatGPT, Gemini, Perplexity and Google AI Overviews answer the tracked customer questions, plus share of voice, cited sources, competitor-owned gaps, the trend, AI crawlability and the off-site reach fold. Every reading carries its own sample count, and the sampling block says what such a count licenses, so treat a change as indicative unless it says otherwise. Read after refresh_scan and before any AI visibility or GEO work. Read-only, free. Pass prompt_id to drill into one question.
Solo lectura
Esquema de entrada
{'type': 'object', 'properties': {'prompt_id': {'type': 'string', 'description': 'Drill into one tracked question by its id (from the prompts list) for the engine answer text and citations.'}}, 'additionalProperties': False}
get_voice_profile
The structured voice every AfterLaunch growth marketing draft is written in: tone, characteristic phrases, vocabulary, sentence style and what it avoids. register says which you got, and they do not sound alike: brand is the website's voice, personal is the founder's own writing, imported came from a brief. has_profile false means that voice is not extracted yet: an answer, not an error. Read-only, free.
Solo lectura
Esquema de entrada
{'type': 'object', 'properties': {'register': {'enum': ['brand', 'personal', 'imported'], 'type': 'string', 'description': "Which voice to read. Omit for the current one. Use 'personal' for anything the founder posts in their own name."}}, 'additionalProperties': False}
list_connections
Which growth data sources and distribution channels are connected: GA4 and Search Console (the measurement behind SEO and outcomes), Google Business Profile, and the LinkedIn / Reddit posting channels. Each row carries an honest state: connected, not_connected, or not_available with the reason it is shut on this account. Read before start_connection so you never offer a connection that cannot be made. Read-only, free.
Solo lectura
Esquema de entrada
{'type': 'object', 'properties': {}, 'additionalProperties': False}
list_feed
The ranked backlog of growth marketing moves prepared for this product across SEO, AI visibility (GEO), competitors and distribution: title, why, area, status, rank, whether readable full-draft material is waiting (has_draft), and draft_kind (a full draft, a brief to complete, or null). It also carries posture: who may do it, act (you can), draft_only (you draft, a person posts) or founder_voice (the founder only). Read it before improvising growth work of your own. The material BODY is not here: call get_move for the one you are working on. Live moves only unless you pass include_resolved; pass since for what is new while the deep scan fills the board. Read-only.
Solo lectura
Esquema de entrada
{'type': 'object', 'properties': {'since': {'type': 'string', 'description': 'ISO-8601. Returns only moves first seen after it. Pass the newest first_seen_at you already hold so a move is never returned twice.'}, 'verbosity': {'enum': ['compact', 'full'], 'type': 'string', 'description': "Default 'compact': no material bodies, so a long board stays cheap to read; has_draft and draft_kind say whether each move carries an inspectable artefact, an assignment, or nothing readable. Use 'full' only when you need every body at once."}, 'include_resolved': {'type': 'boolean', 'description': 'Include resolved moves (shipped, skipped, archived, expired) as well as the live ones. Default false.'}}, 'additionalProperties': False}
list_kb_pages
The Memory pages: the shared record the growth marketing engine drafts from (business basics, audience, competitors, voice samples, recent observations). Summaries with a size hint; fetch a body with get_kb_page. Read-only, free.
Solo lectura
Esquema de entrada
{'type': 'object', 'properties': {}, 'additionalProperties': False}
list_outputs
The drafted marketing and distribution content produced for this product, newest first: id, loop_type, kind, status and title. Use an id with get_output for the body. Read-only, free.
Solo lectura
Esquema de entrada
{'type': 'object', 'properties': {}, 'additionalProperties': False}
list_queue
Unclaimed preparation jobs, oldest first. Each row carries job_id and its nullable attempt_id. Call pick_up_job with both exact values before starting. Queue summaries never include prepared_content. Free; requires the 'act' scope.
Esquema de entrada
{'type': 'object', 'properties': {}, 'additionalProperties': False}
list_tracked_prompts
The customer questions AfterLaunch tracks: the AI visibility (GEO) question set every measurement is taken against. Returns prompts in tracking order, cap (a hard 15) and used, plus curated: false means AfterLaunch generated them and any can be replaced. Read before track_prompt or untrack_prompt so you never duplicate a question or guess at the room left. Read-only, free, on every plan.
Solo lectura
Esquema de entrada
{'type': 'object', 'properties': {}, 'additionalProperties': False}
pick_up_job
Try to claim one queued preparation attempt. Pass job_id and the exact nullable attempt_id from list_queue. Start work only when the response says claim_won:true. An unchanged result is a non-winner and must not start work. Free; requires the 'act' scope.
Esquema de entrada
{'type': 'object', 'required': ['job_id', 'attempt_id'], 'properties': {'job_id': {'type': 'string', 'description': 'Job id (uuid), from list_queue.'}, 'attempt_id': {'type': ['string', 'null'], 'description': 'Exact attempt id from list_queue; null only for a stored legacy job.'}, 'session_url': {'type': 'string', 'description': 'Your own session URL, if you have one, so the founder can open where the work is happening.'}}, 'additionalProperties': False}
poll_connection
Did the founder finish connecting the growth data source you handed them a link for? Pass the poll_token start_connection returned. Reports pending (wait poll_after_seconds and ask again), connected, expired (mint a fresh link) or not_found. Idempotent: nothing is spent or consumed. Read-only, free.
Solo lectura
Esquema de entrada
{'type': 'object', 'required': ['poll_token'], 'properties': {'poll_token': {'type': 'string', 'description': 'The poll_token start_connection returned.'}}, 'additionalProperties': False}
propose_move
Put a discussion thread you found onto the founder's growth board as a pending move. WHEN: you have read a thread on a community they work (a subreddit, Hacker News, a forum) that the board does not carry, and can say why it is worth their twenty minutes. It lands at the tail of the board, keyed to the thread so a repeat lands on one row, and comes back with its posture: on Reddit or Hacker News that is draft_only, meaning you draft and the founder posts, and you must never post there yourself. Only community_reply and community_answer. Free; 'act' scope; a fixed number a day. A thread already on the board hands back its existing move id. WHAT COMES BACK: the move id and posture, so you can save a draft with update_draft next.
Esquema de entrada
{'type': 'object', 'required': ['title', 'why', 'kind', 'target'], 'properties': {'why': {'type': 'string', 'maxLength': 600, 'minLength': 20, 'description': 'Why it is worth their time, in one or two sentences.'}, 'kind': {'enum': ['community_reply', 'community_answer'], 'type': 'string', 'description': 'community_answer for a question thread; otherwise community_reply.'}, 'draft': {'type': 'string', 'maxLength': 8000, 'description': 'Optional: your drafted reply.'}, 'title': {'type': 'string', 'maxLength': 140, 'minLength': 10, 'description': 'The thread, as the founder would name it.'}, 'target': {'type': 'string', 'description': 'The https address of the thread itself.'}, 'sources': {'type': 'array', 'items': {'type': 'string'}, 'maxItems': 5, 'description': 'Optional: up to five https addresses behind the why.'}}, 'additionalProperties': False}
record_claim
Put one measured number the founder will stand behind in public into the claim library, so every later reply and growth marketing post can cite it with its caveat. WHEN: a real measurement lands and the founder says they would defend it. Record the NUMBER and the caveat together; a number without its caveat is what this library exists to prevent. Never record an estimate, a projection, a rival's figure, or anything you inferred rather than measured. Free; requires the 'act' scope. Recording the same claim twice replaces your earlier wording; a pinned claim is left as it is. WHAT COMES BACK: the top of their board with move ids.
Esquema de entrada
{'type': 'object', 'required': ['text', 'trigger', 'number', 'caveat'], 'properties': {'held': {'type': 'boolean', 'description': 'True to record it and block its use.'}, 'text': {'type': 'string', 'maxLength': 300, 'minLength': 10, 'description': 'The claim in one sentence.'}, 'caveat': {'type': 'string', 'maxLength': 500, 'minLength': 10, 'description': 'What it does not prove, against your own interest.'}, 'number': {'type': 'string', 'maxLength': 200, 'minLength': 1, 'description': 'The measurement, with its unit and comparison.'}, 'trigger': {'type': 'array', 'items': {'type': 'string', 'maxLength': 60, 'minLength': 2}, 'maxItems': 10, 'minItems': 1, 'description': 'Keywords saying when this claim is relevant.'}}, 'additionalProperties': False}
record_content
File a growth idea (optional channels, kind, score), original X draft or research outcome. Research appends a result to its idea; send expected_updated_at unchanged from the calendar. It keeps evidence holds and never authorises drafting. Requires 'act' scope; no spend or posting. Keep run_key stable. Drafts need action_kind social_post and one idea_id or source_idea; source_url is evidence. adopt_legacy only reclassifies an exact saved replay (a reply keeps its X destination). Completion uses the move verbs.
Esquema de entrada
{'type': 'object', 'required': ['operation'], 'properties': {'why': {'type': 'string', 'maxLength': 5000, 'minLength': 1}, 'text': {'type': 'string', 'maxLength': 20000, 'minLength': 1}, 'title': {'type': 'string', 'maxLength': 300, 'minLength': 1}, 'channel': {'enum': ['x'], 'type': 'string'}, 'idea_id': {'type': 'string', 'format': 'uuid'}, 'run_key': {'type': 'string', 'maxLength': 160, 'minLength': 1}, 'research': {'type': 'object', 'required': ['outcome', 'summary', 'method', 'limitations', 'sources'], 'properties': {'method': {'type': 'string', 'maxLength': 5000, 'minLength': 1}, 'outcome': {'enum': ['supported', 'not_supported', 'inconclusive'], 'type': 'string'}, 'sources': {'type': 'array', 'items': {'type': 'object', 'required': ['title', 'url', 'observed_at'], 'properties': {'url': {'type': 'string', 'format': 'uri', 'maxLength': 2048}, 'title': {'type': 'string', 'maxLength': 300, 'minLength': 1}, 'observed_at': {'type': 'string', 'format': 'date-time'}}, 'additionalProperties': False}, 'maxItems': 50}, 'summary': {'type': 'string', 'maxLength': 5000, 'minLength': 1}, 'limitations': {'type': 'string', 'maxLength': 5000, 'minLength': 1}}, 'additionalProperties': False}, 'claim_ids': {'type': 'array', 'items': {'type': 'string', 'format': 'uuid'}, 'maxItems': 20}, 'operation': {'enum': ['idea', 'draft', 'research'], 'type': 'string'}, 'source_url': {'type': 'string', 'format': 'uri', 'maxLength': 2048}, 'action_kind': {'enum': ['social_post'], 'type': 'string'}, 'source_idea': {'type': 'object', 'required': ['title', 'needs_data'], 'properties': {'kind': {'enum': ['opinion', 'educational', 'amplify'], 'type': 'string'}, 'link': {'type': 'string', 'format': 'uri', 'maxLength': 2048}, 'angle': {'type': 'string', 'maxLength': 3000, 'minLength': 1}, 'score': {'type': 'number', 'maximum': 10, 'minimum': 0}, 'title': {'type': 'string', 'maxLength': 300, 'minLength': 1}, 'channels': {'type': 'array', 'items': {'enum': ['x', 'linkedin', 'article', 'seo'], 'type': 'string'}, 'maxItems': 4, 'minItems': 1, 'uniqueItems': True}, 'needs_data': {'type': 'boolean'}}, 'additionalProperties': False}, 'adopt_legacy': {'type': 'object', 'required': ['output_id', 'action_kind'], 'properties': {'output_id': {'type': 'string', 'format': 'uuid'}, 'action_kind': {'enum': ['social_post', 'community_reply'], 'type': 'string'}}, 'additionalProperties': False}, 'expected_updated_at': {'type': 'string', 'format': 'date-time'}}, 'additionalProperties': False}
record_insight
Write one durable thing you have learned about this founder or their product into AfterLaunch's Memory, the record every growth and marketing draft is written from. WHEN: the moment the founder tells you something that will still be true next month and that AfterLaunch could not have measured itself. A standing preference, a rule about how they write, a fact not on the site yet, or what a shipped move actually earned. Recording it is part of the job, not a favour: AfterLaunch drafts from Memory, so anything you keep to yourself is a correction the next draft will need again. Record what LASTS. Never record chatter, a passing mood, a restatement of get_snapshot or get_kb_page, or anything you inferred rather than heard. One sentence in the founder's own terms, 10 to 500 characters. Free; requires the 'act' scope. Recording the same insight twice replaces your earlier note; a pinned note is left as it is. WHAT COMES BACK: the top of their board with move ids, so recording hands you your next instruction without a second call.
Esquema de entrada
{'type': 'object', 'required': ['insight', 'kind'], 'properties': {'kind': {'enum': ['preference', 'voice', 'fact', 'outcome'], 'type': 'string', 'description': 'preference = a standing choice about how they work. voice = how they write (a rule they approved goes to record_voice_rule). fact = something true about the product. outcome = what a shipped move earned.'}, 'insight': {'type': 'string', 'maxLength': 500, 'minLength': 10, 'description': "The durable insight, as one plain sentence in the founder's own terms."}, 'source_move_id': {'type': 'string', 'description': 'Optional growth move id (uuid), from list_feed, when the insight surfaced while working one.'}}, 'additionalProperties': False}
record_voice_rule
Save one writing rule the person approved into their OWN voice, never the brand's. The morning marketing posts drafted for them follow it, get_move and get_voice_profile carry it, and they see and remove it in Memory. WHEN: only after they approve it in words, e.g. a yes to a rule you proposed from how they edited a draft before posting. Never record one they did not approve. One sentence. At most 12. Free; requires the 'act' scope.
Esquema de entrada
{'type': 'object', 'required': ['text'], 'properties': {'text': {'type': 'string', 'maxLength': 200, 'minLength': 10, 'description': 'The rule as approved, in one sentence.'}}, 'additionalProperties': False}
redraft_output
Replace a drafted marketing output's body before it is shipped. Manual replacement only: the AI redraft stays in the app. A draft carrying an unfilled placeholder or a broken link is refused, and the previous draft is kept as revision history. Free; requires the 'act' scope and Founder tier.
Esquema de entrada
{'type': 'object', 'required': ['output_id', 'draft'], 'properties': {'draft': {'type': 'string', 'description': 'The replacement draft body, 1 to 20000 characters.'}, 'output_id': {'type': 'string', 'description': 'Output id (uuid), from list_outputs.'}, 'draft_fence': {'type': 'object', 'required': ['move_id', 'move_state', 'move_updated_at', 'job_id', 'attempt_id', 'job_state', 'job_updated_at', 'candidate_id', 'draft'], 'properties': {'draft': {'type': 'string', 'maxLength': 20000}, 'job_id': {'type': ['string', 'null'], 'format': 'uuid'}, 'move_id': {'type': 'string', 'format': 'uuid'}, 'job_state': {'type': ['string', 'null']}, 'attempt_id': {'type': ['string', 'null'], 'format': 'uuid'}, 'move_state': {'type': 'string'}, 'candidate_id': {'type': 'string', 'format': 'uuid'}, 'job_updated_at': {'type': ['string', 'null'], 'format': 'date-time'}, 'move_updated_at': {'type': 'string', 'format': 'date-time'}}, 'description': 'For a content pilot edit, return draft_fence unchanged from get_move or get_output. Refresh after a conflict.', 'additionalProperties': False}}, 'additionalProperties': False}
refresh_scan
SPENDS MONEY: run an on-demand AI visibility scan (scan='ai_visibility'), the GEO measurement of how the answer engines represent this product against its competitors. Needs the 'write' scope, a paid plan or an active trial, and an Idempotency-Key you mint. Bounded by the credit balance and the per-tenant daily and monthly caps. One scan per type per product per local day; a repeat that day replays the original result, regardless of the key.
Esquema de entrada
{'type': 'object', 'required': ['scan', 'idempotency_key'], 'properties': {'scan': {'enum': ['ai_visibility'], 'type': 'string', 'description': "The scan to refresh. Only 'ai_visibility' today."}, 'idempotency_key': {'type': 'string', 'description': 'Client-minted key (1-200 chars). Reuse the same key on a retry.'}}, 'additionalProperties': False}
replenish_feed
SPENDS MONEY: run the growth-move generator on demand to top up the Feed with fresh marketing moves across SEO, AI visibility, competitors and distribution. Needs the 'write' scope, a paid plan or an active trial, and an Idempotency-Key you mint. Bounded by the credit balance and the per-tenant daily and monthly caps. Once a day per product.
Esquema de entrada
{'type': 'object', 'required': ['idempotency_key'], 'properties': {'idempotency_key': {'type': 'string', 'description': 'Client-minted key (1-200 chars). Reuse the same key on a retry.'}}, 'additionalProperties': False}
report_job
Report a claimed attempt as running, ready_for_review or failed, always with its exact attempt_id. Ready needs prepared_content or a prepared asset_url and remains unpublished until the founder confirms. State shipped is retained only for stored legacy jobs whose attempt_id is null. Omitting an attempt never turns managed work into legacy work. Free; requires the 'act' scope.
Esquema de entrada
{'type': 'object', 'required': ['job_id', 'attempt_id', 'state'], 'properties': {'state': {'enum': ['running', 'ready_for_review', 'shipped', 'failed'], 'type': 'string'}, 'job_id': {'type': 'string', 'description': 'Job id (uuid), from list_queue.'}, 'asset_url': {'type': 'string', 'description': 'URL of the prepared asset. This does not claim publication.'}, 'attempt_id': {'type': ['string', 'null'], 'description': 'Exact attempt id; null only when list_queue identified a legacy job.'}, 'fail_reason': {'type': 'string', 'maxLength': 500, 'description': "Required with 'failed': what stopped you."}, 'receipt_url': {'type': 'string', 'description': 'A permalink to the proof.'}, 'session_url': {'type': 'string', 'description': 'Your own session URL, if you have one.'}, 'prepared_content': {'type': 'string', 'maxLength': 20000, 'description': 'Prepared result body for ready_for_review.'}}, 'additionalProperties': False}
review_move
Apply one explicit founder review decision: revise the current managed attempt, withdraw unfinished work, adopt an inspected legacy result, or correct a recorded publication. Revision starts a new attempt only when this transaction wins. This never publishes anything. Free; requires the 'act' scope.
Esquema de entrada
{'type': 'object', 'required': ['move_id', 'operation', 'job_id', 'expected_attempt_id'], 'properties': {'note': {'type': ['string', 'null'], 'maxLength': 2000}, 'job_id': {'type': ['string', 'null']}, 'move_id': {'type': 'string'}, 'asset_url': {'type': ['string', 'null']}, 'operation': {'enum': ['revise', 'withdraw', 'adopt_legacy_result', 'correct_publication'], 'type': 'string', 'description': 'adopt_legacy_result requires a null expected attempt, exact move CAS, exact legacy job CAS when job_id is present, and inspected prepared content or asset URL.'}, 'prepared_content': {'type': ['string', 'null'], 'maxLength': 20000}, 'expected_attempt_id': {'type': ['string', 'null'], 'description': 'Exact managed attempt. Null identifies legacy work and requires exact move CAS plus legacy job CAS when job_id is present.'}, 'expected_move_state': {'enum': ['pending', 'taken_on', 'shipped', 'skipped', 'archived', 'expired', None], 'type': ['string', 'null']}, 'expected_legacy_state': {'type': ['string', 'null'], 'description': 'get_move: prepared_result.legacy_state ?? state.'}, 'expected_move_updated_at': {'type': ['string', 'null']}, 'expected_legacy_updated_at': {'type': ['string', 'null']}}, 'additionalProperties': False}
set_output_status
Resolve one drafted marketing output in the founder's review queue (from list_outputs): action 'ship' marks it done or posted WITHOUT publishing anywhere, action 'skip' dismisses it. WHEN: call 'ship' the moment the founder confirms the content is actually out, with their go and never on your own; call 'skip' when they decide against it. Posting is the human's decision; reporting the outcome is yours, and it is not optional, because an unreported result leaves the record blind to what the work earned. Report only what is true: a draft you have written is not a draft that went out. This never posts to a channel: real publishing is approve_output (egress scope, human-approved). Free; requires the 'act' scope and Founder tier.
Esquema de entrada
{'type': 'object', 'required': ['output_id', 'action'], 'properties': {'action': {'enum': ['ship', 'skip'], 'type': 'string', 'description': "'ship' resolves it as done / posted without publishing; 'skip' dismisses it."}, 'output_id': {'type': 'string', 'description': 'Output id (uuid), from list_outputs.'}}, 'additionalProperties': False}
set_voice_axes
Write the calibrated leans from a voice round into the FOUNDER'S OWN voice profile, the personal register, never the brand's. Two voices live here and they do not sound alike: the brand's came from the website and is what marketing pages and listings use, and this verb cannot touch it. WHEN: after a round, once an axis has enough answers to read. Send one write per round, not one per pair, and leave out an axis with too few observations: that is not a lean. Send only the axes that moved; the rest keep what they had. Free; requires the 'act' scope. WHAT COMES BACK: every axis on record, and the top of their board.
Esquema de entrada
{'type': 'object', 'required': ['axes'], 'properties': {'axes': {'type': 'object', 'description': "Keyed by axis id, each { lean, strength }. lean is 'a' or 'b', the pole this voice sits nearer; strength is the share of that axis's observations that fell on the leaning side, so 0.5 is an even split and 1 is every observation one way.", 'additionalProperties': {'type': 'object', 'required': ['lean', 'strength'], 'properties': {'lean': {'enum': ['a', 'b'], 'type': 'string'}, 'strength': {'type': 'number', 'maximum': 1, 'minimum': 0.5}}, 'additionalProperties': False}}}, 'additionalProperties': False}
ship_move
Record completion only after the founder explicitly confirms it. Use prepared_result after reviewing the current prepared attempt, or independent_work when the founder completed it separately. Site changes need a live published_url to ship; without one they stay prepared. This records an attestation; it never publishes anything. Free; requires the 'act' scope.
Esquema de entrada
{'type': 'object', 'required': ['move_id', 'completion_kind', 'job_id', 'attempt_id', 'founder_confirmed'], 'properties': {'note': {'type': ['string', 'null'], 'maxLength': 2000}, 'job_id': {'type': ['string', 'null']}, 'move_id': {'type': 'string', 'description': 'Move id (uuid), from list_feed.'}, 'attempt_id': {'type': ['string', 'null']}, 'planned_url': {'type': ['string', 'null'], 'description': "Future address of a prepared page on the founder's own site."}, 'published_url': {'type': ['string', 'null'], 'description': 'The actual public URL, when the completed task has one. This is distinct from a prepared asset.'}, 'completion_kind': {'enum': ['prepared_result', 'independent_work'], 'type': 'string'}, 'founder_confirmed': {'type': 'boolean', 'const': True}, 'expected_move_state': {'enum': ['pending', 'taken_on', 'shipped', 'skipped', 'archived', 'expired', None], 'type': ['string', 'null'], 'description': 'Required with expected_move_updated_at for independent_work.'}, 'expected_legacy_state': {'type': ['string', 'null'], 'description': 'get_move: prepared_result.legacy_state ?? state.'}, 'expected_move_updated_at': {'type': ['string', 'null'], 'description': 'Required with expected_move_state for independent_work.'}, 'expected_legacy_updated_at': {'type': ['string', 'null']}}, 'additionalProperties': False}
skip_move
Dismiss a growth move (Skip in the Feed). Free; requires the 'act' scope. Optional feedback_key (closed vocabulary, see the enum) plus a free-text feedback_note explain why, which improves future marketing drafts.
Esquema de entrada
{'type': 'object', 'required': ['move_id'], 'properties': {'move_id': {'type': 'string', 'description': 'Move id (uuid), from list_feed.'}, 'feedback_key': {'enum': ['not_relevant', 'wrong_voice', 'wrong_angle', 'wrong_timing', 'low_quality', 'duplicate', 'other'], 'type': 'string', 'description': 'Why it was dismissed. Closed vocabulary; unknown keys are ignored by the learning loop.'}, 'feedback_note': {'type': 'string', 'maxLength': 500, 'description': 'Optional free-text detail alongside feedback_key.'}}, 'additionalProperties': False}
start_connection
Connect a growth data source or distribution channel: mint a one-time link the FOUNDER opens in their own browser to approve it. You never complete the consent yourself; it is bound to their session. Returns url (hand it to the founder), poll_token, poll_after_seconds and expires_at; the link lasts 15 minutes. Then poll_connection until it reports connected. Refuses in plain words, before minting anything, when a connector is shut on this account. Free, spends nothing.
Esquema de entrada
{'type': 'object', 'required': ['provider'], 'properties': {'provider': {'type': 'string', 'description': 'Which connector to connect. Use a provider id from list_connections: ga4, gsc, gbp, linkedin or reddit.'}}, 'additionalProperties': False}
track_prompt
Add one customer question to the AI visibility (GEO) set AfterLaunch measures this product on. Free, spends nothing. Two honest consequences: changing the set makes the NEXT scheduled scan run at full depth instead of skipping ahead, and it re-baselines the week-over-week trend, because a comparison across two different question sets is not a real move. So add deliberately rather than churning the list. 10 to 200 characters, deduplicated, hard cap of 15. Requires the 'config' scope and the Founder plan; on a free trial the questions stay readable and create_checkout mints the upgrade link.
Esquema de entrada
{'type': 'object', 'required': ['text'], 'properties': {'text': {'type': 'string', 'maxLength': 200, 'minLength': 10, 'description': 'The customer question to track, as a person would ask an AI assistant, e.g. "What is the best invoicing tool for UK freelancers?".'}}, 'additionalProperties': False}
undo_move
Restore a just-shipped or just-skipped growth move to pending: the self-correction verb for a wrong ship_move or skip_move. Free; requires the 'act' scope. Idempotent on a move already pending. It never unwinds a real channel publish: a posted output stays posted, and an archived or expired move cannot be restored.
Esquema de entrada
{'type': 'object', 'required': ['move_id'], 'properties': {'move_id': {'type': 'string', 'description': 'Move id (uuid), from list_feed.'}}, 'additionalProperties': False}
untrack_prompt
Remove one customer question from the AI visibility (GEO) set, freeing a slot against the cap of 15. Free, spends nothing. Same two honest consequences as track_prompt: the next scheduled scan runs at full depth, and the week-over-week trend re-baselines. Matched on the question text, ignoring case and punctuation, and IDEMPOTENT. Requires the 'config' scope and the Founder plan.
Esquema de entrada
{'type': 'object', 'required': ['text'], 'properties': {'text': {'type': 'string', 'description': 'The tracked question to remove, from list_tracked_prompts. Matched ignoring case and punctuation.'}}, 'additionalProperties': False}
update_draft
Replace a pending growth move's marketing draft body before shipping. A draft carrying an unfilled placeholder or a broken link is refused rather than saved. Free; requires the 'act' scope.
Esquema de entrada
{'type': 'object', 'required': ['move_id', 'draft_content'], 'properties': {'move_id': {'type': 'string', 'description': 'Move id (uuid), from list_feed.'}, 'draft_fence': {'type': 'object', 'required': ['move_id', 'move_state', 'move_updated_at', 'job_id', 'attempt_id', 'job_state', 'job_updated_at', 'candidate_id', 'draft'], 'properties': {'draft': {'type': 'string', 'maxLength': 20000}, 'job_id': {'type': ['string', 'null'], 'format': 'uuid'}, 'move_id': {'type': 'string', 'format': 'uuid'}, 'job_state': {'type': ['string', 'null']}, 'attempt_id': {'type': ['string', 'null'], 'format': 'uuid'}, 'move_state': {'type': 'string'}, 'candidate_id': {'type': 'string', 'format': 'uuid'}, 'job_updated_at': {'type': ['string', 'null'], 'format': 'date-time'}, 'move_updated_at': {'type': 'string', 'format': 'date-time'}}, 'description': 'For a content pilot edit, return draft_fence unchanged from get_move or get_output. Refresh after a conflict.', 'additionalProperties': False}, 'draft_content': {'type': 'string', 'description': 'The replacement draft body, 1 to 20000 characters.'}}, 'additionalProperties': False}
whoami
Confirm the AfterLaunch key works before any growth or marketing work: which product run it is bound to, its scopes, tier and trial_ends_at, plus onboarding (feed_ready is false while the Growth Snapshot deep scan is still building, so wait before reading the Feed) and credits once metering is live. Call this first.
Solo lectura
Esquema de entrada
{'type': 'object', 'properties': {}, 'additionalProperties': False}
Eliminado
set_scan_config
1 de October de 2026 a las 02:44
Eliminado
set_loop_cadence
1 de October de 2026 a las 02:44
Eliminado
set_loop_autonomy
1 de October de 2026 a las 02:44
Eliminado
run_loop
1 de October de 2026 a las 02:44
Modificado
record_insight
1 de October de 2026 a las 02:44
Añadido
record_voice_rule
1 de October de 2026 a las 02:44
Modificado
untrack_prompt
25 de September de 2026 a las 02:50
Modificado
track_prompt
25 de September de 2026 a las 02:50
Modificado
list_tracked_prompts
25 de September de 2026 a las 02:50
Modificado
ship_move
25 de September de 2026 a las 02:50
Modificado
get_visibility
25 de September de 2026 a las 02:50
Modificado
get_business_context
19 de September de 2026 a las 02:41
Añadido
report_job
17 de September de 2026 a las 12:39
Añadido
pick_up_job
17 de September de 2026 a las 12:39
Añadido
list_queue
17 de September de 2026 a las 12:39
Añadido
propose_move
17 de September de 2026 a las 12:39
Añadido
record_insight
17 de September de 2026 a las 12:39
Añadido
dismiss_gap
17 de September de 2026 a las 12:39
Añadido
get_scoreboard
17 de September de 2026 a las 12:39
Añadido
untrack_prompt
17 de September de 2026 a las 12:39
Añadido
track_prompt
17 de September de 2026 a las 12:39
Añadido
list_tracked_prompts
17 de September de 2026 a las 12:39
Añadido
disconnect_connection
17 de September de 2026 a las 12:39
Añadido
poll_connection
17 de September de 2026 a las 12:39
Añadido
start_connection
17 de September de 2026 a las 12:39
Añadido
list_connections
17 de September de 2026 a las 12:39
Añadido
create_topup
17 de September de 2026 a las 12:39
Añadido
create_checkout
17 de September de 2026 a las 12:39
Añadido
set_scan_config
17 de September de 2026 a las 12:39
Añadido
set_loop_cadence
17 de September de 2026 a las 12:39