# TuraMCP API (Phase 1 portal)

Base URL: `https://www.turamcp.com`

All endpoints below require a **session cookie** from passwordless login on turamcp.com (`POST` login flow). They are for the human portal, not for MCP clients.

MCP clients use the issued PAT:

```
Authorization: Bearer mcp_live_…
```

or

```
X-API-Key: mcp_live_…
```

## Projects

### GET /api/mcp/projects

List projects for the signed-in user.

Response:

```json
{
  "projects": [
    {
      "id": "uuid",
      "name": "prod MCP",
      "audience": "https://mcp.example.com",
      "allowedRedirectOrigins": null,
      "createdAt": "…",
      "updatedAt": "…"
    }
  ]
}
```

### POST /api/mcp/projects

Body:

```json
{
  "name": "prod MCP",
  "audience": "https://mcp.example.com",
  "allowedRedirectOrigins": ["https://cursor.com"]
}
```

`allowedRedirectOrigins` is optional (reserved for Phase 2 OAuth redirects).

### PATCH /api/mcp/projects/:id

Update `name`, `audience`, and/or `allowedRedirectOrigins`.

### DELETE /api/mcp/projects/:id

Deletes the project and its PATs.

## Personal access tokens

### GET /api/mcp/pats

Lists active PATs. Returns `keyPrefix` only (never the full secret).

### POST /api/mcp/pats

Body:

```json
{
  "name": "cursor-dev",
  "projectId": "uuid"
}
```

Response includes the full `key` **once**:

```json
{
  "pat": {
    "id": "uuid",
    "projectId": "uuid",
    "name": "cursor-dev",
    "keyPrefix": "mcp_live_ab",
    "createdAt": "…",
    "key": "mcp_live_…"
  }
}
```

### DELETE /api/mcp/pats/:id

Soft-revokes the token (`revokedAt` set).

## PAT introspection (MCP clients / resource servers)

No session cookie. Authenticate with the PAT itself.

### POST /api/mcp/introspect

Headers:

```
Authorization: Bearer mcp_live_…
```

or

```
X-API-Key: mcp_live_…
```

Optional body:

```json
{ "audience": "https://www.turamcp.com/api/demo-mcp/mcp" }
```

When `audience` is set, the project’s audience must match or the response is `403`.

Success (`200`):

```json
{
  "valid": true,
  "projectId": "uuid",
  "projectName": "TuraMCP demo",
  "audience": "https://www.turamcp.com/api/demo-mcp/mcp",
  "patId": "uuid",
  "patPrefix": "mcp_live_ab",
  "userId": "uuid"
}
```

Failure (`401` / `403`):

```json
{ "valid": false, "error": "Invalid or revoked token" }
```

## Hosted demo MCP

Streamable HTTP resource (turamcp.com only):

```
https://www.turamcp.com/api/demo-mcp/mcp
```

Accepts PAT (`mcp_live_…`) or OAuth access JWT (Bearer). Required audience: the same URL.

Tools:

| Tool | Description |
|---|---|
| `turamcp_ping` | `{ "ok": true }` |
| `turamcp_whoami` | project / token identity for the Bearer |

Protected resource metadata: `/.well-known/oauth-protected-resource/demo-mcp`

## OAuth 2.1 authorization server (Phase 2)

Issuer: `https://www.turamcp.com`

| Endpoint | Purpose |
|---|---|
| `GET /.well-known/oauth-authorization-server` | AS metadata (RFC 8414) |
| `GET /.well-known/openid-configuration` | Same metadata (compat) |
| `GET /.well-known/jwks.json` | Public keys for JWT verify |
| `POST /oauth/register` | Dynamic client registration (RFC 7591) |
| `GET /oauth/authorize` | Browser consent + email login |
| `POST /api/oauth/authorize/approve` | Session-authenticated consent |
| `POST /oauth/token` | `authorization_code` + `refresh_token` (PKCE S256) |

Access tokens are ES256 JWTs (`iss`, `sub`, `aud`, `client_id`, `project_id`, `scope`, `exp`). Resource servers validate via JWKS and audience check. Introspect also accepts JWTs.

Optional env: `TURAMCP_JWT_PRIVATE_JWK` (ES256 private JWK JSON). If unset, a key is created in `mcp_as_signing_keys`.

## Token format

| Prefix / type | Use |
|---|---|
| `mcp_live_` | Production PATs for MCP clients |
| OAuth JWT | Short-lived access tokens from `/oauth/token` |
| `tl_live_` | TuraLogin website API keys (do not use for MCP) |

PATs are SHA-256 hashed at rest.

## Rate limits

Portal create/list endpoints are session-authenticated. Enforce per-user abuse limits at the edge as needed. Do not hammer create-PAT in a loop.
