curl --request GET 'https://api.voicecheap.ai/oauth/authorize?client_id=mcp_client_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA&redirect_uri=https%3A%2F%2Fassistant.example.com%2Foauth%2Fcallback&response_type=code&response_mode=query&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM&code_challenge_method=S256&resource=https%3A%2F%2Fapi.voicecheap.ai%2Fmcp&scope=account%3Aread+projects%3Aread+offline_access&state=example-client-csrf-state'
const input = {
client_id: 'mcp_client_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
redirect_uri: 'https://assistant.example.com/oauth/callback',
response_type: 'code',
response_mode: 'query',
code_challenge: 'E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM',
code_challenge_method: 'S256',
resource: 'https://api.voicecheap.ai/mcp',
scope: 'account:read projects:read offline_access',
state: 'example-client-csrf-state',
};
const response = await fetch(
'https://api.voicecheap.ai/oauth/authorize?client_id=mcp_client_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA&redirect_uri=https%3A%2F%2Fassistant.example.com%2Foauth%2Fcallback&response_type=code&response_mode=query&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM&code_challenge_method=S256&resource=https%3A%2F%2Fapi.voicecheap.ai%2Fmcp&scope=account%3Aread+projects%3Aread+offline_access&state=example-client-csrf-state',
{
method: 'GET',
headers: {},
redirect: 'manual',
},
);
console.log(response.status, await response.text());
import os
import requests
response = requests.request(
"GET",
"https://api.voicecheap.ai/oauth/authorize?client_id=mcp_client_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA&redirect_uri=https%3A%2F%2Fassistant.example.com%2Foauth%2Fcallback&response_type=code&response_mode=query&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM&code_challenge_method=S256&resource=https%3A%2F%2Fapi.voicecheap.ai%2Fmcp&scope=account%3Aread+projects%3Aread+offline_access&state=example-client-csrf-state",
headers={},
timeout=120,
allow_redirects=False,
)
print(response.status_code, response.text)
OAuth i protokół MCP
Rozpocznij autoryzację konta MCP
Utwórz krótkotrwałe żądanie autoryzacji i przekieruj użytkownika na stronę logowania oraz zgody na uprawnienia VoiceCheap.
GET
/
oauth
/
authorize
curl --request GET 'https://api.voicecheap.ai/oauth/authorize?client_id=mcp_client_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA&redirect_uri=https%3A%2F%2Fassistant.example.com%2Foauth%2Fcallback&response_type=code&response_mode=query&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM&code_challenge_method=S256&resource=https%3A%2F%2Fapi.voicecheap.ai%2Fmcp&scope=account%3Aread+projects%3Aread+offline_access&state=example-client-csrf-state'
const input = {
client_id: 'mcp_client_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
redirect_uri: 'https://assistant.example.com/oauth/callback',
response_type: 'code',
response_mode: 'query',
code_challenge: 'E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM',
code_challenge_method: 'S256',
resource: 'https://api.voicecheap.ai/mcp',
scope: 'account:read projects:read offline_access',
state: 'example-client-csrf-state',
};
const response = await fetch(
'https://api.voicecheap.ai/oauth/authorize?client_id=mcp_client_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA&redirect_uri=https%3A%2F%2Fassistant.example.com%2Foauth%2Fcallback&response_type=code&response_mode=query&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM&code_challenge_method=S256&resource=https%3A%2F%2Fapi.voicecheap.ai%2Fmcp&scope=account%3Aread+projects%3Aread+offline_access&state=example-client-csrf-state',
{
method: 'GET',
headers: {},
redirect: 'manual',
},
);
console.log(response.status, await response.text());
import os
import requests
response = requests.request(
"GET",
"https://api.voicecheap.ai/oauth/authorize?client_id=mcp_client_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA&redirect_uri=https%3A%2F%2Fassistant.example.com%2Foauth%2Fcallback&response_type=code&response_mode=query&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM&code_challenge_method=S256&resource=https%3A%2F%2Fapi.voicecheap.ai%2Fmcp&scope=account%3Aread+projects%3Aread+offline_access&state=example-client-csrf-state",
headers={},
timeout=120,
allow_redirects=False,
)
print(response.status_code, response.text)
Utwórz krótkotrwałe żądanie autoryzacji i przekieruj użytkownika na stronę logowania oraz zgody na uprawnienia VoiceCheap.
GET https://api.voicecheap.ai/oauth/authorize
Uwierzytelnianie
Brak na tej trasie. Dalszy proces wyrażania zgody w przeglądarce wymaga zalogowania użytkownika, a zatwierdzenie wymaga dostępu do kwalifikującego się płatnego konta.Parametry zapytania
string
wymagane
client_id zwrócony przez rejestrację dynamiczną lub dokładny publiczny adres HTTPS dokumentu metadanych klienta.Minimalna długość: 1. Maksymalna długość: 2048. Wzorzec:
^[^\u0000-\u001F\u007F]+$.string
wymagane
Musi być dokładnie zgodny z jednym z redirect_uris zarejestrowanych dla tego klienta.Minimalna długość: 1. Maksymalna długość: 2048. Wzorzec:
^[^\u0000-\u001F\u007F]+$.field
wymagane
Wartość określona w pełnym schemacie danych wejściowych.Wymagana wartość: “code”.
field
Wartość określona w pełnym schemacie danych wejściowych.Wymagana wartość: “query”. Wartość domyślna: “query”.
string
wymagane
Skrót SHA-256 oryginalnego code_verifier zakodowany jako Base64url, bez dopełnienia.Minimalna długość: 43. Maksymalna długość: 43. Wzorzec:
^[A-Za-z0-9_-]{43}$.field
wymagane
Wartość określona w pełnym schemacie danych wejściowych.Wymagana wartość: “S256”.
string
wymagane
Wymagana jest dokładna wartość odbiorcy zasobu: użyj wartości resource z metadanych chronionego zasobu tego środowiska. W produkcji jest to https://api.voicecheap.ai/mcp. Inny adres bazowy, ścieżka lub końcowy ukośnik są odrzucane.Format: “uri”.
string
Uprawnienia z scopes_supported rozdzielone spacjami, opcjonalnie z offline_access. Nieobsługiwane nazwy i wartości zawierające wyłącznie białe znaki są odrzucane; duplikaty są usuwane. Pominięcie scope lub brak uprawnień produktu, na przykład samo openid lub samo offline_access, wybiera część wspólną domyślnych zakresów odczytu i zakresów produktu zarejestrowanych dla tego klienta. email wymaga openid; samo email jest odrzucane. Żądane uprawnienia produktu muszą być zarejestrowane dla tego klienta. Uprawnienia tożsamości muszą być jawnie zażądane i zatwierdzone przez użytkownika; pominięcie scope nie żąda uprawnień tożsamości.Minimalna długość: 1. Maksymalna długość: 2048. Wzorzec:
^ *(?: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))* *$.string
Opcjonalna nieprzezroczysta wartość zwracana bez zmian w końcowym wywołaniu zwrotnym. Użyj nowej, nieprzewidywalnej wartości i zweryfikuj ją po stronie klienta.Minimalna długość: 1. Maksymalna długość: 2048. Wzorzec:
^[^\u0000-\u001F\u007F]+$.string
Opcjonalna nieprzezroczysta wartość nonce zwracana w tokenie ID po przyznaniu openid. Zweryfikuj ją w kliencie.Minimalna długość: 1. Maksymalna długość: 2048. Wzorzec:
^[^\u0000-\u001F\u007F]+$.string
Wartość tekstowa.Wymagana wartość: “consent”.
Schemat techniczny
Schemat techniczny
{
"type": "object",
"properties": {
"client_id": {
"type": "string",
"minLength": 1,
"maxLength": 2048,
"pattern": "^[^\\u0000-\\u001F\\u007F]+$",
"description": "The client_id returned by dynamic registration, or the exact public HTTPS URL of the client metadata document."
},
"redirect_uri": {
"type": "string",
"minLength": 1,
"maxLength": 2048,
"pattern": "^[^\\u0000-\\u001F\\u007F]+$",
"description": "Must exactly match one of this client's registered redirect_uris."
},
"response_type": {
"const": "code"
},
"response_mode": {
"const": "query",
"default": "query"
},
"code_challenge": {
"type": "string",
"minLength": 43,
"maxLength": 43,
"pattern": "^[A-Za-z0-9_-]{43}$",
"description": "Base64url SHA-256 digest of the original code_verifier, without padding."
},
"code_challenge_method": {
"const": "S256"
},
"resource": {
"type": "string",
"format": "uri",
"description": "Required exact resource audience: use the resource value from this environment's protected-resource metadata. In production this is https://api.voicecheap.ai/mcp. A different origin, path, or trailing slash is rejected.",
"examples": [
"https://api.voicecheap.ai/mcp"
]
},
"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, selects the default read scopes intersected with this client's registered product scopes. email requires openid; email alone is rejected. Requested product permissions must be registered for this client. Identity permissions must be explicitly requested and approved by the user; omitting scope requests no identity permissions.",
"examples": [
"account:read projects:read offline_access"
]
},
"state": {
"type": "string",
"minLength": 1,
"maxLength": 2048,
"pattern": "^[^\\u0000-\\u001F\\u007F]+$",
"description": "Optional opaque value echoed on the final callback. Use a fresh unpredictable value and verify it in the client."
},
"nonce": {
"type": "string",
"minLength": 1,
"maxLength": 2048,
"pattern": "^[^\\u0000-\\u001F\\u007F]+$",
"description": "Optional opaque nonce echoed in the ID token when openid is granted. Verify it in the client."
},
"prompt": {
"type": "string",
"const": "consent"
}
},
"required": [
"client_id",
"redirect_uri",
"response_type",
"code_challenge",
"code_challenge_method",
"resource"
],
"additionalProperties": true
}
Przykłady żądań
Stosuj udokumentowany sposób kodowania i uwierzytelniania dla tej ścieżki. Struktura odpowiedzi i reguły idempotencji API akcji dotyczą wyłącznie wywołań akcji.curl --request GET 'https://api.voicecheap.ai/oauth/authorize?client_id=mcp_client_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA&redirect_uri=https%3A%2F%2Fassistant.example.com%2Foauth%2Fcallback&response_type=code&response_mode=query&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM&code_challenge_method=S256&resource=https%3A%2F%2Fapi.voicecheap.ai%2Fmcp&scope=account%3Aread+projects%3Aread+offline_access&state=example-client-csrf-state'
const input = {
client_id: 'mcp_client_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
redirect_uri: 'https://assistant.example.com/oauth/callback',
response_type: 'code',
response_mode: 'query',
code_challenge: 'E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM',
code_challenge_method: 'S256',
resource: 'https://api.voicecheap.ai/mcp',
scope: 'account:read projects:read offline_access',
state: 'example-client-csrf-state',
};
const response = await fetch(
'https://api.voicecheap.ai/oauth/authorize?client_id=mcp_client_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA&redirect_uri=https%3A%2F%2Fassistant.example.com%2Foauth%2Fcallback&response_type=code&response_mode=query&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM&code_challenge_method=S256&resource=https%3A%2F%2Fapi.voicecheap.ai%2Fmcp&scope=account%3Aread+projects%3Aread+offline_access&state=example-client-csrf-state',
{
method: 'GET',
headers: {},
redirect: 'manual',
},
);
console.log(response.status, await response.text());
import os
import requests
response = requests.request(
"GET",
"https://api.voicecheap.ai/oauth/authorize?client_id=mcp_client_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA&redirect_uri=https%3A%2F%2Fassistant.example.com%2Foauth%2Fcallback&response_type=code&response_mode=query&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM&code_challenge_method=S256&resource=https%3A%2F%2Fapi.voicecheap.ai%2Fmcp&scope=account%3Aread+projects%3Aread+offline_access&state=example-client-csrf-state",
headers={},
timeout=120,
allow_redirects=False,
)
print(response.status_code, response.text)
Odpowiedź
Przekierowanie HTTP na stronę zgody VoiceCheap. Brak treści wyniku JSON. Location zawiera nieprzezroczystą wartość request; następnie użytkownik loguje się i wybiera uprawnienia.HTTP/1.1 302 Found
Cache-Control: no-store
Pragma: no-cache
Referrer-Policy: no-referrer
Location: https://app.voicecheap.ai/mcp/authorize?request=mcp_req_BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
Nagłówki odpowiedzi
{
"Cache-Control": "no-store",
"Pragma": "no-cache",
"Referrer-Policy": "no-referrer",
"Location": "https://app.voicecheap.ai/mcp/authorize?request=mcp_req_BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
}
Uwagi do operacji
- Rozpoznawane parametry skalarne muszą być podane jednokrotnie jako niepuste ciągi znaków bez znaków sterujących ASCII ani DEL. Powtórzone pola zapytania lub formularza są dekodowane jako tablice i odrzucane przy odczycie jako wartości skalarne.
- Zakoduj każdą wartość zapytania w formacie URL. redirect_uri musi mieć dokładnie taki zapis, jaki został zarejestrowany dla tego klienta.
- Używaj wyłącznie S256; plain PKCE i odpowiedzi implicit/token nie są obsługiwane. Zachowaj pierwotny code_verifier o długości 43–128 znaków do wymiany tokenu.
- Parametr resource jest obowiązkowy i musi być dokładnie równy adresowi URL zasobu MCP wybranego środowiska.
- Domyślny zestaw zakresów uprawnień produktu to account:read usage:read projects:read transcription:read subtitles:read tts:read voices:read images:read thumbnails:read. Żądanie korzystające z wartości domyślnych jest zawężane do zakresów zarejestrowanych przez klienta; jeśli nie pozostanie żaden zakres uprawnień produktu, autoryzacja kończy się niepowodzeniem.
- Zakres składający się wyłącznie z offline_access korzysta z domyślnego wyboru zakresów produktu. offline_access jest usuwany przed wyświetleniem lub przyznaniem uprawnień do produktu.
- Prośby o zgodę wygasają po 10 minutach i można na nie odpowiedzieć raz. Użytkownik może zatwierdzić tylko niepusty podzbiór żądanych uprawnień produktu.
- Po zatwierdzeniu wywołanie zwrotne klienta otrzymuje code, iss oraz pierwotne state, jeśli zostało podane. Kod autoryzacyjny wygasa po 2 minutach i można go wymienić tylko raz.
- Po odmowie adres wywołania zwrotnego klienta otrzymuje error=access_denied, error_description, iss oraz oryginalne state, jeśli zostało podane; kod nie jest wydawany.
- Nieprawidłowe metadane klienta, niezgodności przekierowań, PKCE, zakresów lub resource powodują bezpośrednie błędy JSON OAuth; nie są przekierowywane do niezweryfikowanego adresu wywołania zwrotnego.
- Publiczny limit autoryzacji wynosi 30 żądań na minutę na adres IP klienta i jest współdzielony przez procesy robocze.
- openid i email to uprawnienia tożsamości, niezależne od uprawnień produktu, akceptowane tylko wtedy, gdy są ogłaszane. email wymaga openid. Podczas pierwszej autoryzacji żądanie zawierające wyłącznie zakresy tożsamości używa domyślnych uprawnień produktu pokazanych na ekranie zgody.
- client_id zwrócony przez rejestrację dynamiczną lub dokładny publiczny adres HTTPS dokumentu metadanych klienta.
- OpenID Connect obsługuje prompt=consent. Inne wartości prompt i max_age są odrzucane; cicha autoryzacja i wymuszone ponowne logowanie nie są obsługiwane.
Błędy
| Status HTTP | Kod | Znaczenie lub sposób rozwiązania |
|---|---|---|
| 400 | invalid_request | Treść żądania lub rozpoznany parametr są nieprawidłowe, nieobecne, zduplikowane lub mają niewłaściwe kodowanie. |
| 400 | invalid_client | client_id jest nieznany albo nie można pobrać lub zweryfikować dokumentu metadanych klienta. |
| 400 | unsupported_response_type | response_type nie ma wartości code. |
| 400 | invalid_target | Brakuje resource lub jego wartość nie jest dokładnie adresem URL MCP środowiska. |
| 400 | invalid_scope | Żądany zakres produktu nie jest obsługiwany, nie jest zarejestrowany lub nie pozostawia żadnego użytecznego uprawnienia. |
| 429 | temporarily_unavailable | Osiągnięto publiczny limit częstotliwości żądań OAuth. Przed ponowieniem poczekaj na zakończenie bieżącego okna. |
| 500 | server_error | Autoryzacja jest tymczasowo niedostępna. Spróbuj ponownie później. |
| 503 | temporarily_unavailable | Metadane klienta są tymczasowo niedostępne. Spróbuj ponownie później. |
Czy ta strona była pomocna?

