فاز 13 · درس 17

درگاه بی‌وضعیت MCP و پذیرش در رجیستری

نوع
مفهومی
زمان
حدود 75 دقیقه
زبان‌ها
Python
پیش‌نیاز
فاز 13 · درس 15 (امنیت)، فاز 13 · درس 16 (مجوزدهی)
یک نقطه اتصال هندسی مرکزی که بسته‌های داده منظم را به چندین شبکه مجزا هدایت می‌کند بدون آنکه رشته یا اتصالی پایدار برقرار باشد
فهرست مطالب
  1. اهداف یادگیری
  2. صورت‌مسئله
  3. مفهوم اصلی
  4. مسیر مدرن درگاه
  5. سیاست محیط اجرا تصمیم اصلی درگاه است
  6. یک اندپوینت POST واحد
  7. پیاده‌سازی مکانیزم کشف در تمام لایه‌ها
  8. قابلیت‌های کلاینت در هر درخواست
  9. نام‌گذاری قطعی و مدیریت فضاهای نام
  10. قفل کردن توصیف‌گرهای تاییدشده
  11. رجیستری‌ها به کشف کمک می‌کنند، نه به تصمیم‌گیری
  12. میانجی‌گری اطلاعات کاربری
  13. محدودیت نرخ درخواست بدون استفاده از نشست
  14. ثبت زنجیره‌ی تصمیم‌ها در حسابرسی
  15. استریمینگ SSE در دامنه‌ی درخواست
  16. اعلان‌های بلندمدت تغییرات
  17. تعامل چندمرحله‌ای (MRTR) از طریق درگاه
  18. مسیریابی افزونه‌ی Tasks
  19. مرز سازگاری
  20. پیاده‌سازی از صفر
  21. استفاده از ابزارهای واقعی
  22. خروجی این درس
  23. تمرین‌ها
  24. اصطلاحات کلیدی
  25. برای مطالعه‌ی بیشتر

وقتی پروژه‌های نرم‌افزاری بر پایه مدل‌های زبانی رشد می‌کنند، اتصال مستقیم کلاینت به تک‌تک ابزارها و سرورها مدیریت دسترسی‌ها را ناپایدار و آسیب‌پذیر می‌کند. پاسخ مدرن به این چالش، پیاده‌سازی یک درگاه (MCP gateway) متمرکز است که درخواست‌ها را بدون نیاز به نگهداری نشست‌های سنگین دریافت، اعتبارسنجی و مسیریابی کند.

در این درس یاد می‌گیرید چطور چندین سرور MCP را پشت یک اندپوینت واحد با پروتکل 2026-07-28 تجمیع کنید، سیاست‌های تفکیک دسترسی (RBAC) و محدودیت نرخ درخواست را اعمال کنید و با قفل کردن توصیف‌گرها (Descriptor pins) مانع از تغییرات ناخواسته یا مخرب در ابزارها شوید.

درگاه (Gateway) باید هر مسیر را کاملاً شفاف و صریح مشخص کند. پروتکل 2026-07-28 مرزهای متد، نام، نسخه، قابلیت، هویت، کش و ردگیری (Trace) را بدون نیاز به نشست در لایه‌ی بستر انتقال فراهم می‌کند.

اهداف یادگیری

  • تجمیع چند سرور MCP پشت یک اندپوینت 2026-07-28 بدون چسبندگی نشست (Session affinity).
  • اعتبارسنجی فراداده‌های هر درخواست و هدرهای مسیریابی، پیش از اعمال سیاست یا فوروارد کردن.
  • ترکیب (Merge) ابزارها با فضای نام پایدار، ترتیب قطعی، قفل توصیف‌گرها (Descriptor pins)، کنترل دسترسی نقش‌محور (RBAC) و کش خصوصی.
  • برخورد با رکوردهای رجیستری به‌عنوان شواهد کشف که همچنان نیازمند سیاست پذیرش هستند.
  • مسیریابی صحیح SSE در دامنه‌ی درخواست، subscriptions/listen، تلاش‌های مجدد MRTR و فراخوانی‌های افزونه‌ی Tasks.
  • ایزوله‌سازی دست‌دادن و پشتیبانی از نشست‌های قدیمی از مسیر مدرن.

صورت‌مسئله

اتصال مستقیم یک کلاینت به یک سرور ساده است؛ اما در استقرارهای بزرگ‌تر، باید پاسخی پایدار و منسجم برای پرسش‌های دشوارتر داشته باشید:

  • کدام سرورها مجازند؟
  • هر کاربر یا سرویس احرازهویت‌شده (Principal) به چه ابزارهایی دسترسی دارد و می‌تواند آن‌ها را فراخوانی کند؟
  • اگر دو سرور پشتیبان نام یکسانی ارائه دهند چه اتفاقی می‌افتد؟
  • تغییرات توصیف‌گرها چگونه بازبینی می‌شوند؟
  • محدودیت نرخ درخواست و رویدادهای حسابرسی (Audit) در کجا اعمال می‌شوند؟
  • آیا هر نمونه از درگاه می‌تواند درخواست بعدی را پردازش کند؟

