# now.shiply/shiply (remote · shiply.now)

Publish any app in one call: SQL database, functions, email, and a custom domain. Flat price.

- Trust score: 82/100 (high trust)
- Change this week: +8
- Registry status: active
- Liveness: live
- Owner verified: no
- Last scored: 2026-08-03

## Components

- remote · `shiply.now`: 82/100 (this document), [markdown](https://verifymcp.io/servers/now-shiply-shiply/shiply.md), [page](https://verifymcp.io/servers/now-shiply-shiply/shiply)

## Channel facts

- Endpoint: `https://shiply.now/mcp`
- Transports: `streamable-http`
- Auth: `none`
- Version: `1.1.0`

## Trust breakdown

How this component scores in each security and reliability category. Every signal is checked automatically against the live server, and we only credit what we can confirm. Scores are 0–100 per category. Scoring method: https://verifymcp.io/docs/scoring (what has changed: https://verifymcp.io/docs/scoring/changelog)

Scored 2026-08-03.

- **Endpoint Security**: 94/100
  - The endpoint's TLS certificate is valid, in date, and uses a strong key.
  - Authorisation is enforced on tool calls, advertised via RFC 9728 protected-resource metadata. Discovery is public, which costs nothing: no tool can be invoked without a token.
  - HTTPS is enforced; there's no plaintext access path.
  - The HSTS (Strict-Transport-Security) header is present.
  - DNSSEC check failed: this domain isn't protected by DNSSEC.
  - The authorisation server offers only Dynamic Client Registration (RFC 7591), which MCP 2026-07-28 deprecated in favour of Client ID Metadata Documents.
- **Transport & Reachability**: 100/100
  - Verified streamable-http transport via a live MCP handshake.
- **Schema Quality & AI Usability**: 77/100
  - 100% of prompts and resources have a non-trivial description (not blank, and not just the item's name).
  - AI-judged instruction clarity (good).
  - Tool/resource definitions use about 9168 tokens (~78/item across 117 items; 114 tools + 3 resources), lean.
  - Usage-examples check failed: none of the tools include examples.
- **Stability & Change Management**: 27/100
  - Stability observed for 8 of 30 days with no destabilising changes; credit accrues until the full window elapses.
- **Tool Coverage**: 100/100
  - 100% of tools have a non-trivial description (not blank, and not just the tool's name).
  - 99% of tool parameters carry a description.
  - Structured output schemas are declared (100% of tools); any adoption earns full credit.
- **Capabilities**: 100/100
  - Implements a supported MCP spec version (2025-11-25); the latest is 2026-07-28.

## Install

### Claude

```bash
claude mcp add --transport http now-shiply-shiply https://shiply.now/mcp
```

### Codex

```toml
[mcp_servers.now-shiply-shiply]
url = "https://shiply.now/mcp"
```

### opencode

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "now-shiply-shiply": {
      "type": "remote",
      "url": "https://shiply.now/mcp",
      "enabled": true
    }
  }
}
```

### OpenClaw

```bash
openclaw mcp add now-shiply-shiply --url https://shiply.now/mcp --transport streamable-http
```

### Hermes

```yaml
mcp_servers:
  now-shiply-shiply:
    url: "https://shiply.now/mcp"
```

### Other

```json
{
  "mcpServers": {
    "now-shiply-shiply": {
      "type": "http",
      "url": "https://shiply.now/mcp"
    }
  }
}
```

The mcpServers block is a cross-client convention. Remote transports vary, so check your client's docs.

## Changelog

Every change recorded for this component, newest first. Days that predate change tracking, or that we cannot explain, say so: "we were watching and nothing happened" and "we were not watching" are different claims.

### 2026-08-03 (score 82, +1)

No change was recorded against any check on this day. Stability & Change Management went from 23 to 27. That category is still filling its 30-day observation window: 7 days of observed history at the previous scan, 8 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-07-31 (score 81, +6)

- [functional] We updated how we score, so this day's move reflects our rubric, not a change to the server

### 2026-07-30 (score 75, −1)

- [functional] We updated how we score, so this day's move reflects our rubric, not a change to the server

### 2026-07-29 (score 76, +1)

No change was recorded against any check on this day. Stability & Change Management went from 7 to 10. That category is still filling its 30-day observation window: 2 days of observed history at the previous scan, 3 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-07-28 (score 75, +1)

No change was recorded against any check on this day. Stability & Change Management went from 3 to 7. That category is still filling its 30-day observation window: 1 days of observed history at the previous scan, 2 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-07-27 (score 74, 0)

- [functional] We updated how we score, so this day's move reflects our rubric, not a change to the server

### 2026-07-26 (score 74)

First indexed and scored.

## MCP tools (114)

### `publish_site` (~278 tokens)

Publish a site

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 Bearer shp_ key sites are permanent. ≤50 files / 2 MB inline; bigger: REST flow per https://shiply.now/llms.txt. index.html serves at /. spaMode for client-side routing.

Input parameters:

- `claimToken` (string): UPDATE an existing anonymous site (from the original publish result)
- `client` (object): optional: file this under a client (the publish/site is grouped in their customer view)
- `files` (array, required): site files; index.html required for a homepage
- `slug` (string): UPDATE an existing site you own (requires Bearer key)
- `spaMode` (boolean): serve index.html for unknown paths (client-side routing)
- `title` (string): display title for the site

Output parameters:

- `result`

### `site_status` (~52 tokens)

SSL + readiness check

Check any shiply slug or custom hostname: TLS certificate (issuer, days left) + HTTPS probe. ready=true means live.

Input parameters:

- `target` (string, required): slug (my-site) or hostname (www.example.com)

Output parameters:

- `result`

### `verify_site` (~81 tokens)

Verify a live deploy

Edge-check a shiply slug or custom hostname and return a structured readiness report: status (LIVE/PENDING), SSL details (valid, issuer, daysLeft), HTTP probe, and a presigned thumbnail URL when available. Use this after publishing to confirm the site is reachable.

Input parameters:

- `target` (string, required): slug (my-site) or hostname (www.example.com)

Output parameters:

- `result`

### `list_sites` (~39 tokens)

List my sites

List the sites owned by this API key. Optional clientId filters to one client.

Input parameters:

- `clientId` (string): only sites filed under this client

Output parameters:

- `result`

### `get_site` (~34 tokens)

Site detail

Site settings + version history for one of my sites.

Input parameters:

- `slug` (string, required): site slug, e.g. my-site

Output parameters:

- `result`

### `delete_site` (~41 tokens)

Delete a site

PERMANENTLY delete a site and all stored files. Irreversible — confirm with the user first.

Input parameters:

- `slug` (string, required): site slug to delete

Output parameters:

- `result`

### `rollback_site` (~59 tokens)

Roll back a site

Re-point a site to any finalized version (rollback or roll-forward). Get version ids from get_site. Serving updates immediately.

Input parameters:

- `slug` (string, required): site slug to re-point
- `versionId` (string, required): finalized version id from get_site

Output parameters:

- `result`

### `list_versions` (~68 tokens)

List a site's deploys

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.

Input parameters:

- `slug` (string, required): site slug to list deploys for

Output parameters:

- `result`

### `pull_site` (~80 tokens)

Pull a site's current files

Download the current files of a site you own (or created via a platform connection) so you can edit and republish to the same slug with publish_site. Static sites return editable source; framework/SSR sites return the built bundle (`.shiply/bundle/*`), not original source.

Input parameters:

- `slug` (string, required): site slug to pull files for

Output parameters:

- `result`

### `set_handle` (~109 tokens)

Set a vanity handle

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>.)

Input parameters:

- `handle` (string, required): new vanity handle, 3-30 chars a-z 0-9 -
- `slug` (string, required): current site slug

Output parameters:

- `result`

### `duplicate_site` (~75 tokens)

Duplicate a site

Server-side copy of an owned site under a new slug — instantly live. Copies files + title; does NOT copy access settings, domains, or data. Great for iterating on variants.

Input parameters:

- `slug` (string, required): site slug to copy
- `title` (string): display title for the new copy (defaults to source title)

Output parameters:

- `result`

### `promote_site` (~75 tokens)

Promote a preview to a production site

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.

Input parameters:

- `destSlug` (string, required)
- `srcSlug` (string, required)

Output parameters:

- `result`

### `set_link` (~139 tokens)

Mount a site at a path

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.

Input parameters:

- `hostSlug` (string, required): slug of the owned host site
- `location` (string, required): path to mount at, e.g. "docs", or "__root__" for the host root
- `remove` (boolean): unmount instead of mounting
- `targetSlug` (string): slug of the owned site to serve there (required unless remove=true)

Output parameters:

- `result`

### `set_site_access` (~142 tokens)

Set site access control

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.

Input parameters:

- `allowedDomains` (array): allowlisted email domains when mode='restricted'
- `allowedEmails` (array): allowlisted emails when mode='restricted'
- `mode` (string, required): public = anyone; password = supply password; restricted = supply allowedEmails/allowedDomains
- `password` (string): required when mode='password'
- `slug` (string, required): owned site slug to protect

Output parameters:

- `result`

### `get_site_access` (~56 tokens)

Read site access control

Read an owned site's current access policy (mode: public/password/restricted, allowedEmails, allowedDomains, hasPassword). Read-only counterpart to set_site_access — check before changing it.

Input parameters:

- `slug` (string, required): owned site slug

Output parameters:

- `result`

### `export_account` (~34 tokens)

Export account data

Return a JSON bundle of the user's profile, sites, Site Data, drives, and metadata (secrets excluded). Data portability.

Output parameters:

- `result`

### `whoami` (~51 tokens)

Account overview

Who am I? Returns the signed-in account: email, @handle, plan + limits, counts of sites/domains/drives, and connected DNS providers. Call this first to orient before managing sites or domains.

Output parameters:

- `result`

### `get_account_status` (~122 tokens)

Account plan + capability matrix

Get the signed-in account's plan, capabilities, and upgrade URL. Call this FIRST when figuring out what features you have access to — it tells you exactly what's available and what's blocked. The upgrade_url is human-clickable; show it in chat when a feature requires a higher plan. Returns plan id + name + subscription status, hard limits (sites, databases, custom domains, drives), and a capability matrix listing every gated feature (workers_lite, databases_neon_postgres, custom_domains, etc.) with whether you have access and the minimum plan needed.

Output parameters:

- `result`

### `list_drives` (~42 tokens)

List drives

List the user's private cloud Drives (id, name). Optional clientId filters to one client.

Input parameters:

- `clientId` (string): only drives filed under this client

Output parameters:

- `result`

### `create_drive` (~64 tokens)

Create a drive

Create a private cloud Drive (plan-limited). Pass client to file it under a client.

Input parameters:

- `client` (object): optional: file this under a client (the publish/site is grouped in their customer view)
- `name` (string, required): display name for the new drive

Output parameters:

- `result`

### `drive_list_files` (~60 tokens)

List drive files

List files in a Drive (driveId = drv_…, or "default"). Optional prefix filter.

Input parameters:

- `driveId` (string, required): drive id (drv_…) or "default"
- `prefix` (string): only list files under this path prefix

Output parameters:

- `result`

### `drive_put_file` (~118 tokens)

Write a drive file

Write a file into a Drive (driveId = drv_… or "default"). content is utf8 or base64. Use for agent memory, notes, context, assets.

Input parameters:

- `content` (string, required): file contents (utf8 text, or base64 when encoding=base64)
- `driveId` (string, required): drive id (drv_…) or "default"
- `encoding` (string): default utf8; base64 for binary
- `path` (string, required): destination path inside the drive, e.g. notes/context.md

Output parameters:

- `result`

### `drive_delete_file` (~46 tokens)

Delete a drive file

Delete a file from a Drive.

Input parameters:

- `driveId` (string, required): drive id (drv_…) or "default"
- `path` (string, required): path of the file to delete

Output parameters:

- `result`

### `publish_from_drive` (~81 tokens)

Publish a drive as a site

Snapshot a Drive (or a prefix of it) into a new live site at <slug>.shiply.now. Files copied server-side.

Input parameters:

- `driveId` (string, required): drive id (drv_…) or "default"
- `prefix` (string): only snapshot files under this path prefix
- `title` (string): display title for the new site

Output parameters:

- `result`

### `set_profile` (~190 tokens)

Set up a public profile

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.

Input parameters:

- `autoAdd` (boolean): auto-list newly published sites on the profile
- `enable` (boolean): show (true) or hide (false) the public profile
- `handle` (string): 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)

Output parameters:

- `result`

### `feature_site` (~67 tokens)

Feature a site on Explore

Toggle whether an owned, public site appears in the public shiply Explore gallery (https://shiply.now/explore). Only public-access sites are eligible.

Input parameters:

- `show` (boolean, required): true to feature on Explore, false to remove
- `slug` (string, required): owned, public site slug

Output parameters:

- `result`

### `set_variable` (~127 tokens)

Save an encrypted variable

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).

Input parameters:

- `name` (string, required): variable name, UPPER_SNAKE_CASE, e.g. SUPABASE_URL
- `value` (string, required): value to store (encrypted, ≤8 KiB)

Output parameters:

- `result`

### `list_variables` (~33 tokens)

List variables

List the encrypted variables. Values are masked unless reveal=true.

Input parameters:

- `reveal` (boolean): return plaintext values instead of masked

Output parameters:

- `result`

### `delete_variable` (~25 tokens)

Delete a variable

Remove one variable by name.

Input parameters:

- `name` (string, required): variable name to delete

Output parameters:

- `result`

### `attach_variable` (~83 tokens)

Attach a variable to a site

Expose one saved variable to ONE owned site's Worker env (plain_text binding). Opt-in per site — unattached variables are never injected, because the Worker runs the site's own code. Takes effect on the site's next function deploy.

Input parameters:

- `name` (string, required): variable name to attach, e.g. SUPABASE_URL
- `slug` (string, required): owned site slug

Output parameters:

- `result`

### `detach_variable` (~48 tokens)

Detach a variable from a site

Stop exposing a variable to a site's Worker env. Takes effect on the site's next function deploy.

Input parameters:

- `name` (string, required): variable name to detach
- `slug` (string, required): owned site slug

Output parameters:

- `result`

### `list_site_variables` (~36 tokens)

List variables attached to a site

Names of the variables attached to an owned site's Worker env (values never shown here).

Input parameters:

- `slug` (string, required): owned site slug

Output parameters:

- `result`

### `list_databases` (~85 tokens)

List my databases

List the SQL databases (D1 or Neon Postgres) on my account, including which owned site (if any) each is attached to. Call this BEFORE db_query/db_schema-style work to discover a databaseId — those live on a per-database MCP server reached via GET /api/v1/databases/{id} (see llms.txt), which this id feeds.

Output parameters:

- `result`

### `create_database` (~128 tokens)

Create a database

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.

Input parameters:

- `binding` (string): Worker binding name, UPPER_SNAKE (defaults to a name derived from `name`)
- `name` (string, required): database name, a-z 0-9 -, 2-63 chars
- `provider` (string): defaults to d1
- `siteSlug` (string): owned site slug to attach immediately

Output parameters:

- `result`

### `delete_database` (~44 tokens)

Delete a database

PERMANENTLY delete a database and all its data. Irreversible — confirm with the user first.

Input parameters:

- `id` (string, required): database id (from list_databases)

Output parameters:

- `result`

### `attach_database` (~64 tokens)

Attach a database to a site

Bind an existing database to one owned site's Worker env (the binding name chosen at create_database time). Takes effect on the site's next function/publish deploy.

Input parameters:

- `id` (string, required): database id (from list_databases)
- `siteSlug` (string, required): owned site slug

Output parameters:

- `result`

### `data_list_collections` (~56 tokens)

List Site Data collections

List collections declared in an owned site's .shiply/data.json with current record counts. Empty list means the site has no manifest yet — scaffold one with `shiply data init`.

Input parameters:

- `slug` (string, required): owned site slug

Output parameters:

- `result`

### `data_query` (~94 tokens)

Query records from a collection

Page records from an owned site's collection, newest-first. limit ≤ 200 (default 50). cursor from a previous response's nextCursor.

Input parameters:

- `collection` (string, required): collection name from data_list_collections
- `cursor` (string): nextCursor from a previous response's page
- `limit` (integer): max records to return, ≤200 (default 50)
- `slug` (string, required): owned site slug

Output parameters:

- `result`

### `data_insert` (~89 tokens)

Insert a record into a collection

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.

Input parameters:

- `collection` (string, required): collection name to insert into
- `record` (object, required): the record fields to insert as key/value pairs
- `slug` (string, required): owned site slug

Output parameters:

- `result`

### `data_export_collection` (~99 tokens)

Export records (capped)

Return up to `limit` records (default 1000, max 5000) from a collection — for snapshotting into agent context. For larger sets use the CLI: `shiply data export <slug> <collection>`.

Input parameters:

- `collection` (string, required): collection name to export
- `limit` (integer): max records to return (default 1000, max 5000)
- `slug` (string, required): owned site slug

Output parameters:

- `result`

### `add_domain` (~76 tokens)

Connect a custom domain

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.

Input parameters:

- `hostname` (string, required): full hostname to serve, e.g. www.example.com
- `slug` (string, required): owned site slug to serve there

Output parameters:

- `result`

### `add_custom_domain` (~67 tokens)

Register a custom domain

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.

Input parameters:

- `domain` (string, required): registrable domain you own, e.g. example.com

Output parameters:

- `result`

### `add_subdomain` (~136 tokens)

Point a subdomain at a site

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.

Input parameters:

- `domain` (string, required): registrable parent domain, e.g. example.com
- `slug` (string, required): owned site slug to serve there
- `subdomain` (string, required): subdomain label, or "@"/"" for the apex

Output parameters:

- `result`

### `set_primary_subdomain` (~123 tokens)

Pick the canonical URL for a custom domain

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.

Input parameters:

- `domain` (string, required): registered custom domain, e.g. example.com
- `hostname` (string, required): full hostname to make primary, e.g. www.example.com

Output parameters:

- `result`

### `list_custom_domains` (~32 tokens)

List custom domains

List registered custom domains grouped with their subdomains, each subdomain's site and status, and the detected provider.

Output parameters:

- `result`

### `connect_provider` (~77 tokens)

Connect the domain's DNS provider

Start one-click DNS connect for a registered custom domain. For Cloudflare-hosted domains this returns an authorize URL — SHOW THE USER the url as a clickable link; after they authorize, records are written automatically. For other providers, add the records manually.

Input parameters:

- `domain` (string, required): registered custom domain to connect, e.g. example.com

Output parameters:

- `result`

### `sync_dns` (~63 tokens)

Sync DNS records

For a connected custom domain, (re)write the CNAME records for all its subdomains automatically and report what changed. For unconnected domains, returns the records to add manually.

Input parameters:

- `domain` (string, required): registered custom domain to sync, e.g. example.com

Output parameters:

- `result`

### `check_custom_domain` (~85 tokens)

Check a custom domain

Check whether a custom domain's subdomains are live: re-polls Cloudflare cert status + probes DNS/TLS/HTTPS on each subdomain. Poll this after connect_provider / add_subdomain to confirm the domain is serving. Returns per-subdomain status + tls + http + ready.

Input parameters:

- `domain` (string, required): registered custom domain to check, e.g. example.com

Output parameters:

- `result`

### `remove_custom_domain` (~43 tokens)

Remove a custom domain

Remove a registered custom domain and all its subdomains; they stop serving immediately.

Input parameters:

- `domain` (string, required): registered custom domain to remove, e.g. example.com

Output parameters:

- `result`

### `list_domains` (~15 tokens)

List custom domains

List connected custom domains with status.

Output parameters:

- `result`

### `check_domain` (~41 tokens)

Check a custom domain

Refresh certificate status + live TLS/HTTPS probe for a connected domain (by id from list_domains).

Input parameters:

- `id` (string, required): connected domain id from list_domains

Output parameters:

- `result`

### `remove_domain` (~34 tokens)

Disconnect a custom domain

Remove a connected domain (by id). It stops serving immediately.

Input parameters:

- `id` (string, required): connected domain id from list_domains

Output parameters:

- `result`

### `get_analytics` (~21 tokens)

Site analytics

Daily page views per site for the last 30 days.

Output parameters:

- `result`

### `create_test` (~133 tokens)

Create an email demand test

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.

Input parameters:

- `cta` (string): call-to-action button label
- `headline` (string, required): landing-page headline
- `idea` (string, required): the product/idea name
- `price` (string): price to display, e.g. "$29/mo"
- `sub` (string): subheadline / supporting line

Output parameters:

- `result`

### `list_tests` (~19 tokens)

List demand tests

List your demand tests with signups + confirmed counts.

Output parameters:

- `result`

### `get_test_status` (~77 tokens)

Demand test status (the verdict)

ONE consolidated object: page funnel (views, signups, confirmed, conversion) ⊕ email events (delivered/opened/clicked/bounced) ⊕ a computed verdict. The single place to check progress — never query email separately.

Input parameters:

- `testId` (string, required): demand test id from create_test / list_tests

Output parameters:

- `result`

### `send_broadcast` (~101 tokens)

Broadcast to confirmed subscribers

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.

Input parameters:

- `html` (string, required): email HTML body (unsubscribe link added automatically)
- `subject` (string, required): email subject line
- `testId` (string, required): demand test id whose confirmed subscribers to email
- `text` (string): plain-text fallback body

Output parameters:

- `result`

### `resend_confirmation` (~55 tokens)

Resend a confirmation email

Re-send the double-opt-in confirmation to a signup that has not confirmed yet.

Input parameters:

- `email` (string, required): the unconfirmed signup email to re-send to
- `testId` (string, required): demand test id the signup belongs to

Output parameters:

- `result`

### `verify_claim` (~113 tokens)

Verify a Shiply claim pairing code

Confirm a pairing code shown in the user's browser at https://shiply.now/claim/<slug>?pair=1. Use ONLY in the agent session that originally published the site — it reads the claimToken from .shiply.json in the current working directory and proves to Shiply that this agent session is authorised to claim the site. After verification the user is auto-redirected to /welcome and the site binds to their account.

Input parameters:

- `code` (string, required): the SHIPLY-XXXXXXXX code in the user's browser

Output parameters:

- `result`

### `list_inbox` (~75 tokens)

List inbox threads

List the user's email inbox threads (outbound demand-test sends + inbound replies / unsubscribes / complaints / bounces). Filter by tag.

Input parameters:

- `filter` (string): default all
- `limit` (integer): max threads to return, ≤200
- `offset` (integer): number of threads to skip (pagination)

Output parameters:

- `result`

### `read_thread` (~44 tokens)

Read an inbox thread

Return the thread metadata + all messages in chronological order. Use list_inbox first to get a threadId.

Input parameters:

- `threadId` (string, required): thread id from list_inbox

Output parameters:

- `result`

### `summarize_thread` (~45 tokens)

AI-summarize an inbox thread

One-paragraph summary of the thread, oriented to the most actionable signal (interest, complaint, question, unsubscribe).

Input parameters:

- `threadId` (string, required): thread id from list_inbox

Output parameters:

- `result`

### `reply_to_thread` (~147 tokens)

Reply to an inbox thread

Send an email reply on an existing thread. Goes FROM the original recipient address (the <slug>@shiply.now alias the sender used) and TO the original sender. Threaded via RFC 5322 In-Reply-To so Gmail/Outlook group it with the original. Subject defaults to 'Re: <original>' when omitted. Cap at 20,000 chars. Use after read_thread to make sure you're replying to the right conversation.

Input parameters:

- `body` (string, required): reply body, ≤20,000 chars
- `subject` (string): subject; defaults to 'Re: <original>'
- `threadId` (string, required): thread id from list_inbox to reply on

Output parameters:

- `result`

### `mark_thread_read` (~68 tokens)

Mark a thread read

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.

Input parameters:

- `threadId` (string, required): thread id from list_inbox to mark read

Output parameters:

- `result`

### `archive_thread` (~58 tokens)

Archive a thread

Soft-archive the thread (sets archivedAt). Hidden from the default inbox view; surface again with list_inbox filter=archived. Reverse with unarchive_thread.

Input parameters:

- `threadId` (string, required): thread id from list_inbox to archive

Output parameters:

- `result`

### `unarchive_thread` (~58 tokens)

Unarchive a thread

Restore an archived thread (clears archivedAt). It reappears in the default inbox list. Pair with list_inbox filter=archived to find archived threadIds first.

Input parameters:

- `threadId` (string, required): archived thread id to restore

Output parameters:

- `result`

### `forward_thread` (~155 tokens)

Forward an inbox message to a new recipient

Forward a message from a thread (default: the most recent message) to a NEW recipient with an optional intro note. Body is composed as note + standard '---------- Forwarded message ----------' quote of the original. Goes from the thread's existing shiply alias so replies still route through the inbox. Subject defaults to 'Fwd: <original>'.

Input parameters:

- `messageId` (string): specific message to forward (default: most recent)
- `note` (string): intro note prepended above the forwarded quote
- `subject` (string): subject; defaults to 'Fwd: <original>'
- `threadId` (string, required): thread id from list_inbox to forward from
- `to` (string, required): new recipient email address

Output parameters:

- `result`

### `list_test_inbox_addresses` (~71 tokens)

List per-test inbox addresses

Return every active demand test's reply / inbound address (<slug>@<sitesDomain>). Use this when you need to TELL someone where to email — e.g. drafting a reply or sharing a test's contact address. Mail sent to these aliases lands in /dashboard/inbox tied to the test.

Output parameters:

- `result`

### `list_unsubscribes` (~48 tokens)

List unsubscribes

Shortcut for list_inbox with filter=unsubscribes — shows every thread tagged as an opt-out request.

Input parameters:

- `limit` (integer): max threads to return, ≤200

Output parameters:

- `result`

### `list_suppressions` (~49 tokens)

List suppressed emails / domains

Return the user's suppression list — addresses (and full domains) that shiply skips when sending. Bounces, complaints, manual user adds, and AI-detected unsubscribes all land here.

Output parameters:

- `result`

### `add_suppression` (~112 tokens)

Suppress an email or domain

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.

Input parameters:

- `kind` (string, required): 'email' for one address, 'domain' for everyone @example.com
- `notes` (string): optional reason / note for the suppression
- `value` (string, required): e.g. 'spammy@example.com' or 'competitor.com'

Output parameters:

- `result`

### `remove_suppression` (~42 tokens)

Remove from suppression list

Delete one suppression by id. Use list_suppressions first to find the id.

Input parameters:

- `suppressionId` (string, required): suppression id from list_suppressions

Output parameters:

- `result`

### `list_complaints` (~33 tokens)

List complaints + bounces

Return threads tagged as complaints (spam reports) OR bounces (recipient rejected). Read these before any further sending.

Output parameters:

- `result`

### `list_projects` (~128 tokens)

List my client-intake projects

List the dev's customer-intake projects (newest first). Optional filters: status (draft|intake_open|brief_ready|brief_failed|archived), q (case-insensitive match on label or customer email), limit (default 100). Use to triage what's in flight before opening a specific project.

Input parameters:

- `clientId` (string): only projects filed under this client
- `limit` (integer): max projects to return (default 100)
- `q` (string): case-insensitive match on label or customer email
- `status` (string): filter by project status

Output parameters:

- `result`

### `create_project` (~149 tokens)

Create a client-intake project

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').

Input parameters:

- `customerEmail` (string): customer email; if set, shiply emails them the intake invite
- `customerName` (string): the customer's name
- `label` (string, required): project name shown in the dev dashboard
- `originatedFromSiteId` (string): link this project to an existing site (e.g. a redesign)

Output parameters:

- `result`

### `get_project` (~54 tokens)

Get one project (full row)

Read one of the dev's projects by id — includes label, status, customer details, intake responses, AI brief, drive folder. Use before update_brief / regenerate_brief.

Input parameters:

- `id` (string, required): project id

Output parameters:

- `result`

### `update_brief` (~87 tokens)

Patch the project brief

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.

Input parameters:

- `brief` (object, required): the full replacement brief object (jsonb, ≤500 KB)
- `id` (string, required): project id

Output parameters:

- `result`

### `regenerate_brief` (~77 tokens)

Re-run AI brief generation

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.

Input parameters:

- `id` (string, required): project id to re-run the brief for

Output parameters:

- `result`

### `archive_project` (~64 tokens)

Archive a project

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.

Input parameters:

- `id` (string, required): project id to archive
- `reason` (string): optional reason shown on the project page

Output parameters:

- `result`

### `restore_project` (~63 tokens)

Restore an archived project

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.

Input parameters:

- `id` (string, required): archived project id to restore

Output parameters:

- `result`

### `list_project_files` (~64 tokens)

List files uploaded to a project

Return the customer-uploaded files for one project (path, size, contentType, createdAt). Empty when no drive folder exists yet (no uploads). Use to inspect what intake assets the customer attached.

Input parameters:

- `id` (string, required): project id whose uploaded files to list

Output parameters:

- `result`

### `resend_intake_invite` (~86 tokens)

Re-send the customer intake invite email

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.

Input parameters:

- `id` (string, required): project id to re-send the intake invite for

Output parameters:

- `result`

### `list_listings` (~45 tokens)

List my marketplace listings

Return every marketplace listing the seller owns (any status: draft, live, paused, sold). Includes site slug and current price. Use to see what's for sale across the account.

Output parameters:

- `result`

### `create_listing` (~208 tokens)

List one of my sites for sale

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').

Input parameters:

- `jurisdiction` (string, required): governing jurisdiction, e.g. 'California, USA'
- `pitch` (string): short sales pitch, ≤280 chars
- `priceCents` (integer, required): whole-dollar price in cents, 100–999900
- `siteSlug` (string, required): slug of the owned site to list
- `status` (string): publish state (default draft)
- `termsCustom` (string): custom terms text, ≥50 chars, required when termsMode='custom'
- `termsMode` (string, required): 'standard' uses shiply's template; 'custom' requires termsCustom

Output parameters:

- `result`

### `update_listing` (~160 tokens)

Update one of my listings

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.

Input parameters:

- `jurisdiction` (string): governing jurisdiction, e.g. 'California, USA'
- `pitch`: new sales pitch (null to clear)
- `priceCents` (integer): new whole-dollar price in cents, 100–999900
- `siteSlug` (string, required): slug of the listed site to patch
- `status` (string): new listing status
- `termsCustom`: new custom terms text (null to clear)
- `termsMode` (string): 'standard' template or 'custom' terms

Output parameters:

- `result`

### `delete_listing` (~75 tokens)

Unpublish a listing (set to draft)

Take a listing off the public marketplace by moving it to status='draft'. Marketplace v1 keeps the row so analytics + future re-listing work — there's no hard delete. Sold listings can't be modified. Use to stop accepting offers without losing pricing history.

Input parameters:

- `siteSlug` (string, required): slug of the listed site to unpublish

Output parameters:

- `result`

### `list_my_sales` (~77 tokens)

List orders where I am the seller

Return every marketplace order for sites the user sold (incl. pending, paid, refunded, failed, disputed). Most recent first. Use to surface revenue + which orders are still inside the 30-day refund window (refundExpiresAt > now).

Input parameters:

- `limit` (integer): max orders to return (default 100, max 500)

Output parameters:

- `result`

### `list_my_orders` (~73 tokens)

List orders where I am the buyer

Return every marketplace order the user PURCHASED. Most recent first. Shows the acquired site, paid amount, and whether the order is still inside the 30-day refund window. Use to recap what the user owns by purchase.

Input parameters:

- `limit` (integer): max orders to return (default 100, max 500)

Output parameters:

- `result`

### `refund_order` (~98 tokens)

Refund one of my sales

Issue a full refund on a paid order the user sold. Must be inside the 30-day refund window (server enforces). Triggers a Stripe refund; the webhook flips the order to 'refunded' and reverts site ownership to the seller. Idempotent on already-refunded orders.

Input parameters:

- `orderId` (string, required): id of the paid order to refund (from list_my_sales)
- `reason` (string): optional refund reason

Output parameters:

- `result`

### `get_connect_status` (~72 tokens)

Stripe Connect onboarding status

Return the seller's Stripe Connect state: not_started | in_progress | pending_verification | ready | disabled. When status != 'ready' the user can't list sites. Includes a one-shot onboardingUrl (if not_started or in_progress) and dashboardUrl (if ready). Refreshes from Stripe on every call.

Output parameters:

- `result`

### `list_sending_domains` (~55 tokens)

List my sending domains

Return every BYO sending domain the user has added (id, domain, fromAddress, status: pending|verified|failed, DNS records). Use to inspect verification state or find the id of a domain to verify/remove.

Output parameters:

- `result`

### `add_sending_domain` (~76 tokens)

Add a sending domain

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.

Input parameters:

- `domain` (string, required): e.g. mail.yourbrand.com

Output parameters:

- `result`

### `verify_sending_domain` (~72 tokens)

Re-check DNS for a sending domain

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.

Input parameters:

- `id` (string, required): sending domain id from list_sending_domains

Output parameters:

- `result`

### `remove_sending_domain` (~69 tokens)

Remove a sending domain

Delete a BYO sending domain. Any demand tests bound to it fall back to the managed shiply sender. Also GCs the underlying Resend domain. Irreversible — re-adding requires re-verifying DNS.

Input parameters:

- `id` (string, required): sending domain id from list_sending_domains

Output parameters:

- `result`

### `contract_draft` (~100 tokens)

Draft a contract from a brief_ready project

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.

Input parameters:

- `projectId` (string, required): Project to draft a contract for

Output parameters:

- `result`

### `contract_send` (~75 tokens)

Send a draft contract to the customer

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.

Input parameters:

- `contractId` (string, required): draft contract id to send (from contract_draft)

Output parameters:

- `result`

### `contract_amend` (~136 tokens)

Create an amendment to a signed contract

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).

Input parameters:

- `feeDeltaCents` (integer): Optional fee adjustment in cents. Can be negative for descope.
- `parentContractId` (string, required): id of the SIGNED parent contract to amend
- `scopeDelta` (string, required): What's changing — visible to customer.
- `targetCompletionDate` (string): Optional ISO date (YYYY-MM-DD) for revised completion.

Output parameters:

- `result`

### `contract_pdf` (~81 tokens)

Get the signed contract PDF (base64)

Get the signed contract PDF as a base64-encoded download. PDF includes the contract, signature certificate, and any signed amendments. Returns { filename, contentType, base64 }. Errors with conflict:contract_not_signed if the parent contract has not been signed yet.

Input parameters:

- `contractId` (string, required): signed contract id (parent or amendment) to render as PDF

Output parameters:

- `result`

### `contract_status` (~82 tokens)

Read contract state + amendments

Read the current state of a contract: status, sent_at, viewed_at, signed_at, signer info, content_hash, plus any amendments. Use this to check whether a customer has signed yet. Returns { contract, amendments } — the contract row matches GET /api/v1/contracts/{id}.

Input parameters:

- `contractId` (string, required): contract id to read state for

Output parameters:

- `result`

### `deploy_function` (~126 tokens)

Deploy a Worker function to a site

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.

Input parameters:

- `crons` (array): cron triggers to register, ≤20
- `lang` (string): source language (default js)
- `slug` (string, required): site slug to deploy the function to
- `source` (string, required): the Worker source code

Output parameters:

- `result`

### `get_function` (~39 tokens)

Get the deployed function for a site

Return the deployed function source + metadata for a site, or null if no function deployed.

Input parameters:

- `slug` (string, required): site slug whose function to fetch

Output parameters:

- `result`

### `remove_function` (~53 tokens)

Remove the deployed function from a site

Remove the deployed Worker function from a site (and all its routes, secrets, and cron triggers). Site falls back to static-only serving. Irreversible.

Input parameters:

- `slug` (string, required): site slug whose function to remove

Output parameters:

- `result`

### `set_secret` (~101 tokens)

Set a Worker secret on a site

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.

Input parameters:

- `name` (string, required): secret name, UPPER_SNAKE_CASE; available as env.<NAME>
- `slug` (string, required): site slug whose function gets the secret
- `value` (string, required): secret value (encrypted at rest), ≤8 KiB

Output parameters:

- `result`

### `list_secrets` (~37 tokens)

List secret names for a site

List secret names (values not returned) for a site's deployed function.

Input parameters:

- `slug` (string, required): site slug whose secret names to list

Output parameters:

- `result`

### `remove_secret` (~49 tokens)

Remove a secret from a site

Remove a secret from a site's deployed function. The binding disappears on next request.

Input parameters:

- `name` (string, required): secret name to remove
- `slug` (string, required): site slug whose function holds the secret

Output parameters:

- `result`

### `list_crons` (~44 tokens)

List cron triggers for a site

List cron triggers for a site's deployed function. Each cron is (path, schedule, lastRunAt).

Input parameters:

- `slug` (string, required): site slug whose cron triggers to list

Output parameters:

- `result`

### `set_cron` (~101 tokens)

Set or update a cron trigger

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).

Input parameters:

- `path` (string, required): URL path the cron handler fires on
- `schedule` (string, required): crontab schedule in UTC, e.g. "0 * * * *"
- `slug` (string, required): site slug whose function gets the cron

Output parameters:

- `result`

### `remove_cron` (~46 tokens)

Remove a cron trigger

Remove a cron trigger from a site's deployed function.

Input parameters:

- `path` (string, required): URL path of the cron to remove
- `slug` (string, required): site slug whose cron to remove

Output parameters:

- `result`

### `get_function_logs` (~136 tokens)

Read recent function logs

Read recent runtime logs for a site's per-site Worker (console output, request summaries, exceptions) from Cloudflare Workers Observability — 7-day retention, newest first. Use this to debug a deployed function: each event has timestamp, level, message, outcome, statusCode, requestId, and CPU/wall time. Also returns a CF dashboard deep-link.

Input parameters:

- `limit` (integer): max events to return (default 50)
- `since` (integer): look back this many minutes (default 60, max 10080 = 7 days)
- `slug` (string, required): site slug whose function logs to read

Output parameters:

- `result`

### `send_email` (~111 tokens)

Send an email from a site

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.

Input parameters:

- `html` (string, required): email HTML body
- `slug` (string, required): site slug to send from (<slug>.shiply.now sender)
- `subject` (string, required): email subject line
- `text` (string): plain-text fallback body
- `to` (string, required): recipient email address

Output parameters:

- `result`

### `list_site_inbox` (~55 tokens)

List a site's email inbox threads

Read the email threads (received, sent, web captures) for the agent's sites. Optionally scoped to one site by slug.

Input parameters:

- `slug` (string): limit to one site by slug; omit for all sites

Output parameters:

- `result`

### `set_mailbox` (~149 tokens)

Configure a site collection's email behavior

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.

Input parameters:

- `branding` (object): branding applied to mailbox emails
- `collection` (string, required): Site Data collection to turn into a mailbox
- `doubleOptIn` (boolean): require email confirmation before a contact is active
- `notifyOwner` (boolean): email the owner on each new capture
- `notifyTo` (string): address to send owner notifications to
- `sendingDomainId` (string): BYO sending domain id to send from
- `slug` (string, required): site slug the collection belongs to

Output parameters:

- `result`

### `list_mailbox_contacts` (~84 tokens)

List a mailbox's contacts

List captured contacts for a (site, collection) mailbox, optionally filtered by status (signed_up/confirmed/unsubscribed). Returns email, status, confirmedAt, createdAt, and captured fields.

Input parameters:

- `collection` (string, required): mailbox collection name
- `slug` (string, required): site slug the mailbox belongs to
- `status` (string): filter contacts by status

Output parameters:

- `result`

### `send_mailbox_broadcast` (~115 tokens)

Broadcast to a mailbox's confirmed audience

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.

Input parameters:

- `collection` (string, required): mailbox collection whose confirmed audience to email
- `html` (string, required): email HTML body (unsubscribe footer added automatically)
- `slug` (string, required): site slug the mailbox belongs to
- `subject` (string, required): email subject line
- `text` (string): plain-text fallback body

Output parameters:

- `result`

## Diagnostics

Captured diagnostic sections: TLS, DNSSEC, Authorisation, Transports. The full working is on the page: https://verifymcp.io/servers/now-shiply-shiply/shiply#diagnostics

## Score history

- 2026-08-03: 82
- 2026-08-02: 81
- 2026-08-01: 81
- 2026-07-31: 81
- 2026-07-30: 75
- 2026-07-29: 76
- 2026-07-28: 75
- 2026-07-27: 74
- 2026-07-26: 74

## Links

- Remote endpoint: https://shiply.now/mcp
- Website: https://shiply.now/
- Changelog RSS feed: https://verifymcp.io/servers/now-shiply-shiply/shiply/changelog.xml
- Changelog JSON feed: https://verifymcp.io/servers/now-shiply-shiply/shiply/changelog.json
- HTML version of this page: https://verifymcp.io/servers/now-shiply-shiply/shiply
