Skip to content
POST /oauth/register

Dynamic client registration. Public and unauthenticated by protocol — any MCP client may register itself, which is why every field is length- and count-bounded and every redirect URI is scheme-checked. The response is the only time `client_secret` is ever returned; it is stored hashed and cannot be read back. Omitting `token_endpoint_auth_method` (or sending `none`) registers a public client that authenticates with PKCE alone, which is how every native MCP client works. Registration grants nothing on its own: a registered client can only act after a user approves it at `GET /oauth/authorize`. Rate limited per client IP.

Request Body

client_namestring

Shown on the consent screen. Defaults to "MCP client". Not verified — see client_name on the grant schema.

client_uristring
grant_typesstring[]

Defaults to both. Any other value is rejected.

Possible values:
authorization_coderefresh_token
logo_uristring

Rendered on the consent screen beside the app name, https: only — an http:, data: or blob: value falls back to a generated monogram, as does one that fails to load. It is fetched with referrer-policy: no-referrer and without credentials. Note that it proves nothing: registration is unauthenticated, so this is a mark the registrant chose, exactly like client_name, and the consent screen says so to the user. redirect_uris remains the only identity signal a lookalike cannot forge.

redirect_urisstring[]

Where authorization codes may be delivered, matched later by exact string. Accepted: any https URI; http only on loopback (localhost, 127.0.0.1, [::1]), the RFC 8252 native-app pattern; or a private-use reverse-DNS scheme such as com.example.app:/callback. Fragments and wildcards are rejected.

response_typesstring[]

Only ["code"] is supported.

Possible values:
code
scopestring

Accepted and ignored; scopes are chosen per authorization.

token_endpoint_auth_methodstring

Defaults to none (public client, PKCE only). Choosing either client_secret_* method issues a secret that the token and revocation endpoints will then require.

Possible values:
noneclient_secret_postclient_secret_basic

Response Body

client_idstring

OAuth client id (ocli_…).

client_id_issued_atinteger

Unix seconds.

client_namestring
client_secretstring

Present only for confidential clients. Returned exactly once — store it now.

client_secret_expires_atinteger

0 — the secret does not expire.

client_uristring
grant_typesstring[]
logo_uristring
redirect_urisstring[]
response_typesstring[]
scopestring

Space-delimited list of every scope this server supports.

token_endpoint_auth_methodstring
curl -X POST 'https://api.elaichi.ai/oauth/register' \
  -H 'Content-Type: application/json' \
  -d '{"client_name":"your_client_name","redirect_uris":[],"grant_types":[],"response_types":[],"token_endpoint_auth_method":"none","client_uri":"your_client_uri","logo_uri":"your_logo_uri","scope":"your_scope"}'
const body = {
  "client_name": "your_client_name",
  "redirect_uris": [],
  "grant_types": [],
  "response_types": [],
  "token_endpoint_auth_method": "none",
  "client_uri": "your_client_uri",
  "logo_uri": "your_logo_uri",
  "scope": "your_scope"
};

const response = await fetch('https://api.elaichi.ai/oauth/register', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify(body),
});

const data = await response.json();
console.log(data);
import os
import requests

url = "https://api.elaichi.ai/oauth/register"
headers = {
    "Content-Type": "application/json",
}
payload = {
    "client_name": "your_client_name",
    "redirect_uris": [],
    "grant_types": [],
    "response_types": [],
    "token_endpoint_auth_method": "none",
    "client_uri": "your_client_uri",
    "logo_uri": "your_logo_uri",
    "scope": "your_scope"
}

response = requests.post(url, headers=headers, json=payload)
print(response.json())