فاز 13 · درس 28

قراردادها و محتوای ابزار در پروتکل MCP

نوع
ساختنی
زمان
حدود 120 دقیقه
زبان‌ها
Python
دروازه‌های امنیتی دیجیتال با قراردادهای هندسی شفاف برای بررسی داده‌های ورودی و خروجی
فهرست مطالب
  1. اهداف یادگیری
  2. صورت مسئله
  3. پایپ‌لاین قرارداد
  4. اسکیمای JSON یک مرز زمان اجراست
  5. محتوای ساختاریافته می‌تواند هر مقدار معتبر JSON باشد
  6. یک اعتبارسنج کوچک هم مرزها را به‌خوبی نشان می‌دهد
  7. هزینه‌ی متفاوت بلوک‌های محتوا
  8. فیلد x-mcp-header فراداده‌ی مسیریابی است
  9. انکود مقادیر پیش از ساخت هدرهای HTTP
  10. بررسی هدر متناظر توسط سرور
  11. مکان‌نماهای صفحه‌بندی مات هستند
  12. تکمیل خودکار یک سطح دسترسی حساس است
  13. دو لایه‌ی خطا
  14. پیاده‌سازی
  15. اجرا و استفاده
  16. کارگاه تعاملی
  17. تمرین عملی
  18. خروجی نهایی
  19. راستی‌آزمایی
  20. حالت‌های شکست در پروداکشن
  21. پیوند با پروژه‌ی پایانی
  22. اصطلاحات کلیدی
  23. برای مطالعه‌ی بیشتر

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

این درس به شما می‌آموزد که چگونه با طراحی پایپ‌لاین پنج‌مرحله‌ای (شامل کشف، پذیرش، فراخوانی، اجرا و مصرف) و تعریف دقیق مرزهای اعتبارسنجی بر پایه‌ی استاندارد JSON Schema 2020-12، ابزارهایی پایدار و قابل اعتماد بسازید. در این مسیر، نحوه‌ی مدیریت انواع بلوک‌های محتوا، ایمن‌سازی هدرهای مسیریابی و کنترل سطح دسترسی در تکمیل خودکار را به‌صورت گام‌به‌گام پیاده‌سازی خواهید کرد.

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

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

  • تعریف ورودی‌ها و خروجی‌های ابزار با JSON Schema 2020-12.
  • اعتبارسنجی نتایج ساختاریافته بدون پیش‌فرضِ شیء بودنِ حتمیِ JSON (JSON Object).
  • انتخاب درست میان متن، تصویر، صوت، پیوند منبع (Resource Link) و منبع جاسازی‌شده (Embedded Resource).
  • رد تعاریف ناامن x-mcp-header پیش از رسیدن ابزار به مدل.
  • انکود مقادیر هدر پارامترها و بررسی برابری دقیقِ هدر با بدنه (Header-to-Body Parity).
  • پیمایش صفحه‌بندی مکان‌نمامحور (Cursor Pagination) بدون تفسیر مقادیر مکان‌نما.
  • محدودسازی و تعیین سطح دسترسی پیشنهادهای completion/complete.

صورت مسئله

فراخوانی یک تابع Python ساده است، اما فراخوانی یک قابلیت از راه دور از طریق میزبان هوش مصنوعی (AI Host)، مسئله‌ای از جنس قرارداد است.

سرور یک توصیف‌گر (Descriptor) منتشر می‌کند. کلاینت آن توصیف‌گر را به زمینه‌ی مدل و رابط کاربری تبدیل می‌کند. مدل آرگومان‌ها را می‌سازد. گیت‌وی (Gateway) ممکن است بر اساس هدرهای متناظر (Mirrored Headers) درخواست را هدایت کند. سرور ابزار را اجرا می‌کند. سپس کلاینت تصمیم می‌گیرد که آیا نتیجه به‌اندازه‌ی کافی امن و معتبر هست که به مدل بازگردانده شود یا خیر.

تنها یک مرز شکننده کافی است تا کل این زنجیره خراب شود.

