Discovery
Both metadata documents are publicly readable and CORS-open.Protected resource metadata
GET https://app.lucenthq.com/.well-known/oauth-protected-resource
Returns the resource server’s identity and which authorization servers
issue tokens for it.
Authorization server metadata
GET https://app.lucenthq.com/.well-known/oauth-authorization-server
Returns the endpoints, supported parameters, and capabilities.
client_credentials are not
supported. plain PKCE is rejected.
Dynamic Client Registration
POST https://app.lucenthq.com/api/oauth/register
Implements RFC 7591.
Rate-limited per IP — busy clients should cache the resulting
client_id rather than re-register.
Request
Response (
201 Created)
client_secret is only present when token_endpoint_auth_method is
client_secret_post. Public clients (the default for native MCP
clients) get client_id only and authenticate with PKCE.
Allowed redirect URIs
The redirect allowlist defends against open-redirect and auth-code injection. Registration rejects URIs outside this list with anInvalidClientMetadataError and an opaque message.
URIs with embedded credentials (
https://user:pass@…) or fragments
(#…) are rejected per RFC 6749 §3.1.2. To add another hosted
origin, email [email protected].
Authorization request
GET https://app.lucenthq.com/oauth/authorize?…
Standard OAuth 2.1 authorization-code request with PKCE:
If the user isn’t signed in to Lucent, they’re routed through
/login
and returned to the consent screen after authentication. If a consent
record already exists for this (client_id, scope) and hasn’t been
revoked, the consent screen is bypassed and the browser is redirected
back to redirect_uri with ?code=…&state=… immediately.
If anything is wrong (unknown client, revoked client, redirect_uri
mismatch, malformed PKCE), the user sees a single opaque error page —
no detail is leaked that would let an unauthenticated probe enumerate
client state.
Token endpoint
POST https://app.lucenthq.com/api/oauth/token
Content-Type: application/x-www-form-urlencoded. Returns
Cache-Control: no-store.
grant_type=authorization_code
redirect_uri must match the value sent at authorize time (RFC
6749 §4.1.3 / OAuth 2.1 §4.1.3). Codes are single-use and expire after
60 seconds. Reuse of an already-redeemed code revokes any tokens
previously issued from it.
grant_type=refresh_token
Response
Revocation endpoint
POST https://app.lucenthq.com/api/oauth/revoke
Implements RFC 7009
and is idempotent — always returns 200 even for unknown tokens.
Tools and scopes
Every token carries theread:lucent scope, which gates the whole MCP
handler via withMcpAuth({ requiredScopes: ["read:lucent"] }) and covers
the four read tools (list_signals, list_issues, get_issue,
list_insights). The write tool, update_issue, additionally requires
write:issues — clients must request that scope during authorization,
and tokens without it get a missing-scope error from the tool.
See the tool reference for arguments and return shapes.