MCP بر اساس مشخصات: سرور واقعاً چیست
یک خط JSON به یک subprocess میفرستید و ۱۳ تعریف ابزار برمیگردد؛ مطابق بازنگری 2026-07-28 که handshake را حذف کرد.
در این صفحه
یک MCP server منتشرشده نصب کنید، یک خط JSON به آن بفرستید، و ببینید چه چیزی برمیگردد.
npm i @modelcontextprotocol/server-everything@2026.8.31
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' \
| npx @modelcontextprotocol/server-everything stdio{"result":{"tools":[{"name":"echo","title":"Echo Tool","description":"Echoes
back the input string","inputSchema":{"$schema":"http://json-schema.org/draft-07/
schema#","type":"object","properties":{"message":{"type":"string","description":
"Message to echo"}},"required":["message"]},"annotations":{"readOnlyHint":true,
… … 7,663 bytes on one line …
"jsonrpc":"2.0","id":1}سیزده تعریف ابزار، در یک خط، از پردازشی که یک خط از ورودی استانداردش خوانده است. شما همین حالا با Model Context Protocol حرف زدهاید، بدون SDK، بدون کتابخانهٔ client و بدون framework. تمام ماجرا همین است: یک transport، یک قالب پیام، و مجموعهٔ کوچکی از متدهای نامدار.
فصل 18 یک ابزار را به دو چیز تعریف کرد — یک JSON Schema که مدل میبیند، و یک endpoint در کد شما که مدل هرگز نمیبیند. فصل 23 یک harness ساخت که کاتالوگی از آنها را نگه میدارد. هیچکدام به پرسشی پاسخ ندادند که تعیین میکند آیا هرکدام از اینها قابل استفادهٔ مجدد هست یا نه: چه کسی schema را مینویسد، و چگونه از دست نویسندهاش وارد prompt شما میشود؟ MCP یکی از پاسخها به این پرسش است، و ارزش دارد آن را از متن اصلی بخوانیم، چون تقریباً هرچه دربارهاش نوشته شده بازنگریای را توصیف میکند که دیگر وجود ندارد.
سه چیز دربارهٔ دستوری که همین حالا اجرا کردید غلط است، و هرکدام یک بخش از این فصل است. هیچ نسخهٔ پروتکلی حمل نمیکرد، پس یک سرور سازگار باید آن را رد میکرد. با این حال پاسخ گرفت، به دلیلی که مشخصات آن را نه یک قابلیت، بلکه یک خطر مینامد. و یکی از سه primitive را درخواست کرد بیآنکه هرگز کشف کند دو primitive دیگر هم وجود دارند.
مسئلهای که حل میکند، و قیاسی که خود spec میسازد
لینک به بخش: مسئلهای که حل میکند، و قیاسی که خود spec میسازدپیش از wire، حسابوکتاب را ببینید. شما برنامهٔ AI دارید و چیزی که باید بتوانند به آنها دسترسی پیدا کنند — تقویم، ticket tracker، پایگاه دادهٔ warehouse، ابزار طراحی. بدون یک قرارداد مشترک، کسی integration مینویسد، و هرکدام یک schema بهعلاوهٔ یک endpoint بهعلاوهٔ داستان authentication بهعلاوهٔ بار نگهداری است. با قرارداد مشترک، فروشندهٔ ابزار یک server مینویسد، فروشندهٔ برنامه یک client مینویسد، و مجموع میشود .
این مشاهده تازه نیست، و مشخصات میگوید ایده از چه کسی آمده است:
MCP takes some inspiration from the Language Server Protocol, which standardizes how to add support for programming languages across a whole ecosystem of development tools. In a similar way, MCP standardizes how to integrate additional context and tools into the ecosystem of AI applications.1
این مقایسه را جدی بگیرید، نه صرفاً بهعنوان تعریف و تمجید. پیش از آن پروتکل، پشتیبانی از یک زبان در یک editor یعنی یک plugin برای هر editor؛ بعد از آن، تیم زبان یک server منتشر میکرد و هر editor آن را دریافت میکرد. معیار موفقیت ظرافت نبود، این بود که تعداد integrationها دیگر ضرب نمیشد. همین منطق اینجا هم برقرار است: ارزش در تعداد پیادهسازیهاست، نه در طراحی. پروتکلی که فقط دو محصول با آن حرف میزنند، یک قالب داده با تشریفات اضافه است.
روی wire واقعاً چه چیزی است
لینک به بخش: روی wire واقعاً چه چیزی استپیامهای MCP همان JSON-RPC 2.0 هستند. یک request شیئی است با jsonrpc، یک id، یک method و params اختیاری؛ یک response همان id را حمل میکند و یا result دارد یا error؛ یک notification درخواستی بدون id است و پاسخی نمیگیرد. مشخصات سه محدودیت هم اضافه میکند: id باید string یا number باشد و نباید null باشد، نباید با request دیگری که هنوز در جریان است تداخل داشته باشد، و هر result باید یک فیلد resultType حمل کند.2
روی stdio transport — همان که دستور بالا استفاده کرد — قانون framing این است: هر پیام، یک خط:
Messages are delimited by newlines, and MUST NOT contain embedded newlines. […] The server MUST NOT write anything to its
stdoutthat is not a valid MCP message.3
همین بند آخر رایجترین راهی است که یک server دستساز را خراب میکند، و بیصدا خراب میکند: یک console.log سرگردان، یک progress bar، یک deprecation warning از یک dependency، و line parser کلاینت به چیزی میرسد که JSON نیست. راه فرار در همان بخش است — server may هرچه میخواهد در stderr بنویسد، و client should not آن را خطا حساب کند. reference server بالا در هر اجرا Starting default (STDIO) server... را روی stderr چاپ میکند، و برای همین pipe هنوز کار کرد.
transport استاندارد دیگر Streamable HTTP است: هر پیام یک POST به یک endpoint واحد است، و پاسخ یا یک شیء JSON است یا یک stream در محدودهٔ همان request از Server-Sent Events — همان wire format که فصل 14 دستی parse کرد. معناشناسی در هر دو یکسان است، چون transport یک binding است: framing و delivery را تعریف میکند، نه معنا را.4
اولین چیزی که غلط بود: نسخهای وجود نداشت
لینک به بخش: اولین چیزی که غلط بود: نسخهای وجود نداشتدستور بالا tools/list و هیچ چیز دیگری فرستاد. طبق بازنگری فعلی، آن request malformed است، و یک server سازگار باید آن را رد کند.
از 2026-07-28 به بعد، MCP پروتکلی stateless است، و مشخصات بدون ابهام میگوید:
The Model Context Protocol (MCP) is a stateless protocol: all the information needed to process a request is contained in the request itself. A server processes each request independently; no state should be inferred from previous requests, even those on the same connection or stream.2
پس هر request نسخهٔ پروتکل خودش و قابلیتهای client خودش را حمل میکند، در یک شیء رزروشدهٔ _meta داخل params. دو فیلد از آنها در تکتک requestها الزامیاند؛ requestی که هرکدام را نداشته باشد malformed است و server must با -32602 جواب بدهد:2
کلید _meta | الزامی | چیست |
|---|---|---|
io.modelcontextprotocol/protocolVersion | بله | بازنگریای که این request با آن حرف میزند، مثلاً "2026-07-28" |
io.modelcontextprotocol/clientCapabilities | بله | آنچه client میتواند در این request برای server انجام دهد |
io.modelcontextprotocol/clientInfo | نه (اما should) | نام و نسخهٔ client، فقط برای نمایش و logها |
io.modelcontextprotocol/logLevel | نه | حداقل سطح log که server باید برای این request منتشر کند |
اگر کامل بنویسیم، یک tools/list درست چنین است — و این آخرین باری است که این فصل metadata را کامل نشان میدهد، چون از اینجا به بعد روی هر request هست:
{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{"_meta":{
"io.modelcontextprotocol/protocolVersion":"2026-07-28",
"io.modelcontextprotocol/clientCapabilities":{"elicitation":{"form":{}}},
"io.modelcontextprotocol/clientInfo":{"name":"bare-hands","version":"0.0.1"}}}}شیء capability همان negotiation است. دیگر هیچ گام negotiation جداگانهای وجود ندارد: client در هر request اعلام میکند چه کارهایی میتواند بکند، server در result اعلام میکند چه کارهایی میتواند بکند، و هیچیک از دو طرف نباید از قابلیتی استفاده کند که طرف دیگر ادعا نکرده است. سروری که به قابلیتی نیاز دارد که client اعلام نکرده must با -32021 جواب بدهد و capability گمشده را در data.requiredCapabilities نام ببرد. سروری که نسخهٔ درخواستی را نمیفهمد must با -32022 جواب بدهد و نسخههایی را که میفهمد فهرست کند.2
clientهایی که جواب را از ابتدا میخواهند میتوانند درخواستش کنند: server/discover یک RPC اجباری است که نسخههای پشتیبانیشده، capabilities، identity و یک بلوک اختیاری از instructions را در یک round trip برمیگرداند.5 فراخواندنش اختیاری است. پیادهسازیاش نیست.
دومین چیزی که غلط بود: سرور legacy بود
لینک به بخش: دومین چیزی که غلط بود: سرور legacy بوددستور کار کرد. طبق بازنگری فعلی نباید کار میکرد، و دلیل کار کردنش ارزش اندازهگیری دارد نه یک پاراگراف، چون وضعیت کل ecosystem را در یک خط نشان میدهد.
reference server را همانطور probe کنید که مشخصات به یک client مدرن میگوید probe کند:
echo '{"jsonrpc":"2.0","id":1,"method":"server/discover","params":{"_meta":{
"io.modelcontextprotocol/protocolVersion":"2026-07-28",
"io.modelcontextprotocol/clientCapabilities":{}}}}' \
| npx @modelcontextprotocol/server-everything stdio{"jsonrpc":"2.0","id":1,"error":{"code":-32601,"message":"Method not found"}}این شاخهٔ سوم قانون سازگاری است: یک DiscoverResult یعنی مدرن، یک خطای مدرنِ شناختهشده یعنی مدرن اما با نسخهٔ غلط، و هر چیز دیگر — از جمله -32601 — یعنی legacy، برگرد به handshake initialize.3 پس همین کار را بکنید، و بازنگری فعلی را بخواهید:
→ {"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2026-07-28",
"capabilities":{},"clientInfo":{"name":"bare-hands","version":"0.0.1"}}}
← {"result":{"protocolVersion":"2025-11-25","capabilities":{"tools":{"listChanged":true},
"prompts":{"listChanged":true},"resources":{"subscribe":true,"listChanged":true},
"logging":{},"tasks":{…},"completions":{}},"serverInfo":{"name":"mcp-servers/everything",
"title":"Everything Reference Server","version":"2.0.0"},"instructions":"…"}}client درخواست 2026-07-28 داد و server با 2025-11-25 جواب داد. در 7 سپتامبر 2026، official reference server — بستهٔ npm به نام @modelcontextprotocol/server-everything، نسخهٔ 2026.8.31، منتشرشده در 31 اوت 2026 — بازنگری فعلی را پیادهسازی نمیکند. TypeScript SDKای هم که بر پایهٔ آن ساخته شده، طبق تاریخها، پیادهسازی نمیکند: انتشار 1.30.0 در 27 ژوئیهٔ 2026 بیرون آمد، یک روز پیش از خود بازنگری.
پیامد را بخوانید، نه حاشیه را. تقریباً هرچه دربارهٔ MCP نوشته شده، پروتکلی را توصیف میکند با handshake initialize، یک session، یک request roots/list که server برای client میفرستد، و یک HTTP+SSE transport. هر چهار مورد حذف شدهاند یا در مسیر حذفاند. وقتی هر چیزی دربارهٔ MCP میخوانید، از جمله همین صفحه، اولین چیزی که باید دنبالش بگردید شمارهٔ بازنگری است.
و دلیل اینکه همان دستور اول کار کرد، در مشخصات بهعنوان خطر آمده است نه قابلیت:
some legacy servers do not validate that a request arrives after
initializeand would process an era-ambiguous method (such astools/call) under legacy semantics. Probing yields a deterministic failure instead.3
اندازهگیری شد: فرستادن tools/list به آن server بدون هیچ handshakeای کل کاتالوگ را برمیگرداند. متدی که باید رد میشد سرو شد، و دقیقاً به همین دلیل است که مشخصات میگوید حتی وقتی فقط از نسخههای مدرن پشتیبانی میکنید، اول با server/discover probe کنید.
سه نقش، و جملهای که باید از کل سند نقل کرد
لینک به بخش: سه نقش، و جملهای که باید از کل سند نقل کردMCP سه طرف دارد، و تمایز بین دو مورد اول همان چیزی است که مردم قاطی میکنند:
Host. برنامه: محصول chat، editor، agent. مالک conversation، مدل، credentials و رضایت کاربر است. clientها را میسازد و مرز امنیتی بین آنها را enforce میکند.
Client. یک connector داخل host. هر client با دقیقاً یک server حرف میزند — یک رابطهٔ سختگیرانهٔ 1:1 — و نسخهٔ پروتکل و capabilities را به هر requestی که route میکند وصل میکند.
Server. یک پردازش یا service که resources، tools و prompts را expose میکند. میتواند local یا remote باشد، مستقل عمل میکند، و کل کارش یک حوزهٔ متمرکز است.6
این قانون «دقیقاً یک server» صرفاً bookkeeping نیست. همان چیزی است که اصل طراحی زیر را قابل پیادهسازی میکند، و اگر قرار باشد از مشخصات فقط یک جمله بردارید، همین است:
Servers should not be able to read the whole conversation, nor "see into" other servers. Servers receive only necessary contextual information. Full conversation history stays with the host. Each server maintains isolation. Cross-server interactions are controlled by the host.6
این جمله مدل ذهنیای را که بیشتر مردم با آن وارد میشوند واژگون میکند. یک weather server که به assistant خود وصل میکنید نمیبیند چه پرسیدهاید. یک tools/call با argumentsی که مدل انتخاب کرده میبیند، و هیچ چیز دیگر — نه turnهای قبلی، نه system prompt شما، نه resultهایی که calendar server یک لحظه پیش برگردانده است. اگر دو server باید همکاری کنند، host عمداً مقداری را از یکی به دیگری حمل میکند، چون مدل چنین خواسته است. برای همین isolation همان ویژگی امنیتیای است که فصل 30 به آن تکیه میکند: یک server compromiseشده blast radius کوچک و تعریفشدهای دارد، و بزرگ کردنش نیازمند همکاری host است.
سومین چیز: سه primitive، مرتبشده بر اساس اینکه چه کسی کنترل دارد
لینک به بخش: سومین چیز: سه primitive، مرتبشده بر اساس اینکه چه کسی کنترل دارددستور اول از آن server ابزارها را خواست و سیزده مورد گرفت. دو سؤال دیگر را هم از آن بپرسید و آنها را هم جواب میدهد: resources/list هفت مورد برمیگرداند، prompts/list چهار مورد. هیچکدام ظاهر نشدند، چون چیزی آنها را نخواست. و این ما را به ستون آموزشی MCP میرساند، که در مشخصات بهصورت جدولی آمده و تقریباً هیچکس نقلش نمیکند:
| Primitive | Control | Description | Example |
|---|---|---|---|
| Prompts | User-controlled | قالبهای تعاملی که با انتخاب کاربر invoke میشوند | Slash commands، گزینههای menu |
| Resources | Application-controlled | دادهٔ contextای که client attach و مدیریت میکند | محتوای فایل، history گیت |
| Tools | Model-controlled | functionهایی که برای انجام action در اختیار LLM قرار میگیرند | API POST requests، نوشتن فایل |
نه «سه راه برای expose کردن یک capability». سه پاسخ به اینکه چه کسی تصمیم میگیرد این اتفاق بیفتد. مدل تصمیم میگیرد tool را call کند. برنامه تصمیم میگیرد resource را attach کند. انسان تصمیم میگیرد prompt را اجرا کند. اگر این را اشتباه بفهمید، feature هنوز کار میکند، اما در زمان غلط و به دلیل غلط کار میکند.
روشنترین راه برای حس کردنش تقویم است. اینجا serverای داریم که همان تقویم را سه بار expose میکند، هر بار بهعنوان یکی از primitiveها، در صد خط Node ساده و بدون dependency:
const TOOL = {
name: "create_event",
description: "Create a calendar event. Writes to the calendar.",
inputSchema: {
type: "object",
properties: {
title: { type: "string", description: "Event title." },
startsAt: { type: "string", format: "date-time", description: "Start, ISO 8601 UTC." },
},
required: ["title"],
},
};
switch (method) {
case "resources/read":
return ok(id, { contents: [{ uri: "calendar://week",
mimeType: "application/json", text: JSON.stringify(EVENTS) }],
ttlMs: 60000, cacheScope: "private" });
case "prompts/get":
return ok(id, { description: PROMPT.description, messages: [{ role: "user",
content: { type: "text", text: `Read calendar://week and draft a plan. ` +
`Focus: ${params.arguments?.focus ?? "balance"}.` } }] });
case "tools/list":
return ok(id, { tools: [TOOL], ttlMs: 300000, cacheScope: "public" });
}آن را اجرا کنید و از هر سه راه بپرسید. خروجی واقعی، یک پیام در هر خط روی wire، اینجا برای صفحه wrap شده، با request _meta و بلوک identity سرور حذفشده:
→ resources/read {"uri":"calendar://week"}
← {"resultType":"complete","contents":[{"uri":"calendar://week",
"mimeType":"application/json","text":"[{\"id\":\"e1\",\"title\":\"Standup\",
\"startsAt\":\"2026-09-07T09:00:00Z\"},{\"id\":\"e2\",\"title\":\"Design review\",
\"startsAt\":\"2026-09-09T15:00:00Z\"}]"}],"ttlMs":60000,"cacheScope":"private"}
→ prompts/get {"name":"prepare_week","arguments":{"focus":"deep work"}}
← {"resultType":"complete","description":"Read the week and draft a plan.",
"messages":[{"role":"user","content":{"type":"text",
"text":"Read calendar://week and draft a plan. Focus: deep work."}}]}
→ tools/call {"name":"create_event","arguments":{"title":"Dentist",
"startsAt":"2026-09-10T08:30:00Z"}}
← {"resultType":"complete","content":[{"type":"text",
"text":"Created e3: Dentist at 2026-09-10T08:30:00Z"}],
"structuredContent":{"id":"e3","title":"Dentist","startsAt":"2026-09-10T08:30:00Z"},
"isError":false}سه متد، سه شکل، یک تقویم. حالا نکته:
خواندن هفته یک resource است
لینک به بخش: خواندن هفته یک resource استبا URI آدرسدهی میشود، inert است، و برنامه تصمیم میگیرد آیا آن را به conversation attach کند یا نه. هیچ چیز در پروتکل به مدل اجازه نمیدهد خودش سراغش برود. result شامل ttlMs و cacheScope است، که در این بازنگری جدیدند، تا client بتواند هفته را بهجای polling برای یک دقیقه cache کند.
ساختن یک event یک tool است
لینک به بخش: ساختن یک event یک tool استschema دارد، side effect دارد، و مدل تصمیم میگیرد چه زمانی آن را call کند. result آن شامل isError است، همان فیلدی که فصل 18 برایش استدلال کرد: validation failure بهعنوان tool result برمیگردد که مدل میتواند بخواند و اصلاح کند، نه بهعنوان protocol error.
«هفتهام را آماده کن» یک prompt است
لینک به بخش: «هفتهام را آماده کن» یک prompt استیک template نامدار و argumentپذیر است که انسان invoke میکند — همان slash command در menu. messages برمیگرداند، نه answer. راهی است برای اینکه نویسندهٔ server phrasingای را منتشر کند که با ابزارهای خودش کار میکند؛ دقیقاً همان دانشی که نویسندهٔ server دارد و کاربر ندارد.
تقریباً همه هر سهٔ اینها را tool میسازند. نتیجه کاتالوگی است که در آن یک read که برنامه باید بیصدا attach میکرد، برای attention مدل با writeای رقابت میکند که نیاز به approval دارد، و چیزی که یک انسان برایش دکمه میخواست زیر schema دفن میشود. درست انجام دادنش هیچ هزینهای ندارد، و پیش از نوشتن حتی یک خط تصمیمگیری میشود.
سرور نمیتواند شما را call کند
لینک به بخش: سرور نمیتواند شما را call کندcalendar tool یک argument الزامی دارد، title، و یک startsAt اختیاری. از آن بخواهید بدون date یک event بسازد، و چیز جالبی برمیگردد:
→ tools/call {"name":"create_event","arguments":{"title":"Dentist"}}
← {"resultType":"input_required",
"inputRequests":{"when":{"method":"elicitation/create","params":{"mode":"form",
"message":"When should \"Dentist\" start?",
"requestedSchema":{"type":"object",
"properties":{"startsAt":{"type":"string","format":"date-time"}},
"required":["startsAt"]}}}},
"requestState":"eyJ0aXRsZSI6IkRlbnRpc3QifQ=="}server هیچ requestی نفرستاد. به همان requestی که گرفته بود پاسخ داد، با resultType: "input_required" و توضیح اینکه هنوز چه چیزی لازم دارد. client پاسخ را از انسان جمع میکند، و سپس call اصلی را دوباره میفرستد — با یک id جدید، همراه با inputResponses و echo کردن requestState opaque:
→ tools/call {"name":"create_event","arguments":{"title":"Dentist"},
"inputResponses":{"when":{"action":"accept",
"content":{"startsAt":"2026-09-10T08:30:00Z"}}},
"requestState":"eyJ0aXRsZSI6IkRlbnRpc3QifQ=="}
← {"resultType":"complete","content":[{"type":"text",
"text":"Created e3: Dentist at 2026-09-10T08:30:00Z"}],"isError":false}این Multi Round-Trip Requests است، که در بازنگری فعلی معرفی شد، و جایگزین طراحی قدیمی شد که در آن serverها JSON-RPC request را به clientها برمیگرداندند. مشخصات transport اکنون قانون را صریح میگوید: «servers do not initiate JSON-RPC requests and clients do not send JSON-RPC responses».4 initiative فقط یک جهت دارد، و متعلق به host است.
دو feature سمت client روی همین سازوکار سوارند، و یکیشان نامی دارد که شما را زمین میزند.
Elicitation یعنی server از انسان چیزی میخواهد: فرمی با JSON Schema عمداً محدود — objectهای flat، propertyهای primitive، بدون nesting — تا هر client بتواند بدون layout engine آن را render کند. یک قانون سخت دارد: serverها must not از form mode برای درخواست «passwords, API keys, access tokens, or payment credentials» استفاده کنند، و must برای آنها از URL mode استفاده کنند، که کاربر را به صفحهای میفرستد که client هرگز نمیخواند.7
Sampling یعنی server از مدل host درخواست generation میکند، تا server بتواند بدون داشتن API key هوشمند باشد. و اینجا هشدار واژگانی لازم است، چون این کلمه در این دوره از قبل معنای دیگری دارد: این sampling فصل 17 نیست. اینجا هیچ چیز دربارهٔ temperature، top-p یا شکل یک توزیع احتمال نیست. یک model call تودرتو است که از مسیر پروتکل به عقب سفر میکند.
دلیل دومی هم هست که سراغش نروید: از همین بازنگری، sampling deprecated است، کنار roots و logging، تحت SEP-2577، با migration پیشنهادی رکوراست — «integrate directly with LLM provider APIs instead of Sampling».8 ایده از نظر فنی شکست نخورد؛ نتوانست surface area خود را توجیه کند، و پروتکلی که میتواند چیزها را حذف کند سالمتر از پروتکلی است که نمیتواند.
عمداً خرابش کنید: connectionها session نیستند
لینک به بخش: عمداً خرابش کنید: connectionها session نیستندStatelessness تا وقتی آزمایش نشود شبیه جزئیات wire-format به نظر میرسد. exchange سهپیامی بالا را بردارید و هر پیام را در یک پردازش جداگانه اجرا کنید — یک node calendar.mjs تازه، بدون shared memory، بدون اینکه چیزی منتقل شود:
process A tools/call (no date) → resultType: input_required
requestState: eyJ0aXRsZSI6IkRlbnRpc3QifQ==
process B tools/call (with the answer, same requestState)
→ resultType: complete
"Created e3: Dentist at 2026-09-10T08:30:00Z"
process C resources/read calendar://week
→ events: 2 (Standup, Design review)Process B، که هرگز سؤال را ندیده بود، یک multi-round-trip call را که Process A شروع کرده بود کامل کرد. هدف requestState همین است: continuation در پیام سفر میکند، پس هیچ چیز به یکی بودن process وابسته نیست.
Process C همان شکست است. event ساخته شد و آنجا نیست — چون toy server، EVENTS را در یک array در سطح module نگه میدارد، و array سطح module همان connection state است. note مشخصات اشتباه را دقیق نام میبرد:
an open connection, such as a STDIO process, is not a conversation or session: clients may interleave unrelated requests on the same transport, and a server must not treat connection or process identity as a proxy for conversation or session continuity.2
راهحل تجویزشده session نیست. یک handle صریح است: creation tool یک شناسهٔ opaque برمیگرداند، و هر call بعدی آن را بهعنوان argument معمولی میگیرد. پروتکل اصلاً مفهومی از آن ندارد — «from the wire's perspective a handle is an ordinary string in a tool result and an ordinary argument to subsequent tool calls».9 یعنی مدل مسئول حمل کردن آن است، و server مسئول validate کردن اینکه این caller اجازهٔ استفاده از آن را در تکتک callها دارد، چون handle یک نام است نه permission.
یک سرور پیش از آنکه کاری بکند چقدر هزینه دارد
لینک به بخش: یک سرور پیش از آنکه کاری بکند چقدر هزینه داردهر toolای که server expose میکند schemaای است که در هر request وارد prompt شما میشود، و فصل 24 اندازه گرفت این با window چه میکند. MCP یک line item دوم اضافه میکند که بهسادگی از قلم میافتد، پس هر دو را روی reference server بالا میشماریم.
13 tool definitions (name + description + inputSchema): 1,307 tokens
cheapest tool, get-tiny-image 52
costliest tool, gzip-file-as-resource 235
server `instructions`, returned by discovery: 312 tokens
------
one server, connected, before it is used: 1,619 tokensدو مشاهده. اولی arithmetic است: پنج server با این اندازه وصل کنید و تقریباً هشت هزار token از window شما در هر turn، برای همیشه، اشغال میشود، چه مدل از هیچکدام استفاده کند چه نکند — همین سازوکار پشت کاهش 150,000 به 2,000 است که فصل 24 نقل کرد، و دلیل وجود just-in-time tool discovery.
دومی نکتهای امنیتی است که لباس حسابداری پوشیده. instructions متن natural-language است، نوشتهٔ نویسندهٔ server، که وارد prompt host میشود، و tool descriptionهای کنار آن هم همینطورند. مشخصات در principles امنیتی خودش میگوید با این چه باید کرد: tool annotations و descriptions «should be considered untrusted, unless obtained from a trusted server»، و hostها «must obtain explicit user consent before invoking any tool».1 وصل کردن یک MCP server افزودن یک dependency نیست. یعنی به یک غریبه 1,619 token از system prompt خود و حق call شدن میدهید. فصل 30 اتفاقی است که وقتی آن غریبه hostile باشد میافتد.
بخش تاریخدار: بازنگری 2026-07-28، و چیزهایی که میشکند
لینک به بخش: بخش تاریخدار: بازنگری 2026-07-28، و چیزهایی که میشکندهمهچیز در این بخش دربارهٔ بازنگری پروتکل 2026-07-28 درست است، بازنگری فعلی، خواندهشده در 7 سپتامبر 2026. بازنگریها بهشکل YYYY-MM-DD تاریخگذاری میشوند و تاریخ همان آخرین باری است که تغییری ناسازگار با گذشته انجام شده است.10 سند normative یک فایل TypeScript است، schema/2026-07-28/schema.ts؛ JSON Schema کنار آن از همان تولید میشود، برای همین مشخصات اینجا در TypeScript خوانده میشود و آموزش MCP از هر چیز دیگر آموزش یک translation است.
| چه چیزی تغییر کرد | قبلاً | اکنون | چه چیزی را میشکند |
|---|---|---|---|
| Handshake | initialize + notifications/initialized، یک بار برای هر connection | حذف شده؛ هر request نسخه و capabilities _meta را حمل میکند | هر client نوشتهشده پیش از این بازنگری |
| Sessions | header Mcp-Session-Id، state در محدودهٔ connection | حذف شده؛ state در handleهای صریحِ mintشده توسط server سفر میکند | list endpointهایی که برای هر connection متفاوت بودند |
| Discovery | از result initialize استنباط میشد | server/discover، که serverها must پیادهسازی کنند | هیچ چیز، اما حالا پیادهسازیاش اجباری است |
| Server-to-client calls | server، roots/list، sampling/createMessage، elicitation/create میفرستاد | InputRequiredResult و retry از سمت client | هر serverی که request را به client push میکرد |
| شکل result | هر objectی | resultType الزامی: "complete" یا "input_required" | هیچ چیز: نبودن فیلد باید "complete" خوانده شود |
| Subscriptions | HTTP GET stream، resources/subscribe | یک stream subscriptions/listen با opt-in typeها | endpoint GET حذف شده است |
| Stream resumption | replay Last-Event-ID روی Streamable HTTP | حذف شده؛ stream شکسته request را از دست میدهد، با id جدید دوباره صادر کنید | clientهایی که به redelivery تکیه داشتند |
| Roots | یک feature سمت client که serverها میتوانستند بخواهند | deprecated (SEP-2577)؛ pathها را بهعنوان tool arguments یا resource URIs پاس بدهید | هنوز هیچ چیز — پنجرهٔ دوازدهماهه |
| Sampling و logging | client features | deprecated (SEP-2577) | هنوز هیچ چیز — پنجرهٔ دوازدهماهه |
| HTTP+SSE transport | از 2025-03-26 deprecated بود | تحت lifecycle policy (SEP-2596) Deprecated | به Streamable HTTP مهاجرت کنید |
| Client registration | OAuth 2.0 Dynamic Client Registration، RFC 7591 | deprecated به نفع Client ID Metadata Documents | برای authorization serverهایی که آنها را ندارند حفظ شده |
| Error codes | -32002 برای resource not found | -32602؛ -32020–-32099 برای spec رزرو شده | کدهای جدید -32020، -32021، -32022 |
تغییر governance زیر آن جدول از هر ردیف منفردی مهمتر است. این بازنگری یک feature lifecycle and deprecation policy پذیرفت: featureها Active، Deprecated یا Removed هستند، یک feature deprecated مسیر migration خود را مستند میکند و دستکم دوازده ماه در specification میماند تا واجد شرایط حذف شود، و registryای وجود دارد که همهٔ چیزهایی را که اکنون در وضعیت Deprecated هستند فهرست میکند.8 پیش از آن policy، «deprecated» در یک پروتکل AI یعنی هرچه آخرین blog post گفته بود. حالا یعنی یک تاریخ.
نمایش جزئیات
Extensions، بخشی که هنوز هیچکس دربارهاش ننوشته است.
فراتر از core، MCP extensions اختیاری تعریف میکند — «always opt-in and require explicit support from both client and server»، اعلامشده از طریق یک فیلد extensions در capabilities کلاینت و سرور.1 سه مورد ارزش دانستن با نام را دارند:
- Tasks (
io.modelcontextprotocol/tasks)، که در این بازنگری از core protocol بیرون آمد و به یک extension رسمی تبدیل شد: execution ناهمزمان عملیات طولانی، با polling از طریقtasks/get، input در میانهٔ اجرا از طریقtasks/update، و handleهای durable. این پاسخ به toolای است که بیست دقیقه طول میکشد؛ چیزی که فصل 23 با progress event و signalای که به tool میرسد حل کرده بود. - Skills over MCP، یک working group که skillهای agent — موضوع فصل 28 — را از طریق پروتکل discoverable و consumable میکند.
- MCP Apps، UI تعاملی که inline در conversation render میشود: chartها، formها، video playerها.
و توجه کنید «negotiated» حالا یعنی چه: initializationای وجود ندارد که negotiation در آن رخ دهد، پس extension هم مثل همهچیز دیگر per request اعلام میشود.
جایگاه MCP نسبت به هر چیزی که با آن اشتباه گرفته میشود
لینک به بخش: جایگاه MCP نسبت به هر چیزی که با آن اشتباه گرفته میشودواژگان کل این بلوک در یک جا.
| چیست | چه کسی با چه کسی حرف میزند | چه زمانی پاسخ درست است | |
|---|---|---|---|
| یک API ساده | interfaceای برای یک برنامه | کد شما ↔ یک service | شما دارید caller را مینویسید. schema، auth و error handling را کنترل میکنید، و مسئلهٔ discovery برای حل کردن وجود ندارد. |
| MCP | پروتکلی برای expose کردن tools، data و templates به یک برنامهٔ AI | host ↔ server، هرکدام یک client | شخص دیگری capability را نوشته و hostهای زیادی باید بتوانند بدون integration اختصاصی از آن استفاده کنند. |
| RAG | تکنیکی برای یافتن متن و گذاشتنش در prompt | کد شما ↔ index شما | مدل باید چیزی را بداند. فصل 19. MCP راهی برای delivery یک retriever است؛ خودش retriever نیست. |
| Agent skills | پوشهای با یک SKILL.md که مدل میخواند | مدل ↔ یک document | knowledge procedural است — اینکه ما این کار را چطور انجام میدهیم — و prose است، نه function. فصل 28. |
| A2A | پروتکلی برای همکاری agentها بهعنوان peers | agent ↔ agent | طرف دیگر reasoning میکند، plan میریزد و در طول یک task بلند state نگه میدارد، نه اینکه به یک call پاسخ دهد. |
| ACP | قبلاً یک پروتکل جداگانهٔ agent-communication بود | — | دیگر مقایسهٔ زندهای نیست. پایین را ببینید. |
دو مورد از اینها هرکدام یک جمله میخواهند، چون confusion واقعی همانجاست.
MCP در برابر A2A رقابت نیست، و هر دو specification همین را میگویند. مستندات A2A مرز را بر اساس چیزی که آنطرف است میکشد: MCP «defines how an AI agent interacts with and utilizes individual tools and resources, such as a database or an API»، جایی که toolها «specific, often stateless, functions» انجام میدهند؛ A2A با agentها سروکار دارد، «more autonomous systems» که «reason, plan, use multiple tools, maintain state over longer interactions, and engage in complex, often multi-turn dialogues» هستند. خلاصهٔ خودش جملهای است که باید به خاطر سپرد: «A2A is about agents partnering on tasks, while MCP is more about agents using capabilities.»11 این دو تودرتو میشوند — یک برنامه از A2A برای رسیدن به agentهای دیگر استفاده میکند، و هر agent از MCP برای رسیدن به ابزارهای خودش. فصل 25 این خط را داخل یک process کشید، بین پرسیدن از sub-agent و سپردن conversation به آن؛ A2A آن را بین سازمانها میکشد.
MCP در برابر ACP مقایسهای با پیشفرض کهنه است، و دقیقاً به همین دلیل ارزش پاسخ دادن دارد. Agent Communication Protocol یک استاندارد open جداگانه برای پیامرسانی agent-to-agent بود. مستندات خودش حالا با این notice شروع میشود: «ACP is now part of A2A under the Linux Foundation!»12 پاسخ صادقانه به «MCP یا ACP؟» در سپتامبر 2026 این است که سؤال یک گزینه کمتر از چیزی دارد که صفحههای رتبهگرفته برایش وانمود میکنند.
و مقایسهای که بیش از همه میپرسند، mcp vs api، کمجذابترین پاسخ را دارد: MCP یک API است. چیزی که اضافه میکند قدرت نیست، convention است — مجموعهای ثابت از method nameها، یک discovery call، سلسلهمراتب control روی primitiveها، و یک مدل isolation. آزادی طراحی interface خودتان را میدهید و در عوض هر hostای را میگیرید که با پروتکل حرف میزند؛ همان معاملهای که هر پروتکلی همیشه پیشنهاد کرده است.
بعد از این به کجا میرویم
لینک به بخش: بعد از این به کجا میرویمحالا میتوانید specification را بدون مترجم بخوانید، resource را از tool و prompt بر اساس اینکه چه کسی کنترلش میکند تشخیص دهید، وقتی client library به شما دروغ میگوید request را دستی تایپ کنید، و هر مقالهٔ MCPای را که میخوانید بر اساس featureهای deprecatedای که هنوز current آموزش میدهد تاریخگذاری کنید.
کاری که هنوز نکردهاید ship کردن یکی از آنهاست. فصل 27 همان server را دو بار مینویسد — TypeScript و Python، کنار هم، چون MCP تنها قلمرو واقعاً دوزبانهٔ این دوره است و اعداد در هر دو جهت همین را میگویند. دو transport زنده را درست پوشش میدهد، inspector، packaging، و نیمهای از پروتکل را که این فصل عمداً کنار گذاشت: authorization. چون لحظهای که server شما remote باشد نه یک subprocess روی لپتاپ خودتان، client یک غریبه token ارائه میکند، و قانون specification دربارهٔ اینکه با آن چه میتوانید بکنید بهطور غیرمعمول سختگیرانه است.
و این پرسشی را مطرح میکند که فصل بعد باید جواب دهد، و پرسش دوستانهای نیست: اگر tokenای به server شما برسد و برای audience شخص دیگری صادر شده باشد، دقیقاً چه چیزی جلوی شما را میگیرد که آن را forward کنید؟
منابع و روش
لینک به بخش: منابع و روشهر نقلقول، method name، error code و قاعده در این فصل از specification مربوط به Model Context Protocol، بازنگری 2026-07-28، در 7 سپتامبر 2026 خوانده شده است. هر trace بهصورت local روی Node 22 تولید شد: toy calendar server برابر 101 خط بدون dependency است، و reference server همان بستهٔ npm منتشرشدهای است که پایین نام آمده. برای نوشتن این فصل هیچ API پولی call نشد — هیچ چیز اینجا به مدل نیاز ندارد، که خودش نکتهٔ ماجراست.
اندازهگیریها: @modelcontextprotocol/server-everything@2026.8.31، منتشرشده در 31 اوت 2026، ساختهشده روی @modelcontextprotocol/sdk@1.30.0، منتشرشده در 27 ژوئیهٔ 2026 — یک روز پیش از بازنگریای که این فصل توصیف میکند. به server/discover با -32601 جواب میدهد، وقتی 2026-07-28 خواسته میشود 2025-11-25 را negotiate میکند، و tools/list را بدون هیچ handshakeای serve میکند. کاتالوگ آن 13 ابزار در 7,663 بایت است؛ تعداد tokenها o200k_base از طریق tiktoken است، روی name، description و inputSchema هر تعریف، که همان چیزی است که provider در prompt شما render میکند، نه وزن JSON-RPC frame.
Anthropic، Code execution with MCP: building more efficient agents، 4 نوامبر 2025، منبع عدد 150,000 به 2,000 است، که در فصل 24 نقل و استفاده شد و اینجا فقط reference داده شده است.
ارجاعات
لینک به بخش: ارجاعات-
Specification،
modelcontextprotocol.io/specification/latest(redirect به/2026-07-28)، خواندهشده در 7 سپتامبر 2026. منبع مقایسه با Language Server Protocol؛ statement اینکه specification «based on the TypeScript schema inschema.ts» است؛ خلاصهٔ base-protocol («Stateless, self-contained requests»، «Per-request capability negotiation»)، فهرست extensionها (Tasks، Skills over MCP، MCP Apps) و statement اینکه extensionها «are always opt-in and require explicit support from both client and server»؛ و principles امنیت و Trust & Safety، از جمله «Hosts must obtain explicit user consent before invoking any tool» و برخورد با tool annotations بهعنوان untrusted. ↩ ↩2 ↩3 -
Base Protocol،
modelcontextprotocol.io/specification/2026-07-28/basic. منبع constraints مربوط به JSON-RPC (id غیر null، عدم reuse از id،resultTypeالزامی)؛ بخش Statelessness و note آن که process باز stdio session نیست؛ جدول reserved-key مربوط به_metaو وضعیت required/optional هر فیلد per-request؛ قانون-32602برای فیلد required گمشده؛ قانونMissingRequiredClientCapability(-32021)؛ و policy تخصیص error-code. ↩ ↩2 ↩3 ↩4 ↩5 -
stdio transport،
modelcontextprotocol.io/specification/2026-07-28/basic/transports/stdio. منبع newline-delimited framing rules، requirement خلوصstdout، allowance مربوط بهstderr، و backward-compatibility probe سهنتیجهای — از جمله warning اینکه بعضی legacy serverها متدهای era-ambiguous را بدون handshake پردازش میکنند، که measurement این فصل بازتولیدش میکند. ↩ ↩2 ↩3 -
Transports overview،
modelcontextprotocol.io/specification/2026-07-28/basic/transports. منبع framing مربوط به «a transport is a binding» و statement اینکه serverها JSON-RPC request را initiate نمیکنند و clientها JSON-RPC response نمیفرستند. ↩ ↩2 -
Discovery،
modelcontextprotocol.io/specification/2026-07-28/server/discover. منبع mandatory بودنserver/discover، shape مربوط بهDiscoverResult، و فیلدinstructionsکه بهعنوان «optional natural-language guidance for LLMs on how to use this server effectively» توصیف شده است. ↩ -
Architecture،
modelcontextprotocol.io/specification/2026-07-28/architecture. منبع تعریفهای host/client/server، قانون 1:1 client-to-server، چهار اصل طراحی که اصل isolation آن اینجا بدون bullet پنجمش نقل شده، «Host process enforces security boundaries»، و بخش capability-negotiation. ↩ ↩2 -
Elicitation،
.../client/elicitation، و Sampling،.../client/sampling. منبع دو elicitation mode و schema محدود آنها؛ ممنوعیت درخواست credentials از طریق form mode؛ تعریف sampling، requirement مربوط به human-in-the-loop، و deprecation warning متصل به آن. ↩ -
Key Changes،
modelcontextprotocol.io/specification/2026-07-28/changelog، و Feature lifecycle and deprecation policy،.../community/feature-lifecycle. منبع همهٔ ردیفهای جدول تغییر: حذف sessions و headerMcp-Session-Id(SEP-2567)؛ statelessness و حذفinitialize(SEP-2575)؛server/discover(SEP-2575)؛subscriptions/listen(SEP-2575)؛ Multi Round-Trip Requests وresultType(SEP-2322)؛ حذف stream resumability (SEP-2575)؛ deprecation مربوط به Roots، Sampling و Logging (SEP-2577)؛ reclassification مربوط به HTTP+SSE (SEP-2596)؛ deprecation مربوط به Dynamic Client Registration به نفع Client ID Metadata Documents؛ renumbering مربوط به error-code؛ و پنجرهٔ deprecation دوازدهماهه. ↩ ↩2 -
Tools،
modelcontextprotocol.io/specification/2026-07-28/server/tools، و Server Features،.../server. منبع جدول control-hierarchy که بالا بازتولید شد؛ شکلهایtools/listوtools/call؛ تمایزisErrorبین protocol errors و tool execution errors؛ قواعد نام tool و note مربوط به namespace که «prefixing tool names with a server identifier» را توصیه میکند؛ و guidance غیر normative «Stateful Tools» دربارهٔ handleهای صریح. ↩ -
Versioning،
modelcontextprotocol.io/specification/versioning. منبع scheme مربوط بهYYYY-MM-DD، stateهای Draft/Current/Final revision، تأیید اینکه 2026-07-28 current است، و قواعد negotiation per-request. جدول tier مربوط به SDK درmodelcontextprotocol.io/docs/sdk، TypeScript، Python، C#، Go و Rust را در Tier 1، Java و Ruby را در Tier 2، و Swift، PHP و Kotlin را در Tier 3 فهرست میکند. ↩ -
A2A Protocol، نسخهٔ 1.0.0،
a2a-protocol.org— specification و صفحهٔ A2A and MCP: Relationship and Distinction، خواندهشده در 7 سپتامبر 2026. منبع تمایز tools-against-agents، statement اینکه دو پروتکل «address distinct but highly complementary needs»، و formulation مربوط به partnering/using. ↩ -
Agent Communication Protocol،
agentcommunicationprotocol.dev، خواندهشده در 7 سپتامبر 2026: «ACP is now part of A2A under the Linux Foundation!»؛ bannerای که بالای specificationای اضافه شده که هنوز کامل serve میشود — architecture، agent manifest، agent discovery، message structure، stateful agents، run lifecycle و فهرست REST endpointها همگی هنوز 200 جواب میدهند. specification ناپدید نشد؛ project شد. ↩