این پنج حالت شکست را در نظر بگیرید:

  • توصیف‌گر خروجی را شیء اعلام می‌کند، اما سرور یک آرایه بازمی‌گرداند.
  • کلاینت با دیدن رشته‌ی خالی در nextCursor، صفحه‌بندی را متوقف می‌کند.
  • یک پارامتر توکن درون هدر HTTP منعکس می‌شود و واسطه‌ها آن را می‌بینند.
  • مقدار مسیریابیِ یونیکد به‌صورت هدر خام ارسال می‌شود؛ در نتیجه گیت‌وی و سرور مبدأ، بایت‌های متفاوتی را تفسیر می‌کنند.
  • اندپوینت تکمیل خودکار، محیط پروداکشن (Production) را به کاربری پیشنهاد می‌دهد که اصلاً به آن دسترسی ندارد.

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

پایپ‌لاین قرارداد

هر فراخوانی ابزار را مثل گذر از پنج گیت در نظر بگیرید:

  1. کشف (Discover): خواندن قطعی و صفحه‌بندی‌شده‌ی فهرست ابزارها.
  2. پذیرش (Admit): اعتبارسنجی هر توصیف‌گر و اِعمال سیاست‌های امنیتی محلی.
  3. فراخوانی (Invoke): اعتبارسنجی آرگومان‌ها و ساخت فراداده‌های بستر انتقال.
  4. اجرا (Execute): اجرای تابعِ کنترل‌کننده (Handler) و دسته‌بندی درست خطاها.
  5. مصرف (Consume): اعتبارسنجی بلوک‌های محتوا و خروجی ساختاریافته پیش از استفاده در مدل.

کنترل گیت‌های پذیرش و مصرف کاملاً در دست میزبان است. سرور نمی‌تواند کلاینت را مجبور کند به یادداشت‌ها (Annotations)، اسکیماها یا خروجی‌هایش اعتماد کند.

اسکیمای JSON یک مرز زمان اجراست

در نگارش 2026-07-28 از پروتکل MCP، فیلدهای inputSchema و outputSchema از اسکیمای JSON استفاده می‌کنند. اگر فیلد $schema مشخص نباشد، نسخه‌ی پیش‌فرض 2020-12 خواهد بود.

اسکیمای ورودی باید یک شیء اسکیما باشد. حتی ابزاری که هیچ آرگومانی ندارد هم باید دقیقاً ورودی‌های مجازش را مشخص کند:

{
  "type": "object",
  "additionalProperties": false
}

این ساختار سخت‌گیرانه‌تر از { "type": "object" } است، چون مورد دوم پراپرتی‌های دلخواه را هم قبول می‌کند.

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

محتوای ساختاریافته می‌تواند هر مقدار معتبر JSON باشد

فیلد structuredContent را به‌صورت ثابت یک دیکشنری در نظر نگیرید. این مقدار می‌تواند:

  • یک شیء (Object)؛
  • یک آرایه (Array)؛
  • یک رشته (String)؛
  • یک عدد (Number)؛
  • یک بولین (Boolean)؛
  • یا null باشد.

این ابزار یک آرایه بازمی‌گرداند:

{
  "name": "tag_catalog",
  "inputSchema": {
    "type": "object",
    "additionalProperties": false
  },
  "outputSchema": {
    "type": "array",
    "items": {"type": "string"}
  }
}

نتیجه‌ی موفق آن معتبر است:

{
  "resultType": "complete",
  "content": [
    {
      "type": "text",
      "text": "[\"contracts\", \"mcp\", \"stateless\"]"
    }
  ],
  "structuredContent": ["contracts", "mcp", "stateless"],
  "isError": false
}

برای حفظ سازگاری، نتایج ساختاریافته باید JSON سریالایزشده را در قالب یک بلوک متنی نیز همراه داشته باشند. اما متن مبنای اعتبارسنجی نیست؛ مبنا structuredContent است.

یک اعتبارسنج کوچک هم مرزها را به‌خوبی نشان می‌دهد

در این درس از زیرمجموعه‌ی محدودی از JSON Schema استفاده می‌کنیم تا بدون وابستگی خارجی در کتابخانه‌ی استاندارد Python بمانیم. این بخش سازوکارهای مورد نیاز ابزارهای نمونه را بررسی می‌کند:

  • انواع شیء، آرایه، رشته، عدد صحیح، عدد اعشاری، بولین و مقدار null؛
  • پراپرتی‌های اجباری؛
  • فیلد additionalProperties: false؛
  • آیتم‌های آرایه؛
  • مقادیر enum؛
  • حداقل طول رشته.

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

هزینه‌ی متفاوت بلوک‌های محتوا

