# MCP OAuth and protocol reference for client developers

> For developers building an MCP client or agent: how SignWith authorizes connections, and how the server behaves at the protocol level.

Source: https://signwith.co/docs/mcp/oauth · Updated 2026-10-02

SignWith follows the [MCP authorization specification](https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization). Clients that support it can connect with just the server URL, `https://app.signwith.co/mcp`.

## Discovery

An unauthenticated request returns `401` with a `WWW-Authenticate` header that points to the protected resource metadata:

```http
WWW-Authenticate: Bearer resource_metadata="https://app.signwith.co/.well-known/oauth-protected-resource/mcp", scope="read write"
```

The authorization server metadata is at `https://app.signwith.co/.well-known/oauth-authorization-server`.

## Authorization

| | |
| --- | --- |
| Flow | Authorization code with PKCE (`S256` only) |
| Client registration | Dynamic Client Registration at `/oauth/register`, or Client ID Metadata Documents |
| Resource indicators | Tokens are bound to `https://app.signwith.co/mcp` |
| Scopes | `read` and `write` |
| Access tokens | 1 hour |
| Refresh tokens | 60 days, rotated on use |
| Revocation | `/oauth/revoke` |
| Responses | Include the `iss` parameter |

On the consent screen, people choose **Full access** (`read` and `write`) or **View only** (`read`). They can see and disconnect connected apps in **Settings → Connected apps**.

OAuth tokens only work on `/mcp`. To call the REST API, use an [API key](https://signwith.co/docs/api/authentication).

### Errors and limits

- If an authorization request from a client that registered itself (Dynamic Client Registration or a Client ID Metadata Document) is invalid, SignWith usually shows the error on its own page instead of redirecting back to the client. Claude and ChatGPT still get the standard OAuth error redirect. Check the request against the authorization server metadata.
- The unauthenticated OAuth endpoints are rate limited per IP address: `/oauth/authorize` and `/oauth/token` at 60 requests a minute each, and `/oauth/register` at 30 an hour. Over the limit, `/oauth/token` returns `429` with the error `slow_down`.

## API keys instead of OAuth

A client can skip OAuth and send an API key in the `Authorization` header:

```http
Authorization: Bearer sw_live_...
```

A read-only key behaves like a View only connection.

## Protocol behaviour

- Transport is Streamable HTTP, and the server is stateless. It only answers POST requests; GET and DELETE return `405`.
- Supported protocol versions: `2025-06-18`, `2025-03-26` and `2024-11-05`.
- Methods: `initialize`, `ping`, `tools/list` and `tools/call`.
- JSON-RPC messages without an `id` are notifications: they aren't executed and get no response. A request made only of notifications returns HTTP `202`. An empty batch returns error `-32600`.
- A failed tool call returns a normal result with `isError: true`, and the API's error `code` and `message` in the content.
- Each tool call runs the matching [REST API](https://signwith.co/docs/api) request, so rate limits (300 requests a minute per connection), credits and validation are the same.

The tools and their arguments are on the [MCP tools](https://signwith.co/docs/mcp/tools) page.
