CodeGym /Kurslar /ChatGPT Apps /Mövcud məhsula ChatGPT App-in inteqrasiyası və SDK/MCP mi...

Mövcud məhsula ChatGPT App-in inteqrasiyası və SDK/MCP miqrasiyaları

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

1. Niyə ümumiyyətlə inteqrasiya və miqrasiyalardan danışırıq

İndiyədək API və alətləri əsasən özümüzə uyğun layihələndirirdik. Real həyatda isə demək olar ki, həmişə əksinə olur: artıq sizdə bunlar var:

  • monolit və ya bir dəstə mikroservis;
  • REST/GraphQL API;
  • illərlə prod-da işləyən biznes məntiqi.

Birdən bir tapşırıq gəlir: “Məhsulumuzu Apps SDK və MCP vasitəsilə ChatGPT-yə qoşun”.

Hər şeyi “ideal MCP serveri”nə yenidən yazmaq — seçim deyil. Mövcud dünyanızın üzərinə diqqətli şəkildə nazik bir qat “geyinmək” lazımdır ki, backend-inizin dilini ChatGPT dilinə çevirsin: alətlər, resurslar və sxemlər.

İkinci problem: məhsul canlıdır. Sxemlər və API dəyişir. Adi frontend-də sahəni dəyişəndə ən azından dərhal TypeScript xətası alırsınız. LLM‑Apps dünyasında isə hər şey daha hiyləgərdir: model inamla köhnə formatı göndərməyə davam edəcək, alət yıxılacaq və compile zamanı səliqəli fail əvəzinə siz bunları alacaqsınız:

  • MCP serverində runtime xətaları;
  • “mən təxminən başa düşdüm, bu sahədən nə istəyirdiniz” tipli hallusinasiya;
  • keyfiyyət insidentləri.

Ona görə də bu mühazirədə MCP+Apps qatına belə baxırıq:

  • mövcud backend-ə adapter;
  • illərlə dəstəklənməli olan kontrakt;
  • miqrasiya obyekti: versiyalar, annotasiyalar, scopes və SDK.

2. İnteqrasiya arxitekturası: mövcud backend üzərində adapter kimi MCP

Əsas mənzərə

Stack-i xatırladaq, amma bu dəfə production prizmasından:

flowchart LR
  U[ChatGPT-də istifadəçi] --> G[ChatGPT modeli]
  G -->|App çağırır| W["Vidcet (Apps SDK, Next.js)"]
  G -->|tools.call| MCP[MCP server / Gateway]
  MCP --> S1["Gift Service (mövcud servisiniz)"]
  MCP --> S2["Commerce Service (sifarişlər, ACP)"]

ChatGPT sizin dünyanızla birbaşa deyil, MCP protokolu vasitəsilə danışır: tools/resources siyahısı, tools/call çağırışları, hadisələrin axınlanması.

Bu sxemdə MCP server — tam da həmin adapterdir: həm ChatGPT-ni (JSON‑RPC, alətlər) bilir, həm də sizin servisləri (REST/DB/növbələr) və birini o birinə çevirir.

MCP Gateway/Adapter kimi

Klassik vəziyyət: sizdə artıq REST endpoint-ləri olan Gift Service var:

// Mövcud REST API nümunəsi
GET  /api/gifts/recommendations?budget=100&occasion=birthday
POST /api/orders

Yeni biznes-məntiq yazmaq əvəzinə, MCP qatı bunu sadəcə Tool-a bükür:

// mcp/tools/recommendGifts.ts
import { z } from "zod";
import { server } from "./mcpServer"; // şərti SDK instansı

const recommendGiftsInput = z.object({
  occasion: z.string(),
  budgetUsd: z.number().int().positive(),
});

server.registerTool({
  name: "recommend_gifts",
  description: "Büdcə daxilində hədiyyə ideyalarını seçir",
  inputSchema: recommendGiftsInput,
  async execute(args) {
    const { occasion, budgetUsd } = recommendGiftsInput.parse(args);
    const res = await fetch(
      `https://api.myapp.com/gifts/recommendations?budget=${budgetUsd}&occasion=${occasion}`,
    );
    return res.json(); // vacib: model və vidcet üçün əlverişli JSON qaytarırıq
  },
});

Hədiyyə seçiminin bütün məntiqi sizin mövcud servisinizin içində qalır. MCP qatı — ChatGPT dilindən sizin API-lərinizin dilinə “nazik tərcüməçi”dir.