آرایه‌ی content می‌تواند انواع مختلفی از محتوا را در خود ترکیب کند.

نوع کاربرد مرز اصلی
text خلاصه‌های خوانا برای انسان و مدل متن را خروجی غیرقابل‌اعتماد در نظر بگیرید
image شواهد تصویری انکودشده با base64 اعتبارسنجی نوع رسانه (Media type) و اندازه
audio خروجی صوتی یا ضبط‌شده با انکود base64 اعتبارسنجی نوع رسانه و سقف مدت‌زمان
resource_link آدرس URI که کلاینت بعداً می‌تواند بخواند احراز هویت مجدد هنگام خواندن منبع در آینده
resource داده‌هایی که مستقیماً درون نتیجه تعبیه شده‌اند اِعمال آنیِ محدودیت‌های اندازه و محتوا

پیوند منبع تضمینی برای این نیست که آن منبع حتماً در resources/list وجود داشته باشد؛ بلکه صرفاً ارجاعی است که در پاسخ این فراخوانی ابزار آمده است. کلاینت هنگام پیمایش این URI همچنان سیاست‌های دسترسی به منبع را اعمال می‌کند.

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

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

فیلد x-mcp-header فراداده‌ی مسیریابی است

هر پراپرتی در inputSchema می‌تواند x-mcp-header را تعریف کند. در بستر Streamable HTTP، کلاینت آن آرگومان را در هدر Mcp-Param-{name} منعکس می‌کند.

{
  "region": {
    "type": "string",
    "x-mcp-header": "Region"
  }
}

با مقدار region: "eu-west"، بستر انتقال می‌تواند این هدر را ارسال کند:

Mcp-Param-Region: eu-west

این یادداشت برای آن گذاشته شده تا لودبالانسر، گیت‌وی یا موتور اِعمال سیاست بتواند بدون نیاز به پارس کردن بدنه‌ی JSON، درخواست را هدایت کند. اینجا اصلاً جای نگهداری اطلاعات هویتی و امنیتی نیست.

پروتکل برای این یادداشت محدودیت‌هایی در نظر گرفته است:

  • نام هدر نباید خالی باشد و باید از ساختار توکنِ نام فیلد در HTTP پیروی کند؛
  • نام هدرها بدون در نظر گرفتن بزرگی و کوچکی حروف (Case-insensitive) باید یکتا باشند؛
  • نوع پراپرتی فقط رشته، عدد صحیح یا بولین است؛
  • نوع number مجاز نیست؛
  • این یادداشت فقط می‌تواند روی اعضای مستقیمِ inputSchema.properties قرار گیرد؛
  • مقادیر عددی صحیح باید بین -9007199254740991 و 9007199254740991 بمانند.

قاعده‌ی محل قرارگیری، ساختاری است و سیاست بسته‌شدن در صورت شکست (Fail-closed) دارد؛ یعنی در صورت هرگونه مغایرت، درخواست رد می‌شود. کل درخت اسکیما را بررسی کنید، نه فقط پراپرتی‌هایی که اعتبارسنج شما به‌طور پیش‌فرض می‌شناسد. اگر این یادداشت درون properties یک شیء تودرتو، شاخه‌ی oneOf، فیلد items، تعریفی که با $ref ارجاع شده، یا در هر کجای اسکیمای خروجی آمده باشد، باید رد شود. برطرف کردن ارجاع (Resolving a reference) آن گره را به یک پراپرتی سطح بالا و مستقیم تبدیل نمی‌کند.

در این درس یک سیاست استقرار هم اضافه می‌کنیم: توصیف‌گرهایی را که نام‌هایی مثل password، secret، token، api_key یا authorization را به هدر می‌فرستند رد کنید. مشخصات رسمی پروتکل به توسعه‌دهندگان سرور توصیه می‌کند پارامترهای حساس را به هدر منتقل نکنند. کلاینت می‌تواند این توصیه را به یک قاعده‌ی سفت‌وسخت در مرحله‌ی پذیرش تبدیل کند.

نام هدر را بررسی و ثبت کنید، نه مقدارش را. کد نمونه Mcp-Param-Region را ثبت می‌کند اما eu-west را از رخدادِ حسابرسی (Audit event) بیرون نگه می‌دارد.

انکود مقادیر پیش از ساخت هدرهای HTTP

