# Website Speedy AI auth.md

This page tells AI agents and the people who build them how to get access to a customer's Website Speedy AI speed data. It is written for agents that act for a human who already has a Website Speedy AI account.

## Short version

- There are two MCP endpoints. `https://mcp.websitespeedy.ai/mcp` is public and needs no login. `https://mcp.websitespeedy.ai/account` needs a login.
- Access to `/account` uses standard OAuth 2.1: the authorization code flow with PKCE. The customer logs in to Website Speedy AI in a browser and approves your agent.
- Everything behind the login is read-only, and a customer can only share the sites they can already see in their own Website Speedy AI account.
- An agent cannot sign up, log in, or get a token on its own. A human customer always logs in and approves. There are no anonymous credentials, no API keys for agents, and no agent identity assertions (ID-JAG) here.

## Who this is for

- Agents and MCP clients that want to read a customer's own site data: Core Web Vitals, open issues, JavaScript errors, lab scores, and slowest pages.
- The customer needs a Website Speedy AI account. New accounts are created by a person at https://websitespeedy.ai/signup. An agent cannot create one.

If you only need public facts (supported platforms, install steps, plans, FAQ, help search, a speed test of a public page), use the public endpoint `https://mcp.websitespeedy.ai/mcp`. No login, no token.

## How an agent gets access

### 1. Discover

Call the account endpoint without a token. It answers `401` with a pointer to its metadata:

```http
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer resource_metadata="https://mcp.websitespeedy.ai/.well-known/oauth-protected-resource", scope="sites:read vitals:read issues:read errors:read"
```

Fetch the protected resource metadata (RFC 9728):

```http
GET https://mcp.websitespeedy.ai/.well-known/oauth-protected-resource
```

It names the resource (`https://mcp.websitespeedy.ai/account`), the scopes, and the authorization server (`https://websitespeedy.ai`). Then fetch the authorization server metadata (RFC 8414):

```http
GET https://websitespeedy.ai/.well-known/oauth-authorization-server
```

Use the endpoint addresses from that document. Do not hard-code them. For reference, they are:

| Purpose | Address |
|---|---|
| Authorization | `https://websitespeedy.ai/oauth/authorize` |
| Token | `https://websitespeedy.ai/oauth/token` |
| Client registration | `https://websitespeedy.ai/oauth/register` |
| Revocation | `https://websitespeedy.ai/oauth/revoke` |
| Public signing keys (JWKS) | `https://websitespeedy.ai/oauth/jwks` |

OpenID Connect is not offered: there is no `openid` scope, no ID token, and no `/.well-known/openid-configuration`.

### 2. Register a client

Registration is open and free (OAuth 2.0 Dynamic Client Registration, RFC 7591). Clients are public clients: there is no client secret.

```http
POST https://websitespeedy.ai/oauth/register
Content-Type: application/json

{
  "client_name": "Example Agent",
  "redirect_uris": ["https://agent.example.com/oauth/callback"],
  "grant_types": ["authorization_code", "refresh_token"],
  "response_types": ["code"],
  "token_endpoint_auth_method": "none"
}
```

The answer contains your `client_id`. Redirect addresses must use https; plain http is accepted only for a local app on `localhost`, `127.0.0.1` or `[::1]` (any port).

Instead of registering, you can use the https address of a Client ID Metadata Document as your `client_id`. The document must be served on port 443, contain that same address as `client_id`, and describe either a public client (`"token_endpoint_auth_method": "none"`) or a client that signs its token requests (`"token_endpoint_auth_method": "private_key_jwt"` with an https `jwks_uri` and RS256 keys). A signing client sends `client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer` and a `client_assertion` JWT (RFC 7523) with `iss` and `sub` set to its `client_id` and `aud` set to `https://websitespeedy.ai` or the token endpoint address.

Registering a client gives no access to any data. It only lets you start the login step below.

### 3. Ask the customer to log in and approve

Create a PKCE code verifier and its S256 code challenge, then open this address in the customer's browser:

```
https://websitespeedy.ai/oauth/authorize
  ?response_type=code
  &client_id=YOUR_CLIENT_ID
  &redirect_uri=https://agent.example.com/oauth/callback
  &scope=sites:read vitals:read
  &state=RANDOM_VALUE
  &code_challenge=CODE_CHALLENGE
  &code_challenge_method=S256
  &resource=https://mcp.websitespeedy.ai/account
```

