پرش به محتوا
26/30فصل 26 از 30

MCP بر اساس مشخصات: سرور واقعاً چیست

یک خط JSON به یک subprocess می‌فرستید و ۱۳ تعریف ابزار برمی‌گردد؛ مطابق بازنگری 2026-07-28 که handshake را حذف کرد.

در این صفحه

یک MCP server منتشرشده نصب کنید، یک خط JSON به آن بفرستید، و ببینید چه چیزی برمی‌گردد.

terminalBASH
npm i @modelcontextprotocol/server-everything@2026.8.31
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' \
  | npx @modelcontextprotocol/server-everything stdio
TEXT
{"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، حساب‌وکتاب را ببینید. شما NN برنامهٔ AI دارید و MM چیزی که باید بتوانند به آن‌ها دسترسی پیدا کنند — تقویم، ticket tracker، پایگاه دادهٔ warehouse، ابزار طراحی. بدون یک قرارداد مشترک، کسی N×MN \times M integration می‌نویسد، و هرکدام یک schema به‌علاوهٔ یک endpoint به‌علاوهٔ داستان authentication به‌علاوهٔ بار نگهداری است. با قرارداد مشترک، فروشندهٔ ابزار یک server می‌نویسد، فروشندهٔ برنامه یک client می‌نویسد، و مجموع می‌شود N+MN + M.

این مشاهده تازه نیست، و مشخصات می‌گوید ایده از چه کسی آمده است:

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ها دیگر ضرب نمی‌شد. همین منطق اینجا هم برقرار است: ارزش در تعداد پیاده‌سازی‌هاست، نه در طراحی. پروتکلی که فقط دو محصول با آن حرف می‌زنند، یک قالب داده با تشریفات اضافه است.

پیام‌های 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 stdout that 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 هست:

one line, split for the pageTEXT
{"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 کند:

terminalBASH
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
TEXT
{"jsonrpc":"2.0","id":1,"error":{"code":-32601,"message":"Method not found"}}

این شاخهٔ سوم قانون سازگاری است: یک DiscoverResult یعنی مدرن، یک خطای مدرنِ شناخته‌شده یعنی مدرن اما با نسخهٔ غلط، و هر چیز دیگر — از جمله -32601 — یعنی legacy، برگرد به handshake initialize.3 پس همین کار را بکنید، و بازنگری فعلی را بخواهید:

TEXT
→ {"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 initialize and would process an era-ambiguous method (such as tools/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 می‌رساند، که در مشخصات به‌صورت جدولی آمده و تقریباً هیچ‌کس نقلش نمی‌کند:

PrimitiveControlDescriptionExample
PromptsUser-controlledقالب‌های تعاملی که با انتخاب کاربر invoke می‌شوندSlash commands، گزینه‌های menu
ResourcesApplication-controlledدادهٔ contextای که client attach و مدیریت می‌کندمحتوای فایل، history گیت
ToolsModel-controlledfunctionهایی که برای انجام action در اختیار LLM قرار می‌گیرندAPI POST requests، نوشتن فایل

نه «سه راه برای expose کردن یک capability». سه پاسخ به اینکه چه کسی تصمیم می‌گیرد این اتفاق بیفتد. مدل تصمیم می‌گیرد tool را call کند. برنامه تصمیم می‌گیرد resource را attach کند. انسان تصمیم می‌گیرد prompt را اجرا کند. اگر این را اشتباه بفهمید، feature هنوز کار می‌کند، اما در زمان غلط و به دلیل غلط کار می‌کند.

روشن‌ترین راه برای حس کردنش تقویم است. اینجا serverای داریم که همان تقویم را سه بار expose می‌کند، هر بار به‌عنوان یکی از primitiveها، در صد خط Node ساده و بدون dependency:

calendar.mjs — the parts that matterJS
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 سرور حذف‌شده:

TEXT
→ 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}

سه متد، سه شکل، یک تقویم. حالا نکته:

با URI آدرس‌دهی می‌شود، inert است، و برنامه تصمیم می‌گیرد آیا آن را به conversation attach کند یا نه. هیچ چیز در پروتکل به مدل اجازه نمی‌دهد خودش سراغش برود. result شامل ttlMs و cacheScope است، که در این بازنگری جدیدند، تا client بتواند هفته را به‌جای polling برای یک دقیقه cache کند.

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 بسازد، و چیز جالبی برمی‌گردد:

TEXT
→ 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:

TEXT
→ 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، بدون اینکه چیزی منتقل شود:

TEXT
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 بالا می‌شماریم.

o200k_base tokensTEXT
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 است.

چه چیزی تغییر کردقبلاًاکنونچه چیزی را می‌شکند
Handshakeinitialize + notifications/initialized، یک بار برای هر connectionحذف شده؛ هر request نسخه و capabilities _meta را حمل می‌کندهر client نوشته‌شده پیش از این بازنگری
Sessionsheader Mcp-Session-Id، state در محدودهٔ connectionحذف شده؛ state در handleهای صریحِ mintشده توسط server سفر می‌کندlist endpointهایی که برای هر connection متفاوت بودند
Discoveryاز result initialize استنباط می‌شدserver/discover، که serverها must پیاده‌سازی کنندهیچ چیز، اما حالا پیاده‌سازی‌اش اجباری است
Server-to-client callsserver، roots/list، sampling/createMessage، elicitation/create می‌فرستادInputRequiredResult و retry از سمت clientهر serverی که request را به client push می‌کرد
شکل resultهر objectیresultType الزامی: "complete" یا "input_required"هیچ چیز: نبودن فیلد باید "complete" خوانده شود
SubscriptionsHTTP GET stream، resources/subscribeیک stream subscriptions/listen با opt-in typeهاendpoint GET حذف شده است
Stream resumptionreplay Last-Event-ID روی Streamable HTTPحذف شده؛ stream شکسته request را از دست می‌دهد، با id جدید دوباره صادر کنیدclientهایی که به redelivery تکیه داشتند
Rootsیک feature سمت client که serverها می‌توانستند بخواهندdeprecated (SEP-2577)؛ pathها را به‌عنوان tool arguments یا resource URIs پاس بدهیدهنوز هیچ چیز — پنجرهٔ دوازده‌ماهه
Sampling و loggingclient featuresdeprecated (SEP-2577)هنوز هیچ چیز — پنجرهٔ دوازده‌ماهه
HTTP+SSE transportاز 2025-03-26 deprecated بودتحت lifecycle policy (SEP-2596) Deprecatedبه Streamable HTTP مهاجرت کنید
Client registrationOAuth 2.0 Dynamic Client Registration، RFC 7591deprecated به نفع 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 به یک برنامهٔ AIhost ↔ server، هرکدام یک clientشخص دیگری capability را نوشته و hostهای زیادی باید بتوانند بدون integration اختصاصی از آن استفاده کنند.
RAGتکنیکی برای یافتن متن و گذاشتنش در promptکد شما ↔ index شمامدل باید چیزی را بداند. فصل 19. MCP راهی برای delivery یک retriever است؛ خودش retriever نیست.
Agent skillsپوشه‌ای با یک SKILL.md که مدل می‌خواندمدل ↔ یک documentknowledge procedural است — اینکه ما این کار را چطور انجام می‌دهیم — و prose است، نه function. فصل 28.
A2Aپروتکلی برای همکاری agentها به‌عنوان peersagent ↔ 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 داده شده است.

  1. Specification، modelcontextprotocol.io/specification/latest (redirect به /2026-07-28)، خوانده‌شده در 7 سپتامبر 2026. منبع مقایسه با Language Server Protocol؛ statement اینکه specification «based on the TypeScript schema in schema.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

  2. 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

  3. 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

  4. 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

  5. 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» توصیف شده است.

  6. 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

  7. Elicitation، .../client/elicitation، و Sampling، .../client/sampling. منبع دو elicitation mode و schema محدود آن‌ها؛ ممنوعیت درخواست credentials از طریق form mode؛ تعریف sampling، requirement مربوط به human-in-the-loop، و deprecation warning متصل به آن.

  8. Key Changes، modelcontextprotocol.io/specification/2026-07-28/changelog، و Feature lifecycle and deprecation policy، .../community/feature-lifecycle. منبع همهٔ ردیف‌های جدول تغییر: حذف sessions و header Mcp-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

  9. 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های صریح.

  10. 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 فهرست می‌کند.

  11. 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.

  12. 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 شد.


تهیه‌شده توسط

David Vicente Campos

بنیان‌گذار NeuraLIA Labs و هم‌بنیان‌گذار MyRealFood

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

بیشتر درباره نویسنده

منتشرشده توسط NeuraLIA Labs.

پست‌های جدید را در ایمیل خود دریافت کنید

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

فهرست دوره

Abstract software decision engine with branching paths, probability nodes, and glowing gates.
jev12 دقیقه مطالعه

مدل هوش مصنوعی Jev برای تصمیم ساخته شده، نه نثر

Jev از TypeSafe AI توجه‌ها را جلب کرده چون هوشمندی نرم‌افزار را مسئله‌ای احتمالاتی می‌بیند: شاخه درست را انتخاب کنید، میزان اطمینان را کنار آن بگذارید، و وقتی کد به یک تصمیم نیاز دارد برای نوشتن متن به یک LLM پول ندهید.

Abstract agent runtime sorting documents, memory blocks and pointer nodes inside a bounded context frame.
context-engineering13 دقیقه مطالعه

مهندسی کانتکست برای عامل‌های AI بلندافق

عامل‌های طولانی‌اجرا فقط به‌خاطر کوچک بودن پنجره شکست نمی‌خورند. وقتی فایل‌ها، خروجی ابزارها و تاریخچهٔ کهنه وظیفه‌ای را که عامل قرار بود تمام کند کنار می‌زنند، شکست رخ می‌دهد.

آماده‌اید انتخاب مدل را به LIA بسپارید؟

با همه مدل‌های هوش مصنوعی در یک جا بسازید — همین امروز رایگان شروع کنید.