مقدار یک پارامتر تنها زمانی می‌تواند به‌صورت متن ساده فرستاده شود که رشته‌ای غیرخالی از کاراکترهای اسکی (ASCII) قابل مشاهده از ! تا ~ باشد و به نشانه‌ی کنترلی انکودینگ (Encoding sentinel) شبیه نباشد. هر مقدار دیگری باید دقیقاً در این قالب بیاید:

=?base64?{Base64UTF8}?=

بخش Base64UTF8 همان base64 استاندارد روی بایت‌های دقیق UTF-8 است. مقدار را پیش از این کار خرد، نرمال‌سازی یا جایگزین نکنید. کاراکترهای یونیکد، رشته‌های خالی، فاصله‌ها، تب‌ها، کاراکترهای کنترلی، CR یا LF، فاصله‌های خالی در ابتدا و انتها، و هر مقداری را که با =?base64? شروع می‌شود انکود کنید. انکود مجدد مقادیری که شبیه نشانه‌ی کنترلی هستند باعث می‌شود گیرنده بتواند متن اصلی را دقیقاً بازسازی کند، نه اینکه آن را به‌عنوان ساختار بستر انتقال رمزگشایی (Decode) کند.

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

بررسی هدر متناظر توسط سرور

تولید هدر فقط نیمه‌ی سمت کلاینت ماجراست. در مرز Streamable HTTP، سرور باید:

  1. نام‌های شناخته‌شده‌ی Mcp-Param-* را بدون حساسیت به بزرگی و کوچکی حروف پیدا کند؛
  2. در صورت وجود نشانه‌ی استاندارد base64، دقیقاً آن را رمزگشایی (Decode) کند؛
  3. متن رمزگشایی‌شده را با آرگومان متناظر در بدنه‌ی JSON کاملاً تطبیق دهد؛
  4. اگر هدر شناخته‌شده‌ای ناموجود، تکراری، غیرمنتظره، ناقص یا ناسازگار باشد، درخواست را پیش از فرستادن به مرحله‌ی بعد رد کند.

پاسخ این رد درخواست، کد وضعیت HTTP 400 با کد خطای JSON-RPC به شماره‌ی -32020 است. نه مقدار بدنه و نه هدر انکودشده نباید در گزارش‌های حسابرسی بیایند. فقط نام هدر شناسایی‌شده و دسته‌ی خطا را ثبت کنید.

فایل code/main.py این مرزبندی را مستقیماً مدل‌سازی کرده است. درس 09 ترتیب کامل اعتبارسنجی‌ها در Streamable HTTP، از جمله یکسانی متد و نسخه‌ی پروتکل را پوشش می‌دهد.

مکان‌نماهای صفحه‌بندی مات هستند

عملیات لیست کردن در MCP از صفحه‌بندی مبتنی بر مکان‌نما (Cursor pagination) استفاده می‌کند. سرور اندازه‌ی صفحه و قالب مکان‌نما را تعیین می‌کند و کلاینت تنها با این تصمیم روبه‌روست:

if result.get("nextCursor") is None:
    break
cursor = result["nextCursor"]

هرگز این‌طور ننویسید:

if not result.get("nextCursor"):
    break

رشته‌ی خالی هم یک مکان‌نمای معتبر است. اتکا به مفهوم درستی مقادیر (Truthiness) صفحه‌بندی را زودتر از موعد متوقف می‌کند.

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

سرور نمونه عمداً بعد از صفحه‌ی اول مقدار "" برمی‌گرداند. کلاینت باید در درخواست دوم دقیقاً همین مقدار را بفرستد. لاگ ردگیری آن به این صورت است:

<first request with no cursor>
<second request with cursor "">

مکان‌نماهای نامعتبر خطای JSON-RPC با کد -32602 (پارامترهای نامعتبر) تولید می‌کنند.

تکمیل خودکار یک سطح دسترسی حساس است

متد completion/complete پیشنهادهایی برای آرگومان‌های پرامپت و قالب‌های منبع ارائه می‌دهد. این قابلیت برای فرم‌های تعاملی کاربردی است، اما اگر مهار نشود می‌تواند نام‌هایی را لو بدهد که در حالت عادی پشت متدهای لیست پنهان مانده‌اند.

درخواست تکمیل خودکار، نام یک ارجاع و آرگومانی را که باید تکمیل شود مشخص می‌کند:

