> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sandywp.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Muse connector brief

> Connect Muse to SandyWP over the product MCP. OAuth with PKCE is required for tools/call.

Read this file first. It is the contract for connecting Muse to SandyWP and using the product MCP well.

Canonical URL: [https://docs.sandywp.com/connectors/muse.md](https://docs.sandywp.com/connectors/muse.md)

## What SandyWP is

SandyWP creates disposable WordPress sandboxes for plugin and theme makers. Each sandbox is a real, isolated WordPress install with its own database, files, and public URL, and it is safe to throw away.

A user asks Muse to list sandboxes, check status, open `wp-admin`, or create a test site. The connector does not take payment and never sees card details.

Billing stays on sandywp.com through Polar.

<Warning>
  This brief is for the **product MCP** at `https://app.sandywp.com/mcp`. `https://docs.sandywp.com/mcp` is Mintlify search only and cannot create sandboxes or call SandyWP tools.
</Warning>

## Connection details

| Item             | Value                                                                                                 |
| ---------------- | ----------------------------------------------------------------------------------------------------- |
| Product          | SandyWP                                                                                               |
| Website          | [https://sandywp.com](https://sandywp.com)                                                            |
| Privacy          | [https://sandywp.com/legal/privacy](https://sandywp.com/legal/privacy)                                |
| Terms            | [https://sandywp.com/legal/terms](https://sandywp.com/legal/terms)                                    |
| Support          | [hello@sandywp.com](mailto:hello@sandywp.com)                                                         |
| Agents page      | [https://sandywp.com/agents](https://sandywp.com/agents)                                              |
| MCP endpoint     | `https://app.sandywp.com/mcp`                                                                         |
| Transport        | MCP Streamable HTTP. JSON-RPC 2.0 over HTTPS POST                                                     |
| Responses        | One JSON object per POST, `Content-Type: application/json; charset=utf-8`. The server does not stream |
| Protocol version | Latest `2025-06-18`. Also accepts `2025-03-26` and `2024-11-05`                                       |
| Auth             | OAuth 2.1 with PKCE (S256). Required for `tools/call`. There is no anonymous `tools/call`             |
| Session          | Stateless. `initialize` does not return `Mcp-Session-Id`. Do not require a session header             |

Fetch [https://sandywp.com/agents](https://sandywp.com/agents) before connecting. Do not guess the MCP URL from the marketing homepage.

## Transport notes

1. Send `POST` with `Content-Type: application/json` and `Accept: application/json, text/event-stream`. A JSON-only `Accept` also works.
2. Unauthenticated `GET /mcp` returns HTTP 401 plus a JSON probe and `WWW-Authenticate` pointing at protected-resource metadata. That means the host is up and OAuth is required, so do not treat 401 as a dead server.
3. Authenticated `GET /mcp` returns HTTP 200 with the same probe shape. `DELETE /mcp` returns 405 and sessions need no teardown.
4. `initialize`, `ping`, and `tools/list` may run without a token so a client can import tool metadata. `tools/call` without a bearer access token returns HTTP 401.
5. After `initialize`, send `MCP-Protocol-Version` on later requests. An unknown value returns HTTP 400.
6. Tool results are `content[0].text`. Objects are pretty-printed JSON in that text field, so read it and do not expect a separate `structuredContent` object.

Copy-paste `initialize` (metadata only, no token):

```bash theme={null}
curl -sS -m 30 -D - -X POST 'https://app.sandywp.com/mcp' \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"muse","version":"1.0.0"}}}'
```

If the SDK proposes `2025-03-26` or `2024-11-05`, the server echoes that version. If it proposes anything else, the server answers `2025-06-18` and you continue with the version it returned.

After OAuth, send `Authorization: Bearer <access_token>` on every `tools/call`.

## OAuth with PKCE

SandyWP is both the authorization server and the resource server on `https://app.sandywp.com`. Public MCP clients register dynamically and complete an authorization-code grant with S256 PKCE.

There is no client secret and no refresh-token grant.

Discovery documents (no auth):

| Document                      | URL                                                              |
| ----------------------------- | ---------------------------------------------------------------- |
| Protected resource metadata   | `https://app.sandywp.com/.well-known/oauth-protected-resource`   |
| Authorization server metadata | `https://app.sandywp.com/.well-known/oauth-authorization-server` |
| Authorization endpoint        | `https://app.sandywp.com/connect/authorize`                      |
| Token endpoint                | `https://app.sandywp.com/api/connect/token`                      |
| Registration endpoint         | `https://app.sandywp.com/api/connect/register`                   |

High-level flow:

1. An unauthenticated `tools/call` (or `GET /mcp`) returns HTTP 401 with `WWW-Authenticate` pointing at protected-resource metadata.
2. The client reads authorization-server metadata, then registers itself at `POST /api/connect/register` with its own redirect URIs (RFC 7591). Use the URIs the client actually redirects to, and do not invent or substitute them.
3. The browser opens `/connect/authorize` with `client_id`, an exact registered `redirect_uri`, S256 `code_challenge`, requested scopes, and `resource=https://app.sandywp.com/mcp`.
4. If the account holder is not signed in, SandyWP sends them through login on `https://app.sandywp.com`, then back to consent.
5. The account holder chooses **Approve**. The browser returns a short-lived, single-use authorization code to the registered redirect URI.
6. The client POSTs the code, `client_id`, `redirect_uri`, and matching `code_verifier` to `/api/connect/token` with `grant_type=authorization_code`.
7. The response is a bearer `access_token` (`swp_…`) and the granted `scope`. Send that token on later POSTs to `/mcp`.

Never collect a SandyWP password, a one-time code, or a card number in chat. Consent and login happen on SandyWP's own pages.

A personal API token is a fallback for clients that cannot complete OAuth. Muse should use the OAuth flow above, not ask the user to paste a key.

See [OAuth connector flow](/api-reference/oauth) for the registration and token-exchange contracts.

## Access and usage

A SandyWP account is required. Free, Plus, Pro, Max, and Workspace plans all work.

Guest-only sandboxes are not an MCP login.

Rate limits and sandbox quotas follow the connected account's plan. Creating a sandbox counts against the active-sandbox limit.

MCP calls are also rate-limited per token. See [Plans and limits](/guides/plans).

Billing, plan changes, and payment methods stay on sandywp.com through Polar. Never collect card details in chat.

## Meta E2E review

Use this account for Meta's end-to-end connector review. Do not ask for or store a password.

| Item                                     | Value                                                                                                         |
| ---------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| Email                                    | `muse-review@sandywp.com`                                                                                     |
| Email verified                           | Yes                                                                                                           |
| MFA, SMS, or email confirmation at login | None. Sign in on `https://app.sandywp.com`, then choose **Approve** on the consent screen                     |
| Auth                                     | OAuth with PKCE, as in the flow above                                                                         |
| Seeded data                              | One sandbox is already present. Call `sandywp_list_sites` after connect. Do not invent a second site or a URL |

If login or consent fails, stop and report the tool or HTTP error. Do not guess a workaround.

## Core recipes

Call tools only after OAuth. Use the `id` and `publicUrl` values the server returned. Never invent them.

### A. List sites and check status

1. `sandywp_list_sites` with `{}`.
2. Each item includes `id`, `slug`, `status`, and `publicUrl` when the server has them.
3. For one site, `sandywp_site_status` with `{ "siteId": "<id from the list>" }`.
4. `site.status` is one of `creating`, `ready`, `expired`, `failed`, `pending_delete`, `deleted`, `cleanup_failed`. Report the returned status. Do not infer ready from a URL you made up.

### B. Magic login link

1. Confirm the sandbox `status` is `ready` with `sandywp_site_status`.
2. `sandywp_magic_login` with `{ "siteId": "<id>" }`.
3. Give the user the returned `url` and `expiresAt` exactly. The link is a reusable bearer credential until it expires, and anyone who has it can enter `wp-admin`.
4. Never construct a login URL. If the tool errors, say so.

### C. Create a sandbox

1. `sandywp_create_site` with optional `{ "siteName": "muse-review-test" }`. All fields are optional.
2. By default the tool waits up to about 60 seconds. If `site.status` is still `creating`, poll `sandywp_site_status` with that `siteId` until `ready` or `failed`.
3. Pass `"background": true` only when you will poll. Do not tell the user the site is live while status is `creating`.
4. Optional create fields include `phpVersion` (`8.5`, `8.4`, `8.3`, `8.2`, `8.1`, `7.4`; default `8.3`) and `plugins` (wordpress.org slugs, max 10).

### D. Deploy a plugin (optional)

1. Confirm the sandbox is `ready`.
2. `sandywp_deploy_plugin` with `{ "siteId": "<id>", "pluginSlug": "query-monitor" }`. Provide exactly one of `pluginSlug`, `zipUrl`, or `artifactId`.
3. The tool waits up to about 60 seconds. If it returns an in-flight job, poll `sandywp_get_job` with `{ "siteId": "<id>", "jobId": "<jobId>" }`.
4. This remote server cannot read local files. For a local ZIP, the user runs `npx @sandywp/cli deploy <site> <plugin.zip>`.

### E. Preview a GitHub pull request (optional)

1. `sandywp_preview_github_pr` with `{ "repository": "owner/repo", "destination": "plugin", "folderName": "my-plugin" }`. `pullNumber` is optional when the repository URL already includes `/pull/N`.
2. This uses the account GitHub App. It does not mint per-sandbox SSH deploy keys.
3. If GitHub is not connected, the tool returns `needs_github_connect` and a dashboard URL. Send the human to that URL. Do not invent a deploy key.
4. Poll `sandywp_site_status` until `ready`, then `sandywp_magic_login` if the user needs `wp-admin`.

`sandywp_whoami` confirms which account is connected. `sandywp_usage` reports plan and active-sandbox count.

## Rules

1. Quote only what the server returned. Never invent a site URL, slug, status, job result, or login link; if a tool did not return it, you do not know it.
2. Never ask for card numbers, security codes, passwords, or one-time codes in chat. Payment and plan changes happen on sandywp.com through Polar, with the user's approval.
3. Confirm with the user before calling a destructive tool. That includes `sandywp_delete_site`, `sandywp_reset_site`, `sandywp_delete_path`, `sandywp_rotate_demo_launch_webhook_secret`, and `sandywp_delete_demo_launch_webhook`.
4. `sandywp_magic_login` mints a sensitive, reusable `wp-admin` URL. Show it to the user with its expiry. Do not store it in a public place.
5. Product MCP is `https://app.sandywp.com/mcp`. Docs MCP is `https://docs.sandywp.com/mcp`. Do not call product tools against the docs MCP.
6. If a tool returns `isError: true` or HTTP 401, say so. A 401 means complete OAuth. Do not fill the gap with invented sandboxes.
7. Creates and deploys are jobs. Poll `sandywp_site_status` or `sandywp_get_job` until a terminal state before claiming success.

## Links

* [SandyWP for AI agents](https://sandywp.com/agents)
* [OAuth connector flow](/api-reference/oauth)
* [API keys](/guides/api-keys)
* [Plans and limits](/guides/plans)
* [GitHub pull request previews](/guides/github)
* [Privacy Policy](https://sandywp.com/legal/privacy)
* [Terms of Service](https://sandywp.com/legal/terms)
* Support: [hello@sandywp.com](mailto:hello@sandywp.com)