درگاه بین کلاینت‌ها و سرورهای پشتیبان MCP می‌نشیند؛ یک اندپوینت واحد MCP ارائه می‌دهد، سیاست‌های عمومی و فراگیر را اعمال می‌کند و درخواست‌های تاییدشده را به مقصد می‌فرستد.

در طراحی‌های قدیمی‌تر درگاه، معمولاً یک نشست کلاینت روی چند نشست سرور پشتیبان تسهیم (Multiplex) و مقدار Mcp-Session-Id بازنویسی می‌شد. این معماری صرفاً برای سازگاری با گذشته است؛ هسته‌ی پروتکل 2026-07-28 اساساً هیچ نشستی در لایه‌ی پروتکل ندارد.

مفهوم اصلی

مسیر مدرن درگاه

برای هر درخواست، این مراحل طی می‌شود:

  1. احراز هویت درخواست‌کننده از طریق مجوزهای بستر انتقال.
  2. اعتبارسنجی MCP-Protocol-Version، Mcp-Method، Mcp-Name و params._meta.
  3. مجوزدهی به هویت درخواست‌کننده، منبع، متد، ابزار و آرگومان‌ها.
  4. اعمال سیاست‌های توصیف‌گر، رجیستری، نرخ درخواست و داده.
  5. ساخت یک درخواست تازه و خودکفا برای سرور پشتیبان انتخاب‌شده.
  6. اعتبارسنجی پاسخ سرور پشتیبان و بازگرداندن پاسخ درگاه.
  7. ثبت رویداد حسابرسی بدون لاگ کردن اطلاعات حساس و سکرت‌ها.

هیچ‌کدام از این مراحل نیازی به نشست پنهان در لایه‌ی پروتکل ندارند. وضعیت برنامه همچنان می‌تواند در پایگاه‌های داده، شناسه‌های صریح، Tasks یا وضعیت MRTR با حفاظت یکپارچگی داده نگهداری شود.

سیاست محیط اجرا تصمیم اصلی درگاه است

پذیرش (Admission) تعیین می‌کند کدام نسخه‌ی سرور پشتیبان اجازه‌ی ورود به درگاه را دارد؛ اما یک فراخوانی زنده را مجاز نمی‌کند. درگاه برای تک‌تک درخواست‌ها، سیاست را مجدداً ارزیابی می‌کند: بر اساس هویت احرازشده، صادرکننده و منبع، مستأجر (Tenant)، متد و نام تطبیق‌یافته، آرگومان‌های نرمال‌شده، قفل توصیف‌گر پذیرفته‌شده، سلامت فعلی سرور پشتیبان، اشتراک قابلیت‌ها، طبقه‌بندی داده، وضعیت نرخ درخواست و هرگونه تایید مشروط به عملیات.

این ترتیب اولویت حیاتی است. ممکن است رکورد یک رجیستری فعال بماند، در حالی که نقش کاربر لغو شده است؛ یا یک توصیف‌گر همچنان قفل باشد، اما آرگومان مقصد از مرز مستأجر عبور کند؛ یا یک سرور پشتیبان تاییدشده بماند، اما سیاست‌های مهار بحران، فراخوانی‌های تغییردهنده‌ی وضعیت را قرنطینه کرده باشند. بنابراین، سیاست محیط اجرا تصمیم‌گیرنده‌ی اصلی برای مجاز دانستن یا رد درخواست است و شواهد رجیستری و توصیف‌گر صرفاً ورودی‌های آن هستند.

تصمیم مجاز بودن را تحت عنوان یک اتصال یا شناسه‌ی نشستِ حذف‌شده کش نکنید. اگر سرویس سیاست‌گذاری در دسترس نبود، از سیاست شکست (Failure policy) مشخص‌شده برای آن کلاس عملیات پیروی کنید. یک پیش‌فرض امن این است که برای تغییرات وضعیت و خواندن داده‌های حساس بلافاصله رد شود (Fail closed)؛ در حالی که مسیرهای خواندن عمومیِ تاییدشده تنها در صورتی که مدل ریسک اجازه دهد، می‌توانند برای مدتی کوتاه از آخرین سیاست معتبر شناخته‌شده استفاده کنند. مشخص کنید کدام نسخه‌ی سیاست و کدام مسیر شکست این تصمیم را گرفته است، سپس پاسخ سرور پشتیبان را پیش از بازگرداندن اعتبارسنجی کنید.

یک اندپوینت POST واحد

در نسخه‌ی مدرن Streamable HTTP، تمام پیام‌های JSON-RPC از طریق متد POST ارسال می‌شوند:

POST /mcp
Authorization: Bearer <gateway-token>
MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/call
Mcp-Name: notes.search
Accept: application/json, text/event-stream

درگاه می‌تواند در پاسخ به این POST، فرمت JSON یا SSE در دامنه‌ی درخواست برگرداند. متدهای GET و DELETE برای درخواست‌های مدرن خطای 405 برمی‌گردانند. مقادیر Mcp-Session-Id و Last-Event-ID هیچ‌گونه اختیارات، چسبندگی یا قابلیت بازپخشی ایجاد نمی‌کنند.

مقادیر هدر و بدنه باید کاملاً همخوانی داشته باشند. در صورت عدم تطابق، قبل از جستجوی سرور پشتیبان، درخواست را با خطای -32020 رد کنید. با این کار، متعادل‌کننده‌های بار (Load balancers)، درگاه‌ها و محدودکننده‌های نرخ درخواست می‌توانند بدون پارس کردن کل بدنه مسیر را تعیین کنند و در عین حال یکپارچگی سرتاسری حفظ شود.

اعتبارسنجی را دقیقاً با همین ترتیب انجام دهید: انواع داده‌ی JSON-RPC و فراداده‌ها، برابری هدر و بدنه، و سپس پشتیبانی از نسخه‌ی تطبیق‌یافته. عدم تطابق، خطای HTTP 400 با کد -32020 برمی‌گرداند. اگر هدر و بدنه روی نسخه‌ای توافق دارند که پشتیبانی نمی‌شود، خطای HTTP 400 با کد -32022 و دقیقاً با مقدار data به شکل {"supported":["2026-07-28"],"requested":"<actual>"} برگردانید. متد ناشناخته خطای HTTP 404 با کد -32601 برمی‌گرداند.

کلاس ProtocolError فیلد اختیاری data را حمل می‌کند و درگاه آن را در آبجکت خطای JSON-RPC سریال‌سازی می‌کند. اعلان (Notification) هیچ idای ندارد، بنابراین هرگز پاسخ موفقیت یا خطای JSON-RPC دریافت نمی‌کند. یک اعلان HTTP پذیرفته‌شده کد 202 با بدنه‌ی خالی برمی‌گرداند.

پیاده‌سازی مکانیزم کشف در تمام لایه‌ها

درگاه متد server/discover را برای کلاینت‌ها پیاده‌سازی می‌کند. همچنین خودش عملیات کشف را روی تک‌تک سرورهای پشتیبان اجرا می‌کند تا از نسخه‌های پروتکل، قابلیت‌ها و افزونه‌های آن‌ها باخبر شود.

نمونه‌ی نتیجه‌ی درگاه:

{
  "resultType": "complete",
  "supportedVersions": ["2026-07-28"],
  "capabilities": {
    "tools": {"listChanged": true}
  },
  "ttlMs": 30000,
  "cacheScope": "private",
  "_meta": {
    "io.modelcontextprotocol/serverInfo": {
      "name": "enterprise-gateway",
      "version": "2.0.0"
    }
  }
}

فقط اشتراک قابلیت‌هایی را اعلام کنید که درگاه می‌تواند به‌صورت سرتاسری تضمین کند. اگر سرور پشتیبان قابلیتی دارد، به این معنی نیست که ارائه‌ی عمومی آن حتماً امن است. از طرف دیگر، اعلام قابلیت درگاه بدون اینکه سرور پشتیبان از آن پشتیبانی کند، فایده‌ای ندارد.

فیلد serverInfo صرفاً داده‌های نمایشی و تشخیصیِ خوداظهاری است؛ از آن به‌عنوان سند رجیستری یا اثبات ناشر استفاده نکنید.

قابلیت‌های کلاینت در هر درخواست

هر درخواست فورواردشده به پوشش فراداده‌ی جاری _meta نیاز دارد:

{
  "io.modelcontextprotocol/protocolVersion": "2026-07-28",
  "io.modelcontextprotocol/clientCapabilities": {},
  "io.modelcontextprotocol/clientInfo": {
    "name": "enterprise-gateway",
    "version": "1.0.0"
  }
}

قابلیت‌های کلاینت بیرونی را کورکورانه برای سرور پشتیبان کپی نکنید. در اینجا درگاه نقش کلاینتِ سرور پشتیبان را دارد. فقط قابلیت‌هایی را اعلام کنید که درگاه می‌تواند آن‌ها را به‌درستی میانجی‌گری کند.

نام‌گذاری قطعی و مدیریت فضاهای نام

ابزارهای سرورهای پشتیبان را زیر نام‌های عمومی و پایدار merge کنید:

notes.search
notes.create
issues.list
issues.open

نگاشتی از نام عمومی به سرور پشتیبان و نام اصلی ابزار نگه دارید. در صورت تداخل نام‌ها، هرگز گزینه‌ی اول یا آخر را تصادفی انتخاب نکنید. نام عمومی بخشی از توافق‌نامه‌ی تایید و حسابرسی است؛ بنابراین تغییر آن یک جابه‌جایی ساختاری (Migration) به‌شمار می‌رود.