Bəzən MCP qatı sorğuları bir neçə backend servisinə marşrutlaşdırır. Bu halda o, tam hüquqlu MCP Gateway-ə çevrilir — bu rolunuzu prod və şəbəkə bölməsində daha dərindən müzakirə edəcəksiniz.

Monolith-integrated MCP vs Sidecar MCP

Bu MCP qatını “bərkidə” biləcəyiniz iki əsas variant var.

Mətnlə bu belə görünür:

Variant Təsvir MCP kodu harada yerləşir
Monolith-integrated Hər şey bir Next.js/Node servisində Next.js API marşrutlarında və ya Express-də
Sidecar MCP Ayrı konteyner/servis, API ilə danışır Ayrı Node/Go tətbiqi

Kiçik layihələrdə çox vaxt birinci variant kifayət edir: Next.js tətbiqi, Vercel-ə deploy, elə orada /mcp və ya /api/mcp route-u, və MCP server digər API-lərin yanında yaşayır.

Nümunə (xeyli sadələşdirilmiş):

// app/api/mcp/route.ts (Next.js 16)
import { NextRequest } from "next/server";
import { mcpHandler } from "@/mcp/server";

export async function POST(req: NextRequest) {
  const body = await req.json();
  const response = await mcpHandler.handle(body); // JSON-RPC sorğusu
  return new Response(JSON.stringify(response), {
    headers: { "content-type": "application/json" },
  });
}

Daha yetkin arxitekturda, bir neçə domen servisi (Gift, Commerce, Analytics) olduqda, MCP qatını ayrıca Gateway servisinə çıxarmaq əlverişlidir. O, ChatGPT-dən MCP trafiki qəbul edəcək və alətin adına görə müxtəlif backend-lərə çağırışları marşrutlaşdıracaq.

Vacib məqam: ChatGPT və Apps SDK baxımından bu, yenə də tək MCP serverdir. Onun konkret harada işləməsi — monolitin içində, yoxsa ayrıca mikroservis kimi — sizin arxitektura seçiminizdir.

MCP qatının arxitekturasını anladıq: o, monolitin içində də yaşaya, ayrı Gateway kimi də işləyə bilər. Növbəti sual isə bu qatın nə qəbul edib nə qaytardığıdır — burada səhnəyə sxemlər və kontraktlar çıxır.

3. Single Source of Truth: sxemlər, tiplər və kontrakt testləri

Əgər sizdə daxili DTO-lar, xarici REST kontraktları və üstəlik alətlər üçün MCP sxemləri varsa — “sxemləri gözə görə çəkmək” cazibəsi böyükdür. Nəticə məlumdur:

  • backend-də sahəni dəyişirsiniz, alətin schema-sını yeniləməyi unudursunuz;
  • model köhnə formatı göndərməyə davam edir;
  • şən bir runtime zooparkı əldə edirsiniz.

Normal yol: məlumat strukturları üçün tək həqiqət nöqtəsi yaratmaq və onu hər yerdə istifadə etmək. TypeScript dünyasında bunu Zod və ya oxşar kitabxanalarla çox rahat etmək olur; MCP SDK onları JSON Schema-ya konvert etməyi bacarır.

GiftGenius üçün ümumi Zod sxemi

Tutaq ki, tədris GiftGenius layihəmizdə Gift servisi artıq girişin validasiyası üçün Zod istifadə edir:

// domain/gifts.ts
import { z } from "zod";

export const giftRecommendationInputSchema = z.object({
  occasion: z.string().describe("Səbəb: birthday, wedding və s."),
  budgetUsd: z.number().int().positive(),
  recipientProfile: z.string().describe("Şəxsin qısa təsviri"),
});

export type GiftRecommendationInput = z.infer<
  typeof giftRecommendationInputSchema
>;

Bu sxem həmçinin istifadə olunur:

  • REST endpoint-də (sorğu gövdəsinin yoxlanması üçün);
  • MCP alətində (inputSchema kimi);
  • testlərdə (fixturalar üçün əsas kimi).

Sxemi MCP alətinə qoşuruq

// mcp/tools/recommendGifts.ts
import { giftRecommendationInputSchema } from "@/domain/gifts";
import { server } from "../mcpServer";

server.registerTool({
  name: "recommend_gifts",
  description: "Profil və büdcəyə görə hədiyyə seçimi",
  inputSchema: giftRecommendationInputSchema,
  async execute(args) {
    const input = giftRecommendationInputSchema.parse(args);

    const res = await fetch("https://api.myapp.com/gifts/recommendations", {
      method: "POST",
      headers: { "content-type": "application/json" },
      body: JSON.stringify(input),
    });

    return res.json();
  },
});

SDK Zod sxemini JSON Schema-ya özü konvert edir; ChatGPT onu tools/list içində görəcək. Bu, iki problemi dərhal həll edir:

  • alətin arqument tipləri və kod sərt şəkildə bağlanır;
  • sxemi dəyişəndə TypeScript kompilyatoru həm işləyicini yeniləməyə məcbur edəcək.

MCP ↔ backend üçün kontrakt testləri

Kontrakt testləri burada qorxulu söz deyil, olduqca praktik bir neçə yoxlamadır.

Ən sadə unit/contract testi belə görünə bilər:

// tests/mcp/recommendGifts.contract.test.ts
import { giftRecommendationInputSchema } from "@/domain/gifts";

test("nümunə sorğu alətin sxeminə uyğundur", () => {
  const sample = {
    occasion: "birthday",
    budgetUsd: 150,
    recipientProfile: "həmkar, qadcetləri sevir",
  };

  expect(() => giftRecommendationInputSchema.parse(sample)).not.toThrow();
});

Belə test bütün dünyanın mükəmməl olduğunu zəmanət vermir, amma sxemi dəyişdirib fixturaları yeniləməyi unutduğunuz halda backend gözləntiləri ilə MCP qatı arasındakı uyğunsuzluğu heç olmasa tutur.

Sonra eyni yanaşma asanlıqla bunlara genişlənir:

  • xarici API cavablarının mock edilməsi (Stripe, CMS);
  • test mühitində real MCP serverinə qarşı MCP kliendinin qaçırılması.

4. Tools və resources üçün versiyalaşdırma strategiyaları

Sxemlər gec-tez dəyişəcək. Əsas — bunu “sadəcə sahəni adını dəyişəcəm, nə ola bilər ki” ruhunda etməməkdir. LLM dünyasında bu, təkcə build-i deyil, modelin davranışını da poza bilər: köhnə promptlar, yadda saxlanmış dialoqlar və golden case-lər köhnə kontraktı gözləməyə davam edəcək.

Əlavəedici vs breaking dəyişikliklər

Dəyişiklikləri şərti iki kateqoriyaya bölmək olar.

Əlavəedici dəyişikliklər — nəsə əlavə edirsiniz, amma heç nəyi sındırmırsınız:

  • cavabda yeni, məcburi olmayan sahə;
  • defolt dəyərli yeni, məcburi olmayan arqument;
  • enum-a əlavə dəyərlər; UI və model onlara neytral yanaşa bilər.

Məsələn, alətin cavabına deliveryEstimateDays sahəsini əlavə etmisiniz, amma köhnə vidcet onu sadəcə nəzərə almır. Bu təhlükəsizdir: sxem genişlənə bilər, amma heç kəs onu istifadə etməyə məcbur deyil.

Breaking dəyişikliklər — mövcud gözləntiləri sındırırsınız:

  • əvvəl olmayan sahəni məcburi edirsiniz;
  • tipi dəyişirsiniz (string → obyekt);
  • arqumentlərin mənasını dəyişirsiniz (büdcə USD → yerli valyutada, amma sahə adlarını dəyişmirsiniz).

Belə hallarda yeganə təhlükəsiz yol — alətin yeni versiyasını çıxarmaqdır.

Tool_v2 pattern-i

Klassik pattern: sizdə recommend_gifts var idi, sxemi ciddi dəyişmək istəyirsiniz. Köhnə alətə toxunmursunuz, yenisini yaradırsınız — recommend_gifts_v2.

// v1
const recommendGiftsInput_v1 = z.object({
  occasion: z.string(),
  budgetUsd: z.number().int().positive(),
});

// v2: valyuta və çatdırılma filtrlərinə dəstək
const recommendGiftsInput_v2 = z.object({
  occasion: z.string(),
  maxPrice: z.number().int().positive(),
  currency: z.enum(["USD", "EUR", "GBP"]),
  deliverByDate: z.string().optional(); // ISO sətir
});

server.registerTool({
  name: "recommend_gifts",
  description: "DEPRECATED: recommend_gifts_v2 istifadə edin",
  inputSchema: recommendGiftsInput_v1,
  async execute(args) { /* köhnə məntiq */ },
});

server.registerTool({
  name: "recommend_gifts_v2",
  description:
    "Büdcə, valyuta və çatdırılma müddətinə görə hədiyyə seçimi",
  inputSchema: recommendGiftsInput_v2,
  async execute(args) { /* yeni məntiq */ },
});

Model və köhnə promptlar/agentlər recommend_gifts-dan istifadə etməyə davam edəcəklər; siz onları yeniləyənədək. Yeni ssenariləri isə artıq recommend_gifts_v2 ilə yazırsınız.

Miqrasiya dövründən sonra:

  • golden case-lər və agentlər v2-yə keçirilib;
  • metriklər v1-in demək olar ki, çağırılmadığını göstərir;

artıq v1-i tədricən söndürməyə başlamaq olar (məsələn, əvvəlcə dev/staging-də alət siyahısından gizlətmək, sonra prod-da).

Resursların versiyalaşdırılması

Tools — versiya tələb edən yeganə şey deyil. Əgər sizdə resurslar (resources) var — məsələn, statik hədiyyə kataloqu — onları da versiyalaşdırmaq daha yaxşıdır.

Populyar variantlar:

  • versiyanı resurs adına salmaq: gift_catalog.v1.json, gift_catalog.v2.json;
  • və ya versiyanı URI/parametrlə ötürmək: /api/catalog?version=1.

Məqsəd eynidir: artıq işləyən ssenarilərin “ayağının altındakı” məlumatları dəyişməmək, onlara kataloqun dəqiq sabitlənmiş versiyasını vermək.

Downtime olmadan miqrasiyalar

Alətin tipik miqrasiya dövrü:

  1. Köhnəsinin yanında yeni alət versiyası (_v2) əlavə edirsiniz.
  2. App/agentlər/system‑prompt-u elə yeniləyirsiniz ki, onlar yeni versiyadan istifadə etsin.
  3. Hər iki variant üçün golden case-ləri və LLM‑eval-ı işlədirsiniz, kritik ssenarilər üçün keyfiyyətin düşmədiyinə əmin olursunuz.
  4. v1v2 istifadəsi (və xətalar) üzrə metrikləri izləyirsiniz.
  5. v1-ə trafik sıfıra yaxınlaşdıqdan sonra onu deaktiv etməyə başlayırsınız.

Bu yanaşma sxem miqrasiyaları, SDK/protokol yeniləmələri və Auth dəyişiklikləri üçün də yaxşı işləyir. Alətlərin və resursların necə təkamül etdiyini — v1/v2 və diqqətli əlavəedici dəyişikliklər vasitəsilə — anladıq. Kontraktın ikinci böyük hissəsi — autentifikasiya və avtorizasiya: OAuth, scopes və .well-known. Onlar da illərlə yaşayır və diqqətli miqrasiya tələb edir.

5. Autentifikasiyanın təkamülü: .well-known, scopes və mövcud OAuth

Məhsulunuz artıq OAuth 2.1/OpenID Connect dünyasında yaşayırsa, MCP vasitəsilə ChatGPT inteqrasiyası “daha bir login” deyil, ümumi qaydalarla Authorization Server-lə danışmalı yeni bir klientdir.

MCP və .well-known/oauth-protected-resource

Tam OAuth 2.1/OpenID Connect və Auth Server konfiqurasiyası barədə kursun ayrı modulunda ətraflı danışırıq (auth moduluna baxın). Burada bizi yalnız praktik aspekt maraqlandırır: MCP resursu ChatGPT-yə OAuth ilə qorunduğunu necə bildirir və linking axını necə işə düşür.

Qorunan MCP resursları üçün standart pattern:

  • MCP serveriniz xüsusi /.well-known/oauth-protected-resource endpoint-i təqdim edir;
  • cavabda bu resursun nə olduğunu və hansı AS (Authorization Server) ilə qorunduğunu deyir;
  • MCP çağırışında 401 zamanı server WWW-Authenticate başlığını həmin .well-known-ə istinadla qaytarır, və ChatGPT özü OAuth axınını (“Link account”) işə salır.

Express-də minimal nümunə:

// mcp-auth/.well-known.ts
import express from "express";
const app = express();

app.get("/.well-known/oauth-protected-resource", (_req, res) => {
  res.json({
    resource: "https://mcp.myapp.com",
    authorization_servers: [
      "https://auth.myapp.com/.well-known/openid-configuration",
    ],
  });
});

app.listen(3000);

401 üçün kliendə ipucu verən işləyici:

res
  .status(401)
  .set(
    "WWW-Authenticate",
    'Bearer resource_metadata="https://mcp.myapp.com/.well-known/oauth-protected-resource"',
  )
  .end();

ChatGPT bu başlığı görəndə hansı AS-ə getməli olduğunu və sizin MCP resursunuz üçün OAuth axınını necə başlatmalı olduğunu anlayır.

Scopes və avtorizasiya miqrasiyaları

Scopes — miqrasiyaların daha bir mənbəyidir. Bunu auth modulunda ətraflı müzakirə etmişik, amma inteqrasiya/miqrasiya kontekstində bir neçə məqam önəmlidir.

Təsəvvür edin ki, GiftGenius əvvəlcə yalnız kataloqu oxuya bilirdi (gifts.read), sonra isə sifariş yaratmaq üçün gifts.write əlavə etdiniz. Sizə gərək:

  • yeni scope-u klient konfiqurasiyasına (ChatGPT App) əlavə etmək;
  • MCP serverini elə yeniləmək ki, bu scope-u yalnız həqiqətən nəyisə dəyişən alətlər üçün tələb etsin;
  • lazım gələrsə, dəyişiklikləri .well-known-da təsvir etmək.

UX nöqteyi-nəzərindən, istifadəçi yeni funksionallıqdan növbəti dəfə istifadə etməyə çalışanda ChatGPT tətbiqi üçün “icazələri genişləndirmək” sorğusunu görə bilər. Bunun xəbərdarlıqsız, davam edən dialoqun ortasında baş verməsini istəmirsiniz — buna görə belə dəyişiklikləri:

  • elan edin (release notes, sənədləşmə);
  • test AS ilə staging-də yoxlayın;
  • alət təsvirlərini (destructiveHint və s.) yeniləməklə birləşdirin ki, model “təhlükəli” tools-u şüurlu şəkildə çağırsın.

6. Metaməlumat və annotasiyalar: kontraktın üzərində hint qatı

Auth qatı sizin App vasitəsilə kim nə edə bilər sualına cavab verir. Amma hətta düzgün token və scopes olduqda belə, modelin alətlərinizi necə çağıracağı və istifadəçiyə hərəkətləri necə izah edəcəyi önəmlidir. Burada əlavə hint qatı işə düşür: metaməlumat və annotasiyalar.

Kontrakt (schema) alətin qəbul edib qaytardığını deyir. Metaməlumat və annotasiyalar isə modelə onu necənə vaxt çağırmağı anlamağa kömək edir. Bu, App-i təkamül etdirdikdə xüsusilə əhəmiyyətlidir: yeni destructive hərəkətlər əlavə etdikdə, UI dəyişdikdə, xarici dünya ilə inteqrasiyalar tətbiq etdikdə.

_meta["openai/widgetDescription"]widgetCSP

Apps SDK və MCP təsvirlərində _meta adlı xüsusi sahə var; OpenAI protokolun öz genişlənmələrini ora əlavə edir. Məsələn:

  • _meta["openai/widgetDescription"] — vidcetinizin nə göstərdiyinin qısa təsviri; model onu UI-ni “təkrar danışmamaq” və App-i düzgün anons etmək üçün istifadə edə bilər;
  • _meta["openai/widgetCSP"] — vidcetinizin ehtiyac duyduğu CSP domenlərinin deklarasiyası (fetch/şəkillər/skriptlər üçün).

UI-ni dəyişəndə (məsələn, sifarişin rəsmiləşdirilməsi üçün yeni addım əlavə edəndə) widgetDescription-u yeniləmək faydalıdır ki, model istifadəçiyə baş verənləri düzgün izah etməyə davam etsin.

Alət annotasiyaları (readOnlyHint, destructiveHint, openWorldHint)

Annotasiyalar — UX və təhlükəsizliyə nəzərəçarpacaq təsir göstərən sadə boolean flag-lərdir:

  • readOnlyHint: true — alət heç nəyi dəyişmir (oxu). Model onu artıq təsdiqlərsiz çağıra bilər.
  • destructiveHint: true — alət nəyisə silə/dəyişə bilər. ChatGPT açıq təsdiq istəyəcək.
  • openWorldHint: true — alət məlumatları xaricə yayımlayır və ya “çox şey” qaytara bilər, bu da xülasələndirmə tələb edə bilər.

Annotasiyalı alət deskriptoru nümunəsi:

server.registerTool({
  name: "delete_saved_gift",
  description: "İstifadəçinin saxlanmış hədiyyəsini silir",
  inputSchema: z.object({ giftId: z.string() }),
  annotations: {
    readOnlyHint: false,
    destructiveHint: true,
    openWorldHint: false,
  },
  async execute({ giftId }) {
    // ...hədiyyəni silirik
  },
});

Miqrasiya zamanı yeni “təhlükəli” alətlər əlavə etdikdə, annotasiyalar sizin dostunuzdur: onlar ChatGPT-nin onları gizli şəkildə icra etməsinin qarşısını alır və daha ehtiyatlı davranışa sövq edir.

Anlamaq vacibdir ki, annotasiyalar “həqiqi” müdafiə deyil. Onlar yalnız kliendin və modelin davranışına təsir edir. Həqiqi təhlükəsizliyi serveriniz təmin edir (Auth, scopes, validasiya).

7. SDK və MCP spesifikasiyalarının miqrasiyaları

MCP və Apps SDK aktiv inkişaf edir — capabilities-də yeni sahələr, yeni mesaj tipləri, yeni _meta/annotations peyda olur. Sənədlər dürüstcə xəbərdarlıq edir: “2025 il vəziyyətinə” — və bununla yaşamalıyıq.

Ona görə SDK və spes versiyalarının miqrasiyası App həyatının normal hissəsidir, “nə vaxtsa sonra” deyil.

Tipik apqreyd prosesi

Sağlam yeniləmə ssenarisi təxminən belədir:

  1. Yeni Apps SDK/MCP SDK versiyasının changelog‑unu oxuyursunuz. Potensial breaking dəyişiklikləri qeyd edirsiniz.
  2. Asılılıqları dev/staging mühitində yeniləyirsiniz, prod-a toxunmadan.
  3. MCP Inspector / Jam və ya başqa kliendi işlədirsiniz:
    • handshake-i yoxlayırsınız;
    • tools/list / resources/list;
    • bir neçə sınaq tools/call.
  4. Yeni imkanlara uyğun olaraq alət təsvirlərini və _meta-nı yeniləyirsiniz:
    • məsələn, yeni annotations və ya widgetDescription əlavə edirsiniz.
  5. Keyfiyyət baxımından App-in davranışının pisləşmədiyinə əmin olmaq üçün əvvəlki mühazirələrdə danışdığımız golden case-ləri və LLM‑eval-ı işlədirsiniz.
  6. Yalnız bundan sonra yeniləmələri prod-a çıxarırsınız, imkan daxilində trafikin bir hissəsinə canary/feature‑flag ilə.

Nümunə: yeni SDK versiyasında openWorldHint əlavə edirik

Tutaq ki, yeni Apps SDK versiyası openWorldHint üçün dəstək əlavə etdi və siz bunu çox səs‑küy qaytara bilən xarici rəyləri axtaran search_public_reviews alətinə tətbiq etmək qərarına gəldiniz.

Addımlar belə görünür:

  • SDK və tipləri yeniləyirsiniz;
  • alət deskriptorunda annotations.openWorldHint = true əlavə edirsiniz;
  • system‑prompt-u yeniləyirsiniz ki, agent indi xarici dünyaya sorğu gedəcəyini istifadəçiyə açıq izah etsin;
  • özəl məlumat/PII ilə bağlı suallar üzrə xüsusilə safety golden case-ləri işlədirsiniz ki, model həddindən artıq “danışqan” olmasın.

SDK və annotasiya yeniləmə prosesini müzakirə etdik. İndi isə bunların hamısına konkret ssenaridə — recommend_gifts alətinin təkamülündə baxaq.

8. Mini-case: GiftGenius-da recommend_gifts təkamülü

Gəlin hər şeyi konkret ssenaridə bir yerə yığaq.

İlkin versiya

Əsas alət belə görünürdü:

const recommendGiftsInput_v1 = z.object({
  occasion: z.string(),
  budgetUsd: z.number().int().positive(),
  recipientProfile: z.string(),
});

server.registerTool({
  name: "recommend_gifts",
  description: "USD ilə hədiyyə ideyalarını seçir",
  inputSchema: recommendGiftsInput_v1,
  async execute(args) {
    const input = recommendGiftsInput_v1.parse(args);
    return giftService.recommend(input); // daxili funksiya
  },
});

Hər şey əladır, ABŞ və tək valyuta olanadək.

Yeni biznes tələbləri: multivalyuta və deadline

Məhsul komandası yeni tələblərlə gəlir:

  • EUR/GBP dəstəyi lazımdır;
  • çatdırılma deadline-ını nəzərə almaq lazımdır (ad günü üç gün sonradırsa, bir ayda gələn hədiyyələri göstərməmək);
  • cavaba çatdırılma vaxtı qiymətləndirilməsini əlavə etmək arzu olunur.

Sadəlövh yanaşma: sahələri sadəcə dəyişmək:

  • budgetUsd-u maxPrice ilə əvəz edirik;
  • currency əlavə edirik;
  • cavaba deliveryEstimateDays əlavə edirik.

Nə səhv gedəcək?

Köhnə promptlar (golden case-lər və system‑prompt təsviri daxil olmaqla) və yadda saxlanmış dialoqlar hələ də budgetUsd göndərəcək. Model onun artıq olmadığını bilmir. MCP qatı parse zamanı yıxılmağa başlayacaq. ChatGPT App-in davranışı real istifadəçilərdə qəfil pozulacaq.

Düzgün yol:

  1. Yeni sxem və _v2 adlı yeni alət əlavə edirik.
const recommendGiftsInput_v2 = z.object({
  occasion: z.string(),
  maxPrice: z.number().int().positive(),
  currency: z.enum(["USD", "EUR", "GBP"]),
  recipientProfile: z.string(),
  deliverByDate: z.string().optional(),
});

server.registerTool({
  name: "recommend_gifts_v2",
  description:
    "Valyutanı və istənilən çatdırılma tarixini nəzərə alaraq hədiyyə seçimi",
  inputSchema: recommendGiftsInput_v2,
  async execute(args) {
    const input = recommendGiftsInput_v2.parse(args);
    return giftService.recommendV2(input); // yeni məntiq
  },
});
  1. recommend_gifts-i olduğu kimi saxlayırıq, description-da DEPRECATED qeydi əlavə edirik.
  2. System‑prompt-u və App təsvirlərini yeniləyirik ki, model recommend_gifts_v2-yə üstünlük versin (təlimatlarda açıq yaza bilərsiniz).
  3. GiftGenius vidcetini cavabın yeni formatını anlamaq üçün yeniləyirik: deliveryEstimateDays sahəsi və s.
  4. Tipik ssenarilər (müəyyən tarixədək hədiyyə seçimi) üçün golden case-ləri LLM‑eval ilə işlədirik.

Testlər və observability

İstəyəcəyiniz bir neçə test:

Yeni giriş üçün kontrakt testi:

test("v2 EUR və deadline ilə ssenarini qəbul edir", () => {
  const sample = {
    occasion: "birthday",
    maxPrice: 100,
    currency: "EUR",
    recipientProfile: "həmkar",
    deliverByDate: "2025-12-24",
  };

  expect(() => recommendGiftsInput_v2.parse(sample)).not.toThrow();
});

Prod-da müşahidə:

  • recommend_gifts_v2 vs recommend_gifts çağırışlarının payı metrikası;
  • v1 üzrə error-rate (artmasını gözləmirik);
  • miqrasiyadan əvvəl/sonra golden case-lər üzrə LLM‑eval skoru (əvvəlki mühazirələrdən bunu necə etmək lazım olduğunu artıq bilirsiniz).

v2 həm keyfiyyətdə, həm də istifadə metrikalarında “qalib” gələndə, v1-in deaktivləşdirilməsini ehtiyatla planlaşdırmaq olar.

Üç fikrə qədər sadələşdirsək: (1) MCP — nazik adapterdir, yeni monolit deyil; (2) sxemlər, auth və annotasiyalar — ChatGPT ilə backendiniz arasında uzunömürlü kontraktdır; onları adi API-lər qədər diqqətlə versiyalaşdırmaq və test etmək lazımdır; (3) istənilən SDK/spes miqrasiyası — staging, golden case-lər və observability ilə normal mühəndislik prosesidir; “cümə axşamı paketi yenilə” deyil. ChatGPT App-ə bu prizma ilə baxsanız, mövcud məhsulla inteqrasiyalar xaos kimi görünməyəcək.

9. MCP/SDK inteqrasiyası və miqrasiyalarında tipik səhvlər

Səhv №1: MCP-ni “yeni backend” kimi görmək, nazik adapter kimi yox.
Bəzən MCP qatına bütün biznes məntiqini daşımaq istəyirsiniz: DB müraciətləri, domen qaydaları, hesablamalar. Bu, MCP serverini backend-in qalan hissəsi ilə sinxronlaşdırılması çətin olan daha bir monolitə çevirir. MCP-ni mövcud servislər üzərində Gateway/Adapter kimi saxlamaq daha sağlamdır: bütün domen məntiqi ChatGPT-dən əvvəl harada idisə, elə orada qalır, MCP isə yalnız JSON-u ora-bura çevirir.

Səhv №2: Eyni obyekt üçün müxtəlif sxemlər.
Yayğın antipattern — “hədiyyə” üçün üç tərifə sahib olmaq: biri DB-də, biri REST API-də, biri MCP alətində, və hamısı azacıq fərqli. Nəticədə statik tipləndirmə, kontraktlar, testlər və sağlam məntiq pozulur. Tək bir sxemdən (Zod/TypeBox və s.) Single Source of Truth kimi istifadə və MCP üçün JSON Schema generasiyası bu riski xeyli azaldır.

Səhv №3: Sxemlərin səhv miqrasiyası — “səssiz” breaking change.
Sahəni adını dəyişmək və ya mənasını dəyişmək, amma alətin adını dəyişməmək — gizli regresyə aparır. Model köhnə formatı göndərməyə davam edəcək, insident yalnız istifadəçilərin bir hissəsində və xeyli gec üzə çıxacaq. Ciddi dəyişikliklərdə mütləq *_v2 çıxarın, köhnə versiyanı paralel işlək saxlayın, deprecation qeydlərindən və monitorinqdən istifadə edin.

Səhv №4: Auth dəyişikliklərini və scopes-u görməməzlikdən gəlmək.
Yan təsirlər olan yeni alət əlavə etdiniz, amma scopes və .well-known-u yeniləməyi unutdunuz? İstifadəçi ssenarinin ortasında 401 ala bilər və ya əksinə, MCP-niz adekvat avtorizasiya olmadan destructive əməliyyatları icra etməyə başlaya bilər. Auth qatının miqrasiyalarını sxem miqrasiyaları qədər diqqətlə planlayın: staging, testlər və hüquqların tədricən genişləndirilməsi ilə.

Səhv №5: Annotasiyalardan istifadə etməmək (destructiveHint, readOnlyHint, openWorldHint).
Modele hansı alətlərin təhlükəsiz, hansının potensial təhlükəli olduğunu deməsəniz, o, gözlənilməz davrana bilər: zərərsiz get_catalog üçün təsdiq istəsin, amma xəbərdarlıq etmədən məlumat silsin. Düzgün annotasiyalar istifadəçi üçün davranışı proqnozlaşdırıla bilən edir və keyfiyyət və təhlükəsizlik insidentləri riskini azaldır.

Səhv №6: SDK-nı golden case-lərsiz “prod”da yeniləmək.
Yeni SDK/spes versiyası sahələr əlavə edə, handshake davranışını dəyişə və ya mesaj strukturunu yeniləyə bilər. “Asılılıqları yenilə və deploy et” desəniz, keyfiyyət regresi riski var (model lazımi aləti çağırmağı dayandırdı, səhv formulyasiyaları dəyişdi və s.). Əvvəlcə — dev/staging, MCP Inspector, daha sonra golden case-lər və LLM‑eval, yalnız bundan sonra — prod.

Səhv №7: Biznes məntiqinin bir alət versiyasına sərt bağlanması.
Daxili Gift Service məntiqi birbaşa recommend_gifts-dən asılı olduqda, recommend_gifts_v2-yə ağrısız keçmək çətinləşir. Ən yaxşı təcrübə — öz qaydalarına görə təkamül edən daxili servisə malik olmaq, *_v1, *_v2 alətləri isə yalnız thin‑adapterlər kimi köhnə və yeni xarici kontraktları ümumi domen strukturlarına map edir.

Səhv №8: Alət versiyaları üzrə observability-nin olmaması.
Loglarda və metriklərdə hansı alətin və versiyanın çağırıldığını ayırd etmirsinizsə, miqrasiyaların sazlanması falçılığa çevrilir. Alətin adını, sxem/SDK versiyasını və əsas parametrləri loglayın — beləliklə, istənilən regresi konkret dəyişikliyə bağlamaq daha asan olacaq.

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