(URL-encode the values. The line breaks are only for reading.)

Rules:

- PKCE with `S256` is required. The `plain` method is refused.
- `state` is required.
- `resource` must be exactly `https://mcp.websitespeedy.ai/account`.
- `redirect_uri` must match a registered one exactly.
- Ask only for the scopes you need.

The customer logs in to Website Speedy AI (if they are not logged in already) and sees a consent screen with the name of your client and the access you asked for. They choose Allow or Deny. On Allow, the browser returns to your `redirect_uri` with a `code` and your `state`. The code works once and expires after 60 seconds.

### 4. Exchange the code for tokens

```http
POST https://websitespeedy.ai/oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
&code=THE_CODE
&redirect_uri=https://agent.example.com/oauth/callback
&client_id=YOUR_CLIENT_ID
&code_verifier=CODE_VERIFIER
&resource=https://mcp.websitespeedy.ai/account
```

The answer contains an `access_token`, a `refresh_token`, `expires_in`, and the granted `scope`.

### 5. Call the account endpoint

Send the access token in the `Authorization` header on every request. Never put it in the address.

```http
POST https://mcp.websitespeedy.ai/account
Authorization: Bearer ACCESS_TOKEN
Content-Type: application/json
```

The endpoint speaks the Model Context Protocol over Streamable HTTP, the same way as the public endpoint. Call `tools/list` to get the tools and their exact arguments.

## Scopes in plain words

| Scope | What it allows | Tools |
|---|---|---|
| `sites:read` | See the list of the customer's sites | `list_my_sites` |
| `vitals:read` | Read Core Web Vitals from real visitors, lab scores, and the slowest pages of a site | `get_core_web_vitals`, `get_lab_scores`, `get_slowest_pages` |
| `issues:read` | Read the open speed issues found on a site | `get_open_issues` |
| `errors:read` | Read the JavaScript errors recorded on a site | `get_js_errors` |

A tool call without the needed scope is answered with `403` and `error="insufficient_scope"`. Ask the customer again with the extra scope.

## Token lifetimes

- Access token: valid for 1 hour. It is a signed JWT (RS256) that only works at `https://mcp.websitespeedy.ai/account`.
- Refresh token: valid for 30 days and rotating. Each time you use it you get a new access token and a new refresh token, and the old refresh token stops working. Using an old refresh token again cancels the whole chain, and the customer has to approve again.

To refresh:

```http
POST https://websitespeedy.ai/oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token
&refresh_token=THE_REFRESH_TOKEN
&client_id=YOUR_CLIENT_ID
```

A `401` from the account endpoint means the token is missing, expired, or revoked. Refresh once. If that fails, start again at step 3.

## Revocation

To end access, send the token to the revocation endpoint (RFC 7009). Revoking a refresh token also ends the access tokens that came from it.

```http
POST https://websitespeedy.ai/oauth/revoke
Content-Type: application/x-www-form-urlencoded

token=THE_TOKEN
&token_type_hint=refresh_token
&client_id=YOUR_CLIENT_ID
```

Revoke tokens when the customer disconnects your agent or when you no longer need them.

## What is public without login

`https://mcp.websitespeedy.ai/mcp` stays open to everyone, with no login and no token. It has seven read-only tools: supported platforms, install instructions, plans and pricing, FAQ, help search, speed test, and signup link. Its description is at https://mcp.websitespeedy.ai/.well-known/mcp/server-card.json.

## Limits

- Read-only. No tool changes a site, a setting, a plan, or an account.
- Only the customer's own sites: the sites they own or have been given access to as a team member. A site the customer cannot see is answered the same way as a site that does not exist.
- No other customer's data, no email addresses, no billing details, and no script source code are returned.
- Requests are rate limited. On `429`, wait and try again later.
- Agent-only registration is not available. This service does not issue credentials to an agent without a customer logging in, does not accept ID-JAG identity assertions, and does not run an email or code based claim step. The only way in is the login and approval described above.

## Help and contact

- Help center: https://help.websitespeedy.ai/
- Overview for AI agents: https://websitespeedy.ai/llms.txt
- Privacy policy: https://websitespeedy.ai/privacy-policy
- Terms of use: https://websitespeedy.ai/terms-of-use