خروجی tools/list باید کاملاً قطعی باشد. وقتی سطح دسترسی بر اساس هویت درخواست‌کننده تفاوت دارد، cacheScope: private برگردانید. یک مقدار محدود ttlMs بار ناشی از کشف مکرر سرورهای پشتیبان را کاهش می‌دهد، بدون آنکه خطر نشت لیست اختصاصی یک کاربر به زمینه‌های دسترسی دیگر پیش بیاید.

توصیف‌گر هر ابزاری که در معرض دید قرار می‌گیرد، باید شامل نام پایدار، توضیحات و inputSchema با ریشه‌ی آبجکت باشد. مدیریت فضای نام نباید فیلدهای الزامی توصیف‌گر را حذف کند. نتیجه‌ی لیست کامل همچنین شامل resultType، فراداده‌های هویت سرور و راهنماهای کش (Cache hints) است.

قفل کردن توصیف‌گرهای تاییدشده

در زمان پذیرش، ساختار توصیف‌گر کامل را استاندارد (Canonicalize) کنید و چکیده‌ی رمزنگاری‌شده‌ی (Digest) آن را با نام عمومی و معتبر ذخیره کنید. هنگام لیست کردن و زمان فراخوانی، توصیف‌گر زنده را با چکیده‌ی تاییدشده مقایسه کنید.

اگر تغییری رخ داده بود:

  • آن را از tools/list حذف کنید.
  • فراخوانی‌های مستقیم را رد کنید.
  • یک رویداد حسابرسی ثبت کنید.
  • پیش از به‌روزرسانی قفل، منتظر اعمال سیاست یا تایید مجدد انسانی بمانید.

درگاه نقطه‌ی تمرکز بسیار مفیدی برای اعمال قوانین است، اما توصیف‌گری را که برای نخستین‌بار دیده می‌شود خودبه‌خود امن نمی‌کند؛ بازبینی اولیه در هر حال الزامی است.

رجیستری‌ها به کشف کمک می‌کنند، نه به تصمیم‌گیری

فایل server.json در یک رجیستری، فراداده‌های انتشار را فراهم می‌کند. یک رکورد مبتنی بر پکیج می‌تواند به این شکل باشد:

{
  "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
  "name": "com.example/notes",
  "description": "Example notes MCP server.",
  "version": "1.0.0",
  "packages": [
    {
      "registryType": "npm",
      "identifier": "@example/notes-mcp",
      "version": "1.0.0",
      "transport": {"type": "stdio"}
    }
  ]
}

فراداده‌های انتشار حاوی تصمیم امنیتی درگاه نیستند. شواهد مربوط به ناشر تاییدشده و منشأ و سندیت را در وضعیت پذیرش جداگانه‌ای نگه دارید:

{
  "registryName": "com.example/notes",
  "registryVersion": "1.0.0",
  "publisher": {"namespace": "com.example", "status": "verified"},
  "provenance": {
    "source": "registry.modelcontextprotocol.io",
    "recordId": "com.example/notes@1.0.0"
  },
  "admission": {"status": "approved", "reviewedBy": "gateway-policy"}
}

درگاه ساختار server.json را بررسی می‌کند و آن را به آن وضعیت خارجی پیوند می‌دهد. درگاه همچنان نیازمند سیاست پذیرش اختصاصی خود است.

برای هر سرور پشتیبان پذیرفته‌شده، این موارد را ثبت کنید:

  • شناسه و رجیستری دقیق رکورد.
  • شواهد مربوط به دامنه‌ی تاییدشده یا فضای نام ناشر.
  • بستر انتقال و اندپوینت مجاز.
  • نسخه‌ی قفل‌شده یا سیاست ارتقای تاییدشده.
  • چکیده‌ی توصیف‌گر یا تکه کد (Artifact).
  • صادرکننده و منبع مجاز برای مجوزدهی.
  • بازبین، زمان تایید و تاریخ انقضا.

صرف اینکه نام نمایشی یک سرور شبیه محصولی آشنا است، آن را قبول نکنید. حضور در رجیستری را معادل بررسی امنیتی عملیاتی در نظر نگیرید. سرورهای خصوصی را می‌توان با همین ساختار شواهد پذیرش کرد، حتی اگر هرگز در یک رجیستری عمومی ظاهر نشوند.

این درس درزها و آرتیفکت‌های مرزی درگاه را پیاده‌سازی می‌کند: اتصال شواهد انتشار به پذیرش محلی، پیش از آنکه یک سرور پشتیبان امکان مسیریابی پیدا کند. درس 30: زنجیره‌ی تأمین رجیستری MCP، پذیرش، رانش و بازگشت به عقب کنترل پلین کاملی برای اثبات دقیق فضای نام، منشأ و سندیت تکه کد، قفل‌های تغییرناپذیر، رانش (Drift) توصیف‌گر زنده، تطبیق وضعیت رجیستری، دفترکل پذیرش ضد دستکاری و بازگشت به عقب مبتنی بر شواهد می‌سازد. آن وضعیت زنجیره‌ی تأمین را از تصمیمات زمان اجرای هر درخواست که در بالا گفته شد جدا نگه دارید.

میانجی‌گری اطلاعات کاربری

درگاه هویت فراخواننده‌های خود را احراز می‌کند و به‌طور مستقل هویت خود را نزد سرورهای پشتیبان به تایید می‌رساند. اطلاعات کاربری سرورهای پشتیبان هرگز به کلاینت فرستاده نمی‌شود.

این نگاشت‌ها را کاملاً صریح نگه دارید:

outer principal -> gateway role and policy
backend issuer + resource -> backend registration and token

هرگز توکن درگاه بیرونی را به سرور پشتیبان تحویل ندهید. هرگز توکن یک سرور پشتیبان را در صادرکننده یا منبع متفاوتی استفاده نکنید. اگر ابزاری از طرف یک کاربر نهایی کاری انجام می‌دهد، این تفویض اختیار را با تبادل توکن از پیش طراحی‌شده یا مدل کلیمز (Claims) حفظ کنید، نه اینکه با یک اکانت سرویسِ مشترک نقش کاربر را جعل کنید.

محدودیت نرخ درخواست بدون استفاده از نشست

کلید محدودیت‌ها را بر اساس هویت احرازشده، صادرکننده، منبع، ابزار عمومی، کلاس هزینه و پنجره‌ی زمانی بسازید. شناسه‌ی نشست وجود ندارد و حتی اگر وجود داشت، به‌راحتی قابل دور زدن و تغییر بود.

اعتبارسنجی‌های کم‌هزینه را پیش از شروع پردازش‌های سنگین اعمال کنید. مشخص کنید که آیا فراخوانی‌های ردشده پای سوءاستفاده (Abuse limits) حساب می‌شوند، از سهمیه‌ی تجاری (Business quotas) کسر می‌شوند یا هر دو.

ثبت زنجیره‌ی تصمیم‌ها در حسابرسی

اطلاعات کافی برای بازسازی یک فراخوانی را ذخیره کنید:

  • شناسه‌های درخواست و شناسه‌ی ردگیری.
  • هویت احرازشده و صادرکننده.
  • ابزار عمومی و مسیر سرور پشتیبان.
  • نسخه‌ی قفل توصیف‌گر.
  • تصمیم اتخاذشده بر اساس سیاست و دلیل آن.
  • تاخیر و کلاس نتیجه.
  • دور MRTR یا شناسه‌ی وظیفه (Task) در صورت وجود.

توکن‌های حامل (Bearer tokens)، کدهای احراز هویت، توکن‌های تازه‌سازی، سکرت‌های خام و آرگومان‌های حساس غیرضروری را پیش از ثبت بپوشانید (Redact).

استریمینگ SSE در دامنه‌ی درخواست

یک متد POST معمولی در صورتی که پردازش آن درخواست به‌صورت جریانی باشد، می‌تواند پاسخ SSE در دامنه‌ی همان درخواست برگرداند. بستن استریم پاسخ، همان درخواست HTTP مدرنِ در حال پردازش را لغو می‌کند.

استریم GET جداگانه نسازید و قولی برای بازپخش با Last-Event-ID ندهید؛ این‌ها فرضیات بسترهای انتقال قدیمی هستند.

اعلان‌های بلندمدت تغییرات

برای دریافت اعلان تغییرات لیست‌ها و منابع، کلاینت‌های مدرن متد subscriptions/listen را از طریق POST می‌فرستند و پاسخی از جنس SSE دریافت می‌کنند. فیلترهای اعلان از فیلدهای صریح و تک‌سطحیِ toolsListChanged، promptsListChanged، resourcesListChanged و resourceSubscriptions استفاده می‌کنند:

{
  "jsonrpc": "2.0",
  "id": "listen-tools",
  "method": "subscriptions/listen",
  "params": {
    "notifications": {
      "toolsListChanged": true
    },
    "_meta": {
      "io.modelcontextprotocol/protocolVersion": "2026-07-28",
      "io.modelcontextprotocol/clientCapabilities": {}
    }
  }
}

نخستین رویداد، زیرمجموعه‌ی پشتیبانی‌شده را تایید (Acknowledge) می‌کند. شناسه‌ی اشتراک در آن، همان شناسه‌ی JSON-RPC درخواستی است که استریم را باز کرده است:

{
  "jsonrpc": "2.0",
  "method": "notifications/subscriptions/acknowledged",
  "params": {
    "_meta": {
      "io.modelcontextprotocol/subscriptionId": "listen-tools"
    },
    "notifications": {
      "toolsListChanged": true
    }
  }
}

سپس درگاه تنها انواع تغییرات تاییدشده را به کلاینت فوروارد می‌کند. تمام اعلان‌های ارسالی روی آن استریم، مقدار یکسانی از io.modelcontextprotocol/subscriptionId را در params._meta به همراه دارند. هیچ‌گونه بازپخش خودکار یا گوش دادن مجدد خودکار وجود ندارد. هنگام اتصال مجدد، کلاینت اشتراک را دوباره باز می‌کند و لیست‌های مورد نیازش را تازه می‌سازد. خاتمه‌ی نرمِ آغازشده از سمت سرور، نتیجه‌ی کامل نهایی را که با همان شناسه‌ی اشتراک برچسب خورده برمی‌گرداند.

مسیر مدرن جایگزین resources/subscribe، resources/unsubscribe و استریمینگ‌های GET مستقل و ناخواسته شده است. این موارد را فقط در مسیری قدیمی و جداشده با شرط نسخه نگه دارید.

تعامل چندمرحله‌ای (MRTR) از طریق درگاه

وقتی سرور پشتیبان مقدار resultType: input_required را برمی‌گرداند، درگاه تنها در صورتی مجاز به فوروارد آن است که کلاینت بیرونی از درخواست ورودیِ خواسته‌شده پشتیبانی کند. مقدار requestState را بایت‌به‌بایت حفظ کنید، مگر اینکه درگاه عمداً بخواهد این تعامل را خاتمه داده و دوباره ارسال کند.

کلاینت ابزار عمومیِ اولیه را با یک شناسه‌ی جدید JSON-RPC و به همراه inputResponses مجدداً فراخوانی می‌کند. درگاه این تلاش مجدد را مجدداً تایید اعتبار می‌کند، همان مسیر عمومی را می‌سنجد و درخواست تازه‌ای به سرور پشتیبان می‌فرستد. نباید فرض کرد دور قبلی تاییدیه‌ی نامحدود صادر کرده است.

مسیریابی افزونه‌ی Tasks

تسک‌ها یک افزونه‌ی رسمی هستند که با io.modelcontextprotocol/tasks شناخته می‌شوند، نه جایگزینی برای نشست در هسته‌ی پروتکل.

کلاینت افزونه را داخل قابلیت‌های هر درخواست اعلام می‌کند و درگاه تنها در صورتی آن را در مکانیزم کشف به نمایش می‌گذارد که بتواند چرخه‌ی عمر آن را به‌طور کامل و سرتاسری مدیریت کند. برای یک tools/call پشتیبانی‌شده، فقط سرور پشتیبان تصمیم می‌گیرد که پاسخ معمولی بدهد یا پاسخ با resultType: task. نتیجه‌ی یک تسک، مقادیر taskId، status، زمان‌ها، ttlMs و مقدار اختیاری pollIntervalMs را مستقیماً در پاسخ به همراه دارد. پیش از ارسال این پاسخ، وضعیت تسک باید به‌صورت پایدار قابل خواندن باشد.

درگاه هویت احرازشده و مسیر سرور پشتیبان را برای شناسه‌ی مات تسک ذخیره می‌کند. فراخوانی‌های بعدی tasks/get، tasks/update و tasks/cancel از params.taskId به‌عنوان Mcp-Name استفاده می‌کنند که کلید مسیریابی مناسبی به واسطه‌ها می‌دهد. متد tasks/get مقدار resultType: complete را به همراه وضعیت فعلی تسک برمی‌گرداند و نتیجه‌ی نهایی یا خطای پروتکل را در وضعیت پایانی به‌صورت درون‌خطی قرار می‌دهد. متد tasks/update مقادیر کلیددار inputResponses را برای ورودی‌های بلاتکلیفِ تسک ارسال می‌کند و یک تایید کامل و خالی برمی‌گرداند. متد tasks/cancel یک نیت همراه با همکاری است که تاییدیه‌ی کامل و خالی برمی‌گرداند، نه تضمینی قطعی برای توقف کار.

متدهای جدید مثل tasks/list یا tasks/result را پیاده‌سازی نکنید؛ این‌ها متعلق به مدل آزمایشی قدیمی هستند. تسکی که به ورودی نیاز دارد، درخواست‌های تعبیه‌شده‌ی کامل را از طریق tasks/get نمایش می‌دهد؛ کلاینت از طریق tasks/update به آن‌ها پاسخ می‌دهد، نه با تلاش مجدد برای فراخوانی ابزار اصلی. کلاینت همچنان با بازه‌ی زمانی پیشنهادی نظرسنجی (Poll) را انجام می‌دهد؛ ساخت تسک نیز با هدایت سرور انجام می‌پذیرد.

وضعیت پایدار مسیر تسک، داده‌های برنامه‌ای است که با دستگیره‌ی تسک کلیدگذاری شده، نه یک نشست پروتکل.

مرز سازگاری

اگر درگاه باید به کلاینت یا سرور پشتیبان قدیمی سرویس دهد:

  • دوره یا نسل پروتکل را کاملاً صریح تشخیص دهید.
  • دست‌دادن اولیه، نشست‌های بستر انتقال، استریم‌های GET، اشتراک منابع و اصطلاحات قدیمی تسک‌ها را درون یک تطبیق‌دهنده (Legacy adapter) نگه دارید.
  • هرگز نگذارید یک شناسه‌ی نشست قدیمی به مسیریابی یا فرآیند مجوزدهی مدرن نشت کند.
  • به‌جای تنزل بی‌سروصدای پروتکل (Downgrade)، از یک پروب کشف محدود و سیاست صریح فال‌بک استفاده کنید.
قیف گیت‌وییک اندپوینت، پنج مسئولیت
GATEWAY FUNNELTo every developer the gateway looks like a single MCP server. Inside, each call is authenticated, checked against per-user RBAC, rate limited, compared to the pinned tool-hash manifest, and written to the audit log before routing to the backend that owns the tool. Policy lives in one place instead of five thousand IDE configs.توسعه‌دهنده 1notesتوسعه‌دهنده 2githubتوسعه‌دهنده 3postgresگیت‌ویauthrbacمحدودیت نرخهش‌های تثبیت‌شدهلاگ بازرسی
از دید هر توسعه‌دهنده، گیت‌وی درست مانند یک سرور MCP واحد به نظر می‌رسد. در پشت صحنه، هر درخواست پیش از هدایت به بک‌اندی که مالک ابزار است، احراز هویت می‌شود، با RBAC مختص کاربر تطبیق می‌یابد، محدودیت نرخ درخواست بر آن اعمال می‌شود، با مانیفست هش‌های تثبیت‌شده ابزار مقایسه شده و در لاگ بازرسی ثبت می‌گردد. سیاست‌ها به جای پنج هزار پیکربندی در IDEها، در یک نقطه متمرکز نگهداری می‌شوند.

پیاده‌سازی از صفر

فایل code/main.py یک درگاه پروتکل درون‌برنامه‌ای (In-process) و دو سرور پشتیبان را پیاده‌سازی می‌کند. هر سرور پشتیبان درخواستی تازه با ساختار پروتکل جدید دریافت می‌کند. درگاه قابلیت کشف، خروجی قطعی و فیلترشده بر اساس کاربر برای tools/list، مسیریابی مبتنی بر فضای نام، خواندن server.json رجیستری به‌همراه وضعیت پذیرش خارجی، قفل توصیف‌گرها، RBAC، محدودیت نرخ درخواست بر اساس هویت کاربر، ثبت تصمیم‌های حسابرسی و مدل تایید اشتراک SSE با متد subscriptions/listen را ارائه می‌دهد.

این مدل، بدنه‌های پارس‌شده‌ی درخواست، هدرهای مسیریابی و هویت حامل احرازشده را می‌پذیرد. این پیاده‌سازی یک تطبیق‌دهنده‌ی کامل HTTP نیست و هدرهای Content-Type یا ساختار کامل Accept را پارس نمی‌کند. آن را به تطبیق‌دهنده‌ی Streamable HTTP در درس 09 وصل کنید که نیازمند Content-Type: application/json و مقدار Accept شامل هر دو نوع application/json و text/event-stream است.

اجرای آن:

cd phases/13-tools-and-protocols/17-mcp-gateways-and-registries
python3 code/main.py
python3 -m unittest discover code/tests -v

این پیش‌نمایش، شناسه‌ی درخواست بیرونی و شناسه‌ی درخواست تازه‌ی سرور پشتیبان را چاپ می‌کند تا گام لغزشِ بی‌وضعیت به‌خوبی دیده شود.

استفاده از ابزارهای واقعی

آبجکت‌های درون‌برنامه‌ای سرور پشتیبان را با کلاینت‌های واقعی مبتنی بر پروتکل روز جایگزین کنید. این درزها و آرتیفکت‌های مرزی را دست‌نخورده نگه دارید:

  • رکورد پذیرش پیش از برقراری اتصال.
  • کشف سرور پشتیبان پیش از ارائه‌ی قابلیت‌ها.
  • مشخص کردن نام عمومیِ واجد شرایط پیش از مجوزدهی.
  • قفل توصیف‌گر پیش از لیست کردن یا فراخوانی.
  • فراداده‌های تازه در هر درخواست پیش از فوروارد کردن.
  • اعتبارسنجی نتیجه پیش از بازگرداندن پاسخ.

خروجی این درس

این درس فایل outputs/skill-gateway-bootstrap.md را تولید می‌کند؛ خروجی این فایل یک معماری درگاه مدرن است که بخش‌های ورود، کشف، پذیرش، فضاهای نام، مجوزدهی، کش، استریمینگ، اشتراک‌ها، MRTR، تسک‌ها، مشاهده‌پذیری و ایزوله‌سازی بخش‌های قدیمی را پوشش می‌دهد.

تمرین‌ها

  1. زمینه‌ی ردگیری را به فراداده‌های درخواست بیرونی و فورواردشده اضافه کرده و همبستگی آن‌ها را در رویداد حسابرسی ثبت کنید.
  2. یک سرور پشتیبان با قابلیت پشتیبانی از Tasks اضافه کنید و tasks/get را با استفاده از شناسه‌ی تسک در Mcp-Name مسیریابی کنید.
  3. توصیف‌گر یکی از سرورهای پشتیبان را تغییر دهید و بررسی کنید که هم فرایند کشف و هم فراخوانی مستقیم مسدود شوند.
  4. قابلیتی وابسته به هویت کاربر به سرور اضافه کنید و توضیح دهید چرا کشف قابلیت‌ها در این حالت حتماً باید به‌صورت خصوصی کش شود.
  5. یک رابط تطبیق‌دهنده‌ی قدیمی بنویسید، بدون آنکه هیچ وضعیت موروثی به کلاس مدرن Gateway اضافه شود.

اصطلاحات کلیدی

اصطلاح معنی
MCP gateway سرور سیاست‌گذاری و مسیریابی بین کلاینت‌ها و سرورهای پشتیبان MCP
Admission record شواهد و تصمیم مبتنی بر سیاست که اجازه‌ی ورود یک سرور پشتیبان به درگاه را صادر می‌کند
Qualified tool name مسیر عمومی و پایدار نظیر notes.search
Descriptor pin چکیده‌ی تاییدشده که هنگام کشف و ارسال درخواست بررسی می‌شود
Private cache scope دامنه‌ی کش خصوصی برای محدود کردن نتیجه‌ی کش‌شده به یک زمینه‌ی مجوزدهی واحد
Request-scoped SSE پاسخ استریمینگ که به یک درخواست POST مشخص الصاق می‌شود
subscriptions/listen استریم SSE بازشده توسط کلاینت برای دریافت اعلان‌های تغییرات بلندمدت انتخابی
Task route نگاشت برنامه‌ای از یک شناسه‌ی مات تسک به سرور پشتیبان مربوط به آن
Legacy adapter مرز صریحِ تفکیک‌شده بر اساس نسخه برای پشتیبانی از دست‌دادن و رفتارهای نشست‌های قدیمی

برای مطالعه‌ی بیشتر

خودآزمایی

به سؤال‌ها جواب بدهید تا ببینید چقدر از درس در ذهنتان مانده است.

  1. پیش از درسیک گیت‌وی MCP امروزی چه چیزی را باید بین درخواست‌های عادی کلاینت حفظ کند؟
  2. حین درسنتیجه متد tools/list که بر اساس کاربر (principal) فیلتر شده، معمولاً باید از چه دامنه کشی (cache scope) استفاده کند؟
  3. حین درسیک گیت‌وی چگونه باید فراخوانی ابزار را به بک‌اندهای امروزی فوروارد کند؟
  4. حین درسیک گیت‌وی در مرحله پذیرش، چگونه باید از رکورد رسمی server.json رجیستری استفاده کند؟
  5. پس از درسدر شیوه مدرن Streamable HTTP، اعلان‌های طولانی‌مدتِ تغییرات لیست چگونه باز می‌شوند؟
  6. پس از درسکدام قاعده مسیریابی در افزونه Tasks شیوه جاری و مدرن است؟

سؤالات متداول

چرا هسته پروتکل 2026-07-28 به نشست در لایه بستر انتقال نیاز ندارد؟

در این پروتکل تمام ارتباطات از طریق متد POST ارسال می‌شوند و فراداده‌های هر درخواست به همراه هویت و مسیرها به شکل خودکفا ارسال می‌گردند؛ بنابراین درگاه بدون چسبندگی به نشست کلاینت، درخواست تازه برای سرور پشتیبان تولید می‌کند.

نقش قفل توصیف‌گر (Descriptor pin) در امنیت درگاه چیست؟

درگاه در زمان پذیرش، چکیده معتبر توصیف‌گر را ذخیره می‌کند و در زمان لیست یا فراخوانی با ابزار زنده می‌سنجد؛ در صورت کوچک‌ترین تغییر، ابزار از لیست حذف شده و فراخوانی آن تا تایید مجدد مسدود می‌شود.

اگر هدر و بدنه درخواست از نظر نسخه یا متد همخوانی نداشته باشند چه می‌شود؟

درگاه قبل از ارسال درخواست به سرورهای پشتیبان، تطابق هدر و بدنه را می‌سنجد و در صورت مغایرت بلافاصله خطای HTTP 400 با کد 32020- برمی‌گرداند تا یکپارچگی ارتباط حفظ شود.

ما رو توی گوگل بیشتر ببین

با افزودن نکست ادمین به «منابع ترجیحی» گوگل، درس‌ها و مطالب ما را در بخش اخبار برتر جستجو بیشتر می‌بینید.