# MCP endpoint

Canonical page: https://docs.ovok.com/api/mcp/mcp-endpoint

`POST /mcp`

Ovok's MCP server, for Claude or any MCP client: it sets up the project it is connected to, as one of the project's admins.

**Auth:** an access token from Ovok's MCP OAuth server, never a Medplum token. Clients find it the standard way:
1. A `GET`, `POST` or `DELETE` without a token answers 401 with `WWW-Authenticate: Bearer resource_metadata="…/.well-known/oauth-protected-resource/mcp"`.
2. That document names the authorization server, `<this host>/mcp`. Its metadata is at `/.well-known/oauth-authorization-server/mcp`.
3. The client registers itself at `/mcp/register`, sends the user to `/mcp/authorize` (PKCE S256), and exchanges the code at `/mcp/token`. The answer to the client carries `iss`, this authorization server's issuer (RFC 9207), on allow and on deny.

Sign-in and consent happen on the Ovok console. Only an admin of the project can connect a client, and never to the Super Admin project.

## Behaviour

- Streamable HTTP, stateless: send every JSON-RPC message with `POST`, one per request. A batch answers 400. There are no sessions: `GET` and `DELETE` answer 405 to a caller with a valid token, and 401 without one.
- `server/discover` (MCP 2026-07-28) answers the protocol versions this server speaks, its `tools` capability and its name. None of those versions is 2026-07-28 yet: start with `initialize`.
- `/mcp`, its OAuth routes and both MCP metadata documents answer with `Strict-Transport-Security: max-age=31536000; includeSubDomains`.
- Every request checks the token, then that its account is still an admin of the project. An account that is no longer an admin gets 403 at once, whatever the token's expiry. When that can't be read, the answer is 503: try again.
- Tools act on the project the connection was granted for:
  - `get_project`;
  - `get_settings`, `set_setting`, `set_setting_value`;
  - `list_members`, `invite_member`;
  - `list_apps` (without the apps' secrets), `create_app`;
  - `get_signals`.
- Each tool runs the same service as the matching API route, with the same rules. A refused call answers a tool error carrying the route's status and error body.
- Limits:
  - Each admin may send 300 messages a minute. Over that, the answer is 429 with `Retry-After`.
  - Each tool allows 60 calls a minute per admin; `create_app` and `invite_member` allow 10. Over that, the tool error has status 429 and `retryAfterSec`.
- Tool errors carry the route's status and body for a refusal (4xx). A failure (5xx) is logged and answered without its detail.
- MCP calls are not API usage: like the console's own calls, they are left out of statistics and the plan's monthly request cap.
- Access tokens last an hour. Refresh tokens last 30 days, and each one works once: a refresh answers a new pair. A repeat within 30 seconds, such as parallel refreshes, gets a pair of its own. A refresh token used again later ends the connection, and so does revoking either token. A connection ends 90 days after its consent, however often it refreshes: connect again.

## Example

Add it to Claude Code, which signs in through the browser on first use:

```bash
claude mcp add --transport http ovok https://api.sandbox.ovok.com/mcp
```
