curl --request POST 'https://api.voicecheap.ai/oauth/register' \
--header 'Content-Type: application/json' \
--data '{"client_name":"Acme assistant","redirect_uris":["https://assistant.example.com/oauth/callback"],"token_endpoint_auth_method":"none","grant_types":["authorization_code","refresh_token"],"response_types":["code"],"scope":"account:read projects:read offline_access"}'
const input = {
client_name: 'Acme assistant',
redirect_uris: ['https://assistant.example.com/oauth/callback'],
token_endpoint_auth_method: 'none',
grant_types: ['authorization_code', 'refresh_token'],
response_types: ['code'],
scope: 'account:read projects:read offline_access',
};
const response = await fetch('https://api.voicecheap.ai/oauth/register', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(input),
redirect: 'manual',
});
console.log(response.status, await response.text());
import os
import requests
response = requests.request(
"POST",
"https://api.voicecheap.ai/oauth/register",
headers={"Content-Type":"application/json"},
json={"client_name": "Acme assistant", "redirect_uris": ["https://assistant.example.com/oauth/callback"], "token_endpoint_auth_method": "none", "grant_types": ["authorization_code", "refresh_token"], "response_types": ["code"], "scope": "account:read projects:read offline_access"},
timeout=120,
allow_redirects=False,
)
print(response.status_code, response.text)
OAuth と MCP プロトコル
MCP OAuth クライアントを登録
完全一致するコールバック URL と、範囲を限定したプロダクト権限を指定してパブリッククライアントを登録します。
POST
/
oauth
/
register
curl --request POST 'https://api.voicecheap.ai/oauth/register' \
--header 'Content-Type: application/json' \
--data '{"client_name":"Acme assistant","redirect_uris":["https://assistant.example.com/oauth/callback"],"token_endpoint_auth_method":"none","grant_types":["authorization_code","refresh_token"],"response_types":["code"],"scope":"account:read projects:read offline_access"}'
const input = {
client_name: 'Acme assistant',
redirect_uris: ['https://assistant.example.com/oauth/callback'],
token_endpoint_auth_method: 'none',
grant_types: ['authorization_code', 'refresh_token'],
response_types: ['code'],
scope: 'account:read projects:read offline_access',
};
const response = await fetch('https://api.voicecheap.ai/oauth/register', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(input),
redirect: 'manual',
});
console.log(response.status, await response.text());
import os
import requests
response = requests.request(
"POST",
"https://api.voicecheap.ai/oauth/register",
headers={"Content-Type":"application/json"},
json={"client_name": "Acme assistant", "redirect_uris": ["https://assistant.example.com/oauth/callback"], "token_endpoint_auth_method": "none", "grant_types": ["authorization_code", "refresh_token"], "response_types": ["code"], "scope": "account:read projects:read offline_access"},
timeout=120,
allow_redirects=False,
)
print(response.status_code, response.text)
完全一致するコールバック URL と、範囲を限定したプロダクト権限を指定してパブリッククライアントを登録します。
POST https://api.voicecheap.ai/oauth/register
認証
ありません。登録では、ユーザーのログインやアカウント接続の認可は行われません。リクエストボディ
array
必須
重複を除去する前のコールバック数は1から10です。最小要素数: 1. 最大要素数: 10.
string
任意のクライアントラベル。保存前に前後の空白が除去され、空であってはなりません。最小文字数: 1. 最大文字数: 120. パターン:
^(?=.*\S)[^\u0000-\u001F\u007F]+$. デフォルト値: “MCP client”.field
パブリッククライアントのみ。必須の値: “none”. デフォルト値: “none”.
union
authorization_code は必須で、refresh_token は任意です。省略または null の場合は両方が選択されます。重複する値は削除されます。デフォルト値: [“authorization_code”,“refresh_token”].
array
値のリスト。要素の構造は完全な入力スキーマを参照してください。最小要素数: 1. 最大要素数: 1. デフォルト値: [“code”].
string
scopes_supported の権限をスペース区切りで指定し、任意で offline_access を含められます。未対応の名前や空白のみの値は拒否され、重複は除去されます。scope を省略するか、openid のみや offline_access のみなど製品権限を指定しない場合、対応するすべての製品スコープが登録されます。email には openid が必要で、email のみは拒否されます。OpenID Connect が利用可能な場合、scope を省略しても openid と email がクライアントの対応機能として登録されます。登録だけではアクセス権は付与されず、ID 権限には明示的な認可リクエストとユーザーの同意が必要です。最小文字数: 1. 最大文字数: 2048. パターン:
^ *(?:account:read|usage:read|settings:read|settings:write|team:read|team:write|projects:read|projects:write|projects:delete|translations:write|transcription:read|transcription:write|subtitles:read|subtitles:write|tts:read|tts:write|voices:read|voices:write|images:read|images:write|thumbnails:read|thumbnails:write|folders:read|folders:write|glossary:read|glossary:write|webhooks:read|webhooks:write|publishing:read|publishing:write|offline_access|openid|email)(?: +(?:account:read|usage:read|settings:read|settings:write|team:read|team:write|projects:read|projects:write|projects:delete|translations:write|transcription:read|transcription:write|subtitles:read|subtitles:write|tts:read|tts:write|voices:read|voices:write|images:read|images:write|thumbnails:read|thumbnails:write|folders:read|folders:write|glossary:read|glossary:write|webhooks:read|webhooks:write|publishing:read|publishing:write|offline_access|openid|email))* *$.技術スキーマ
技術スキーマ
{
"type": "object",
"properties": {
"redirect_uris": {
"type": "array",
"minItems": 1,
"maxItems": 10,
"items": {
"type": "string",
"minLength": 1,
"maxLength": 2048,
"pattern": "^[^\\s\\u0000-\\u001F\\u007F-\\u009F#\\\\]+$",
"format": "uri",
"anyOf": [
{
"pattern": "^[Hh][Tt][Tt][Pp][Ss]://"
},
{
"pattern": "^http://(?:localhost|127\\.0\\.0\\.1|\\[::1\\])(?::[0-9]{1,5})?(?:/|\\?|$)"
},
{
"const": "cursor://anysphere.cursor-mcp/oauth/callback"
}
],
"description": "An absolute HTTPS callback, an HTTP callback using the exact lowercase loopback spelling localhost, 127.0.0.1, or [::1], or exactly cursor://anysphere.cursor-mcp/oauth/callback. Must parse as a URL with no username/password, whitespace, control characters, backslashes, or fragment. A loopback port must be a valid URL port. The exact spelling is retained."
},
"description": "Between 1 and 10 callbacks before duplicates are removed."
},
"client_name": {
"type": "string",
"minLength": 1,
"maxLength": 120,
"pattern": "^(?=.*\\S)[^\\u0000-\\u001F\\u007F]+$",
"default": "MCP client",
"description": "Optional client label; trimmed before saving and must remain nonempty."
},
"token_endpoint_auth_method": {
"const": "none",
"default": "none",
"description": "Public clients only."
},
"grant_types": {
"anyOf": [
{
"type": "array",
"minItems": 1,
"items": {
"enum": [
"authorization_code",
"refresh_token"
]
},
"contains": {
"const": "authorization_code"
}
},
{
"type": "null"
}
],
"default": [
"authorization_code",
"refresh_token"
],
"description": "Must include authorization_code; refresh_token is optional. Omitted or null selects both. Duplicate values are removed."
},
"response_types": {
"type": "array",
"minItems": 1,
"maxItems": 1,
"items": {
"const": "code"
},
"default": [
"code"
]
},
"scope": {
"type": "string",
"minLength": 1,
"maxLength": 2048,
"pattern": "^ *(?:account:read|usage:read|settings:read|settings:write|team:read|team:write|projects:read|projects:write|projects:delete|translations:write|transcription:read|transcription:write|subtitles:read|subtitles:write|tts:read|tts:write|voices:read|voices:write|images:read|images:write|thumbnails:read|thumbnails:write|folders:read|folders:write|glossary:read|glossary:write|webhooks:read|webhooks:write|publishing:read|publishing:write|offline_access|openid|email)(?: +(?:account:read|usage:read|settings:read|settings:write|team:read|team:write|projects:read|projects:write|projects:delete|translations:write|transcription:read|transcription:write|subtitles:read|subtitles:write|tts:read|tts:write|voices:read|voices:write|images:read|images:write|thumbnails:read|thumbnails:write|folders:read|folders:write|glossary:read|glossary:write|webhooks:read|webhooks:write|publishing:read|publishing:write|offline_access|openid|email))* *$",
"description": "Space-delimited permissions from scopes_supported, optionally including offline_access. Unsupported names and whitespace-only values are rejected; duplicates are removed. Omitting scope or supplying no product scopes, such as openid alone or offline_access alone, registers all supported product scopes. email requires openid; email alone is rejected. When OpenID Connect is available, registration includes openid and email as client capabilities even when scope is omitted. Registration grants no access; identity permissions require an explicit authorization request and user consent.",
"examples": [
"account:read projects:read offline_access"
]
}
},
"required": [
"redirect_uris"
],
"additionalProperties": true
}
リクエスト例
このルートに記載されたエンコード方式と認証方法に従ってください。アクション API のエンベロープと冪等性のルールは、アクションの呼び出しにのみ適用されます。curl --request POST 'https://api.voicecheap.ai/oauth/register' \
--header 'Content-Type: application/json' \
--data '{"client_name":"Acme assistant","redirect_uris":["https://assistant.example.com/oauth/callback"],"token_endpoint_auth_method":"none","grant_types":["authorization_code","refresh_token"],"response_types":["code"],"scope":"account:read projects:read offline_access"}'
const input = {
client_name: 'Acme assistant',
redirect_uris: ['https://assistant.example.com/oauth/callback'],
token_endpoint_auth_method: 'none',
grant_types: ['authorization_code', 'refresh_token'],
response_types: ['code'],
scope: 'account:read projects:read offline_access',
};
const response = await fetch('https://api.voicecheap.ai/oauth/register', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(input),
redirect: 'manual',
});
console.log(response.status, await response.text());
import os
import requests
response = requests.request(
"POST",
"https://api.voicecheap.ai/oauth/register",
headers={"Content-Type":"application/json"},
json={"client_name": "Acme assistant", "redirect_uris": ["https://assistant.example.com/oauth/callback"], "token_endpoint_auth_method": "none", "grant_types": ["authorization_code", "refresh_token"], "response_types": ["code"], "scope": "account:read projects:read offline_access"},
timeout=120,
allow_redirects=False,
)
print(response.status_code, response.text)
レスポンス
登録済みパブリッククライアントのメタデータ。client_id を保存し、登録済みの redirect_uri と完全一致する値と組み合わせて使用してください。client_secret は発行されません。HTTP 201
{
"client_id": "mcp_client_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
"client_id_issued_at": 1792152000,
"client_name": "Acme assistant",
"redirect_uris": ["https://assistant.example.com/oauth/callback"],
"token_endpoint_auth_method": "none",
"grant_types": ["authorization_code", "refresh_token"],
"response_types": ["code"],
"scope": "account:read projects:read offline_access"
}
レスポンスヘッダー
{
"Cache-Control": "no-store",
"Pragma": "no-cache"
}
操作の注意事項
- 認識されるスカラーパラメーターは、ASCII 制御文字や DEL を含まない空でない文字列として、1回だけ指定する必要があります。重複するクエリ/フォームフィールドは配列にデコードされ、スカラーとして読み取る際に拒否されます。
- Content-Type に application/json を使用してください。URL エンコードされた登録本文は OAuth の invalid_request レスポンスで拒否されます。未対応のメディアタイプは、それより前に連携パーサーで拒否される場合があります。
- リダイレクト URI はそのまま保存され、完全一致で比較されます。大文字・小文字、ポートの表記、パス、クエリ、末尾のスラッシュを変更する場合は、その URI を正確に登録する必要があります。
- HTTP コールバックで許可されるのは、ループバック名をそのまま表記した localhost、127.0.0.1、[::1] のみです。プライベートネットワークのホスト、別表記の IP、*.localhost、大文字の LOCALHOST は該当しません。
- カスタム URI スキームのコールバックは、cursor://anysphere.cursor-mcp/oauth/callback と完全に一致するものだけが許可されます。
- すべてのコールバックが検証に合格する必要があります。1 つでも無効なコールバックがあると、登録全体が拒否されます。URL 内の認証情報、空白、制御文字、フラグメント、バックスラッシュは拒否されます。
- クライアントは対応する任意の製品スコープを登録できますが、ユーザーは認可時に、要求されたサブセットを別途承認する必要があります。登録だけではアクセス権は付与されません。
- 対応する付与タイプは authorization_code と、任意の refresh_token だけです。refresh_token なしで登録されたクライアントにはリフレッシュトークンは発行されません。
- 現在の実装では、最上位の未知のメタデータフィールドは無視されます。既知のフィールドには、スキーマに示された制約が適用されます。
- 公開登録エンドポイントの上限は、クライアント IP ごとに 10 分間で 10 リクエストで、ワーカー間で共有されます。JSON 本文は 1 MiB 以内です。
- 登録に成功すると HTTP 201 を返します。
- openid と email は製品権限とは別の ID 権限であり、公開されている場合のみ受け付けられます。email には openid が必要です。初回の認可で ID スコープのみを指定すると、同意画面に表示される既定の製品権限が使われます。
エラー
| HTTP ステータス | コード | 意味または対処方法 |
|---|---|---|
| 400 | invalid_request | 本文または認識されたパラメーターが無効、不足、重複、またはエンコード不正です。 |
| 400 | invalid_client_metadata | コールバック数が無効、クライアントラベルが空、またはクライアント認証、グラントタイプ、レスポンスタイプが未対応です。 |
| 400 | invalid_redirect_uri | コールバック URL が未対応または安全でない形式です。 |
| 400 | invalid_scope | scope 文字列に非対応の権限が含まれているか、要求するスコープがありません。 |
| 413 | REQUEST_TOO_LARGE | リクエストが許可された本文サイズを超えています。JSONの上限は 1 MiB、URLエンコードされたフォームの上限は 32 KiB です。 |
| 415 | UNSUPPORTED_CONTENT_TYPE | 連携の本文パーサーは JSON または URL エンコードされたフォームのみを受け付けます。ルートによっては、どちらか一方のエンコード方式が必須です。 |
| 429 | temporarily_unavailable | 公開 OAuth リクエストのレート上限に達しました。現在の制限期間が終わってから再試行してください。 |
| 500 | server_error | 認可を一時的に利用できません。後で再試行してください。 |
このページは役に立ちましたか?

