# auth.md | Cut.Pro

Agent registration and authentication for Cut.Pro.

```json
{
	"agent_auth": {
		"skill": "https://cut.pro/auth.md",
		"skill_document": "https://cut.pro/.well-known/agent-skills/cutpro-auth/SKILL.md",
		"register_uri": "https://mcp.cut.pro/register",
		"authorization_servers": ["https://mcp.cut.pro/"],
		"protected_resource": "https://mcp.cut.pro/",
		"identity_types_supported": ["anonymous"],
		"anonymous": {
			"credential_types_supported": ["oauth2_access_token"],
			"claim_uri": "https://mcp.cut.pro/register",
			"revocation_uri": "https://mcp.cut.pro/revoke"
		},
		"credential_types_supported": ["oauth2_access_token", "api_key"],
		"claim_uri": "https://mcp.cut.pro/register",
		"revocation_uri": "https://mcp.cut.pro/revoke",
		"events_supported": ["revocation"],
		"methods": [
			{
				"type": "oauth2_dynamic_client_registration",
				"register_uri": "https://mcp.cut.pro/register",
				"authorization_endpoint": "https://mcp.cut.pro/authorize",
				"token_endpoint": "https://mcp.cut.pro/token",
				"revocation_uri": "https://mcp.cut.pro/revoke",
				"grant_types": ["authorization_code", "refresh_token"],
				"code_challenge_methods": ["S256"],
				"scopes": ["cutpro"],
				"credential_types_supported": ["oauth2_access_token"],
				"self_service": true
			},
			{
				"type": "api_key",
				"claim_uri": "https://cut.pro/studio/me/api-keys",
				"revocation_uri": "https://cut.pro/studio/me/api-keys",
				"header": "X-Api-Key",
				"credential_types_supported": ["api_key"],
				"self_service": false
			}
		]
	}
}
```

There are two ways in, and they authenticate differently:

| Surface      | Endpoint                     | Auth                                    |
| ------------ | ---------------------------- | --------------------------------------- |
| REST API v1  | `https://api.cut.pro/api/v1` | Long-lived API key                      |
| MCP server   | `https://mcp.cut.pro`        | OAuth 2.1 (or an API key over stdio)    |
| MCP (apex)   | `https://cut.pro/mcp`        | Same: relayed to the MCP server        |

If you are an agent with a browser-based consent flow, prefer the MCP server:
it can issue you credentials without a human pasting a key. If you are calling
REST endpoints directly, you need an API key.

# MCP server (OAuth 2.1)

`https://mcp.cut.pro` is a Streamable HTTP MCP server exposing the v1 API as
tools. It runs a full OAuth 2.1 authorization server with PKCE and **dynamic
client registration**, so a client can register itself:

- Authorization server metadata (RFC 8414): <https://mcp.cut.pro/.well-known/oauth-authorization-server>
- Protected resource metadata (RFC 9728): <https://mcp.cut.pro/.well-known/oauth-protected-resource>
- Server card (SEP-1649): <https://mcp.cut.pro/server-card>

The issuer is `https://mcp.cut.pro/`; scope is `cutpro`. During the authorization
step the user approves on a consent page and supplies their own API key, which
the server maps server-side to the issued token.

`https://cut.pro/mcp` reaches the same server and accepts the same tokens: it is
a relay on the apex. It exists so the protected resource metadata at
<https://cut.pro/.well-known/oauth-protected-resource> can name an identifier on
its own origin, which RFC 9728 requires. Either endpoint works.

`cut.pro` is **not** an authorization server: it issues no tokens. Its
`/.well-known/oauth-authorization-server` document restates the metadata of the
issuer above, which remains `https://mcp.cut.pro/`.

For local clients (Claude Code, Cursor, Claude Desktop, …) the same server runs
over stdio via `npx -y @cutpro/mcp`, authenticated with `CUTPRO_API_KEY` instead
of OAuth.

# REST API v1 (API key)

Machine access to `https://api.cut.pro/api/v1` uses **long-lived API keys**.
This surface has no OAuth and no token endpoint: an agent cannot provision its
own REST credentials. A human account holder must issue a key.

## Obtaining a key

1. Sign in at <https://cut.pro>.
2. Open **Studio → Account → API keys** (<https://cut.pro/studio/me/api-keys>).
3. Create a key and scope it to one or more workspaces.

The key is shown once at creation time. Only a SHA-256 hash is stored, so a lost
key cannot be recovered: issue a new one.

## Using a key

Send the key on every request, either header works:

```http
GET /api/v1/workspace HTTP/1.1
Host: api.cut.pro
X-Api-Key: <your-key>
```

```http
GET /api/v1/workspace HTTP/1.1
Host: api.cut.pro
Authorization: Bearer <your-key>
```

If the key is scoped to more than one workspace, requests that operate on
workspace-owned resources must also name the workspace:

```http
X-Workspace-Id: <workspace-id>
```

Omitting it when the key spans multiple workspaces returns `400` with an
`allowed_workspace_ids` array listing the valid choices.

## Responses

| Status | Meaning                                                        |
| ------ | -------------------------------------------------------------- |
| `401`  | Key missing, unknown, revoked, or expired                       |
| `400`  | Workspace not specified for a multi-workspace key               |

Keys can be revoked or given an expiry from the same settings page; revocation
takes effect within the credential cache TTL.

## Machine-readable description

- OpenAPI: <https://api.cut.pro/api/v1/openapi.json>
- API catalog: <https://cut.pro/.well-known/api-catalog>
- MCP catalog: <https://cut.pro/.well-known/mcp/catalog.json>
- Site index: <https://cut.pro/llms.txt>

## Browser sessions

The website itself authenticates with httpOnly `access_token` / `refresh_token`
cookies issued after sign-in. These are for first-party browser use and are not
an integration surface: use an API key instead.
