# TuraMCP

Passwordless auth for remote MCP. Users prove email. Cursor, Claude, and other MCP clients get Bearer tokens your MCP server can validate.

**Not an MCP tool host. Auth only.**

Homepage: https://www.turamcp.com  
Dashboard: https://www.turamcp.com/login?redirect=/dashboard/mcp  
OSS resource helpers: https://github.com/johnny-rice/mcp-asgi-http

## What this is

TuraMCP is an **authorization server** for MCP resource servers:

1. Human logs in with email (magic link / code via TuraLogin under the hood).
2. Preferred: MCP client runs OAuth 2.1 + PKCE against turamcp.com (no pasted key). Alternate: issue a PAT (`mcp_live_…`) for CI.
3. The MCP client sends `Authorization: Bearer <token>` on every `/mcp` request.
4. Your server validates via JWKS (JWT) or `POST /api/mcp/introspect` (PAT or JWT).

## Phase 1 + Phase 2 (shipping)

| Capability | Notes |
|---|---|
| Projects | Name + audience (resource URL / id) |
| PATs | Create / list / revoke; prefix only after create; hash at rest |
| OAuth AS | Metadata, JWKS, DCR, `/oauth/authorize`, `/oauth/token` (PKCE S256) |
| Introspect | `POST /api/mcp/introspect` validates PAT or OAuth JWT |
| Demo MCP | `https://www.turamcp.com/api/demo-mcp/mcp` (PAT or JWT) |
| Member login | Session cookie on turamcp.com |

PATs are **separate** from TuraLogin `tl_live_` website API keys.

## OAuth endpoints

- `/.well-known/oauth-authorization-server`
- `/.well-known/jwks.json`
- `/oauth/authorize` (email UI + consent)
- `/oauth/token` (authorization_code + refresh; PKCE S256 required)
- `/oauth/register` (dynamic client registration)

## Quick start

See [QUICKSTART.md](./QUICKSTART.md).

## API

See [API.md](./API.md) for project and PAT portal endpoints.

## Resource server

Introspect (PAT or JWT):

```bash
curl -X POST https://www.turamcp.com/api/mcp/introspect \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"audience":"https://your-mcp.example.com/mcp"}'
```

JWT validation:

```python
auth = JwtAuth(
    issuer="https://www.turamcp.com",
    audience="https://customer-mcp.example.com/mcp",
    jwks_url="https://www.turamcp.com/.well-known/jwks.json",
)
app = mount_mcp(api, server, auth=auth)
```

## Cursor config (hosted demo, OAuth)

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

## Cursor config (PAT fallback)

```json
{
  "mcpServers": {
    "turamcp": {
      "url": "https://www.turamcp.com/api/demo-mcp/mcp",
      "headers": {
        "Authorization": "Bearer mcp_live_REPLACE_ME"
      }
    }
  }
}
```

Project audience must be `https://www.turamcp.com/api/demo-mcp/mcp`.

## Security

- No passwords.
- PATs hashed at rest; one-time display; revocable.
- OAuth access tokens short-lived; PKCE S256 required.
- Bind tokens to project audience when validating.
- Do not log raw tokens or magic-link secrets.

## Related

- TuraLogin (email start/verify): https://www.turalogin.com/
- mcp-asgi-http: https://github.com/johnny-rice/mcp-asgi-http
- MCP auth spec: https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization
