در سیستمهای توزیعشده و مقیاسپذیر هوش مصنوعی، تکیه بر نشستهای دائمی اتصال (Connection Sessions) یکی از بزرگترین چالشهای همگامسازی و مدیریت بار است. نسخه مدرن پروتکل زمینه مدل (Model Context Protocol یا MCP) با حذف کامل نشستهای پروتکلی و مکانیزم سنتی دستدادن (Handshake)، رویکردی کاملاً بیوضعیت (Stateless) را پیش گرفته است.
این تغییر به این معناست که هر درخواست ارسالی روی شبکه باید کاملاً خودتوصیف باشد؛ یعنی تمامی فرادادههای لازم برای تعیین نسخه، قابلیتهای کلاینت، و احراز صلاحیت را درون فیلد `_meta` در ساختار JSON-RPC 2.0 حمل کند. تسلط بر این ساختار برای توسعهدهندگانی که میخواهند ابزارها و سرویسهای مقاوم در برابر قطعی و مستقل از وضعیت زیرساخت طراحی کنند، ضروری است.
نسخهی مدرن MCP هیچ دستدادن (Handshake) و نشست پروتکلی ندارد. هر درخواست باید بهتنهایی فرادادهی کافی برای درکشدن، بررسی مجوز، مسیریابی و تلاش مجدد به همراه داشته باشد.
اهداف یادگیری
- تفکیک سازههای پایهی سرور (Server Primitives) در MCP از قابلیتهای سمت کلاینت.
- ساخت درخواستها و پاسخهای معتبر JSON-RPC 2.0 برای نسخهی
2026-07-28پروتکل MCP. - پیوستکردن نسخهی پروتکل، قابلیتهای کلاینت و هویت کلاینت به تکتک درخواستها.
- استفاده از
server/discoverو مدیریت خطایUnsupportedProtocolVersionErrorبدون نیاز به دستدادن. - ردگیری یک درخواست مستقل، از اعتبارسنجی تا بازگرداندن نتیجهی کامل.
صورت مسئله
یک سرور MCP ممکن است دو درخواست متوالی از دو کلاینت مختلف، با قابلیتهای متفاوت، روی یک فرایند (Process) یا ورکر HTTP یکسان دریافت کند. اگر سرور آنچه را که در درخواست قبلی اعلام شده بود به خاطر بسپارد، ممکن است دسترسیهای اشتباهی اعمال کند یا ساختار دادهی خروجی روی شبکه را اشتباه بفرستد.
نسخهی 2026-07-28 در MCP این ابهام را برطرف میکند. هستهی پروتکل بیوضعیت (Stateless) است. سرور باید دربارهی نحوهی پردازش درخواست فعلی، صرفاً بر اساس همان درخواست تصمیم بگیرد، نه بر اساس تاریخچهی اتصال.
این رویکرد مدل ذهنی را تغییر میدهد. در توالی قدیمی، اول اتصال برقرار میشد، سپس دستدادن انجام میگرفت و در آخر عملیات اجرا میشد. توالی مدرن سادهتر است:
- کلاینت یک درخواست خودتوصیف میفرستد.
- سرور نسخه و قابلیتهای موجود در آن درخواست را اعتبارسنجی میکند.
- سرور متد را اجرا میکند.
- سرور یک نتیجهی نوعدار (Typed) یا خطای JSON-RPC برمیگرداند.
درخواست بعدی نیز همین فرایند را از ابتدا تکرار میکند.
مفاهیم پایه
سازههای پایهی سرور
سرورهای MCP سه سازهی اصلی ارائه میدهند:
- ابزارها (Tools): عملیات تحت کنترل مدل هستند که با
tools/listشناسایی و باtools/callفراخوانی میشوند. - منابع (Resources): دادههای دارای آدرس URI هستند که با
resources/listشناسایی و باresources/readدریافت میشوند. - پرامپتها (Prompts): الگوهای بازکاربردپذیر هستند که با
prompts/listشناسایی و باprompts/getرندر میشوند.
مفاهیم Roots، Sampling و Logging صرفاً برای سازگاری در اسکیمای 2026-07-28 باقی ماندهاند، اما منسوخ (Deprecated) شدهاند. پیادهسازیهای جدید باید برای Roots از ورودیهای صریح ابزار یا منبع، برای Sampling از APIهای مستقیم ارائهدهندگان مدل، و برای Logging از stderr یا OpenTelemetry استفاده کنند. قابلیت استخراج اطلاعات (Elicitation) همچنان از طریق «درخواستهای چند رفتوبرگشتی» (Multi Round-Trip Requests) در دسترس است؛ بهطوریکه سرور یک درخواست ورودی برمیگرداند و کلاینت عملیات اصلی را دوباره تکرار میکند. سرور مدرن هرگز خودش درخواست JSON-RPC مستقلی را آغاز نمیکند.
ساختار بستههای JSON-RPC
پروتکل MCP از JSON-RPC 2.0 استفاده میکند:
- درخواست:
{jsonrpc, id, method, params} - پاسخ:
{jsonrpc, id, result}یا{jsonrpc, id, error} - اعلان (Notification):
{jsonrpc, method, params}بدونid
شناسهی (id) درخواست، صرفاً پاسخ را به همان درخواست مرتبط میکند و نشست پروتکلی نمیسازد.
فرادادههای الزامی درخواست
هر درخواست مدرن یک آبجکت _meta درون params حمل میکند:
{
"jsonrpc": "2.0",
"id": 7,
"method": "tools/list",
"params": {
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientCapabilities": {},
"io.modelcontextprotocol/clientInfo": {
"name": "course-client",
"version": "1.0.0"
}
}
}
}
نسخهی پروتکل و قابلیتهای کلاینت الزامی هستند. هویت کلاینت پیشنهادی است؛ این فیلد اطلاعاتی نمایشی برای دیباگ است که خود کلاینت گزارش میدهد، نه یک مدرک امنیتی.
سرور نباید هیچکدام از این مقادیر را صرفاً از درخواست قبلی، فرایند stdio، اتصال HTTP یا هدر بستر انتقال (Transport) استنتاج کند.
نتایج کامل و هویت سرور
تمام نتایج موفق در پروتکل مدرن شامل resultType هستند. یک نتیجهی نهایی معمولی مقدار "complete" دارد. سرورها همچنین باید هویت خود را در فرادادهی نتیجه اعلام کنند:
{
"jsonrpc": "2.0",
"id": 7,
"result": {
"resultType": "complete",
"tools": [],
"ttlMs": 30000,
"cacheScope": "public",
"_meta": {
"io.modelcontextprotocol/serverInfo": {
"name": "notes-server",
"version": "1.0.0"
}
}
}
}
متدهای tools/list، resources/list، prompts/list، resources/templates/list، resources/read و server/discover نتایج کشپذیر دارند و شامل ttlMs و cacheScope میشوند. یک پیشفرض امن ttlMs: 0 و cacheScope: "private" است. آیتمهای لیست باید ترتیب قطعی (Deterministic) داشته باشند تا پاسخهای معادل، کلیدهای کش پایدار و کانتکست باثباتی برای مدل ایجاد کنند.
کشف بدون دستدادن
همهی سرورهای مدرن باید server/discover را پیادهسازی کنند. کلاینت میتواند پیش از فراخوانی هر متد دیگری، آن را برای دریافت موارد زیر فراخوانی کند:
supportedVersions- قابلیتهای سرور (
capabilities) - راهنمای استفادهی اختیاری (
instructions) - هویت سرور در بخش
_metaنتیجه - راهنماهای کش (Cache hints)
فرایند کشف (Discovery) مفید است، اما سد راه نیست. کلاینت میتواند همان ابتدا tools/list را بفرستد، چون آن درخواست خودش نسخهی پروتکل و قابلیتهایش را همراه دارد.
اگر نسخهی درخواستی پشتیبانی نشود، سرور کد خطای JSON-RPC به شمارهی -32022 را همراه با اطلاعات زیر برمیگرداند:
{
"requested": "2027-01-01",
"supported": ["2026-07-28"]
}
سپس کلاینت نسخهی مدرنی را انتخاب میکند که هر دو طرف پشتیبانی میکنند و درخواست را با یک id جدید در JSON-RPC تکرار میکند.
چرخهی عمر یک درخواست
یک درخواست مدرن را به این ترتیب ردگیری کنید:
- بستهی JSON-RPC را پارس کنید.
- مطمئن شوید مقدار
jsonrpcبرابر"2.0"است،idوجود دارد،methodرشته متنی است وparamsیک آبجکت است. - وجود رشتهی نسخه و آبجکت قابلیتها را در
params._metaالزامی بدانید؛ فرادادهی ناقص یا ناموجود خطای-32602دارد. - در مرز ارتباط HTTP، هدرهای نسخه، متد و هدرهای نام مرتبط را با بدنه مقایسه کنید. عدم تطابق، خطای
-32020است؛ حتی اگر یکی از این دو مقدار نسخه پشتیبانینشده باشد. - بعد از اطمینان از یکسانبودن، اگر نسخهی تطبیقیافته پشتیبانی نمیشود، آن را با
-32022رد کنید. - قابلیتهای الزامی را بررسی کنید، سپس بر اساس
methodمسیردهی انجام دهید و آرگومانهای اختصاصی متد را بسنجید. - پیش از اجرای هندلر (Handler)، عملیات مشخصشده را احراز هویت و مجوزسنجی کنید.
- یک نتیجهی کامل همراه با هویت سرور برگردانید.
- فرادادههای پروتکلِ مربوط به این درخواست را از حافظه پاک کنید.
این ترتیب مانع از آن میشود که دو بخش مختلف سیستم، فراخوانیها را به دو شکل متفاوت تفسیر کنند. نباید گیتوی به Mcp-Name: notes.read مجوز بدهد در حالی که سرور مبدا در حال اجرای params.name: notes.delete است. علاوه بر این، ورودی نامعتبر، تداخل هدرها، مذاکرهی نسخه، نقص قابلیتها، خطای مجوز و خطای هندلر هرکدام شواهد (Evidence) مجزا و مشخصی باقی میمانند.
بستن stdin یا پاسخ HTTP به فعالیت بستر انتقال پایان میدهد، اما نشست پروتکل را نمیبندد؛ چون MCP مدرن اصلاً نشست پروتکلی ندارد.
سازگاری صریح با نسخههای قدیمی
نسخههای تا تاریخ 2025-11-25 از initialize، اعلان notifications/initialized، قابلیتهای وابسته به اتصال، و در نسخههای اولیهی Streamable HTTP، از نشستهای اختیاری پروتکل استفاده میکنند. این رفتارها هنوز هنگام ارتباط یک کلاینت دومنظوره با سروری قدیمی کاربرد دارند.
این دورهها را کاملاً جدا نگه دارید. درخواست مدرن از روی فرادادههای الزامی درون هر درخواست مشخص میشود. اتصال به شیوهی قدیمی نیز فقط از مسیر جایگزینِ (Fallback) مستندشده انتخاب میشود. هرگز بهصورت پیشفرض برای یک سرور نسخهی 2026-07-28 درخواست initialize نفرستید.
بنابراین «بیوضعیت» در هر دوره معنای متفاوتی دارد. در نسخهی 2026-07-28، این یک اصل تغییرناپذیر در پروتکل است: هر درخواست عادی بهطور مستقل تفسیرپذیر است و هیچ نشست MCPای وجود ندارد. اما در نسخههای تا تاریخ 2025-11-25، آمادهسازی اولیه و قابلیتهای توافقشده به اتصال تعلق دارند؛ بنابراین یک تطبیقدهنده (Adapter) سازگاری میتواند این وضعیت اتصال قدیمی را نگه دارد. پیادهسازی سازگار با هر دو دوره به معنای ساخت یک ماشین وضعیت (State Machine) سهلگیر نیست؛ بلکه قرار دادن یک هستهی مدرن بیوضعیت در کنار یک تطبیقدهندهی مجزای قدیمی است، بهطوری که پیش از اجرای هر کدام از پارسرها، تصمیمی صریح برای انتخاب میان آنها گرفته شود.
هیچکدام از این دو تعریف، مانع از ذخیرهی وضعیت پایدار برنامه (Application State) نیستند. گردش کار، تسک یا پیشنویس میتواند پشت یک شناسهی مات (Opaque handle) در فضایی ذخیرهسازی مشترک قرار بگیرد. کلاینت این شناسه را به عنوان ورودی معمولی میفرستد و تکتک رپلیکاها (Replicas) استفاده از آن را احراز هویت و مجوزسنجی میکنند. نباید کانتکست پروتکل وارد این فضای ذخیرهسازی شود تا جای خالی نشستِ حذفشده را پر کند.
پیادهسازی عملی
فایل code/main.py پیامهای مدرن MCP را بدون نیاز به هیچ فریمورکی میسازد، اعتبارسنجی و ردگیری میکند و به مقصد میفرستد. دستور زیر را اجرا کنید:
python3 code/main.py
python3 -m unittest discover code/tests -v
در خروجی برنامه، به سه اصل تغییرناپذیر دقت کنید:
- تکتک درخواستها فیلدهای
_metaخود را تکرار میکنند. - تکتک نتایج موفق، دارای
resultType: "complete"بوده و هویت سرور را دارند. - نتیجهی لیستها ترتیب کاملاً قطعی دارد و راهنماهای کش بهطور صریح در آن آمدهاند.
ارائهی نهایی
خروجی این درس فایل outputs/skill-mcp-handshake-tracer.md است. نام قدیمی فایل حفظ شده، اما ماهیت آن حالا یک ردگیر درخواستهای بیوضعیت است. این ابزار هر پیام را مستقل بررسی میکند و ترافیک مربوط به دستدادن سنتی را فقط زمانی برچسبگذاری میکند که واقعاً وجود داشته باشد.
تمرینها
- نسخهی پروتکل یکی از درخواستها را به
2027-01-01تغییر دهید. بررسی کنید که کد خطای-32022برگردد و دادههای خطا، نسخهی پشتیبانیشده را معرفی کنند. - کلید
io.modelcontextprotocol/clientCapabilitiesرا از درخواست دوم حذف کنید. مطمئن شوید سرور از قابلیتهای اعلامشده در درخواست اول استفاده نمیکند. - ترتیب ذخیرهی ابزارها را در رجیستری حافظه معکوس کنید. بررسی کنید که
tools/listهمچنان همان خروجی با ترتیب قطعی را برگرداند. - مقدار
cacheScopeرا ازpublicبهprivateتغییر دهید. توضیح دهید در هر حالت، کدام کانتکستهای احراز مجوز مجاز به استفادهی مجدد از پاسخ هستند. - تستی برای حذف فیلد اختیاری
clientInfoبنویسید. درخواست باید معتبر بماند، چون اطلاعات هویت کلاینت صرفاً پیشنهادی است و الزامی نیست.
اصطلاحات کلیدی
| اصطلاح | معنا |
|---|---|
| پروتکل بیوضعیت (Stateless protocol) | هر درخواست، فرادادههای لازم برای تفسیر خودش را به همراه دارد |
| فرادادهی درخواست (Request metadata) | نسخه، قابلیتهای کلاینت و هویت پیشنهادی کلاینت در params._meta |
server/discover |
متد الزامی سرور برای نسخهها، قابلیتها، دستورالعملها و هویت |
resultType |
تفکیککنندهی وضعیت در تکتک نتایج موفق مدرن |
| نتیجهی کشپذیر (Cacheable result) | پاسخی که حاوی راهنماهای الزامی ttlMs و cacheScope است |
| دورهی پروتکل (Protocol era) | فرادادههای مدرن در هر درخواست یا آمادهسازی اولیهی قدیمی وابسته به اتصال |
| طول عمر بستر انتقال (Transport lifetime) | طول عمر فرایند، اتصال یا استریم پاسخ؛ جدا از وضعیت نشست پروتکل |
-32022 |
خطای نسخهی پشتیبانینشدهی پروتکل همراه با نسخهی درخواستی و نسخههای پشتیبانیشده |
