CodeGym /Kurslar /ChatGPT Apps /MCP Server-i qorunan resurs kimi tənzimləmə:

MCP Server-i qorunan resurs kimi tənzimləmə: .well-known, Bearer, audience/scope

ChatGPT Apps
Səviyyə , Dərs
Mövcuddur

1. MCP Server Resource Server kimi: nəyi dəqiq tənzimləyirik

Ötən dərsdə biz Auth Server-i — token verən komponenti — tənzimləyirdik. İndi isə bu cütün ikinci tərəfi ilə məşğul olacağıq: bu tokenləri qəbul edib yoxlayan Resource Server kimi MCP‑server.

OAuth 2.1 nöqteyi-nəzərindən sizin MCP serveriniz — Resource Server-dir. O, “resursları” (MCP alətləri, istifadəçi məlumatları) saxlayır və başlıqda access‑token olan sorğuları Authorization: Bearer ... qəbul edir. Tool-u icra etməzdən əvvəl o, tokenin həqiqi olduğunu, vaxtının bitmədiyini, etibarlı avtorizasiya serveri (Auth Server) tərəfindən verildiyini və məhz bu MCP server üçün nəzərdə tutulduğunu, üstəlik lazımi səlahiyyətlərə (scope) malik olduğunu yoxlamalıdır.

İki səviyyəni ayırmaq vacibdir:

  1. Transportun səviyyəsi — burada HTTP başlıqları və tokenlər işlənir. Burada siz:
    • Authorization: Bearer qəbul edib/parslayırsınız,
    • token olmadıqda/səhv olduqda 401 UnauthorizedWWW-Authenticate: Bearer ... qaytarırsınız,
    • düzgün token olduqda istifadəçi kontekstini formalaşdırırsınız.
  2. MCP SDK səviyyəsi, hansı ki, ümumiyyətlə JWT barədə bilməyə borclu deyil. O, sadəcə “artıq autentifikasiya olunmuş” çağırış alır və handler daxilində ctx.userId, ctx.scopes və s.-dən istifadə edə bilər.

Bənzətmə: MCP SDK — mətbəxdə aşpazdır, OAuth‑middleware isə girişdə mühafizəçidir. Aşpaz pasport yoxlamır, o sadəcə sifarişləri hazırlayır.

Tədris nümunəsi kimi GiftGenius-u davam etdirək: http://localhost:3000 ünvanında MCP server list_my_gifts aləti ilə və Auth Server (məsələn, Keycloak və ya öz kiçik AS-iniz) http://localhost:4000-da.

2. .well-known/oauth-protected-resource: MCP resursunuzun “vizit kartı”

Resurs üçün .well-known nə üçündür

ChatGPT (və ya MCP Jam) ilk dəfə MCP serverinizə müraciət edib 401 aldıqda, iki şeyi başa düşməlidir:

  • tokeni haradan almaq lazımdır;
  • bu resurs ümumiyyətlə hansı hüquqları dəstəkləyir.

Bunların hamısını müştərilərə “hardkod” etməmək üçün discovery endpoint istifadə olunur:

GET /.well-known/oauth-protected-resource

Bu endpoint RFC 9728-ə uyğun qorunan resursun metadatası (Protected Resource Metadata) olan JSON qaytarır.

GiftGenius-dan nümunə:

{
  "resource": "http://localhost:3000",
  "authorization_servers": ["http://localhost:4000"],
  "scopes_supported": ["gifts:read", "gifts:write"],
  "bearer_methods_supported": ["header"]
}

OpenAI öz təlimatlarında buna çox yaxın nümunəni göstərir, sadəcə HTTPS və real domenlərlə.

Müştəri (ChatGPT/Jam) bu sənədi oxuyur və:

  • tokenin audience-nin http://localhost:3000 olmalı olduğunu anlayır,
  • hansı authorization_servers ilə işləməli olduğunu (issuer URL) anlayır,
  • dəstəklənən scope-ların siyahısını görür (bu, razılıq ekranını və ipuclarını formalaşdırmağı asanlaşdırır).

Metaməlumat sahələrinin izahı

Əsas sahələrin icmalı:

Sahə Təyinat
resource
MCP serverinin kanonik HTTPS/HTTP identifikatoru. Sonradan tokenin aud dəyəri ilə üst-üstə düşür.
authorization_servers
Avtorizasiya serverlərinizin (Auth Server/issuer) URL siyahısı. Müştəri oraya OAuth/OIDC metaməlumatları üçün gedəcək.
scopes_supported
Dəstəklənən scope-lar massivi; müştəriyə yaxşı UX və düzgün token sorğusu üçün lazımdır.
bearer_methods_supported
Tokenin ötürülmə üsulları: adətən ["header"], yəni Authorization: Bearer ....

Əlavə olaraq bəzən resource_documentation, jwks_uri, introspection_endpoint və s. dərc olunur, lakin baza ssenarisi üçün ilk dördü kifayətdir.

Kritik məqam: resource Auth Server-in tokenin aud dəyərinə qoyduğu ilə üst-üstə düşməlidir. Əks halda — MCP müştərisi (və siz) tokeni rədd edəcək.

Next.js 16-da .well-known reallaşdırması

Tutaq ki, MCP serverimiz Next.js tətbiqində (Apps SDK backend, port 3000) işləyir. Ən sadə yol — route handler yazmaq: app/.well-known/oauth-protected-resource/route.ts:


// app/.well-known/oauth-protected-resource/route.ts
import { NextResponse } from "next/server";

export async function GET() {
  const body = {
    resource: "http://localhost:3000",
    authorization_servers: ["http://localhost:4000"],
    scopes_supported: ["gifts:read", "gifts:write"],
    bearer_methods_supported: ["header"],
  };

  return NextResponse.json(body);
}