{
  "method": "completion/complete",
  "params": {
    "ref": {
      "type": "ref/prompt",
      "name": "deployment_review"
    },
    "argument": {
      "name": "environment",
      "value": "st"
    }
  }
}

نتیجه حداکثر 100 مقدار برمی‌گرداند و ممکن است فیلدهای total و hasMore را هم داشته باشد.

همان مرزبندی سطح دسترسی را که برای پرامپت یا منبع مرجع استفاده می‌کنید، اینجا هم اعمال کنید. در پروژه‌ی نمونه، یک تحلیل‌گر فقط مقادیر development و staging را می‌بیند؛ تنها یک راهبر سیستم مجاز است production را دریافت کند.

تکمیل خودکار در پروداکشن به این موارد هم نیاز دارد:

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

تکمیل خودکار ابزاری کمکی است، نه راهکاری برای دور زدن مرحله‌ی کشف.

دو لایه‌ی خطا

خطاهای پروتکل را از خطاهای اجرای ابزار جدا نگه دارید.

وقتی درخواست MCP اصلاً امکان ارسال و پردازش درست ندارد، از خطای JSON-RPC استفاده کنید:

  • نام ناشناخته‌ی ابزار؛
  • ساختار نامعتبر درخواست؛
  • نبود فراداده‌های درخواست؛
  • مکان‌نمای نامعتبر.

اما زمانی که فراخوانی به ابزار رسیده و خود ابزار خطایی اجرایی و قابل رسیدگی را گزارش می‌کند، از یک نتیجه‌ی کامل همراه با isError: true استفاده کنید:

  • منبع گزارش در دسترس نیست؛
  • تاریخ انتخابی خارج از بازه‌ی پشتیبانی‌شده است؛
  • یک قانون تجاری (Business rule) عملیات را رد می‌کند.

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

اگر ابزار اسکیمای خروجی دارد، خطاهای عملیاتی را درون همان اسکیما مدل‌سازی کنید. در نمونه‌ی route_report، وضعیت شکست همراه با منطقه‌ی درخواستی، مقدار accepted: false، متن خطای خوانا برای انسان و پرچم isError: true بازمی‌گردد.

پیاده‌سازی

فایل code/main.py هر دو سمت این مرز را فقط با استفاده از کتابخانه‌ی استاندارد Python پیاده‌سازی می‌کند.

سمت سرور این موارد را پوشش می‌دهد:

  • اعتبارسنجی فراداده‌های MCP برای تک‌تک درخواست‌ها؛
  • متد server/discover همراه با قابلیت‌های tools و completions؛
  • صفحه‌بندی قطعی برای tools/list؛
  • چهار توصیف‌گر ابزار، از جمله یک مورد که حتماً باید رد شود؛
  • خروجی ساختاریافته از نوع آرایه؛
  • تمام انواع بلوک‌های محتوایی فعلی در ابزارها؛
  • گیت برابری Streamable HTTP که هدرهای شناخته‌شده‌ی پارامترها را رمزگشایی (Decode) می‌کند و در صورت عدم تطابق، HTTP 400 و خطای JSON-RPC با کد -32020 برمی‌گرداند؛
  • تکمیل خودکارِ دارای احراز دسترسی و محدودیت نرخ درخواست.

سمت کلاینت شامل این بخش‌هاست:

  • پذیرش توصیف‌گر؛
  • اعتبارسنجی محل قرارگیری x-mcp-header در کل درخت اسکیما و اِعمال سیاست روی فیلدهای حساس؛
  • انکود دقیق مقادیر به‌صورت اسکیِ قابل مشاهده یا base64 UTF-8؛
  • حلقه‌ی مکان‌نمای مات که رشته‌ی خالی را هم دنبال می‌کند؛
  • اعتبارسنجی آرگومان‌ها و نتایج؛
  • اعتبارسنجی بلوک‌های محتوا؛
  • ثبت رخدادهای حسابرسی برای هدرها، شامل نام‌ها بدون مقادیر.

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

اجرا و استفاده

از ریشه‌ی مخزن اجرا کنید:

cd phases/13-tools-and-protocols/28-mcp-tool-contracts-and-content/code
python3 main.py
python3 -m unittest discover tests -v

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

کارگاه تعاملی

فایل code/main.py را باز کنید و بخش TOOLS را بیابید.

  1. مقدار tag_catalog.outputSchema.type را از array به object تغییر دهید.
  2. دمو را اجرا کنید؛ کلاینت باید آرایه‌ی برگشتی را رد کند.
  3. اسکیما را به حالت اول بازگردانید.
  4. مقدار nextCursor در صفحه‌ی اول را "" نگه دارید؛ سپس کاری کنید صفحه‌ی آخر به‌جای حذف این فیلد، مقدار nextCursor: None برگرداند.
  5. تست‌ها را اجرا کنید و لاگ ردگیری مکان‌نما را مقایسه کنید.
  6. مقدار x-mcp-header: "Authorization" را به یک پراپرتی رشته‌ای اضافه کنید.
  7. تأیید کنید که مرحله‌ی پذیرش، این توصیف‌گر را پیش از رسیدن به فراخوانی رد می‌کند.
  8. مقادیر مختلفی را برای region امتحان کنید: کاراکترهای یونیکد، خط جدید، فاصله‌های اضافی در ابتدا و انتها، و متن دقیق =?base64?SGVsbG8=?=. هدرهای تولیدشده را رمزگشایی (Decode) کنید و مطمئن شوید مقدار اولیه دقیقاً بازیابی می‌شود.
  9. این یادداشت را به بخش‌های دیگر مثل oneOf، items یا تعریف داخل یک $ref ببرید. تأیید کنید که توصیف‌گر رد می‌شود، حتی اگر این شاخه اصلاً در سناریوی دمو استفاده نشود.
  10. هدر شناخته‌شده را حذف کنید یا مقدار رمزگشایی‌شده‌ی آن را تغییر دهید. مطمئن شوید که مرز HTTP وضعیت 400 و کد JSON-RPC -32020 برمی‌گرداند.

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

تمرین عملی

این کارگاه قراردادها را با ساخت یک ابزار به نام search_evidence گسترش دهید.

نیازمندی‌ها:

  1. اسکیمای ورودی فیلدهای query، limit و یک فیلد مسیریابی امن به نام region را بپذیرد.
  2. اسکیمای خروجی یک آرایه از اشیاء شامل uri، title و score باشد.
  3. نتیجه حاوی متن سازگاری و برای هر آیتم، یک پیوند منبع باشد.
  4. آرگومان‌ها پراپرتی‌های ناشناخته را رد کنند.
  5. فیلد limit در لایه‌ی اعتبارسنجی برنامه سقف مشخصی داشته باشد.
  6. کاربری که به یک URI دسترسی ندارد، هرگز آن را در خروجی تکمیل خودکار یا نتیجه‌ی ابزار نبیند.
  7. تست‌ها شامل این موارد باشند: امتیاز (Score) نامنطبق با اسکیما، یادداشت نامعتبر در هدر، و یک فهرست دوصفحه‌ای.
  8. تست‌های مقدار هدر این حالات را پوشش دهند: اسکی قابل مشاهده، یونیکد، کاراکترهای کنترلی، فاصله‌های خالی، متن شبیه نشانه‌ی کنترلی، و هر دو حد مجاز امن اعداد صحیح در جاوااسکریپت.
  9. بخش تست HTTP هدرها را بدون حساسیت به بزرگی و کوچکی نام بپذیرد، اما اگر مقادیر شناخته‌شده ناموجود یا ناسازگار باشند، با وضعیت 400 و کد -32020 آن‌ها را رد کند.

خروجی نهایی

فایل outputs/skill-mcp-contract-reviewer.md یک مهارت بررسی کدِ یکپارچه و قابل استفاده‌ی مجدد است. توصیف‌گر ابزار، نتایج نمونه، نحوه‌ی صفحه‌بندی و سیاست‌های تکمیل خودکار را به آن بدهید؛ این ابزار وضعیت پذیرش، برنامه‌ی اعتبارسنجی نتایج، سیاست هدرها و تست‌های عملی شکست را به شما تحویل می‌دهد.

راستی‌آزمایی

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

  • فراخوانی‌های مکرر tools/list، ابزارها را با همان ترتیب منطقی برگردانند.
  • وقتی nextCursor برابر "" است، کلاینت درخواست دوم را ارسال کند.
  • توصیف‌گر ناامنی که هدر حساس دارد کنار گذاشته شود، در حالی که سایر ابزارها در دسترس بمانند.
  • خروجی آرایه‌ای، اسکیمای خروجی آرایه را پاس کند.
  • خروجی از نوع شیء، در همان اسکیمای آرایه‌ای با شکست مواجه شود.
  • نتایج حاوی خطا حق نداشته باشند اسکیمای خروجیِ منتشرشده را نادیده بگیرند یا آن را نقض کنند.
  • بلوک‌های متنی، تصویر، صوت، پیوند منبع و منبع جاسازی‌شده همگی اعتبارسنجی شوند.
  • رخدادهای حسابرسی هدر، نام‌ها را بدون مقادیر ثبت کنند.
  • متن اسکیِ قابل مشاهده بدون تغییر بماند؛ اما کاراکترهای یونیکد، کاراکترهای کنترلی، رشته‌های دارای فاصله‌ی اضافه، رشته‌های خالی و مقادیر شبیه نشانه‌ی کنترلی با انکود دقیق base64 UTF-8 بدون تغییر ساختاری رفت‌وبرگشت کنند.
  • اعداد صحیح متناظری که خارج از محدوده‌ی امن جاوااسکریپت هستند رد شوند.
  • یادداشت‌های موجود در oneOf، items، اشیاء تودرتو، تعاریف $ref یا اسکیماهای خروجی در مرحله‌ی پذیرش رد شوند.
  • نام هدرهای شناخته‌شده (صرف‌نظر از بزرگی و کوچکی حروف) تنها زمانی تأیید شوند که مقدار رمزگشایی‌شده با بدنه همخوانی کامل داشته باشد؛ در صورت نبود یا عدم تطابق، خطای HTTP 400 و JSON-RPC -32020 برگردانده شود.
  • بخش تکمیل خودکار برای کاربر تحلیل‌گر، هرگز production را برنگرداند.
  • خطای ابزار با isError: true گزارش شود و خطای پروتکل با کد error در JSON-RPC فرستاده شود.

حالت‌های شکست در پروداکشن

حالت شکست چیزی که دیده می‌شود پاسخ درست
کلاینت خروجی را لزوماً شیء فرض می‌کند آرایه‌های معتبر رد می‌شوند یا بدون اعلام خطا درون ظرفی دیگر قرار می‌گیرند اعتبارسنجی با تکیه بر اسکیمای منتشرشده بدون محدود کردن ساختار به شیء
مکان‌نمای خالی معادل False در نظر گرفته می‌شود صفحات انتهایی دریافت نمی‌شوند و از بین می‌روند ادامه‌ی صفحه‌بندی در هر شرایطی که nextCursor وجود دارد و null نیست
انعکاس مقدار حساس در هدر اسرار و داده‌های محرمانه در پروکسی، WAF یا لاگ‌ها افشا می‌شوند رد توصیف‌گر و نگهداری اطلاعات حساس در بدنه‌ی محافظت‌شده‌ی درخواست
ارسال یونیکد یا فاصله‌ی خالی به‌صورت خام در هدر گیت‌وی و مبدأ برداشت متفاوتی می‌کنند یا مقدار تغییر می‌یابد استفاده از انکودینگ دقیق base64 UTF-8 با نشانه‌ی کنترلی و تطبیق پس از رمزگشایی
پنهان شدن یادداشت در شاخه‌های درونی اسکیما کلاینت در مرحله‌ی پذیرش متوجه فراداده‌های مسیریابی نمی‌شود پیمایش کل درخت اسکیما و مجاز دانستن یادداشت فقط در سطح اول پراپرتی‌ها
انعکاس عدد صحیح بسیار بزرگ در هدر واسطه‌های جاوااسکریپتی مقدار فیلد مسیریابی را گرد می‌کنند رد مقادیر خارج از محدوده‌ی امن اعداد صحیح در جاوااسکریپت
عدم تطابق هدر با بدنه گیت‌وی درخواست را به یک مقصد هدایت می‌کند و مبدأ مقصد دیگری را اجرا می‌کند جلوگیری از ارسال پیش از اجرا با خطای HTTP 400 و JSON-RPC -32020
نادیده گرفتن اسکیمای خروجی بخش‌های بعدی پایپ‌لاین، داده‌های نامنطبق و خراب را مصرف می‌کنند اعتبارسنجی خروجی پیش از ارسال به مدل یا استفاده در برنامه
اعتماد پیش‌فرض به پیوند منبع کاربر یک URI را باز می‌کند که مجاز به دیدنش نیست احراز مجدد هویت و بررسی دسترسی در تک‌تک دفعات خواندن منابع
پیشنهادهای عمومی و سراسری در تکمیل خودکار نام‌های پنهان مربوط به سایر مستأجرها (Tenants) لو می‌روند فیلتر کردن بر اساس هویت فراخواننده، ارجاع و سطح دسترسی
در نظر گرفتن یادداشت‌های ابزار به‌عنوان سیاست امنیتی عملیات مخرب بدون دریافت تأیید اجرا می‌شود اِعمال مجوزها و تأییدیه‌ها خارج از محدوده‌ی یادداشت‌ها
یک ابزار معیوب فرآیند کشف را متوقف می‌کند کل سرور از دسترس خارج می‌شود رد توصیف‌گر معیوب و پذیرش مستقل سایر ابزارهای معتبر

پیوند با پروژه‌ی پایانی

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

از فایل خروجی برای ارزیابی این چهار بخش در پروژه‌ی پایانی استفاده کنید:

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

سازگاری گیت‌وی را صرفاً با یک فراخوانی موفق در tools/call تأیید نکنید. توصیف‌گر، لاگ ردگیری صفحات، ابزارهای پذیرفته‌شده، ابزارهای ردشده و حداقل یک نتیجه‌ی اعتبارسنجی‌شده را ثبت و ارزیابی کنید.

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

اصطلاح معنا
inputSchema شیء اسکیمای JSON که آرگومان‌های مجاز ابزار را تعریف می‌کند
outputSchema اسکیمای JSON اختیاری که ساختار structuredContent را مشخص می‌کند
structuredContent هر مقدار معتبر JSON که ابزار به‌عنوان خروجی برمی‌گرداند
Content block داده‌های نوع‌دار از جنس متن، تصویر، صوت، پیوند منبع یا منبع جاسازی‌شده
x-mcp-header یادداشتی در اسکیما که یک آرگومان اولیه (Primitive) را در فراداده‌ی Streamable HTTP منعکس می‌کند
Opaque cursor توکن صفحه‌بندی صادرشده از سمت سرور که کلاینت نباید مقدار آن را تفسیر کند
Completion reference نام پرامپت یا آدرس/قالب منبعی که آرگومان آن با پیشنهادها پر می‌شود
Admission تصمیم کلاینت برای نمایش یا رد یک توصیف‌گر کشف‌شده

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

خودآزمایی

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

  1. پیش از درسابزاری یک outputSchema از نوع array منتشر می‌کند. کدام مقدار structuredContent معتبر است؟
  2. حین درسنتیجه‌ی tools/list حاوی یک رشته‌ی خالی به‌عنوان nextCursor است. کلاینت باید چه کند؟
  3. حین درسدر یک سیاست استقرار سخت‌گیرانه، کدام پارامتر در صورت نشانه‌گذاری با x-mcp-header باید رد شود؟
  4. حین درستفاوت اصلی بین بلوک resource_link و بلوک embedded resource چیست؟
  5. پس از درسکلاینت در مواجهه با یک توصیف‌گر ابزار ناقص یا نامعتبر در صفحه‌ی tools/list چگونه باید رفتار کند؟
  6. پس از درسکدام خطا باید در قالب خطای JSON-RPC بازگردانده شود نه در نتیجه‌ی ابزار با مقدار isError: true؟

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

آیا محتوای ساختاریافته (structuredContent) در ابزارهای MCP حتماً باید یک آبجکت باشد؟

خیر؛ محتوای ساختاریافته می‌تواند هر مقدار معتبر JSON باشد؛ از جمله آرایه، رشته، عدد، مقدار بولین یا حتی null.

چرا نباید خالی بودن رشته در nextCursor را نشانه‌ی پایان صفحه‌بندی دانست؟

مکان‌نماها مات (Opaque) هستند و مقدار رشته‌ی خالی ("") می‌تواند یک مکان‌نمای معتبر باشد. پایان صفحه‌بندی تنها زمانی اتفاق می‌افتد که فیلد nextCursor اصلاً وجود نداشته باشد یا برابر با null بازگردد.

هدف از کاربرد x-mcp-header در پروتکل MCP چیست و چه محدودیتی دارد؟

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

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

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