1. Niyə ümumiyyətlə ChatGPT‑App‑də səlahiyyətlər barədə düşünmək lazımdır (və burada xüsusi risk nədir)
“Adi” veb tətbiqində istifadəçi ilə bazanız arasında cəmi bir neçə qat olur: frontend, API, DB. ChatGPT‑App‑də isə istifadəçi ilə API arasında daha bir aktiv iştirakçı — LLM — peyda olur. Bu, sadəcə “mətn filtri” deyil, həm də aşağıdakıları edə bilən bir varlıqdır:
- özbaşına seçir ki, hansı alətləri hansı arqumentlərlə işə salsın;
- məlumatdakı prompt inyeksiyası ilə aldadıla bilər;
- alətləri “səhv sala” və ya gözləmədiyiniz arqumentlər uydura bilər.
LLM‑ə həddindən artıq səlahiyyət versəniz, klassik Confused Deputy problemini əldə edirsiniz: model sədaqətlə istifadəçinin və ya sənədlərdəki mətnin istədiyini zənn etdiyi şeyi icra edir, lakin bununla belə delete_all_orders əvəzinə get_last_order çağırmalıykən səhv aləti işə sala bilər.
Məqsədimiz:
- Minimuma endirmək auth_token səlahiyyətlərini (ümumilikdə hansı məlumat və əməliyyatlar əlçatandır).
- Məhdudlaşdırmaq ki, konkret ssenaridə modelə ümumiyyətlə hansı alətlər əlçatan olsun.
- Əlavə etmək kritik nəticələri olan yerlərdə insan nəzarətini.
Bütün bunları paranoyasız və hər şeyə total qadağa qoymadan etmək lazımdır, yoxsa App yararsızlaşacaq. Rahatlıqla təhlükəsizlik arasında balans — bu modulun əsas vəzifəsidir.
2. Ekosistemdə giriş modeli: kim nəyə çıxış edir
Qarışıqlıq olmasın deyə, sistemi bütöv şəkildə nəzərdən keçirək. Bir neçə səviyyəmiz var, hər birinin öz məsuliyyət zonası və səlahiyyətləri mövcuddur.
flowchart TD U[ChatGPT-də istifadəçi] --> C[ChatGPT UI + LLM] C --> A["Sizin App (vizual plan + vidcet)"] A --> G[MCP Gateway / API Edge] G --> S[MCP serverləri və mikroservislər] S --> D[Verilənlər bazaları, növbələr, xarici API-lər]
Rollar qısa şəkildə:
- ChatGPT UI və LLM: OpenAI tərəfindən idarə olunur. Siz onlara təlimatlar verirsiniz (system‑prompt, tool descriptions), lakin platformanın daxili tokenlərini və səlahiyyətlərini nəzarətdə saxlamırsınız.
- Sizin App (plan, tools, vidcet): hansı alətlərin əlçatan olduğunu, necə təsvir edildiyini, hansı UX‑təsdiqlərin lazım olduğunu, vidcetin hansı məlumatları göstərə biləcəyini siz müəyyənləşdirirsiniz.
- MCP Gateway / API Edge: burada token yoxlanır, userId, tenantId, scopes siyahısının mappinqi və düzgün servislərə marşrutlaşdırma baş verir.
- MCP serverləri və mikroservislər: alətləri icra edir, DB və xarici API‑lərə sorğular edir. Burada ən sərt yoxlamalar olmalıdır: scopes, tenant‑izolyasiya, giriş məlumatlarının validasiyası.
- Saxlama və xarici API‑lər: son müdafiə xətti (DB səviyyəsində məhdudiyyətlər, xarici xidmət hesablarının səlahiyyətləri).
Əsas fikir: LLM giriş hüquqlarının mənbəyi deyil. MCP serverinə gələn hər şeyi “istifadəçi tərəfindən model vasitəsilə formalaşdırılmış sorğu” kimi qəbul edirik. Əməliyyatın gerçəkdən yerinə yetirilib‑yetirilməyəcəyinə qərar vermək — sizin backend kodunuzun, yox ki, promptun vəzifəsidir.
3. AuthN və AuthZ: nəyi artıq bacarırıq və nə əlavə edirik
Autentifikasiya modulunda artıq bunları etmisiniz:
- AuthN (Authentication) — bu istifadəçinin kim olduğunu müəyyənləşdirirdiniz. OAuth 2.1/PKCE vasitəsilə ChatGPT IdP‑dən token alırdı və sonra onu MCP çağırışlarına əlavə edirdi. Tokenin içində sub, user_id və ya analoqu, bəzən də tenant_id olurdu.
- Baza AuthZ — bəlkə artıq user/admin rollarını ayırır və ən azı “bu istifadəçidir” və ya “admin”mi deyə yoxlayırdınız.
İndi mənzərəni bir az mürəkkəbləşdiririk:
- hər bir auth_token scopes dəsti daşımalıdır — resource:action tipli sətir hüquqları, məsələn, catalog:read, orders:write, payments:create;
- sizin MCP serveriniz bu scopes uyğunluğunu hər bir əməliyyat üçün yoxlamalıdır, tək “girişdə bir dəfə” deyil;
- fərqli alətlər və hətta eyni alətin daxilindəki müxtəlif əməliyyatlar fərqli scopes tələb edə bilər.
OAuth 2.1 terminlərində ChatGPT — “public client”, MCP — “resource server”dir və sizin OAuth serveriniz hansı scopes dəstəkləndiyini və onların nəyimənsə uyğun gəldiyini bilir. MCP resursunun metadata‑sı adətən scopes_supported elan edir ki, ChatGPT istifadəçidən məhz lazım olan icazələri tələb edə bilsin.
4. GiftGenius üçün scopes layihələşdirilməsi
Tədris layihəmiz GiftGenius‑u götürək və onun hansı məlumat domenləri və əməliyyatları olduğunu baxaq. Funksionallıq təxminən belədir:
- kataloqa və hədiyyə kartlarına baxış;
- tarixə əsaslanan tövsiyələr;
- sifarişlərin yaradılması;
- checkout başladılması / vəsaitin tutulması;
- admin tərəfindən kataloqun redaktəsi.
Bir “hər şeyə qadir” giftgenius:full_access etməkdənsə, bunu məntiqli scopes üzrə bölmək daha yaxşıdır.
Adlandırma qaydası: resource:action
resource:action strategiyası yaxşı işləyir, burada:
- resource domeni təsvir edir: catalog, recommendations, orders, payments, admin.
- action əməliyyat tipini təsvir edir: read, write, bəzən daha konkret: create, delete, manage.
GiftGenius üçün nümunə:
| Scope | Nəyə icazə verir |
|---|---|
|
İctimai hədiyyə kataloqunu oxumaq |
|
İstifadəçinin tövsiyə tarixçəsini oxumaq |
|
Yeni sifarişlər yaratmaq |
|
İstifadəçinin sifariş tarixçəsini oxumaq |
|
Ödənişi / checkout‑u başlatmaq |
|
Kataloqu redaktə etmək (yalnız admin UI/dəstək üçün) |
Adi GiftGenius istifadəçisi təxminən belə bir dəst tələb edəcək (boşluqla ayrılaraq sadalanır): catalog:read recommendations:read orders:write orders:read payments:create. Administrator üçün catalog:admin əlavə edirik.
Vacibdir: universal *:* və ya admin:all etməyin. Nə qədər qranulyar olsa, bir hüququ geri çağırmaq bir o qədər asan olur və bütün tətbiqi sındırmadan bunu edə bilərsiniz.
Scopes tipləri: read vs write vs critical
Scopes‑u kateqoriyalara bölmək faydalıdır:
- təhlükəsiz (read): vəziyyəti dəyişmirlər, maksimum məlumatı açıqlayırlar;
- mutasiya edən (write): obyektlər yaradır/dəyişir, ancaq pulu tərpətmir və hər şeyi silmir;
- kritik (critical): ödənişlər, hesabın silinməsi, məlumatların kütləvi silinməsi.
Kritik hüquqlar üçün artırılmış nəzarət tətbiq edin:
- onları minimum sayda istifadəçiyə verin;
- token verilərkən ChatGPT UI‑də istifadəçidən ayrıca razılıq tələb edin;
- MCP tərəfində əlavə təsdiq tələb edin (məsələn, bir dəfəlik PIN — bu, artıq irəli səviyyə ssenariləridir).
Kodda scopes: RequestContext və requireScope
MCP səviyyəsində vahid kontekst tipi saxlamaq rahatdır:
// mcp/context.ts
export interface RequestContext {
userId: string; // kim
tenantId: string; // hansı təşkilat çərçivəsində
scopes: string[]; // tokenə verilmiş səlahiyyətlər
}
// Hüquqların yoxlanması üçün sadə helper
export function requireScope(
ctx: RequestContext,
needed: string
) {
if (!ctx.scopes.includes(needed)) {
throw new Error(`Missing scope: ${needed}`);
}
}
Fərz edilir ki, RequestContext‑i siz tokenin validasiyasından sonra MCP Gateway‑də formalaşdırırsınız: JWT‑ni dekodladınız, imza/vaxt bitməsini yoxladınız, sub, tenant, scope çıxardınız — və sonra bu konteksti bütün alət çağırışlarına əlavə edirsiniz.
Daha sonra tool‑handler‑də:
// mcp/tools/createOrder.ts
import { requireScope, RequestContext } from "../context";
export async function createOrder(
input: CreateOrderInput,
ctx: RequestContext
) {
requireScope(ctx, "orders:write");
// bundan sonra — sifarişin yaradılması məntiqi
}
İndi, model UX‑də gözləmədiyiniz yerdə qəfil createOrder çağırsa belə, orders:write olmadan alət sadəcə icra olunmayacaq.
Alət səviyyəsində securitySchemes
MCP spesifikasiyası hər alət üçün hansı avtorizasiya sxemlərinin və scopes‑un lazım olduğunu göstərməyə imkan verir. Rəsmi nümunələrdə securitySchemes alətin təsvirinə birbaşa qoşulur.
Şərti nümunə:
// mcp/server.ts
server.registerTool(
"createOrder",
{
title: "Create order",
description: "Creates a new order for current user",
inputSchema: {/*...*/},
securitySchemes: [
{ type: "oauth2", scopes: ["orders:write"] }
]
},
async ({ input }, ctx: RequestContext) => {
requireScope(ctx, "orders:write");
// ...
}
);
Burada iki səviyyəli müdafiə var:
- deklarativ: ChatGPT bilir ki, bu alət üçün orders:write lazımdır və hüquqlar olmadıqda auth axınını başladacaq (və ya bunun haqqında istifadəçiyə məlumat verəcək);
- imperativ: real əməliyyatdan əvvəl kodunuz hər şeyi bir daha yoxlayır.
Token varsa, amma scopes çatmırsa, server WWW-Authenticate ilə səhv qaytarmalıdır: Bearer error="insufficient_scope", scope="orders:write" — və ChatGPT istifadəçidən hüquqların genişləndirilməsini tələb edə biləcək (step‑up authorization).
Insight
Rəsmi nümunələrdə securitySchemes istifadə olunur. O, ChatGPT Apps SDK nümunələrində göstərildiyi formada hələ rəsmi spesifikasiyada təsdiqlənməyib. Buna görə onu rəsmi protokolun genişlənməsi kimi qeyd etmək lazımdır — _meta içinə bükmək. Yuxarıdakı nümunənin işlək variantı:
// mcp/server.ts
server.registerTool(
"createOrder",
{
title: "Create order",
description: "Creates a new order for current user",
inputSchema: {/*...*/},
_meta: { // məhz belə
securitySchemes: [
{ type: "oauth2", scopes: ["orders:write"] }
]
}
},
async ({ input }, ctx: RequestContext) => {
requireScope(ctx, "orders:write");
// ...
}
);
5. Per‑tool icazələr və “təhlükəli” alətlər
Scopes “bu auth_token prinsipcə nə edə bilər” sualına cavab verir. Amma tokenin daxilində modelin istifadə edə biləcəyi alətlərin siyahısı da var. Onları da diqqətlə layihələşdirmək lazımdır.
Alətlərin təsnifatı
Şərti olaraq alətləri belə bölək:
- informasiya xarakterli (informational / read‑only): məlumat oxuyur, hesabatlar qurur, yan təsir olmadan nələrisə hesablayır;
- əməliyyat aparan (consequential): vəziyyəti dəyişir, pul tutur, bir şeyləri silir.
ChatGPT Apps sənədlərində read‑only alətləri açıq şəkildə təhlükəsiz kimi qeyd etmək, təhlükəli olanları isə nəticələrini izah etməklə və əlavə UX təsdiqləri ilə təchiz etmək tövsiyə olunur.
Bunu etmək olar:
- alətə annotasiyalar vasitəsilə (məsələn, readOnlyHint, destructiveHint kimi sahələr);
- mətn təsviri vasitəsilə: “Bu alət sifarişləri geri dönmədən silir”;
- confirmation_required adlı ayrıca bayraq vasitəsilə ki, App planınız dialoqa təsdiq addımı daxil etsin.
Kritik əməliyyatlar üçün UX təsdiqləri
Məsələn, GiftGenius‑da chargeCustomer aləti var (vəsaitin tutulmasını başladır). Təbii ki, modelin bunu istifadəçinin razılığı olmadan çağırmasını istəmirsiniz.
App planı səviyyəsində bu belə görünə bilər:
// app/plan/tools.ts (psevdo-kod)
export const tools = [
{
name: "giftgenius.list_catalog",
description: "Hədiyyə kataloqunu göstər",
annotations: { readOnlyHint: true }
},
{
name: "giftgenius.create_order",
description: "Ödənişsiz sifariş yarat",
annotations: { consequential: true }
},
{
name: "giftgenius.charge_customer",
description: "Sifariş üçün vəsaiti tut",
annotations: {
consequential: true,
destructiveHint: true,
confirmationRequired: {
title: "Kartdan vəsait tutulsun?",
message: "N sifarişi üzrə ödəniş icra olunacaq."
}
}
}
];
Sahələrin konkret adları SDK versiyasından asılıdır, ancaq ideya tövsiyələrlə üst‑üstə düşür: read‑only alətləri təhlükəsiz kimi, təhlükəli alətləri isə açıq təsvir və mütləq təsdiq tələb edən kimi qeyd edirik.
Daha sonra vidcetiniz belə reaksiya verə bilər: model charge_customer çağırmağı təklif edərsə, siz istifadəçiyə anlaşıqlı mətnlə modal pəncərə göstərib yalnız “Təsdiqlə” düyməsindən sonra real tool‑call edirsiniz.
Vidcetin sadələşdirilmiş komponent nümunəsi:
// widget/components/ConfirmCharge.tsx
export function ConfirmCharge(props: {
orderId: string;
onConfirm: () => void;
}) {
return (
<div>
<p>{props.orderId} sifarişi üzrə vəsait tutulsun?</p>
<button onClick={props.onConfirm}>
Bəli, ödənişi təsdiqlə
</button>
</div>
);
}
Model “ödəmək vaxtıdır” ideyasını başladır, amma son düyməni insan basır. Bu da təhlükəsizlikçilərin sevdiyi human‑in‑the‑loop deməkdir.
Yalnız agentlər/back‑office üçün alətlər
Daha bir yayğın hal: yalnız agentlər (Agents SDK mənasında) və ya daxili adminlər istifadə edə bilən, “adi” ChatGPT App istifadəçisi üçün nəzərdə tutulmayan alətləriniz var.
Məsələn, rebuildSearchIndex və ya syncCatalogFromERP. Onları daha yaxşıdır:
- adi App üçün ümumi tools siyahısına daxil etməmək;
- ayrı agent/orçestratora konfiqurasiya etmək;
- ayrı scopes və bəlkə də ayrıca Auth konturu ilə qorumaq.
Onları sadəcə App‑in əlçatan alətlər siyahısına əlavə etsəniz, modelin qəfil “Gəlin indi indeksi yenidən quraq, bəlkə hədiyyə tapmağa kömək edər” demək riski artır.
6. Şəbəkə seqmentasiyası və etibar sərhədləri
Hüquqlar təkcə token üzərindəki scopes deyil. İkinci böyük ox — şəbəkənin və xidmətlərin seqmentasiyasıdır.
İdeal mənzərə:
- backend üçün cəmi bir publik giriş var — MCP Gateway/Edge API;
- PII və pul saxlayan hər şey private network/VPC‑də yaşayır və yalnız bu şlüz vasitəsilə əlçatandır;
- backend‑dən çıxan trafik (outbound) icazəli domenlər siyahısı ilə məhdudlaşdırılıb (allowlist: ödəniş xidməti, CRM, öz mikroservisləriniz).
Sxematik olaraq:
flowchart LR ChatGPT -- HTTPS --> Edge[API Gateway / MCP Endpoint] Edge -- private network --> MCP[MCP server] MCP -- private --> DB[(PII‑li DB)] MCP -- private --> SVC[Internal microservices] MCP -- HTTPS (allow) --> Stripe[Payments API]
Burada bir neçə qayda önəmlidir:
- DB və daxili xidmətlər birbaşa internetə çıxmır. Onlara birbaşa giriş yalnız private şəbəkədən və həqiqətən ehtiyacı olan servislərdən mümkündür.
- Edge/Gateway auth və rate‑limiting tətbiq edir. Məhz o, tokeni və scopes‑u yoxlayır, həddən artıq tez‑tez sorğuları kəsir və əsas audit loglarını yazır.
- Egress nəzarəti. MCP server internetdə istənilən URL‑ə gedə bilməməlidir (SSRF hücumları, məlumat sızmaları). Xarici hostların siyahısını açıq şəkildə məhdudlaşdırmaq yaxşıdır.
Praktikada MCP‑ni Vercel, Render və ya Kubernetes klasterində deploi edirsinizsə, bu şeylərin bir qismini əl ilə sazlamırsınız, amma hətta orada da aşağıdakıları ayırmaq olar:
- dev/staging/prod üçün ayrı layihələr/klasterlər;
- hər mühit üçün fərqli mühit dəyişənləri və açarlar;
- ayrı “edge” xidmət (MCP üçün HTTP örtük) və ayrı private xidmətlər.
Nəticədə iki müdafiə oxumuz var: token üzərində hüquqlar (scopes) və şəbəkə sərhədləri. Onlara daha birini — eyni App‑in bir neçə təşkilata xidmət göstərdiyi multi‑tenant rejimini — əlavə edək.
7. Multi‑tenant / təşkilati kontekst
İndiyə qədər zehni olaraq bir istifadəçi ilə işləyirdik. Amma bir çox ChatGPT tətbiqləri multi‑tenantdır: eyni App onlarla şirkətə xidmət edir. GiftGenius‑u asanlıqla korporasiyalar üçün B2B xidmətinə çevirmək olar: hər şöbənin öz kataloqu, büdcəsi, sifarişləri var.
Tenant nədir və onu haradan götürməli
Tenant adətən bunlardan biridir:
- təşkilat/şirkət (Acme Corp);
- iş məkanı (workspace);
- bəzən layihə və ya mühit.
Əsas xüsusiyyət: bir tenantın məlumatları digəri tərəfindən görünməməlidir.
Auth axınında tenant adətən aşağıdakılara qoyulur:
- token claim‑inə (tenant, org_id);
- avtorizasiya sorğusundakı ayrıca parametrə (amma bu, IdP tərəfindən imzalanmış claim qədər etibarlı deyil).
Vacibdir: yalnız yoxlanmış token‑dən gələn tenantId‑yə etibar edirik, alət arqumentlərinə yox. Model {"tenantId": "acme"} yaratsa da, istifadəçinin tokenində tenantId: "globex"dirsə, bunu sındırma cəhdi kimi qəbul etməliyik.
Sorğu kontekstində tenant
tenantId‑ni bizim RequestContext‑ə əlavə edək (yuxarıda artıq etdik) və onu giriş məlumatlarından yenidən təyin etməyə icazə verməyək.
Baza yoxlama:
// mcp/tenant.ts
import { RequestContext } from "./context";
export function enforceTenant<TInput>(
input: TInput & { tenantId?: string },
ctx: RequestContext
) {
if (input.tenantId && input.tenantId !== ctx.tenantId) {
throw new Error("Tenant mismatch");
}
return { ...input, tenantId: ctx.tenantId };
}
Sonra alətdə:
// mcp/tools/listOrders.ts
export async function listOrders(
input: { limit?: number; tenantId?: string },
ctx: RequestContext
) {
const safe = enforceTenant(input, ctx);
return db.order.findMany({
where: { tenantId: safe.tenantId },
take: safe.limit ?? 20
});
}
Arqumentlərdən gələn tenantı görməməzliyə vururuq və onu kontekstdən sərt şəkildə yerinə qoyuruq. Beləcə, LLM və ya hücumçu “başqasının” tenantını “soxuşdurmağa” çalışsa belə, heç nə alınmayacaq.
DB səviyyəsində tenant izoliyasiyası
Memarlıq baxımından müxtəlif variantlar var:
- tenant başına ayrıca DB;
- ayrı sxemlər;
- hər cədvəldə tenant_id olan bir DB və sərt filtrasiya.
Hansı varianta üstünlük versəniz də, qızıl qayda eynidir: heç bir DB sorğusu tenant_id kontekstdən gələn dəyərə görə filtrasiya olunmadan icra edilməməlidir. Xüsusən RAG/vektor axtarışında önəmlidir: tenant filtrini unutsaq, model başqa təşkilatların sənədləri üzrə axtarış edə bilər.
8. Bu, bizim Next.js/Apps SDK tətbiqimizlə necə bağlanır
İndi isə bütün bunları birləşdirib baxaq ki, scopes, tenant və şəbəkə sərhədləri Next.js üzərində Apps SDK layihəmizə necə tətbiq olunur. Gəlin daha konkret olaq və Next.js və Apps SDK koduna baxaq.
Layihəmizdə scopes və tenant harada yaşayır
Tipik tədris layihəsi üçün düzən:
- Next.js tətbiqində (Apps SDK) App/konnektor konfiqi və OAuth callback səhifələri var.
- MCP serverində — ChatGPT‑dən gələn HTTP/SSE sorğularını qəbul edən, tokeni yoxlayan və lazım olan aləti çağıran kod var.
Danışdıqlarımızı ora köçürək:
- MCP resursunun OAuth sazlamalarında GiftGenius üçün scopes_supported elan edirik (catalog:read, orders:write və s.).
- Apps SDK konfiqində alətləri və onların annotasiyalarını (read‑only, consequential, confirmation‑flows) sadalayaraq App‑i təsvir edirik.
- MCP serverində həyata keçiririk:
- tokenin parsinqini və yoxlanmasını;
- RequestContext formalaşdırılmasını: { userId, tenantId, scopes };
- requireScope, enforceTenant və s. helperləri;
- DB çağırışlarını həmişə kontekstdən gələn tenantId ilə.
Sifariş yaradılması üçün “izolyasiya olunmuş” yol nümunəsi
Gəlin bir end‑to‑end ssenarini izləyək.
- İstifadəçi yazır: “Bu dəst üçün 50$ büdcə ilə sifariş et”.
- Model giftgenius.create_order alətini { productId, budget, ... } arqumentləri ilə çağırmaq lazım olduğuna qərar verir.
- ChatGPT yoxlayır: App‑də create_order aləti varmı, onun üçün hansı scopes və securitySchemes yazılıb. Başa düşür ki, orders:write lazımdır.
- Token artıq varsa və orders:write saxlayırsa, sorğu irəli gedir; yoxdursa — ChatGPT lazım olan scope ilə OAuth avtorizasiyasını başladır.
- MCP Gateway sorğunu qəbul edir, tokeni yoxlayır, RequestContext formalaşdırır: userId=123, tenantId="acme", scopes=["catalog:read","orders:write",...].
- MCP daxilində createOrder:
- requireScope(ctx, "orders:write") edir;
- enforceTenant vasitəsilə tenantı fiks edir;
- yalnız tenantId="acme" çərçivəsində sifariş yaradır.
- Əgər sifariş dərhal ödəniş tələb edirsə, model və ya backend charge_customer alətini başladır, burada:
- alət planda confirmationRequired kimi qeyd olunub;
- vidcet ConfirmCharge render edir və istifadəçidən açıq şəkildə təsdiq istəyir.
Beləliklə, dərin müdafiəni qazanırıq: həddən artıq geniş promptlar, prompt‑inyeksiyaları və ya hətta UX‑dəki bug‑lar nəzarətsiz hərəkətlərə gətirməyəcək, çünki piramidanın dibində yenə də sərt scopes, tenant yoxlamaları və kritik əməliyyatlar üçün əl ilə təsdiqlər dayanır.
9. Hüquqların və seqmentasiyanın layihələşdirilməsində tipik səhvlər
Səhv №1: Aşağıdakı kimi bir qalın scope app:full_access.
Bu yanaşma demo üçün rahatdır, prodakşnda təhlükəlidir. Bir token itdi — hər şey itdi. Ayrı bir əməliyyatı dayandırmadan və ya geri çağırmadan digərlərini sındırmadan məhdudlaşdıra bilməzsiniz. Hüquqları domenlərə və əməliyyat tiplərinə görə bölün (read/write/critical).
Səhv №2: Hüquqları yalnız “girişdə” yoxlamaq, alətlərin içində yoxlamamaq.
Bəzən belə edirlər: “ChatGPT token aldısa, demək artıq hər şeyi bacarır”. Sonra createOrder aləti sadəcə çağırılır, halbuki bu konkret token üçün orders:write verilməyib. Düzgün yanaşma — scopes‑u hər alətdə yoxlamaqdır (və ya ən azı bütün mutasiya edən əməliyyatlar üçün mərkəzləşdirilmiş middleware ilə).
Səhv №3: Təhlükəli alətləri işarələməmək və təsdiq tələb etməmək.
Əgər alət pul tutur, məlumatları silir və ya girişləri dəyişirsə, o, model üçün listCatalog kimi eyni görünməməlidir. Aydın annotasiyaların və UX təsdiqlərinin olmaması modelin onu “məntiqə uyğundur” deyə çağırma ehtimalını artırır. Ən azı read‑only və destructive alətləri ayırın və ikinciləri açıq şəkildə işarələyin.
Səhv №4: Alət arqumentlərindən gələn tenantId dəyərinə etibar etmək.
Çox yayğın anti‑pattern: getOrders({ tenantId }) aləti, burada tenantId modeldən gəlir. Onu olduğu kimi istifadə etsəniz, tenantA‑dan olan istifadəçi sadəcə başqa identifikator yazmaqla tenantB məlumatlarına çıxış əldə edə bilər. Tenant yoxlanmış tokendən gəlməli və bütün DB və xarici xidmət sorğularına tətbiq olunmalıdır, istifadəçi dəyərləri isə ya görməməzliyə vurulmalı, ya da uyğunluq üçün yoxlanmalıdır.
Səhv №5: MCP/DB birbaşa internetdən əlçatan olur.
Bəzən sadə prototiplərdə MCP serveri və DB internetdə açıq HTTP/5432 ilə görünür. Prod mühitində belə olmaz: bütün giriş bir qorunan gateway/proxy üzərindən getməlidir və DB private şəbəkədə yaşamalıdır. Əks halda, istənilən zəif endpoint və ya deşikli webhook — məlumatlara birbaşa yol deməkdir.
Səhv №6: Dev və prod üçün eyni scopes/secretlərdən istifadə.
Lokal dev demo zamanı prod məlumatlarının gözlənilmədən silinməsinin sevimli yolu. Hər mühit üçün ayrıca açarlar, scopes və DB olmalıdır. Kimsə dev tokeninə çıxış əldə etsə belə, prod məlumatlarına zərər verə bilməz.
Səhv №7: Modele “imtina etməkdən” çəkinmək.
Bəzən tərtibatçılar narahat olur: “Əgər mən tez‑tez insufficient_scope və ya forbidden qaytarsam, model daha pis işləyəcək”. Praktikada bu normal və gözlənilən davranışdır: model hansı hərəkətlərin əlçatan, hansının əlavə hüquq və ya təsdiq tələb etdiyini “öyrənir”. Daha pisi odur ki, o, etməməli olduğu şeyi “uğurla” edir — məsələn, ikinci dəfə ödəniş aparır.
GO TO FULL VERSION