{"serverId":"mcp-registry/now.shiply/shiply","tools":[{"name":"add_custom_domain","fixed":{"name":"add_custom_domain","description":"Register a registrable domain (e.g. example.com) the user owns and detect its DNS provider. Returns the provider and whether one-click connect is available. Then attach sites with add_subdomain.","inputSchema":{"type":"object","$schema":"http://json-schema.org/draft-07/schema#","required":["domain"],"properties":{"domain":{"type":"string","description":"registrable domain you own, e.g. example.com"}}},"annotations":{"openWorldHint":true,"idempotentHint":false,"readOnlyHint":false,"destructiveHint":false},"title":"Register a custom domain"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: false, destructiveHint: false, idempotentHint: false (inferred from the name).","verify":true}],"tokensBefore":125,"tokensAfter":125},{"name":"add_domain","fixed":{"name":"add_domain","description":"Serve a site on a domain the user owns. Returns the CNAME to add (hostname → cname.shiply.now); the certificate issues automatically once DNS resolves. Poll with check_domain.","inputSchema":{"type":"object","$schema":"http://json-schema.org/draft-07/schema#","required":["hostname","slug"],"properties":{"slug":{"type":"string","description":"owned site slug to serve there"},"hostname":{"type":"string","description":"full hostname to serve, e.g. www.example.com"}}},"annotations":{"openWorldHint":true,"idempotentHint":false,"readOnlyHint":false,"destructiveHint":false},"title":"Connect a custom domain"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: false, destructiveHint: false, idempotentHint: false (inferred from the name).","verify":true}],"tokensBefore":141,"tokensAfter":141},{"name":"add_sending_domain","fixed":{"name":"add_sending_domain","description":"Register a domain the user owns for outbound demand-test sends. Returns DNS records (SPF, DKIM, MX) to add at the DNS provider. After DNS propagates, call verify_sending_domain. Cannot be a shiply.now subdomain.","inputSchema":{"type":"object","$schema":"http://json-schema.org/draft-07/schema#","required":["domain"],"properties":{"domain":{"type":"string","description":"e.g. mail.yourbrand.com"}}},"annotations":{"openWorldHint":true,"idempotentHint":false,"readOnlyHint":false,"destructiveHint":false},"title":"Add a sending domain"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: false, destructiveHint: false, idempotentHint: false (inferred from the name).","verify":true}],"tokensBefore":124,"tokensAfter":124},{"name":"add_subdomain","fixed":{"name":"add_subdomain","description":"Serve an owned site at <subdomain>.<domain> (use subdomain \"@\" or \"\" for the apex — apex needs a provider with CNAME flattening/ALIAS, e.g. Cloudflare). Auto-registers the parent domain. Returns the CNAME record to add (host -> cname.shiply.now); the certificate issues automatically once DNS resolves. Poll with check_domain.","inputSchema":{"type":"object","$schema":"http://json-schema.org/draft-07/schema#","required":["domain","subdomain","slug"],"properties":{"slug":{"type":"string","description":"owned site slug to serve there"},"domain":{"type":"string","description":"registrable parent domain, e.g. example.com"},"subdomain":{"type":"string","description":"subdomain label, or \"@\"/\"\" for the apex"}}},"annotations":{"openWorldHint":true,"idempotentHint":false,"readOnlyHint":false,"destructiveHint":false},"title":"Point a subdomain at a site"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: false, destructiveHint: false, idempotentHint: false (inferred from the name).","verify":true}],"tokensBefore":212,"tokensAfter":212},{"name":"add_suppression","fixed":{"name":"add_suppression","description":"Add an address (or whole domain) to the user's suppression list. Future confirmations and broadcasts will skip it across every test. Use kind='email' for a single address, kind='domain' for everyone @example.com.","inputSchema":{"type":"object","$schema":"http://json-schema.org/draft-07/schema#","required":["kind","value"],"properties":{"kind":{"enum":["email","domain"],"type":"string","description":"'email' for one address, 'domain' for everyone @example.com"},"notes":{"type":"string","description":"optional reason / note for the suppression"},"value":{"type":"string","description":"e.g. 'spammy@example.com' or 'competitor.com'"}}},"annotations":{"idempotentHint":false,"readOnlyHint":false,"destructiveHint":false},"title":"Suppress an email or domain"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: false, destructiveHint: false, idempotentHint: false (inferred from the name).","verify":true}],"tokensBefore":190,"tokensAfter":190},{"name":"archive_project","fixed":{"name":"archive_project","description":"Move a project to status='archived'. Hidden from the default dashboard list. Optional reason is shown on the project page. Restore later with restore_project.","inputSchema":{"type":"object","$schema":"http://json-schema.org/draft-07/schema#","required":["id"],"properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"project id to archive"},"reason":{"type":"string","maxLength":500,"description":"optional reason shown on the project page"}}},"annotations":{"idempotentHint":true,"readOnlyHint":false,"destructiveHint":true},"title":"Archive a project"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: false, destructiveHint: true, idempotentHint: true (inferred from the name).","verify":true}],"tokensBefore":188,"tokensAfter":188},{"name":"archive_thread","fixed":{"name":"archive_thread","description":"Soft-archive the thread (sets archivedAt). Hidden from the default inbox view; surface again with list_inbox filter=archived. Reverse with unarchive_thread.","inputSchema":{"type":"object","$schema":"http://json-schema.org/draft-07/schema#","required":["threadId"],"properties":{"threadId":{"type":"string","description":"thread id from list_inbox to archive"}}},"annotations":{"idempotentHint":true,"readOnlyHint":false,"destructiveHint":true},"title":"Archive a thread"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: false, destructiveHint: true, idempotentHint: true (inferred from the name).","verify":true}],"tokensBefore":112,"tokensAfter":112},{"name":"contract_amend","fixed":{"name":"contract_amend","description":"Create an amendment to a SIGNED parent contract. Scope delta required; fee delta and target date optional. Returns the draft amendment for editing before send — call contract_send with the returned amendment id to fire it. Cannot amend an amendment (amend the parent instead).","inputSchema":{"type":"object","$schema":"http://json-schema.org/draft-07/schema#","required":["parentContractId","scopeDelta"],"properties":{"scopeDelta":{"type":"string","maxLength":20000,"minLength":1,"description":"What's changing — visible to customer."},"feeDeltaCents":{"type":"integer","maximum":1000000000,"minimum":-1000000000,"description":"Optional fee adjustment in cents. Can be negative for descope."},"parentContractId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"id of the SIGNED parent contract to amend"},"targetCompletionDate":{"type":"string","description":"Optional ISO date (YYYY-MM-DD) for revised completion."}}},"annotations":{"idempotentHint":false,"readOnlyHint":false,"destructiveHint":false},"title":"Create an amendment to a signed contract"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: false, destructiveHint: false, idempotentHint: false (inferred from the name).","verify":true}],"tokensBefore":317,"tokensAfter":317},{"name":"contract_draft","fixed":{"name":"contract_draft","description":"Draft a contract from a brief_ready project. Auto-fills 8 fields from the AI brief, Stripe Connect default currency, and dev profile. Returns the contract row with status='draft' so the dev can review fields before sending. After this, edit fields via PATCH /api/v1/contracts/{id} (no MCP edit tool yet), then call contract_send to fire it.","inputSchema":{"type":"object","$schema":"http://json-schema.org/draft-07/schema#","required":["projectId"],"properties":{"projectId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"Project to draft a contract for"}}},"annotations":{"idempotentHint":true,"readOnlyHint":true},"title":"Draft a contract from a brief_ready project"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: true (inferred from the name).","verify":true}],"tokensBefore":217,"tokensAfter":217},{"name":"contract_send","fixed":{"name":"contract_send","description":"Send a draft contract to the customer. Validates all 8 fields are non-empty, computes content_hash, flips project to contract_sent, fires the customer email. Same handler works for amendment drafts — sending an amendment does not move project state.","inputSchema":{"type":"object","$schema":"http://json-schema.org/draft-07/schema#","required":["contractId"],"properties":{"contractId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"draft contract id to send (from contract_draft)"}}},"annotations":{"openWorldHint":true,"idempotentHint":false,"readOnlyHint":false,"destructiveHint":false},"title":"Send a draft contract to the customer"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: false, destructiveHint: false, idempotentHint: false (inferred from the name).","verify":true}],"tokensBefore":196,"tokensAfter":196},{"name":"create_database","fixed":{"name":"create_database","description":"Provision a SQL database — D1 (default, free) or Neon Postgres (--postgres, developer plan). Optionally attach it to an owned site's Worker env in the same call (siteSlug); otherwise attach it later with attach_database.","inputSchema":{"type":"object","$schema":"http://json-schema.org/draft-07/schema#","required":["name"],"properties":{"name":{"type":"string","description":"database name, a-z 0-9 -, 2-63 chars"},"binding":{"type":"string","description":"Worker binding name, UPPER_SNAKE (defaults to a name derived from `name`)"},"provider":{"enum":["d1","neon"],"type":"string","description":"defaults to d1"},"siteSlug":{"type":"string","description":"owned site slug to attach immediately"}}},"annotations":{"idempotentHint":false,"readOnlyHint":false,"destructiveHint":false},"title":"Create a database"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: false, destructiveHint: false, idempotentHint: false (inferred from the name).","verify":true}],"tokensBefore":207,"tokensAfter":207},{"name":"create_drive","fixed":{"name":"create_drive","description":"Create a private cloud Drive (plan-limited). Pass client to file it under a client.","inputSchema":{"type":"object","$schema":"http://json-schema.org/draft-07/schema#","required":["name"],"properties":{"name":{"type":"string","description":"display name for the new drive"},"client":{"type":"object","properties":{"clientId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"an existing client id (skips lookup)"},"clientName":{"type":"string","description":"client's name (used when creating)"},"clientEmail":{"type":"string","format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$","description":"client email — create-or-find by this"},"clientCompany":{"type":"string","description":"client's company (used when creating)"}},"description":"optional: file this under a client (the publish/site is grouped in their customer view)"}}},"annotations":{"idempotentHint":false,"readOnlyHint":false,"destructiveHint":false},"title":"Create a drive"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: false, destructiveHint: false, idempotentHint: false (inferred from the name).","verify":true}],"tokensBefore":313,"tokensAfter":313},{"name":"create_listing","fixed":{"name":"create_listing","description":"Publish (or upsert) a marketplace listing for an owned site. Requires Stripe Connect set up (status='ready' — see get_connect_status). priceCents = whole-dollar between 100 and 999900. termsMode='standard' uses shiply's template; 'custom' requires termsCustom ≥50 chars. jurisdiction is required (e.g. 'California, USA').","inputSchema":{"type":"object","$schema":"http://json-schema.org/draft-07/schema#","required":["siteSlug","priceCents","termsMode","jurisdiction"],"properties":{"pitch":{"type":"string","maxLength":280,"description":"short sales pitch, ≤280 chars"},"status":{"enum":["draft","live"],"type":"string","description":"publish state (default draft)"},"siteSlug":{"type":"string","description":"slug of the owned site to list"},"termsMode":{"enum":["standard","custom"],"type":"string","description":"'standard' uses shiply's template; 'custom' requires termsCustom"},"priceCents":{"type":"integer","maximum":999900,"minimum":100,"description":"whole-dollar price in cents, 100–999900"},"termsCustom":{"type":"string","maxLength":20000,"description":"custom terms text, ≥50 chars, required when termsMode='custom'"},"jurisdiction":{"type":"string","maxLength":80,"minLength":2,"description":"governing jurisdiction, e.g. 'California, USA'"}}},"annotations":{"idempotentHint":false,"readOnlyHint":false,"destructiveHint":false},"title":"List one of my sites for sale"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: false, destructiveHint: false, idempotentHint: false (inferred from the name).","verify":true}],"tokensBefore":362,"tokensAfter":362},{"name":"create_project","fixed":{"name":"create_project","description":"Spin up a new customer-intake project on the dev's account. Returns the project row plus intakeUrl — the public link the customer fills out (10-step wizard). If customerEmail is provided, shiply also emails them the intake invite. Use originatedFromSiteId to link a project to an existing site (e.g. 'redesign this site').","inputSchema":{"type":"object","$schema":"http://json-schema.org/draft-07/schema#","required":["label"],"properties":{"label":{"type":"string","maxLength":200,"minLength":1,"description":"project name shown in the dev dashboard"},"customerName":{"type":"string","maxLength":200,"description":"the customer's name"},"customerEmail":{"type":"string","format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$","maxLength":320,"description":"customer email; if set, shiply emails them the intake invite"},"originatedFromSiteId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"link this project to an existing site (e.g. a redesign)"}}},"annotations":{"idempotentHint":false,"readOnlyHint":false,"destructiveHint":false},"title":"Create a client-intake project"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: false, destructiveHint: false, idempotentHint: false (inferred from the name).","verify":true}],"tokensBefore":347,"tokensAfter":347},{"name":"create_test","fixed":{"name":"create_test","description":"Provision a demand test in one call: deploys a landing page with a native email-capture form and creates a confirmed-subscriber segment. Returns testId + live siteUrl. Share the siteUrl to collect signups; each signup gets a double-opt-in confirmation. Read progress with get_test_status.","inputSchema":{"type":"object","$schema":"http://json-schema.org/draft-07/schema#","required":["idea","headline"],"properties":{"cta":{"type":"string","description":"call-to-action button label"},"sub":{"type":"string","description":"subheadline / supporting line"},"idea":{"type":"string","description":"the product/idea name"},"price":{"type":"string","description":"price to display, e.g. \"$29/mo\""},"headline":{"type":"string","description":"landing-page headline"}}},"annotations":{"idempotentHint":false,"readOnlyHint":false,"destructiveHint":false},"title":"Create an email demand test"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: false, destructiveHint: false, idempotentHint: false (inferred from the name).","verify":true}],"tokensBefore":223,"tokensAfter":223},{"name":"data_insert","fixed":{"name":"data_insert","description":"Insert one record into a collection. Goes through the same public visitor endpoint a browser would use — manifest access.insert decides whether it is allowed. Use to seed waitlist data, test forms end-to-end, etc.","inputSchema":{"type":"object","$schema":"http://json-schema.org/draft-07/schema#","required":["slug","collection","record"],"properties":{"slug":{"type":"string","description":"owned site slug"},"record":{"type":"object","description":"the record fields to insert as key/value pairs","propertyNames":{"type":"string"},"additionalProperties":{}},"collection":{"type":"string","description":"collection name to insert into"}}},"annotations":{"idempotentHint":false,"readOnlyHint":false,"destructiveHint":false},"title":"Insert a record into a collection"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: false, destructiveHint: false, idempotentHint: false (inferred from the name).","verify":true}],"tokensBefore":189,"tokensAfter":189},{"name":"deploy_function","fixed":{"name":"deploy_function","description":"Deploy a Worker function to a site. The function runs on every request to <slug>.shiply.now and can receive webhooks, run on cron triggers, and access bindings (D1, secrets, env vars). Requires Developer plan. Use when the user wants webhook receivers, cron jobs, or a backend for their site.","inputSchema":{"type":"object","$schema":"http://json-schema.org/draft-07/schema#","required":["slug","source"],"properties":{"lang":{"enum":["js","ts"],"type":"string","description":"source language (default js)"},"slug":{"type":"string","description":"site slug to deploy the function to"},"crons":{"type":"array","items":{"type":"object","required":["path","schedule"],"properties":{"path":{"type":"string","maxLength":300,"minLength":1,"description":"URL path the cron handler fires on"},"schedule":{"type":"string","maxLength":60,"minLength":9,"description":"crontab schedule in UTC, e.g. \"0 * * * *\""}}},"maxItems":20,"description":"cron triggers to register, ≤20"},"source":{"type":"string","maxLength":1500000,"minLength":1,"description":"the Worker source code"}}},"annotations":{"idempotentHint":false,"readOnlyHint":false,"destructiveHint":false},"title":"Deploy a Worker function to a site"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: false, destructiveHint: false, idempotentHint: false (inferred from the name).","verify":true}],"tokensBefore":309,"tokensAfter":309},{"name":"drive_put_file","fixed":{"name":"drive_put_file","description":"Write a file into a Drive (driveId = drv_… or \"default\"). content is utf8 or base64. Use for agent memory, notes, context, assets.","inputSchema":{"type":"object","$schema":"http://json-schema.org/draft-07/schema#","required":["driveId","path","content"],"properties":{"path":{"type":"string","description":"destination path inside the drive, e.g. notes/context.md"},"content":{"type":"string","description":"file contents (utf8 text, or base64 when encoding=base64)"},"driveId":{"type":"string","description":"drive id (drv_…) or \"default\""},"encoding":{"enum":["utf8","base64"],"type":"string","description":"default utf8; base64 for binary"}}},"annotations":{"idempotentHint":true,"readOnlyHint":false,"destructiveHint":false},"title":"Write a drive file"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: false, destructiveHint: false, idempotentHint: true (inferred from the name).","verify":true}],"tokensBefore":192,"tokensAfter":192},{"name":"list_versions","fixed":{"name":"list_versions","description":"List a site's finalized deploys newest-first (id, createdAt, isLive, fileCount, bytes), capped at 20. Pair with rollback_site: pick a version id from here and re-point the site to it.","inputSchema":{"type":"object","$schema":"http://json-schema.org/draft-07/schema#","required":["slug"],"properties":{"slug":{"type":"string","description":"site slug to list deploys for"}}},"annotations":{"idempotentHint":true,"readOnlyHint":true},"title":"List a site's deploys"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: true (inferred from the name).","verify":true}],"tokensBefore":115,"tokensAfter":115},{"name":"mark_thread_read","fixed":{"name":"mark_thread_read","description":"Zero the unread counter for a thread. Useful after the agent has read but not acted. read_thread already calls this implicitly; use this explicitly when you want to clear unread without re-fetching the thread body.","inputSchema":{"type":"object","$schema":"http://json-schema.org/draft-07/schema#","required":["threadId"],"properties":{"threadId":{"type":"string","description":"thread id from list_inbox to mark read"}}},"annotations":{"idempotentHint":true,"readOnlyHint":true},"title":"Mark a thread read"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: true (inferred from the name).","verify":true}],"tokensBefore":130,"tokensAfter":130},{"name":"promote_site","fixed":{"name":"promote_site","description":"Copy the EXACT live bytes of one owned site (srcSlug — your preview) into another owned site (destSlug — your production site / custom domain), no rebuild. Dest keeps its slug, domains, and access settings; only the served bytes change.","inputSchema":{"type":"object","$schema":"http://json-schema.org/draft-07/schema#","required":["srcSlug","destSlug"],"properties":{"srcSlug":{"type":"string"},"destSlug":{"type":"string"}}},"annotations":{"idempotentHint":true,"readOnlyHint":true},"title":"Promote a preview to a production site"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: true (inferred from the name).","verify":true}],"tokensBefore":130,"tokensAfter":130},{"name":"publish_from_drive","fixed":{"name":"publish_from_drive","description":"Snapshot a Drive (or a prefix of it) into a new live site at <slug>.shiply.now. Files copied server-side.","inputSchema":{"type":"object","$schema":"http://json-schema.org/draft-07/schema#","required":["driveId"],"properties":{"title":{"type":"string","description":"display title for the new site"},"prefix":{"type":"string","description":"only snapshot files under this path prefix"},"driveId":{"type":"string","description":"drive id (drv_…) or \"default\""}}},"annotations":{"idempotentHint":false,"readOnlyHint":false,"destructiveHint":false},"title":"Publish a drive as a site"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: false, destructiveHint: false, idempotentHint: false (inferred from the name).","verify":true}],"tokensBefore":142,"tokensAfter":142},{"name":"publish_site","fixed":{"name":"publish_site","description":"Publish files to the web → live URL at <slug>.shiply.now. UPDATING: never create a new site for changes — re-call with claimToken (anonymous sites) or slug (sites you own with a Bearer key) and the SAME URL gets the new version. Unchanged files are hash-skipped server-side, so re-publishing (including retrying a failed publish) is cheap — always update the same site rather than creating a new one. Works WITHOUT auth (anonymous: 24h lifetime, returns claimToken/claimUrl — SAVE THEM). With a Beare","inputSchema":{"type":"object","$schema":"http://json-schema.org/draft-07/schema#","required":["files"],"properties":{"slug":{"type":"string","description":"UPDATE an existing site you own (requires Bearer key)"},"files":{"type":"array","items":{"type":"object","required":["path","content"],"properties":{"path":{"type":"string","description":"relative path, e.g. index.html"},"content":{"type":"string","description":"file contents (utf8 text, or base64 when encoding=base64)"},"encoding":{"enum":["utf8","base64"],"type":"string","description":"default utf8; base64 for binary"}}},"description":"site files; index.html required for a homepage"},"title":{"type":"string","description":"display title for the site"},"client":{"type":"object","properties":{"clientId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"an existing client id (skips lookup)"},"clientName":{"type":"string","description":"client's name (used when creating)"},"clientEmail":{"type":"string","format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$","description":"client email — create-or-find by this"},"clientCompany":{"type":"string","description":"client's company (used when creating)"}},"description":"optional: file this under a client (the publish/site is grouped in their customer view)"},"spaMode":{"type":"boolean","description":"serve index.html for unknown paths (client-side routing)"},"agentName":{"type":"string","description":"label shown during the automatic account re-auth flow"},"claimToken":{"type":"string","description":"UPDATE an existing anonymous site (from the original publish result)"}}},"annotations":{"idempotentHint":false,"readOnlyHint":false,"destructiveHint":false},"title":"Publish a site"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: false, destructiveHint: false, idempotentHint: false (inferred from the name).","verify":true}],"tokensBefore":664,"tokensAfter":664},{"name":"regenerate_brief","fixed":{"name":"regenerate_brief","description":"Re-run the MiniMax/Anthropic brief generator from the project's current intake_responses and persist the result. Flips status to brief_ready on success or brief_failed on error. Use after the customer edits answers post-submit, or when the first AI attempt failed.","inputSchema":{"type":"object","$schema":"http://json-schema.org/draft-07/schema#","required":["id"],"properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"project id to re-run the brief for"}}},"annotations":{"openWorldHint":true,"idempotentHint":false,"readOnlyHint":false,"destructiveHint":false},"title":"Re-run AI brief generation"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: false, destructiveHint: false, idempotentHint: false (inferred from the name).","verify":true}],"tokensBefore":193,"tokensAfter":193},{"name":"resend_intake_invite","fixed":{"name":"resend_intake_invite","description":"Re-fire the 'your developer sent you a project intake' email to the project's customer. Throws invalid_request if the project has no customerEmail (the dev needs to set one via the dashboard first — customer email isn't agent-patchable). Use when the customer says they didn't receive the link.","inputSchema":{"type":"object","$schema":"http://json-schema.org/draft-07/schema#","required":["id"],"properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"project id to re-send the intake invite for"}}},"annotations":{"openWorldHint":true,"idempotentHint":false,"readOnlyHint":false,"destructiveHint":false},"title":"Re-send the customer intake invite email"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: false, destructiveHint: false, idempotentHint: false (inferred from the name).","verify":true}],"tokensBefore":205,"tokensAfter":205},{"name":"restore_project","fixed":{"name":"restore_project","description":"Move an archived project back to status='draft' so it reappears in the active list. Idempotent on non-archived projects? No — server rejects the transition unless the project is currently archived.","inputSchema":{"type":"object","$schema":"http://json-schema.org/draft-07/schema#","required":["id"],"properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"archived project id to restore"}}},"annotations":{"idempotentHint":true,"readOnlyHint":false,"destructiveHint":true},"title":"Restore an archived project"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: false, destructiveHint: true, idempotentHint: true (inferred from the name).","verify":true}],"tokensBefore":173,"tokensAfter":173},{"name":"send_broadcast","fixed":{"name":"send_broadcast","description":"Send a campaign to this test's confirmed (double-opt-in) subscribers — the \"we're live\" email. An unsubscribe link is added automatically. Fails if there are no confirmed subscribers yet.","inputSchema":{"type":"object","$schema":"http://json-schema.org/draft-07/schema#","required":["testId","subject","html"],"properties":{"html":{"type":"string","description":"email HTML body (unsubscribe link added automatically)"},"text":{"type":"string","description":"plain-text fallback body"},"testId":{"type":"string","description":"demand test id whose confirmed subscribers to email"},"subject":{"type":"string","description":"email subject line"}}},"annotations":{"openWorldHint":true,"idempotentHint":false,"readOnlyHint":false,"destructiveHint":false},"title":"Broadcast to confirmed subscribers"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: false, destructiveHint: false, idempotentHint: false (inferred from the name).","verify":true}],"tokensBefore":192,"tokensAfter":192},{"name":"send_email","fixed":{"name":"send_email","description":"Send an email from <slug>.shiply.now's managed sender. The site can send transactional/notification email — no SMTP setup. Rate-limited and spam-checked; replies route back to the site inbox.","inputSchema":{"type":"object","$schema":"http://json-schema.org/draft-07/schema#","required":["slug","to","subject","html"],"properties":{"to":{"type":"string","format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$","description":"recipient email address"},"html":{"type":"string","description":"email HTML body"},"slug":{"type":"string","description":"site slug to send from (<slug>.shiply.now sender)"},"text":{"type":"string","description":"plain-text fallback body"},"subject":{"type":"string","description":"email subject line"}}},"annotations":{"openWorldHint":true,"idempotentHint":false,"readOnlyHint":false,"destructiveHint":false},"title":"Send an email from a site"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: false, destructiveHint: false, idempotentHint: false (inferred from the name).","verify":true}],"tokensBefore":235,"tokensAfter":235},{"name":"send_mailbox_broadcast","fixed":{"name":"send_mailbox_broadcast","description":"Send a one-shot broadcast to the confirmed (double-opt-in) subscribers of a (site, collection) mailbox. Spam-checked; unsubscribe footer auto-added. Fails if no confirmed subscribers exist yet.","inputSchema":{"type":"object","$schema":"http://json-schema.org/draft-07/schema#","required":["slug","collection","subject","html"],"properties":{"html":{"type":"string","description":"email HTML body (unsubscribe footer added automatically)"},"slug":{"type":"string","description":"site slug the mailbox belongs to"},"text":{"type":"string","description":"plain-text fallback body"},"subject":{"type":"string","description":"email subject line"},"collection":{"type":"string","description":"mailbox collection whose confirmed audience to email"}}},"annotations":{"openWorldHint":true,"idempotentHint":false,"readOnlyHint":false,"destructiveHint":false},"title":"Broadcast to a mailbox's confirmed audience"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: false, destructiveHint: false, idempotentHint: false (inferred from the name).","verify":true}],"tokensBefore":221,"tokensAfter":221},{"name":"set_cron","fixed":{"name":"set_cron","description":"Set or update a cron trigger on a site's deployed function. Schedule is crontab syntax (UTC). Path is the URL the cron handler should fire on (for the worker's scheduled() handler context).","inputSchema":{"type":"object","$schema":"http://json-schema.org/draft-07/schema#","required":["slug","path","schedule"],"properties":{"path":{"type":"string","maxLength":300,"minLength":1,"description":"URL path the cron handler fires on"},"slug":{"type":"string","description":"site slug whose function gets the cron"},"schedule":{"type":"string","maxLength":60,"minLength":9,"description":"crontab schedule in UTC, e.g. \"0 * * * *\""}}},"annotations":{"idempotentHint":true,"readOnlyHint":false,"destructiveHint":false},"title":"Set or update a cron trigger"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: false, destructiveHint: false, idempotentHint: true (inferred from the name).","verify":true}],"tokensBefore":185,"tokensAfter":185},{"name":"set_handle","fixed":{"name":"set_handle","description":"Give ONE site a vanity URL: rename it to <handle>.shiply.now (3-30 chars, a-z 0-9 -). The old address 301-redirects for 30 days. (For a portfolio page listing all your sites, use set_profile instead — that lives at shiply.now/@<handle>.)","inputSchema":{"type":"object","$schema":"http://json-schema.org/draft-07/schema#","required":["slug","handle"],"properties":{"slug":{"type":"string","description":"current site slug"},"handle":{"type":"string","description":"new vanity handle, 3-30 chars a-z 0-9 -"}}},"annotations":{"idempotentHint":true,"readOnlyHint":false,"destructiveHint":false},"title":"Set a vanity handle"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: false, destructiveHint: false, idempotentHint: true (inferred from the name).","verify":true}],"tokensBefore":152,"tokensAfter":152},{"name":"set_link","fixed":{"name":"set_link","description":"Path-mounting: serve an owned target site at a path on an owned host site (host/docs -> target). location is a path like \"docs\", or \"__root__\" for the host root. Both sites must be owned by you. Pass remove=true to unmount.","inputSchema":{"type":"object","$schema":"http://json-schema.org/draft-07/schema#","required":["hostSlug","location"],"properties":{"remove":{"type":"boolean","description":"unmount instead of mounting"},"hostSlug":{"type":"string","description":"slug of the owned host site"},"location":{"type":"string","description":"path to mount at, e.g. \"docs\", or \"__root__\" for the host root"},"targetSlug":{"type":"string","description":"slug of the owned site to serve there (required unless remove=true)"}}},"annotations":{"idempotentHint":true,"readOnlyHint":false,"destructiveHint":false},"title":"Mount a site at a path"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: false, destructiveHint: false, idempotentHint: true (inferred from the name).","verify":true}],"tokensBefore":214,"tokensAfter":214},{"name":"set_mailbox","fixed":{"name":"set_mailbox","description":"Turn a Site Data collection into a mailbox: double opt-in, owner notifications, sending domain, branding. Call once per (site, collection) to configure how captured leads are handled.","inputSchema":{"type":"object","$schema":"http://json-schema.org/draft-07/schema#","required":["slug","collection"],"properties":{"slug":{"type":"string","description":"site slug the collection belongs to"},"branding":{"type":"object","properties":{"logoUrl":{"type":"string","description":"logo image URL shown in emails"},"brandName":{"type":"string","description":"brand name shown in emails"},"brandColor":{"type":"string","description":"accent color hex, e.g. #2563eb"}},"description":"branding applied to mailbox emails"},"notifyTo":{"type":"string","format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$","description":"address to send owner notifications to"},"collection":{"type":"string","description":"Site Data collection to turn into a mailbox"},"doubleOptIn":{"type":"boolean","description":"require email confirmation before a contact is active"},"notifyOwner":{"type":"boolean","description":"email the owner on each new capture"},"sendingDomainId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"BYO sending domain id to send from"}}},"annotations":{"idempotentHint":true,"readOnlyHint":false,"destructiveHint":false},"title":"Configure a site collection's email behavior"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: false, destructiveHint: false, idempotentHint: true (inferred from the name).","verify":true}],"tokensBefore":425,"tokensAfter":425},{"name":"set_primary_subdomain","fixed":{"name":"set_primary_subdomain","description":"Mark a hostname as the primary (canonical) URL for its site. Sibling hostnames (apex + www both pointed at the same site) start 301-redirecting to it, preserving path + query. The host-side fix for the duplicate-content SEO problem. The first subdomain you add for a site is primary by default; call this only when you need to switch.","inputSchema":{"type":"object","$schema":"http://json-schema.org/draft-07/schema#","required":["domain","hostname"],"properties":{"domain":{"type":"string","description":"registered custom domain, e.g. example.com"},"hostname":{"type":"string","description":"full hostname to make primary, e.g. www.example.com"}}},"annotations":{"idempotentHint":true,"readOnlyHint":false,"destructiveHint":false},"title":"Pick the canonical URL for a custom domain"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: false, destructiveHint: false, idempotentHint: true (inferred from the name).","verify":true}],"tokensBefore":194,"tokensAfter":194},{"name":"set_profile","fixed":{"name":"set_profile","description":"Create or update the user's public PORTFOLIO page at shiply.now/@<handle> (handle 3-30 chars a-z0-9-) — a landing page listing the user's sites. This is NOT a site's address: to give one site a vanity URL like <handle>.shiply.now, use set_handle instead. enable shows the profile; autoAdd auto-lists new sites. Use after publishing to give the user a shareable portfolio.","inputSchema":{"type":"object","$schema":"http://json-schema.org/draft-07/schema#","properties":{"enable":{"type":"boolean","description":"show (true) or hide (false) the public profile"},"handle":{"type":"string","description":"public portfolio handle, 3-30 chars a-z 0-9 -; portfolio lives at shiply.now/@<handle> (a page listing your sites — not a site URL; for a site vanity URL use set_handle)"},"autoAdd":{"type":"boolean","description":"auto-list newly published sites on the profile"}}},"annotations":{"idempotentHint":true,"readOnlyHint":false,"destructiveHint":false},"title":"Set up a public profile"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: false, destructiveHint: false, idempotentHint: true (inferred from the name).","verify":true}],"tokensBefore":252,"tokensAfter":252},{"name":"set_secret","fixed":{"name":"set_secret","description":"Set a CF Worker secret on a site's deployed function. Value is encrypted-at-rest and accessible as env.<NAME> inside the worker. Use for Stripe keys, Resend API keys, etc.","inputSchema":{"type":"object","$schema":"http://json-schema.org/draft-07/schema#","required":["slug","name","value"],"properties":{"name":{"type":"string","pattern":"^[A-Z_][A-Z0-9_]*$","maxLength":80,"description":"secret name, UPPER_SNAKE_CASE; available as env.<NAME>"},"slug":{"type":"string","description":"site slug whose function gets the secret"},"value":{"type":"string","maxLength":8192,"minLength":1,"description":"secret value (encrypted at rest), ≤8 KiB"}}},"annotations":{"idempotentHint":true,"readOnlyHint":false,"destructiveHint":false},"title":"Set a Worker secret on a site"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: false, destructiveHint: false, idempotentHint: true (inferred from the name).","verify":true}],"tokensBefore":190,"tokensAfter":190},{"name":"set_site_access","fixed":{"name":"set_site_access","description":"Protect an owned site (paid plans). mode 'public' (anyone), 'password' (supply password), or 'restricted' (supply allowedEmails and/or allowedDomains — only those can request a login code). Changing any setting signs out existing visitors.","inputSchema":{"type":"object","$schema":"http://json-schema.org/draft-07/schema#","required":["slug","mode"],"properties":{"mode":{"enum":["public","password","restricted"],"type":"string","description":"public = anyone; password = supply password; restricted = supply allowedEmails/allowedDomains"},"slug":{"type":"string","description":"owned site slug to protect"},"password":{"type":"string","description":"required when mode='password'"},"allowedEmails":{"type":"array","items":{"type":"string"},"description":"allowlisted emails when mode='restricted'"},"allowedDomains":{"type":"array","items":{"type":"string"},"description":"allowlisted email domains when mode='restricted'"}}},"annotations":{"idempotentHint":true,"readOnlyHint":false,"destructiveHint":false},"title":"Set site access control"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: false, destructiveHint: false, idempotentHint: true (inferred from the name).","verify":true}],"tokensBefore":270,"tokensAfter":270},{"name":"set_variable","fixed":{"name":"set_variable","description":"Upsert a key/value in the user's encrypted variable store (UPPER_SNAKE name, ≤8 KiB value). Use for API keys the user's sites/agents need, e.g. SUPABASE_URL. NOTE: saving alone does NOT expose it to any site Worker's env — attach it to a specific site with attach_variable (takes effect on that site's next function deploy).","inputSchema":{"type":"object","$schema":"http://json-schema.org/draft-07/schema#","required":["name","value"],"properties":{"name":{"type":"string","description":"variable name, UPPER_SNAKE_CASE, e.g. SUPABASE_URL"},"value":{"type":"string","description":"value to store (encrypted, ≤8 KiB)"}}},"annotations":{"idempotentHint":true,"readOnlyHint":false,"destructiveHint":false},"title":"Save an encrypted variable"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: false, destructiveHint: false, idempotentHint: true (inferred from the name).","verify":true}],"tokensBefore":184,"tokensAfter":184},{"name":"update_brief","fixed":{"name":"update_brief","description":"Overwrite the project's working brief (jsonb). Hard-capped at 500 KB. Use to revise the AI-generated brief by hand; the original AI output is preserved separately in briefAiOriginal so you can always compare. Does not change status.","inputSchema":{"type":"object","$schema":"http://json-schema.org/draft-07/schema#","required":["id","brief"],"properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"project id"},"brief":{"type":"object","description":"the full replacement brief object (jsonb, ≤500 KB)","propertyNames":{"type":"string"},"additionalProperties":{}}}},"annotations":{"idempotentHint":true,"readOnlyHint":false,"destructiveHint":false},"title":"Patch the project brief"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: false, destructiveHint: false, idempotentHint: true (inferred from the name).","verify":true}],"tokensBefore":221,"tokensAfter":221},{"name":"update_listing","fixed":{"name":"update_listing","description":"Patch a listing by siteSlug — change price, pitch, terms, jurisdiction, or status (draft|live|paused). Sold listings cannot be edited. Status transitions enforced server-side. Use to pause sales or drop the price.","inputSchema":{"type":"object","$schema":"http://json-schema.org/draft-07/schema#","required":["siteSlug"],"properties":{"pitch":{"anyOf":[{"type":"string","maxLength":280},{"type":"null"}],"description":"new sales pitch (null to clear)"},"status":{"enum":["draft","live","paused"],"type":"string","description":"new listing status"},"siteSlug":{"type":"string","description":"slug of the listed site to patch"},"termsMode":{"enum":["standard","custom"],"type":"string","description":"'standard' template or 'custom' terms"},"priceCents":{"type":"integer","maximum":999900,"minimum":100,"description":"new whole-dollar price in cents, 100–999900"},"termsCustom":{"anyOf":[{"type":"string","maxLength":20000},{"type":"null"}],"description":"new custom terms text (null to clear)"},"jurisdiction":{"type":"string","maxLength":80,"minLength":2,"description":"governing jurisdiction, e.g. 'California, USA'"}}},"annotations":{"idempotentHint":true,"readOnlyHint":false,"destructiveHint":false},"title":"Update one of my listings"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: false, destructiveHint: false, idempotentHint: true (inferred from the name).","verify":true}],"tokensBefore":323,"tokensAfter":323},{"name":"verify_sending_domain","fixed":{"name":"verify_sending_domain","description":"Trigger Resend to re-check the domain's DNS records, persist the new status. Call after adding the DNS records returned by add_sending_domain. Status flips to 'verified' once SPF + DKIM + MX all check out.","inputSchema":{"type":"object","$schema":"http://json-schema.org/draft-07/schema#","required":["id"],"properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"sending domain id from list_sending_domains"}}},"annotations":{"openWorldHint":true,"idempotentHint":false,"readOnlyHint":false,"destructiveHint":false},"title":"Re-check DNS for a sending domain"},"changes":[{"kind":"annotations","detail":"Added readOnlyHint: false, destructiveHint: false, idempotentHint: false (inferred from the name).","verify":true}],"tokensBefore":181,"tokensAfter":181}],"toolsChanged":41,"tokensSaved":0,"todo":[{"tool":"promote_site","params":["srcSlug","destSlug"]}],"note":"Deterministic fixes. Changes marked verify need a human look before shipping (renames, inferred annotations, inferred types, removed text). Parameter descriptions in `todo` need to be written by someone who knows the API."}