Production-da resource MCP serverinizin prod mühitindəki HTTPS URL-i olmalıdır (məsələn, https://mcp.giftgenius.com) və IdP-dən gələn tokenlərdəki aud ilə üst-üstə düşməlidir.

3. WWW-Authenticate401: MCP “token lazımdır” xəbərini necə verir

Artıq resurs üçün .well-known/oauth-protected-resource “vizit kartı”nı hazırladıq. İndi baxaq, MCP server bunun arxasınca getməyin lazım olduğunu müştəriyə necə bildirir — 401WWW-Authenticate başlığı vasitəsilə.

Baza ssenari: token olmadan gəldi

Təsəvvür edək ki, ChatGPT ilk dəfə list_my_gifts alətini çağırır. Şəbəkə sorğusu təxminən belə görünür:

GET /mcp/tools/list_my_gifts HTTP/1.1
Host: localhost:3000

Token yoxdur. MCP server səssizcə 403 və ya hər hansı HTML səhifəsi verməməlidir. OAuth dünyasında qorunan resursun düzgün davranışı — 401 Unauthorized qaytarmaq və WWW-Authenticate başlığı vasitəsilə müştəriyə necə autentifikasiya olunacağını izah etməkdir.

Düzgün cavab nümunəsi:

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer resource_metadata="http://localhost:3000/.well-known/oauth-protected-resource", scope="gifts:read"
Content-Type: application/json

{"error":"unauthorized","error_description":"Missing or invalid access token"}

Vacib detallar:

  • Bearer sxemi OAuth Bearer token istədiyimizi bildirir;
  • resource_metadata parametri .well-known/oauth-protected-resource URL-ni göstərir;
  • scope parametri minimal tələb olunan hüququ göstərir (məsələn, gifts:read).

MCP Jam və ChatGPT bu başlığı oxumağı bacarır. Onu görən kimi:

  1. .well-known/oauth-protected-resource-u çağıracaqlar.
  2. authorization_servers üzrə Auth Server-i və onun OpenID/OAuth metaməlumatlarını tapacaqlar.
  3. Authorization Code + PKCE axınını işə salacaq, istifadəçiyə giriş səhifəsini açacaq və token alacaqlar.

Yəni WWW-Authenticate — bu, trigger-dir: onsuz müştəri burada OAuth olduğunu belə anlamaq bilmir.

401 cavabları üçün middleware (Next.js)

Bütün qorunan endpoint-lərdə istifadə olunacaq kiçik utilit yazaq. Əvvəlcə — cavabı formalaşdıran funksiya:

// lib/authResponses.ts
import { NextResponse } from "next/server";

export function unauthorized(scope?: string) {
  const wwwAuth = [
    `Bearer resource_metadata="http://localhost:3000/.well-known/oauth-protected-resource"`,
    scope ? `scope="${scope}"` : null,
  ]
    .filter(Boolean)
    .join(", ");

  return new NextResponse(
    JSON.stringify({
      error: "unauthorized",
      error_description: "Missing or invalid access token",
    }),
    {
      status: 401,
      headers: {
        "WWW-Authenticate": wwwAuth,
        "Content-Type": "application/json",
      },
    }
  );
}

İndi istənilən marşrut (məsələn, bizim MCP endpoint) sadəcə return unauthorized("gifts:read") deyə bilər və müştəri düzgün challenge alacaq. unauthorized() funksiyası NextResponse obyektini (standart Response ilə uyğun) qaytarır. Növbəti nümunələrdə bəzən bu obyekti istisna kimi atacağıq və route handler-lərdə məhz Response-u tutacağıq ki, hər route-da 401 cavabının formalaşdırılmasını təkrarlamayaq.

4. Bearer token-in qəbulu və yoxlanması

İndi ən maraqlısı: Bearer tokeni necə qəbul edib yoxlamaq.

Yoxlama harada aparılmalıdır

MCP transportu çox güman ki, sizdə ya:

  • Next.js route handler-də (app/mcp/route.ts) reallaşdırılıb, o, POST qəbul edir və sonra MCP SDK-ya yönləndirir;
  • Express/Fastify serverində, hansı ki, /mcp dinləyir və JSON-u MCP handler-ə ötürür.

Bu variantların hamısında məhz HTTP qatı aşağıdakıları etməlidir:

  1. başlıqdan Authorization-u götürmək;
  2. o olmadıqda/səhv olduqda bizim unauthorized vasitəsilə 401 qaytarmaq;
  3. uğur olduqda — kontekst obyektini (userId, scopes, roles) formalaşdırmaq və onu MCP SDK-ya (handler arqumentləri/kontekst vasitəsilə) ötürmək.

MCP SDK (məsələn, @modelcontextprotocol/sdk) ümumiyyətlə JWT-in nə olduğunu bilməyə də bilər. Bu, sizin məsuliyyət sahənizdir.

Yoxlama variantları: JWT və ya introspection

İki əsas üslub var:

  1. Auth Server-in JWK açarlarından istifadə edərək JWT tokenin imzasını və claim-lərini lokalda yoxlamaq.
  2. Avtorizasiya serverinin /introspect endpoint-nə gedib soruşmaq: “Bu token hələ etibarlıdırmı? Onun scope-ları hansılardır?”.

Bu dərsdə biz belə qəbul edəcəyik ki, Auth Server JWT verir və jwks_uri dərc edir, MCP server isə imzanı və claim-ləri lokalda yoxlayır (bu, daha sürətli və avtonomdur).

verifyAccessToken utiliti (TypeScript)

Məşhur jose (ESM‑friendly) kitabxanasından istifadə edək. Təxminən belə bir helper lazımdır:

// lib/verifyAccessToken.ts
import { jwtVerify, createRemoteJWKSet } from "jose";

const JWKS = createRemoteJWKSet(
  new URL("http://localhost:4000/.well-known/jwks.json")
);
const EXPECTED_ISS = "http://localhost:4000";
const EXPECTED_AUD = "http://localhost:3000";

export async function verifyAccessToken(token: string) {
  const { payload } = await jwtVerify(token, JWKS, {
    issuer: EXPECTED_ISS,
    audience: EXPECTED_AUD,
  });

  return {
    sub: String(payload.sub),
    scopes: String(payload.scope || "").split(" ").filter(Boolean),
    raw: payload,
  };
}

Bu helper-də biz:

  • Auth Server-dən jwks_uri üzrə JWK açarlarını yükləyirik;
  • imzanı və standart claim-ləri (iss, aud) yoxlayırıq;
  • sub (istifadəçi id) və scope-u çıxarırıq (sətir boşluqla ayrıldığı üçün split(" ") edirik).

audience bizim .well-known/oauth-protected-resource-dakı resource ilə üst-üstə düşməlidir; bu da tokenin məhz bizim MCP serverimiz üçün verildiyinə zəmanət verir.

Authorization başlığının sadə yoxlanması

İndi başlıqdan tokeni götürüb verifyAccessToken üzərindən keçirəcək kiçik helper yaradaq:

// lib/getUserFromRequest.ts
import type { NextRequest } from "next/server";
import { unauthorized } from "./authResponses";
import { verifyAccessToken } from "./verifyAccessToken";

export async function getUserFromRequest(req: NextRequest) {
  const auth = req.headers.get("authorization") || "";
  const [, token] = auth.split(" ");

  if (!token) throw unauthorized("gifts:read");

  try {
    return await verifyAccessToken(token);
  } catch {
    throw unauthorized("gifts:read");
  }
}

Diqqət edin: burada biz unauthorized(...) (yəni Response obyektini) istisna kimi atırıq ki, route handler-də onu rahatlıqla tutaq və cavab kimi qaytaraq.

5. audience və scope: tokenin resursa və əməliyyatlara bağlanması

Audience (aud): token “kimə” yazılıb

aud claim-i belə suala cavab verir: token bu resursa məxsusdumu? Bizim halda:

  • Auth Server tokenin aud dəyərini http://localhost:3000 kimi qoyur;
  • bizim .well-known/oauth-protected-resource resource: "http://localhost:3000" dərc edir;
  • verifyAccessToken bunun belə olduğunu yoxlayır.

Əgər token başqa resurs üçün nəzərdə tutulubsa (məsələn, https://api.other-app.com), MCP serveriniz onu “mənə ünvanlanmayıb” deyərək rədd etməlidir.

Tipik səhv — resourceaud sinxronizasiyasını unutmaq; nəticədə hər şey qurulmuş kimi görünür, amma ChatGPT daima 401 alır. Buna “Tipik səhvlər” blokunda qayıdacağıq.

Scopes: “nələri” etmək olar

Tokenin scope claim-i — müştərinin istifadəçidən aldığı səlahiyyətlərin siyahısıdır. Bizim nümunədə:

  • gifts:read — öz hədiyyələrini oxumaq hüququ;
  • gifts:write — hədiyyələri yaratmaq/yeniləmək hüququ.

Bu dəyərlər .well-known/oauth-protected-resource-da scopes_supported kimi görünür ki, müştəri əvvəlcədən nələri tələb edə biləcəyini bilsin.

Avtorizasiya serveri öz discovery sənədində (.well-known/openid-configuration) də scopes_supported dərc edir, amma bu, artıq IdP-nin qlobal scope-lar siyahısıdır (onu .well-known/oauth-protected-resource resurs serveri ilə qarışdırmayın).

Bu iki siyahını qarışdırmayın: resursun scopes_supported-u məhz sizin MCP serverinizə lazım olan hüquqları təsvir edir, IdP-nin scopes_supported-u isə provayderdəki qlobal scope “kataloqu”dur. Müştəri adətən bu iki dünyanın kəsişməsini götürür.

MCP server səviyyəsində etməli olduqlarınız:

  • hər alət üçün hansı scope-ların tələb olunduğunu müəyyənləşdirmək;
  • alət hər çağırıldıqda tokenin bu scope-ları ehtiva etdiyini yoxlamaq.

Helper yazaq:

// lib/requireScope.ts
import { unauthorized } from "./authResponses";

export function requireScope(
  user: { scopes: string[] },
  needed: string[]
) {
  const hasAll = needed.every((s) => user.scopes.includes(s));
  if (!hasAll) throw unauthorized(needed.join(" "));
}

İndi requireScope(user, ["gifts:read"]) funksiyasını aləti icra etməzdən əvvəl çağıra bilərik.

6. MCP alətləri ilə birləşdirmə: token-dən list_my_gifts

Next.js-də MCP marşrutu

Təsəvvür edək ki, HTTP sorğularını işləyə bilən hər hansı SDK bazasında MCP serverimiz var. Next.js baxımından bu təxminən belə görünə bilər:

// app/api/mcp/route.ts
import { NextRequest } from "next/server";
import { unauthorized } from "@/lib/authResponses";
import { getUserFromRequest } from "@/lib/getUserFromRequest";
import { mcpServer } from "@/lib/mcpServer";

export async function POST(req: NextRequest) {
  try {
    const user = await getUserFromRequest(req);

    const body = await req.json();
    const result = await mcpServer.handle(body, { user });

    return Response.json(result);
  } catch (err) {
    if (err instanceof Response) return err; // unauthorized(...)
    console.error(err);
    return unauthorized();
  }
}

Burada vacib olanlar:

  • istifadəçi və scope-ları tokendən çıxarırıq (getUserFromRequest);
  • onları MCP serverinə { user } konteksti vasitəsilə ötürürük;
  • token olmadıqda/səhv olduqda WWW-Authenticate ilə 401 qaytarırıq.

MCP SDK-nın konkret API-si fərqli ola bilər, amma fikir hər yerdə eynidir: artıq “kimin” müraciət etdiyini bilən middleware-lə MCP çağırışını bükmək.

list_my_gifts aləti scope yoxlaması ilə

Tutaq ki, MCP üçün TypeScript SDK istifadə edirik və belə bir şeyimiz var:

// lib/mcpServer.ts (fraqment)
import { createMcpServer } from "@modelcontextprotocol/sdk";
import { requireScope } from "./requireScope";

export const mcpServer = createMcpServer<{ user: any }>();

mcpServer.registerTool(
  "list_my_gifts",
  {
    title: "List my gifts",
    description: "Shows your saved gift ideas.",
    inputSchema: { type: "object", properties: {}, additionalProperties: false },
  },
  async (_input, ctx) => {
    requireScope(ctx.user, ["gifts:read"]);

    const gifts = await loadGiftsForUser(ctx.user.sub);
    return {
      content: [{ type: "text", text: `Found ${gifts.length} gifts` }],
      structuredContent: { gifts },
    };
  }
);

Üç əsas addım atırıq:

  • əsas kodu icra etməzdən əvvəl gifts:read tələb edirik;
  • istifadəçi identifikatoru kimi ctx.user.sub-dan istifadə edirik (tokendən);
  • yalnız həmin istifadəçinin məlumatlarını qaytarırıq.

Beləliklə, alətiniz “ümumi API” olmaqdan çıxır və fərdiləşdirilir — Auth Server-dən gələn Identity-yə bağlanır.

7. Axının xülasəsi: 401-dən uğurlu çağırışa

Hər şeyi yadda saxlamaq üçün indi qorunan MCP serverinizin reallaşdırdığı axının kiçik sxemini toplayaq.

sequenceDiagram
    participant ChatGPT
    participant MCP as MCP Server (3000)
    participant AS as Auth Server (4000)

    ChatGPT->>MCP: POST /api/mcp (no Authorization)
    MCP-->>ChatGPT: 401 + WWW-Authenticate: Bearer resource_metadata=...

    ChatGPT->>MCP: GET /.well-known/oauth-protected-resource
    MCP-->>ChatGPT: { resource, authorization_servers, scopes_supported }

    ChatGPT->>AS: GET /authorize?scope=gifts:read&resource=...
    AS-->>ChatGPT: redirect with ?code=XYZ

    ChatGPT->>AS: POST /token (code + code_verifier)
    AS-->>ChatGPT: { access_token, scope, ... }

    ChatGPT->>MCP: POST /api/mcp Authorization: Bearer token
    MCP->>MCP: verify JWT (iss, aud, exp, scope)
    MCP-->>ChatGPT: tool result for this user

Auth Server sorğularındakı resource parametrinə diqqət edin: o, tokenin aud dəyərinə köçürülür və .well-known/oauth-protected-resource-dakı resource ilə üst-üstə düşməlidir.

8. curl ilə kiçik praktik yoxlama

Özünüzü yoxlamaq üçün iki sorğunu əl ilə edə bilərsiniz.

Birinci — token olmadan MCP çağırışı cəhdi:

curl -i http://localhost:3000/api/mcp \
  -H "Content-Type: application/json" \
  -d '{"method":"tools/call","params":{"name":"list_my_gifts","arguments":{}}}'

Gözlənilir ki, 401 statusunu və WWW-Authenticate-də resource_metadatascope="gifts:read" görəsiniz.

İkinci — Auth Server-dən alınmış düzgün tokenlə:

curl -i http://localhost:3000/api/mcp \
  -H "Authorization: Bearer abc123" \
  -H "Content-Type: application/json" \
  -d '{"method":"tools/call","params":{"name":"list_my_gifts","arguments":{}}}'

İndi, əgər abc123 — düzgün JWT-dirsə və oradakı iss, aud="http://localhost:3000" doğrudursa və scope gifts:read-i ehtiva edirsə, alətin JSON cavabını alacaqsınız və structuredContent.gifts-də cari istifadəçinin hədiyyələri olacaq.

9. MCP Server-i qorunan resurs kimi tənzimləyərkən tipik səhvlər

Aşağıda — elə indi yazdığımız kodu reallaşdırarkən ən çox rast gəlinən tələlər: .well-known, WWW-Authenticate, token verifikasiyası və scope yoxlanışı.

Səhv №1: resourceaudience sinxron deyil.
Çox vaxt .well-known/oauth-protected-resource-da bir resource dəyəri yazılır, Auth Server isə tokenlərdə başqa aud verir. Nəticədə jwtVerify imza və ömür qaydasında olsa belə tokeni atır. Bu, xüsusilə MCP serverin domen/portunu dəyişəndə və .well-known-u və ya Auth Server konfiqurasiyasını yeniləməyi unutduqda asanlıqla pozulur. Bizim nümunədə bu, resource sahəsində http://localhost:3000 sətiri və verifyAccessToken daxilindəki EXPECTED_AUD üçün eyni sətirdir. Ayrı-ayrı yerlərdə uyğunsuzluq olmasın deyə RESOURCE_ID adlı bir konstanta saxlayıb hər iki yerdə ondan istifadə etmək məsləhətdir.

Səhv №2: WWW-Authenticate olmadan 401.
Bəzən tərtibatçılar sadəcə 401 və ya 403 qaytarırlar, amma WWW-Authenticate başlığını əlavə etmirlər. Brauzer baxımından bu normal ola bilər, amma ChatGPT və MCP Jam token üçün hara getməli olduqlarını və hansı scope-ların lazım olduğunu başa düşməyəcəklər. Nəticədə onlar MCP serverinizi “xarab” sayacaq və istifadəçiyə linkləmə UI-ı göstərməyəcəklər. Tələb olunan minimum: WWW-Authenticate: Bearer resource_metadata=".../.well-known/oauth-protected-resource". Daha şəffaf axın üçün scope="..." da əlavə etmək yaxşıdır. Bizim unauthorized() helper-i məhz 401 zamanı bu başlığın həmişə olmasını təmin edir.

Səhv №3: imza və iss yoxlanmadan tokenə etibar.
Bəzən, xüsusən ilkin mərhələdə cazibə böyükdür: “Axı bu token mənim Auth Server-imdən gəlib, elə JSON.parse(atob(..)) edək vəssalam”. Belə etmək olmaz: o zaman uyğun formatlı istənilən tokeni, hətta saxtanı da qəbul edəcəksiniz. Düzgün yanaşma — jwks_uri üzrə açarları yükləmək və imzanı, iss/aud-u kitabxana (jose, jsonwebtoken və s.) vasitəsilə yoxlamaqdır. Yalnız bundan sonra claim məzmununa etibar etmək olar.

Səhv №4: token yoxlamasını biznes məntiqi ilə qarışdırmaq.
Bəzən token yoxlaması alətlərin kodu boyunca “yayılır”: bir alət scope yoxlayır, digəri — yox, haradasa aud yoxlamaq yaddan çıxır, haradasa isə istifadəçi id ümumiyyətlə tool arqumentindən götürülür. Bu, çox qəribə xətalara və potensial boşluqlara səbəb olur. Daha yaxşısı aydın bölgü saxlamaqdır: HTTP səviyyəsindəki middleware tokenlə məşğul olur (imza, iss, aud, ömür), alətdə isə artıq ctx.user-i “həqiqət” kimi götürüb yalnız biznes yoxlamaları ilə (məsələn, rol/tenant) tamamlayırsınız.

Səhv №5: scopes_supported ilə real istifadə olunan scope-ların uyğunsuzluğu.
Daha bir məşhur hal: /.well-known/oauth-protected-resource-da bir scope dəsti dərc edirsiniz, Auth Server-də — başqa, alətlərdə isə üçüncüsünü yoxlayırsınız. ChatGPT/MCP Jam avtorizasiya sorğusunu dərc etdiyiniz scopes_supported-a əsasən formalaşdırır, sizin server isə sonra gərəkli scope yoxdur deyə narazılıq edir. Scope-ları minimuma endirməyə çalışın və onları “vahid həqiqət” kimi idarə edin — məsələn, TypeScript-də enum vasitəsilə; bu enum həm .well-known generasiyasında, həm də Auth Server-də müştərilərin sazlanmasında istifadə olunsun.

Səhv №6: yalnız Apps SDK securitySchemes-ə güvənmək və server tərəfdə yoxlamanı unutmaq.
Apps SDK alətlər üçün securitySchemes təsvir etməyə imkan verir (noauth, oauth2, scope-lar) və ChatGPT istifadəçiyə düzgün UX göstərəcək. Amma bu annotasiyalar serveri avtomatik etibarlı etmir. Hətta alət OAuth token tələb etdiyini elan etsə belə, MCP serveriniz hər sorğuda tokeni, issuer-i, audience-i və scope-ları yoxlamağa borcludur. Əks halda, sadəcə MCP URL-ə birbaşa sorğu göndərməklə yoxlamaları keçmək mümkün ola bilər.

Səhv №7: tokenlərin qısa ömrünü və bitmə işlənməsini unutmaq.
Əgər access token-lər həddindən artıq uzun yaşayırsa, təhlükəsizlik azalır; əgər çox qısadırsa, amma server bitmə halını düzgün idarə etmirsə, istifadəçi daim xətalara rast gələcək. Düzgün model — qısaömürlü access token və exp artıq keçmişdə olduqda MCP serverinin WWW-Authenticate ilə 401 qaytarmağa hazır olmasıdır. Müştəri (ChatGPT) bu zaman OAuth axınını təkrarlayıb tokeni yeniləyəcək.

Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION