هنگام پیادهسازی سرویسهای مبتنی بر پروتکل زمینهی مدل (Model Context Protocol یا MCP)، معمولاً ارتباط موفق بین یک SDK و سرور در محیط تست به عنوان نشانهی درستی کارکرد تلقی میشود. با این حال، در محیطهای عملیاتی واقعی که ترافیک از چندین پروکسی، لایههای کش و واسطههای مختلف عبور میکند، رفتارهای پنهان SDK یا تبدیلهای ناخواسته در هدرها و بدنهی JSON-RPC میتواند سیستم را دچار خطاهای پیشبینینشده یا شکافهای امنیتی جدی کند.
این درس به شما نشان میدهد که چگونه ورای اعتبارسنجیهای انتزاعی SDK بروید و انطباق استاندارد MCP را دقیقاً روی بستر انتقال (wire) ارزیابی کنید. با اجرای چارچوب تست مستقل بر پایهی کتابخانهی استاندارد Python، یاد میگیرید که مرزهای نگارشی را تفکیک کنید، هماهنگی هدرها با بدنهی پیام را بسنجید، تغییرات ایجادشده توسط پروکسیها را ردیابی کنید و فرآیند انتشار یا بازگشت نسخه (rollback) را بر پایهی شواهد عینی و پاکسازیشده از اسرار بنا نهید.
سروری که مسیر بیدردسرش (happy path) با یک SDK کار میکند، لزوماً سازگار با استاندارد (conformant) نیست. انطباق واقعی روی بستر انتقال (wire)، در مرزهای نگارش، میان واسطهها و هنگام بازگشت به نگارش قبلی (rollback) محک میخورد.
اهداف یادگیری
- تبدیل قواعد الزامی پروتکل MCP به متن ارتباطات واقعی (wire transcript) معتبر (golden) و منفی (negative).
- تفکیک کامل رفتار سختگیرانهی
2026-07-28از بازگشت مهارشده به نگارشهای پیشین (bounded legacy fallback). - تمایز قائل شدن میان فیلدهای افزودنی ناشناخته و
resultTypeنامعتبر و ناشناخته. - مقایسهی شواهد خام JSON-RPC با خروجی استانداردشدهی SDK.
- اثبات سلامت هدرها و بدنه در عبور از یک پروکسی واقعی.
- مشروط کردن انتشار نسخه به ارائهی شواهد پاکسازیشده، سلامت سیستم و مستندات معتبر بازگشت به نگارش قبل.
صورت مسئله
کلاینت شما از طریق یک SDK متد tools/list را فراخوانی میکند و فهرست ابزارها را تحویل میگیرد. تست یکپارچگی (integration test) هم پاس میشود.
اما این نتیجه پاسخ پرسشهای کلیدی زیر را نمیدهد:
- آیا در این درخواست، متادیتای مدرن ویژهی هر درخواست ارسال شد؟
- آیا مقادیر
MCP-Protocol-Version،Mcp-MethodوMcp-Nameبا بدنهی JSON-RPC همخوانی داشتند؟ - آیا پاسخ دریافتی روی بستر انتقال دارای
resultTypeمعتبر بود، یا SDK خودش آن را ساخت؟ - آیا کلاینت در مواجهه با یک فیلد افزودنی در آینده، آن را حفظ میکند؟
- آیا یک خطای استاندارد و شناختهشده در نگارش مدرن، ناخواسته باعث اجرای دستدادن (Handshake) با پروتکل قدیمی میشود؟
- آیا پروکسی، کد وضعیت مبدأ (origin) و خطای JSON-RPC را دستنخورده عبور داد؟
- آیا بخش سریالسازی نوتیفیکیشنها، پاسخی ارسال کرده که طبق پروتکل ممنوع است؟
- آیا تیم عملیات میتواند بدون ذخیرهی اسرار و کلیدها، دلیل ارتقای یک نسخه یا بازگشت آن به نگارش قبل را اثبات کند؟
انطباق با استاندارد، مجموعهای از مشخصههای پایدار (invariants) و قابلمشاهده است. چارچوب تستی بسازید که این پایدارها را پیش از آنکه ترافیک پروداکشن با خطا کشفشان کند، ثبت و ارزیابی کند.
تفکیک دوران نگارشها
پروتکل MCP در نگارش 2026-07-28 از متادیتای مستقل به ازای هر درخواست استفاده میکند. یک درخواست مدرن فیلدهای params._meta.io.modelcontextprotocol/protocolVersion و params._meta.io.modelcontextprotocol/clientCapabilities را همراه دارد. نام این کلیدها باید دقیقاً با همین فضای نام (namespaced) بیاید؛ نامهای مستعار و بدون پیشوند مثل protocolVersion یا clientCapabilities نامعتبر هستند. اگر هدرهای متناظر مسیریابی در لایهی HTTP ارسال شوند، مقادیرشان باید با بدنهی JSON-RPC کاملاً یکسان باشد. پاسخهای موفق مدرن نیز حتماً فیلد resultType دارند.
نگارشهای تا 2025-11-25 از دوران راهاندازی اولیهی قدیمیتر استفاده میکنند. در آن نگارشها، پاسخی که فیلد resultType ندارد، تنها زمانی کامل تلقی میشود که کلاینت از قبل وارد این دوران قدیمی شده باشد.
اعتبارسنج مسامحهکاری نسازید که هر دو ساختار را همزمان بپذیرد. دو شاخه داشته باشید:
| شاخه | شواهد ورود | نبود resultType |
راهاندازی اولیه |
|---|---|---|---|
| مدرن | متد server/discover موفق یا دریافت پاسخی با ساختار معتبر مدرن |
نامعتبر | مسیر پیشفرض نیست |
| قدیمی (Legacy) | ثبت اندپوینت در لیست مجاز به همراه پاسخ معتبر initialize قدیمی، پس از یک آزمون مدرنِ بینتیجه |
کامل تلقی میشود | الزام آن دوران است |
این تفکیک مانع از آن میشود که یک نودِ مدرن اما بدشکل، با اعتبارسنجی ضعیفتر پذیرفته شود.
حالت اکید (Strict mode)
در حالت اکید، دریافت شواهدی دال بر رفتار مدرن الزامی است. متد server/discover موفق، شاخهی مدرن را اثبات میکند. دریافت یک خطای شناختهشدهی JSON-RPC مدرن نیز اثبات همین شاخه است. در این صورت یا باید درخواست را اصلاح کرد یا متوقف شد. هرگز نباید به این دلیل که سرور خطای -32020، -32021 یا -32022 بازگردانده، پروتکل را به نگارش قدیمی تقلیل داد.
حالت بازگشت به نگارش پیشین (Fallback mode)
در این حالت، فقط یک بار آزمون مدرن و مهارشده انجام میشود. رخدادهایی مثل تایماوت، پاسخ خالی، قطع اتصال یا پاسخ ناشناخته قطعی نیستند و اثبات نمیکنند سرور از نگارش قدیمی استفاده میکند. تنها اندپوینتی که صریحاً برای سازگاری تنظیم شده یا در لیست مجاز آمده، میتواند یک آزمون قدیمیِ مهارشده دریافت کند. کلاینت تنها زمانی به شاخهی قدیمی تغییر مسیر میدهد که پاسخ initialize آن آزمون و نسخهی توافقشدهی قدیمی را اعتبارسنجی کرده باشد.
بازگشت به نگارش پیشین به معنی «تلاش با پروتکل قدیمی پس از هر خطا» نیست. خطای شناختهشدهی مدرن حاوی اطلاعات مفیدی برای اصلاح درخواست است. تقلیل نگارش بعد از چنین خطایی میتواند ناهماهنگی هدرها، نبود اعلام قابلیتها یا عدم پشتیبانی از نسخه را پنهان کند.
این قاعده جلوی مهاجم، قطعی شبکه یا پروکسیهای فیلترکننده را میگیرد تا نتوانند با حذف پاسخ مدرن، سیستم را وادار به تقلیل نگارش کنند. سیاست اندپوینت، مشاهدات آزمون مدرنِ بینتیجه، شواهد عینی نگارش قدیمی و دوران انتخابشده را همیشه در کنار هم ثبت کنید.
دوران انتخابشده را در کنار تمام متن ارتباطات ضبط کنید؛ بدون این مشخصه، نبود یک فیلد ممکن است در یک تست معتبر و در تستی دیگر نامعتبر دیده شود.
ساخت مجموعهی متن ارتباطات (Transcript Corpus)
فیکسچر متن ارتباطات، وقایع واقعی ردوبدلشده روی بستر شبکه را ثبت میکند، نه فقط فراخوانی SDK را:
{
"name": "golden-modern-list",
"era": "modern",
"headers": {
"MCP-Protocol-Version": "2026-07-28",
"Mcp-Method": "tools/list"
},
"request": {
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list",
"params": {
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientCapabilities": {}
}
}
},
"responseStatus": 200,
"responseBody": {
"jsonrpc": "2.0",
"id": 1,
"result": {
"resultType": "complete",
"tools": []
}
}
}
دو دسته فیکسچر نگه دارید.
متن ارتباطات تأییدشده (Golden transcripts)
این موارد، رفتارهای موردقبول را اثبات میکنند:
- درخواست کشف یا متد مدرن همراه با متادیتا و هدرهای هماهنگ
- نتیجهی کامل با تمام فیلدهای الزامی
- نتیجهی
input_requiredدر شرایطی که متد اجازه دارد ورودی بیشتری بخواهد - نتیجهی مربوط به افزونه (extension)، تنها پس از اعلام قابلیت متناظر
- نتیجهی قدیمی بدون
resultType، اما فقط در دورانی که به عنوان نگارش قدیمی انتخاب شده است - پردازش نوتیفیکیشن بدون ارسال هیچ پاسخی در قالب JSON-RPC
متن تأییدشده باید دقیق باشد، نه لزوماً حجیم. شناسهها و برچسبهای زمانی متغیر را قطعی نگه دارید یا پیش از مقایسه، آنها را استانداردسازی (Canonicalization) کنید.
متن ارتباطات منفی (Negative transcripts)
این موارد، صحت رفتارهای عدم پذیرش و رد درخواست را اثبات میکنند:
- ناهماهنگی میان هدر و بدنه
- نبود قابلیتهای اختصاصی هر درخواست
- مطابقت با نسخهی پشتیبانینشده از پروتکل
- نبود
resultTypeدر پاسخهای مدرن - مقدار ناشناخته یا اعلامنشده برای
resultType - مقدار
jsonrpcغیر از2.0یا شناسهای با مقدار یا نوع متناقض در JSON - پاسخی که همزمان دارای
resultوerrorباشد، یا هیچکدام را نداشته باشد - خطایی فاقد
codeعددی صحیح وmessageمتنی - نگاشت یک خطای مشخص پروتکل به کد وضعیت نادرست HTTP
- ارسال پاسخ در ازای دریافت نوتیفیکیشن
- بستهی JSON-RPC بدشکل و نامعتبر
- سرپوش گذاشتن پروکسی روی خطای پروتکل و تبدیل آن به خطایی عمومی
در هر سناریوی منفی، مرز رد شدن و کد خطای پایدار را بسنجید. اکتفا به این که «فراخوانی با شکست مواجه شد» خیلی کلی است. خطای 500 ناشی از پروکسی با خطای -32020 صادرشده از سرور مبدأ هر دو نشاندهندهی شکست هستند، اما مفهوم کاملاً متفاوتی برای تیم عملیات دارند.
فیکسچر ناهماهنگی هدر باید شامل پاسخ واقعی HTTP 400 سرور به همراه ساختار JSON-RPC، شناسهی متناظر درخواست و کد خطای -32020 باشد. اعتبارسنج داخلی باید هر زمان که با HeaderMismatch روبهرو شد این شرط را بررسی کند؛ ارزیابی پاسخ را به یک فلگ اختیاری در تست موکول نکنید. پاسخی با کد HTTP 500 و بدون بدنه، حتی اگر کد رد درخواست داخلی درست باشد، رد میشود. چارچوبی که به محض خطای اعتبارسنجِ درخواستش متوقف شود، فقط خودش را آزموده است نه رفتار سرور روی شبکه را.
پروژهی رسمی انطباق MCP به عنوان یک مجموعهتست بیرونی و مرجع نسخهبندیشده بسیار ارزشمند است، اما متن ارتباطات محلی خود را هم حفظ کنید. این دادهها رفتار پروکسی، SDK، احراز هویت، افزونهها و مسیر انتشار ویژهی سیستم شما را ثبت میکنند که هیچ مجموعهی عمومی از آنها مطلع نیست.
همخوانی مقادیر هدر با بدنهی RPC الزامی است
در نگارش مدرن Streamable HTTP، واسطهها میتوانند با کمک هدرهای متناظر به مسیریابی و اعمال سیاست بپردازند. با این حال، مرجع نهایی پروتکل همچنان بدنهی JSON-RPC است. هرگونه ناهماهنگی نشانهی خدشه به یکپارچگی دادهها است، نه راهنمایی برای انتخاب یکی از مقادیر.
اعتبارسنجی را دقیقاً با این ترتیب پیش ببرید:
- ساختار بستهی JSON-RPC و انواع دادههای متادیتا را اعتبارسنجی و تجزیه کنید.
- هدر
MCP-Protocol-Versionرا باparams._meta.io.modelcontextprotocol/protocolVersionمقایسه کنید. - هدر
Mcp-Methodرا با فیلدmethodمقایسه کنید. - در صورت وجود نام برای مسیریابی متد،
Mcp-Nameرا با مقدار متناظر در بدنه مطابقت دهید. - پس از اثبات تطابق کامل، بررسی کنید که آیا نگارش و مجموعهی قابلیتهای تطبیقیافته پشتیبانی میشوند یا خیر.
این توالی مشخص میکند خطا از نوع ناهماهنگی (-32020) است یا عدم پشتیبانی از نسخه (-32022). همچنین مانع از آن میشود که یک گیتوی نام ابزاری را از روی هدر تأیید کند، اما سرور مبدأ نام متفاوتی را از داخل بدنه به اجرا دربیاورد.
نام هدرهای HTTP نسبت به بزرگی و کوچکی حروف حساس نیستند، اما مقادیر آنها حساس هستند (case-sensitive). نام هدرها را پیش از جستجو استاندارد کنید و هدرهای تکراریِ متناقض را نپذیرید. در صورتی که مقدار Mcp-Name ناامن است، کاراکترهای غیر ASCII دارد یا با فاصلههای خالی شروع و تمام میشود، نشانهی کدگذاریشدهی UTF-8 آن را دقیقاً با قالب =?base64?{Base64EncodedValue}?= رمزگشایی (decode) کرده و با بدنه بسنجید. نشانهی ناقص، مقدار Base64 یا UTF-8 نامعتبر، یا ارسال خام مقادیر ناامن را با خطای -32020 رد کنید. وجود فاصلهی خالی خام در ابتدا و انتهای مقدار، حتی اگر عیناً در بدنه تکرار شده باشد نامعتبر است؛ چراکه این مقدار باید پیش از انتقال روی شبکه با این نشانه کدگذاری میشد.
یک واسطه ممکن است پیش از رسیدن درخواست به سرور MCP، ساختار نامعتبر HTTP را پس بزند و خطایی صرفاً در لایهی HTTP بازگرداند. مبدأ بازگشت خطا (واسطه یا سرور مبدأ) را ثبت کنید. سرور مبدأ MCP باید در صورت دریافت یک درخواست معتبر JSON-RPC، قرارداد خطاهای این پروتکل را رعایت کند.
فیلد ناشناخته با نتیجهی ناشناخته متفاوت است
سازگاری رو به جلو نیازمند دو قاعدهی متفاوت است.
فیلدهای افزودنی ناشناخته
اشیاء بخش نتیجه (Result) و نگاشتهای _meta ممکن است فیلدهای تازهای دریافت کنند. اعتبارسنج باید بسته به نقشش در سیستم، این فیلدها را حفظ کند یا نادیده بگیرد؛ مگر اینکه با قرارداد رزروشدهی پروتکل در تضاد باشند. در کد نمونه، کل ساختار نتیجهی خام به عنوان سند حفظ شده و فیلد futureHint در کنار مقادیر شناختهشده پذیرفته میشود.
اگر نقش پروکسی شفاف را دارید، نگهداشتن فیلدهای ناشناخته امنتر از حذف آنهاست. اما اگر یک کلاینت اپلیکیشن هستید، نادیده گرفتنشان ایرادی ندارد. تست تفاضلی شما باید نشان دهد که SDK این فیلد را حذف کرده است تا این رفتار کاملاً آگاهانه باشد.
مقدار ناشناخته در resultType
فیلد resultType نقش تعیینکننده (discriminator) را دارد. نتایج هستهی مدرن مقادیر complete یا input_required میگیرند. یک افزونه تنها در صورتی میتواند مقدار دیگری اضافه کند که قابلیت آن از پیش اعلام شده باشد؛ به عنوان مثال، افزونهی Tasks مجاز است در چارچوب قابلیت توافقشدهاش مقدار task را بازگرداند.
یک مقدار تعیینکنندهی ناشناخته یا اعلامنشده را هرگز نباید به عنوان complete فرض کرد. کلاینت از چرخهی حیاتی که ممکن است نادیده گرفته شود اطلاعی ندارد، بنابراین باید درخواست را رد کند.
بنابراین یک پاسخ خام میتواند همزمان یک فیلد ناشناختهی مجاز و یک نوع نتیجهی غیرمجاز داشته باشد. هر دو سناریو را تست کنید.
تعیینکننده فقط لایهی اول است. بعد از آن باید بار دادهی (payload) متناسب با هر متد را بررسی کرد. نتیجهی complete در tools/list نیازمند آرایهای از tools است که تعاریفشان نامهای یکتا و غیرخالی، توضیحات کارآمد و ساختار inputSchema بر پایهی شیء داشته باشند. نتیجهی task فقط برای فراخوانی واجد شرایط tools/call همراه با قابلیت Tasks معتبر است و ارائهی taskId، وضعیت شناختهشده، زمانهای ساخت و بهروزرسانی، ttlMs و فاصلهی مجاز برای واکشی اختیاری (polling interval) در آن الزامی است. نتیجهی complete در completion/complete شیء completion با حداکثر 100 رشته متنی، فیلد اختیاری و نامنفی total که از تعداد مقادیر بازگشتی کمتر نباشد، و فیلد بولی اختیاری hasMore میخواهد. یک resultType با املای درست، عیب بار دادهی نامعتبر را نمیپوشاند.
قانون تغییرناپذیر نوتیفیکیشنها
یک نوتیفیکیشن در JSON-RPC فاقد فیلد id است. گیرنده به هیچ عنوان نباید پاسخی مبنی بر موفقیت یا خطای JSON-RPC بفرستد.
برای نوتیفیکیشنهای استاندارد روی HTTP، این چارچوب منتظر کد HTTP 202 با بدنهی کاملاً خالی است. پروتکل MCP در نگارش 2026-07-28 روی بستر انتقال Streamable HTTP هیچ نوتیفیکیشن هستهای از کلاینت به سرور تعریف نکرده است. در کد نمونه صرفاً از یک نوتیفیکیشن افزونهی دورهمان تحت یک فضای نام استفاده شده تا ارسال یکطرفه در بخش سریالسازی سنجیده شود؛ آن را متد رسمی جدیدی در هسته تلقی نکنید.
علاوه بر هندلرها، بخش سریالسازی (serializer) را هم تست کنید. گاهی هندلر خروجی None میدهد اما میدلورها آن را داخل یک شیء JSON با پیام موفقیت کپسوله میکنند. باید بایتهای نهاییِ خروجی بررسی شوند.
ارزیابی مقایسهای SDK (SDK Differential)
بسیاری از SDKها بایتهای روی شبکه را به ساختارهای دادهای زبان مقصد تبدیل میکنند. این کار مفید است، اما یک شیء ساختیافته و نرمالشده سند دقیقی از دادهی خام دریافتی نیست.
برای سناریوهای پرریسک، این چهار بخش را ذخیره کنید:
- کد وضعیت، هدرها و بدنهی خام پاسخ پیش از رمزگشایی (decode) توسط SDK.
- مقدار بازگشتی یا خطای استانداردشده در لایهی SDK.
- تصویر کردن (Projection) معنایی موردانتظار برای دوران انتخابی.
- فیلدهایی که توسط SDK بالا کشیده شده، ساخته شده، حذف شده یا تغییر یافتهاند.
در کد نمونه، حذف متادیتای عملیاتی شبکه نظیر resultType، _meta، ttlMs و cacheScope توسط SDK مجاز شمرده شده و مقایسهی بار داده با برنامهی اصلی صورت میگیرد؛ اما اگر فیلدی مثل futureHint حذف شود، به عنوان از دست رفتن دادهی معنایی ثبت خواهد شد.
هر اختلافی لزوماً باگ SDK نیست؛ هدف، شفاف کردن فرآیند این تبدیلهاست. مشخص کنید که مؤلفهی شما یک کلاینت نهایی است (که میتواند فیلد افزوده را نادیده بگیرد) یا یک واسطهی شفاف (که موظف به حفظ آن است).
این آزمون تفاضلی را برای تکتک SDKها و نسخههایی که منتشر میکنید اجرا کنید. اگر دو SDK یک داده را متفاوت تفسیر کنند، باید سیاست انتشار تکلیف رفتار درست را معلوم کند، نه این که بعد از وقوع، سادهترین خروجی را انتخاب کنید.
ثبت شواهد عبور از پروکسی
بسیاری از خطاهای MCP در محیطهای عملیاتی ناشی از زنجیرهی چند پروسه است. سه نما را مستند کنید:
| نما | حداقل شواهد لازم |
|---|---|
| ورودی (Ingress) | هدرهای درخواست، بدنهی JSON-RPC، نوع محتوا (content type)، مسیر احرازهویتشده، زمان دریافت |
| مبدأ (Origin) | هدرها و خلاصه دادهی (digest) بدنهی فورواردشده، وضعیت سرور مبدأ، هدرها و بدنهی پاسخ |
| خروجی (Egress) | وضعیت نهایی برای کلاینت، هدرها، بدنه و زمان ارسال |
کد نمونه دو تغییر رایج را ردیابی میکند:
- خطای HTTP 400 یا 404 با ساختار JSON-RPC در مبدأ، توسط پروکسی به یک خطای 500 عمومی تبدیل شود
- بدنهی خروجی JSON-RPC با پاسخ دریافتی از سرور مبدأ تفاوت داشته باشد
برای مواردی مثل نوع محتوا، هدر Accept، فشردهسازی، جریان SSE به ازای هر درخواست، هدرهای کش و کدهای پیگیری (trace correlation)، اعتبارسنجیهای متناسب بیفزایید. در صورت مجاز بودن سیاستهای امنیتی، ترافیک قبل و بعد از پایانهی TLS را هم بسنجید، اما برای ردیابی مسیر، هرگز اطلاعات هویتی و توکنها را لاگ نکنید.
پاکسازی دادهها پیش از خروج از حافظه
پاکسازی دادههای حساس (Redaction) جزئی از فرآیند انطباق است، نه مرحلهای برای تمیزکاریهای بعدی. این کار باید پیش از سریالسازی، محاسبهی هش، ذخیره در لاگ، تولید گزارشهای تست یا آپلود خطاها صورت بگیرد.
کد نمونه ابتدا نام کلیدها را با حروف کوچک و بدون نویسههای جداکننده استاندارد میکند و سپس مقادیر کلیدهایی چون Authorization، Cookie، Set-Cookie، X-Api-Key، accessToken، clientSecret، registrationAccessToken، token، password، secret و api_key را به شکل بازگشتی ماسک میکند. استانداردسازی (Canonicalization) و لیست سیاه باید یکپارچه باشند تا تغییر نگارش نامها (مانند camelCase، خط تیره، زیرخط یا نقطه) نتواند سیاستها را دور بزند. در سیستمهای عملیاتی باید تمهیداتی متناسب با پارامترهای هر متد هم اضافه شود؛ چرا که فیلدهای به ظاهر سادهای چون query هم ممکن است حاوی دادههای هویتی یا تحت مقررات باشند.
بستهی شواهدِ پاکسازیشده را هش کنید. لاگهای خام را فقط در سامانههای موقت، مجاز و محدود نگه دارید و صرفاً برای عیبیابیهای خاص استفاده کنید. خلاصهی هش اثبات میکند که تصمیمگیری بر اساس کدام دادهی پاکسازیشده انجام گرفته است، بدون آنکه مقادیر حذفشده فاش شوند.
پیوند دادن ارزیابی سلامت و بازگشت به نگارش قبل با فرآیند انتشار
انطباق با پروتکل برای انتشار نسخه لازم است، اما کافی نیست. سامانهای کاملاً منطبق نیز ممکن است با مشکلاتی مثل تایماوت، نشت حافظه یا بار اضافی روی سرویسهای وابسته روبهرو شود.
یک بازهی ارزیابی سلامت پیش از استقرار نسخه تعریف کنید:
- حداقل حجم نمونهها
- حداکثر نرخ خطا
- حداکثر صدک تاخیر (Latency)
- محدودیتهای مصرف منابع یا اشباع (Saturation)
- مدتزمان پایش
- مقایسه با خط مبنا (Baseline) پذیرفتهشده
همچنین پیش از انتشار، تمام شواهد بازگشت به نگارش قبل را مشخص و آماده کنید:
- نگارش دقیق نسخهی پیشین (Prior)
- خلاصهی هش شواهد قبولی آن نسخه
- پینکردن فایلهای خروجی و توصیفگرها با هش SHA-256
- وضعیت فعلی در رجیستری (Registry)
- آخرین گزارش سلامت آن نسخه
- شیوهنامهی بازگرداندن مسیر ترافیک
- گواهی دیجیتال (attestation) با امضای هویت معتبر و مسئول انتشار برای همین فیلدهای دقیق
نسخهای که قرار است سامانهی فعلی در صورت شکست به آن برگردد، باید از قبل تأیید شده و سالم باشد، نه اینکه بعد از خرابی کاندیدای جدید به فکر بررسی آن بیفتید. انتشاری که راهکار بازگشت امن و آمادهای نداشته باشد، هنوز برای پروداکشن آماده نیست.
اگر استقرار نسخهی جدید موفق نبود و اطلاعات بازگشت به نسخهی قبلی کامل نبود، ترافیک را متوقف کنید و حدس نزنید. مفهوم کنترل عملیاتی با «بازگشت به هر آنچه قبلاً کار میکرد» متفاوت است.
معیارهای پذیرش را به بررسیهای سادهای مثل خالی نبودن فیلد نسخه، مقدار healthy: "yes" یا رشتههای متنی دلخواه محدود نکنید. کد نمونه به نوع دادهی دقیق، وضعیت فعال، سه هش SHA-256، امضاکنندهی مورد اعتماد و یک گواهی معتبر HMAC-SHA-256 روی کل بستهی بازگشت نیاز دارد. کلید تست موجود در کد نمونه برای مقاصد نمایشی است؛ در محیط عملیاتی باید از کلیدهای محافظتشده، نتایج تأیید KMS یا مدل اعتبارسنج (Verifier) کلید عمومی در گیت انتشار استفاده شود.
این گیت ورود هرگونه بستهای را که فاقد متن ارتباطات، خروجی آزمون SDK یا گزارش پروکسی باشد رد میکند. هر بخش باید هش شواهد (Evidence) معتبر ارائه دهد. وضعیت سبز در پایش سلامت نمیتواند جای خالی شواهدی را پر کند که هرگز در سیستم ثبت نشدهاند.
پیادهسازی از صفر
چارچوب آزمون را با کتابخانهی استاندارد اجرا کنید:
cd phases/13-tools-and-protocols/31-mcp-conformance-versioning-and-operations
python3 code/main.py
این دمو دقیقاً 15 متن ارتباطات معتبر و منفی (شامل سناریوهای درست و بدشکل completion) را بررسی میکند، نتیجهی خام را با خروجی SDK میسنجد، پروکسی خطاکار را که خطای مبدأ را دگرگون کرده شناسایی میکند، پارامترهای سلامت را پایش میکند، گواهی شواهد بازگشت به نگارش قبل را میسنجد و نسخهی هدف برای rollback را مشخص میسازد.
خروجی موردانتظار:
{
"transcriptsPassed": 15,
"transcriptsTotal": 15,
"sdkDroppedFields": ["futureHint"],
"proxyIssues": [
"proxy collapsed a protocol error into HTTP 500",
"proxy changed the origin JSON-RPC body"
],
"releaseAction": "rollback",
"evidenceDigest": "..."
}
فایل code/main.py را با این ترتیب مطالعه کنید:
- تابع
validate_request()قواعد اختصاصی هدر و ساختار هر دوره را بررسی میکند. - تابع
validate_result()بین نبود فیلدهای نگارش قدیمی، مقادیر معتبر مدرن، افزونهها و دادههای نامعتبر تفکیک قائل میشود. - تابع
select_era()قواعد حالت اکید و بازگشت مهارشده به نگارشهای پیشین را پیادهسازی میکند. - تابع
run_transcript()فیکسچرهای تأییدشده و منفی را ارزیابی میکند. - تابع
compare_sdk_view()مغایرتهای ناشی از استانداردسازی را مشخص میکند. - تابع
inspect_proxy()شواهد مربوط به ورودی، مبدأ و خروجی را تطبیق میدهد. - تابع
redact()پیش از تولید هش شواهد، اسرار و کلیدها را پاکسازی میکند. - تابع
rollback_evidence_ready()فیلدهای پینشده و گواهی انتشار نسخه را تأیید میکند. - متد
ReleaseGate.evaluate()گزارشهای انطباق، SDK، پروکسی، پایش سلامت و شواهد بازگشت به نگارش قبل را ترکیب میکند.
استفاده از ابزارهای واقعی
این چارچوب را در چهار نقطهی کلیدی به کار بگیرید:
- با هر تغییر پیادهسازی و با استفاده از یک تطبیقدهنده (Adapter) درونبرنامهای.
- روی نسخههای ساختهشدهی سرور و کلاینت روی بستر انتقال (Transport) واقعی شبکه.
- در مسیر گیتویها و پروکسیهای محیط آزمایشی (staging).
- حین انتشار مرحلهای (canary rollout) همراه با مانیتورینگ سلامت زنده و شواهد بازگشت.
نام فیکسچرها را در تمام لایهها یکپارچه نگه دارید. مفهوم حالتی مثل negative-header-body-mismatch باید در تستهای واحد، سرتاسری (End-to-end)، پروکسی و انتشار مرحلهای کاملاً یکسان باشد. به تناسب مرز تست، هش شواهد تغییر میکند اما نیازمندیها ثابت میمانند.
قالب فیکسچرها را تحت سیستم کنترل نسخه (Version Control) مدیریت کنید. شواهد پالایششدهی اجرا را در سامانهی انتشار نگه دارید و فقط در زمان وقوع حادثه و با دسترسیهای خاص، اجازهی ثبت لاگهای خام کوتاهمدت را بدهید.
کارگاه تعاملی
آزمایش اول: اثبات مرز دورانها
از داخل دایرکتوری code، پایتون را اجرا کنید:
cd phases/13-tools-and-protocols/31-mcp-conformance-versioning-and-operations/code
python3 -q
دستورهای زیر را وارد کنید:
from main import *
validate_result({"tools": []}, "legacy")
validate_result({"tools": []}, "modern")
فراخوانی با ساختار قدیمی، مقدار complete را نتیجه میگیرد. اما در حالت مدرن خطای ProtocolViolation رخ میدهد. حالا فرآیند fallback را بیازمایید:
select_era({"kind": "timeout"}, "fallback")
select_era(
{"kind": "timeout"},
"fallback",
legacy_allowed=True,
legacy_evidence={"kind": "initialize_success", "protocolVersion": LEGACY_VERSION},
)
select_era({"kind": "jsonrpc_error", "code": -32021}, "fallback")
پاسخ اول تایماوت میشود و به دلیل عدم وجود شواهد قدیمی، سیستم دسترسی را قطع میکند (fail closed)؛ زیرا سکوت نشانی از قدیمی بودن سرور نیست. فراخوانی دوم تنها به این دلیل وارد شاخهی قدیمی میشود که در تنظیمات مجاز شمرده شده و یک نتیجهی معتبر در راهاندازی اولیهی قدیمی دریافت کرده است. دریافت خطای شناختهشدهی نبودِ قابلیت، شاخهی مدرن را اثبات میکند.
آزمایش دوم: فیلدهای افزودنی در برابر مقادیر تعیینکننده
validate_result({"resultType": "complete", "tools": [], "futureHint": True}, "modern")
validate_result({"resultType": "future_mode", "tools": []}, "modern")
نتیجهی اول فیلد futureHint را حفظ میکند، اما نتیجهی دوم به دلیل مقدار ناشناخته در تعیینکنندهی چرخهی حیات بلافاصله رد میشود.
آزمایش سوم: مشاهدهی تغییرات ناشی از SDK
compare_sdk_view(
{"resultType": "complete", "tools": [], "futureHint": {"mode": "new"}},
{"tools": []},
)
معین کنید که این مؤلفه مجاز به نادیده گرفتن futureHint است یا باید آن را ارسال کند. این تصمیم را در سیاستهای انتشار بگنجانید؛ اجازه ندهید تفاوتهای تفاضلی بیسرصدا پاک شوند.
آزمایش چهارم: اصلاح رفتار پروکسی
سناریوی دمو را طوری تغییر دهید که بستهی خروجی، کد وضعیت و بدنهی سرور مبدأ را دستنخورده عبور دهد. دوباره فایل python3 main.py را اجرا کنید. خطاهای پروکسی رفع میشوند، اما اختلاف در لایهی SDK همچنان مانع از ارتقای نسخه میشود. سپس با گنجاندن futureHint در خروجی SDK، مشاهده کنید که پس از قبولی تمامی شواهد، وضعیت به promote تغییر میکند.
تمرین عملی
پشتیبانی از سناریوهای ارتباطی بر بستر SSE به ازای هر درخواست را به این چارچوب اضافه کنید.
الزامات:
- ثبت وضعیت پاسخ، نوع محتوا، توالی رویدادهای SSE و پایان جریان داده.
- اثبات اینکه هر رویداد JSON-RPC حاوی یک نتیجه یا خطای معتبر برای همان دوران است.
- افزودن یک سناریوی منفی برای حالتی که پروکسی کل جریان را قبل از ارسال بافر میکند.
- افزودن یک سناریوی منفی برای رویدادی در SSE که شناسهی JSON-RPC آن با درخواست تفاوت دارد.
- ماسک کردن دادههای محرمانه پیش از ثبت رویدادها در شواهد.
- اضافه کردن مدتزمان برقراری استریم، تاخیر در اولین رویداد و تعداد رخدادها به معیارهای سنجش سلامت.
- ملزم کردن گیت انتشار به انتخاب یک هدف بازگشتِ مستند در صورت بروز خطا در استریم.
موفقیت زمانی است که سناریوی آزمایشی هم مستقیم و هم از مسیر پروکسی اجرا شود و گزارشی ارائه دهد که دقیقاً مرز تغییر رفتار را مشخص کند.
خروجی این درس
این درس فایل outputs/skill-mcp-conformance-release-gate.md را تولید میکند. با کمک آن، تغییرات کلاینت، سرور، گیتوی یا SDK را به یک ماتریس ارزیابی انطباق نسخهبندیشده و تصمیمگیری برای انتشار تبدیل کنید. این سند به دادههای خام شبکه، سناریوهای منفی، تعیین صریح دوران نسخه، ارزیابی مقایسهای SDK، بررسی پروکسی، پاکسازی اطلاعات، آستانههای سلامت و شواهد بازگشت به نگارش قبل نیاز دارد.
اعتبارسنجی
اجرای دمو و تستهای قطعی:
cd phases/13-tools-and-protocols/31-mcp-conformance-versioning-and-operations
python3 code/main.py
python3 -m unittest discover -s code/tests -v
فرآیند اعتبارسنجی باید موارد زیر را اثبات کند:
- تمامی متنهای ارتباطی تأییدشده و منفی به نتیجهی موردانتظار برسند
- درخواستهای مدرن نیازمند کلیدهای متادیتا با فضای نام دقیق باشند
- نام هدرهای HTTP بدون حساسیت به حروف بزرگ و کوچک بررسی شده و مقادیر کدگذاریشدهی
Mcp-Nameبا دقت رمزگشایی شوند - ناهماهنگی در هدر و بدنه، کد خطای استاندارد نگارش مدرن را بازگرداند
- نگارش پاسخ، شناسه، عدم همزمانی نتیجه و خطا، ساختار پیامهای خطا و نگاشت صحیح روی HTTP کنترل شوند
- الزامات مربوط به فهرست ابزارها، وظایف و ساختارهای بار دادهی completion رعایت شوند
- با مشاهدهی هر خطای
HeaderMismatch، ارائهی پاسخ واقعی HTTP 400 به همراه کد-32020در ساختار JSON-RPC الزامی باشد - فاصلههای خالیِ کدگذارینشده در هدر
Mcp-Nameرد شوند، در حالی که مقادیر صحیح کدگذاریشده با نشانه سالم باقی بمانند - نبود فیلد
resultTypeصرفاً در نگارشهای قدیمیِ انتخابشده معتبر شناخته شود - فیلدهای افزودنی در ارزیابی خام پذیرفته شوند، اما نوع نتیجههای ناشناخته مردود شوند
- مقادیر اختصاصی افزونه در فیلد نتیجه، وابسته به معرفی قبلی آن قابلیت باشد
- خطاهای شناختهشدهی مدرن به هیچ عنوان باعث بازگشت به پروتکل قدیمی نشوند
- نوتیفیکیشنها پاسخی در قالب JSON-RPC برنگردانند
- حذف متادیتای عملیاتی توسط SDK از پاک شدن دادههای معنایی تمیز داده شود
- تبدیل خطای مبدأ به خطای عمومی توسط پروکسی کشف شود و کلیدهای محرمانه با انواع نامگذاریها (شامل حالتهای شتری و جداکنندهها) بهصورت بازگشتی ماسک شوند
- ارتقای نسخه، نیازمند متن ارتباطات غیرخالی، ارزیابی SDK و پروکسی و شواهد عملیاتی سلامت باشد
- ارتقا و بازگشت، هر دو نیازمند یک هدف بازگشتِ احرازهویتشده، پینشده، فعال و سالم باشند
حالتهای شکست در پروداکشن
| شکست | گزارش تستهای ضعیف | آنچه چارچوب آزمون باید اثبات کند |
|---|---|---|
| SDK فیلد تعیینکنندهی غایب را میسازد | «متد tools/list با موفقیت اجرا شد» | پاسخ مدرن خام فاقد resultType بوده و نامعتبر است |
کلاینت بعد از خطای -32021 نگارش را تقلیل میدهد |
«تلاش مجدد با پروتکل قدیمی موفق بود» | خطای شناختهشدهی مدرن تقلیل نگارش را ممنوع میکند |
| نتیجهی ناشناخته به عنوان کامل فرض میشود | «پاسخ پردازش شد» | فیلد تعیینکنندهی معرفینشده در چرخهی حیات باید رد شود |
| پروکسی یک ابزار را تأیید کرده ولی سرور ابزار دیگری را اجرا میکند | «درخواست به سرور رسید» | هدر Mcp-Name در تکتک گامهای لغزش (Hop) با نام موجود در بدنه همخوانی دارد |
| چارچوب آزمون قبل از خواندن پاسخ سرور خطا میدهد | «تست ناهماهنگی هدر پاس شد» | پاسخ HTTP 400 و کد خطای -32020 از سرور خوانده و ارزیابی شدهاند |
| پروکسی خطای 400 سرور را به 500 عمومی تبدیل میکند | «خطا در سرویس بالادستی» | کد وضعیت و پیام خطای سرور مبدأ در خروجی حفظ شده است |
لایهی نوتیفیکیشن پیام {result: null} صادر میکند |
«هندلر مقداری برنگرداند» | پاسخ خروجی نهایی کاملاً خالی است و هیچ پیامی در قالب JSON-RPC وجود ندارد |
| فیلد افزوده توسط SDK حذف میشود | «اشیاء نوعدار مطابقت دارند» | ساختار خام در مقایسه با خروجی استانداردشده، فیلد مفقود را نمایش میدهد |
| بستهی گزارش خرابی حاوی توکن دسترسی است | «فایل لاگ ذخیره شد» | پاکسازی اطلاعات قبل از ایجاد هش، ثبت در لاگ یا آپلود انجام گرفته است |
| ساختار نگارشی کلیدها فیلتر پاکسازی را دور میزند | «کلید api_key در لیست سیاه وجود دارد» | تمام انواع نامگذاری (شتری و خط فاصلهدار) پیش از ارزیابی استانداردسازی میشوند |
| نسخهی قناری به دلیل نبود داده سالم به نظر میرسد | «هیچ خطایی ثبت نشد» | شرط وجود حداقل حجم نمونه برای دادهها الزامی است |
| بازگشت به نسخهای نامشخص و ناشناخته | «نسخهی قبلی بازگردانده شد» | نسخهی هدف، هش پذیرش، پینها، وضعیت و معیارهای سلامت بهطور کامل موجود است |
قاعدهی عملیاتی
بایتهایی را که میفرستید، بایتهایی را که هر واسطه جلوتر میفرستد، رفتاری را که هر SDK به نمایش میگذارد و شواهدی را که تیم عملیات در شرایط بحرانی نیاز دارد بسنجید. سازگاری باید یک branch کاملاً صریح باشد. بازگشت به نگارش قبل هم یک اقدام مستند در فرآیند انتشار است. هیچکدام از این دو نباید پیامد جانبی و تصادفی یک تجزیهکنندهی سهلانگار باشند.
