---
name: pwanow
description: Deploy a static site or PWA to PwaNow and verify it's actually working, using PwaNow's hosted MCP server. Use this whenever the user asks to deploy, publish, or ship a folder/build output to PwaNow (or to "my pwanow site"), or to check on/test/redeploy an existing PwaNow site.
---

# PwaNow deploy & test

PwaNow (`https://pwanow.com`) hosts static sites and PWAs at `https://{name}.pwanow.com`. Its MCP server is **hosted, not local** - there's nothing to install. Configure your MCP client with:

- URL: `https://api.pwanow.com/mcp`
- Header: `Authorization: Bearer <their API key>` (created in the PwaNow dashboard's API Keys page, starts with `pwanow_live_`)

**Never print, log, or otherwise echo the raw API key value back into your output.** If you need to reference it, call it "the configured API key."

**If you're running inside the Claude Code VS Code extension, don't use `claude mcp add`** - project-scoped servers registered that way aren't picked up by extension sessions, and the fix is not a restart of Claude Code. Create a `.mcp.json` in your project root instead:

```json
{
  "mcpServers": {
    "pwanow": {
      "type": "http",
      "url": "https://api.pwanow.com/mcp",
      "headers": { "Authorization": "Bearer pwanow_live_..." }
    }
  }
}
```

and add `.claude/settings.local.json` with `{"enabledMcpjsonServers": ["pwanow"]}` to skip the trust prompt. Then tell the user: **press Ctrl-Shift-P (Cmd-Shift-P on macOS) and run "Developer: Reload Window"** - that's what loads the new `.mcp.json` and makes the pwanow tools appear. A full quit-and-relaunch also works but isn't necessary; don't tell the user to just "restart Claude Code" without naming this command, since that's the concrete step that actually does it. Remember to gitignore both files - they carry your live API key.

## Why the workflow has a manual zip/upload step

The MCP server runs on PwaNow's infrastructure, not on the user's machine - it has **no access to the local filesystem**. It cannot zip a folder for you. That step is yours to do with your own shell/file tools; the server only issues the upload URL and checks the result afterward.

## Deploy recipe

Given a local folder to publish (e.g. a build output directory) and a desired site name:

1. **Create the site** (skip if one already exists - use `list_sites` to check first): call `create_site` with the desired name.
   - Names are lowercase letters/numbers/hyphens, 3-63 characters, can't start/end with a hyphen.
   - Reserved names you can't use: `www`, `api`, `app`, `admin`, `dashboard`, `billing`, `mcp`, `cdn`, `static`, `assets`, `mail`, `ftp`, `status`, `docs`, `blog`, `support`, `help`, `staging`, `dev`, `test`. If the requested name is reserved or taken, pick a close variant (e.g. append `-app` or `-site`) rather than asking the user to choose, unless you genuinely have no reasonable option.
2. **Verify the folder has an `index.html` at its root** before proceeding - PwaNow rejects uploads that don't.
3. **Get an upload URL**: call `get_upload_url` with the site's ID. It returns a presigned URL and repeats these instructions.
4. **Zip and upload it yourself**, using your own shell tool:
   ```
   cd <the folder> && zip -r /tmp/site.zip . && curl -X PUT --upload-file /tmp/site.zip '<uploadUrl>' -H 'Content-Type: application/zip'
   ```
5. **Poll `get_site_status`** every couple of seconds until `status` is no longer `uploading` or `processing`.
   - If it becomes `upload_failed`, read `failureReason` (almost always a missing root `index.html`) and fix the zip contents before retrying from step 3.
6. **Call `test_site`** with the site ID. This is server-side - PwaNow fetches the live URL itself. Read the returned `checks` array.
7. **Only report success to the user after `test_site` returns `passed: true`.** If any check failed, explain which one and why (using each check's `detail`) rather than declaring victory. A missing `manifest.json` or service worker is *not* a failure by itself (`test_site` marks those informational and `ok: true`) - only report those as noteworthy if the user's project was clearly meant to be a full PWA (has a manifest/service worker in the source and it didn't show up correctly live).

## Other tools

- `list_sites` - see everything the caller owns before creating a duplicate.
- `get_site_status` - check status/URL of one site without re-testing it.
- `delete_site` - permanent; confirm with the user before calling this unless they were explicit about wanting the site gone.

## Tone

Report the live URL (`https://{name}.pwanow.com`) once `test_site` passes. Don't narrate every intermediate polling step to the user - just the final result and anything that needed a retry.
