edit.pink
Pink Editor docs

Authentication

Signing in with OAuth, API keys, and what each site role can do.

Every request to the MCP server is authenticated, initialize and tools/list included. There are two ways in, and both end with the same credential: a Pink API key (cm_live_…) tied to your account.

Way inBest forWhat you configure
Sign in (OAuth)claude.ai, ChatGPT, Claude Desktop, Claude Code, CursorOnly the server URL. The client signs you in on first use.
API keyScripts, workflow tools, scheduled jobs, clients that can't open a browserA key you create on the Connect page

Either way, the key acts as you: it reaches every site you own or are a member of, and it can do anything your role on that site allows. Treat it like a password.

Sign in (OAuth)

Point a client at https://app.edit.pink/api/mcp without a credential and the server answers 401 with a challenge that tells the client where to sign in:

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="pink-mcp", resource_metadata="https://app.edit.pink/.well-known/oauth-protected-resource"
Content-Type: application/json
 
{"error":"unauthorized","error_description":"Run OAuth device flow — see WWW-Authenticate header."}

MCP clients that support authorization follow that link, sign you in at app.edit.pink, and ask you to approve the connection once. Pink supports:

Protected resource metadata/.well-known/oauth-protected-resource (also at /.well-known/oauth-protected-resource/api/mcp)
Authorization server metadata/.well-known/oauth-authorization-server (also at …/api/mcp)
Grantsauthorization_code with PKCE (S256), and the device code grant
Client registrationDynamic (/api/oauth/register); public clients, no client secret
Scopemcp
TokenA cm_live_… API key, returned as the access_token, sent as Authorization: Bearer …

The token does not expire on its own. It stops working when you revoke it on the Connect page.

The stdio bridge

The local bridge (@editpink/mcp, which the Claude Desktop .dxt also runs) signs in with a device code. On the first tool call it opens a browser tab at https://app.edit.pink/device with a short code to approve; once you approve, it stores the key in ~/.editpink-mcp-state.json (readable only by you) and retries the call. If you revoke that key later, calls fail with unauthenticated; delete ~/.editpink-mcp-state.json and the bridge signs in again on its next call.

API keys

Create a key on the Connect page (API keys → New key). The full key is shown once; copy it then. The list shows each key's prefix, when it was created and last used, and lets you revoke it. A revoked key stops working at once.

Send it one of three ways:

# 1. As a bearer token (Cursor, scripts, your own client)
curl https://app.edit.pink/api/mcp \
  -H "Authorization: Bearer cm_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"list_sites","arguments":{}}}'
 
# 2. In the URL, for clients with no header setting (custom connectors, Claude Code)
https://app.edit.pink/api/mcp/cm_live_YOUR_KEY
 
# 3. To the stdio bridge, as an environment variable
EDITPINK_API_KEY=cm_live_YOUR_KEY npx -y @editpink/mcp

A key in the URL is a secret in the URL: anyone who sees the URL can use your account. Prefer the header wherever the client allows it.

When the key is wrong

SituationResponse
No credential401, {"error":"unauthorized", …}, with the WWW-Authenticate challenge above
Key unknown, revoked or expired, or not a cm_live_ key401, {"error":"invalid_token", …}, and the challenge carries error="invalid_token"
Key could not be checked (a passing fault on our side)503, {"error":"temporarily_unavailable", …}, with no challenge. Retry with the same key.

Sites and roles

A key reaches every site your account owns or is a member of. list_sites returns them, each with your role:

RoleWhoCan
OwnerThe account that created the siteEverything, including members, publishing settings and billing. The site's credit usage is charged to the owner.
ManagerInvited memberManage the site (members, publishing settings) and all content work. Spends the owner's credits.
EditorInvited memberContent work only, not members or publishing settings. Spends the owner's credits.

Selecting a site you are not a member of fails with site_access_revoked, and one that does not exist with site_not_found. A tool call on a bound site you have since lost access to (or that was deleted) fails with pinned_site_invalid: call list_sites and select again. See Responses and errors.

Keep keys safe

  • Use one key per integration, so you can revoke one without breaking the rest.
  • Never put a key in client-side code or a public repository.
  • If a key leaks, revoke it on the Connect page and create a new one.

On this page