MCP מוסבר מול המפרט: מהו שרת באמת
שורת JSON אחת לתהליך משנה, ו-13 הגדרות כלים חוזרות — מול גרסת 2026-07-28 שהסירה את ה-handshake.
בעמוד הזה
התקינו שרת MCP שפורסם, שלחו לו שורת 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, בלי ספריית לקוח ובלי framework. זה כל הסיפור: transport, פורמט הודעות, וקבוצה קטנה של מתודות בעלות שם.
פרק 18 הגדיר כלי כשני דברים — JSON Schema שהמודל רואה, ו-endpoint בקוד שלכם שהמודל לעולם לא רואה. פרק 23 בנה harness שמחזיק קטלוג שלהם. אף אחד מהם לא ענה על השאלה שקובעת אם משהו מזה ניתן לשימוש חוזר: מי כותב את ה-schema, ואיך הוא מגיע ממי שכתב אותו אל ה-prompt שלכם? MCP הוא תשובה אחת לשאלה הזאת, וכדאי לקרוא אותה במקור, כי כמעט כל מה שנכתב עליו מתאר גרסה שכבר לא קיימת.
שלושה דברים בפקודה שהרצתם עכשיו שגויים, וכל אחד מהם הוא סעיף בפרק הזה. היא לא נשאה גרסת פרוטוקול, ולכן שרת תואם היה מסרב לה. היא קיבלה תשובה בכל זאת, מסיבה שהמפרט קורא לה סכנה ולא פיצ׳ר. והיא ביקשה אחד משלושה primitives בלי לגלות בכלל ששני האחרים קיימים.
הבעיה שהוא פותר, והאנלוגיה שהמפרט עצמו עושה
קישור למקטע: הבעיה שהוא פותר, והאנלוגיה שהמפרט עצמו עושהלפני ה-wire, החשבון. יש לכם אפליקציות AI ו- דברים שהן צריכות להגיע אליהם — יומן, מערכת כרטיסים, מסד נתונים של מחסן, כלי עיצוב. בלי חוזה משותף, מישהו כותב אינטגרציות, וכל אחת מהן היא schema ועוד endpoint ועוד סיפור אימות ועוד נטל תחזוקה. עם חוזה כזה, ספק הכלי כותב שרת, ספק האפליקציה כותב לקוח, והסך הכול הוא .
זאת לא תובנה חדשה, והמפרט אומר של מי היה הרעיון:
MCP לוקח השראה מסוימת מ-Language Server Protocol, שמתקנן איך להוסיף תמיכה בשפות תכנות על פני אקוסיסטם שלם של כלי פיתוח. באופן דומה, MCP מתקנן איך לשלב context וכלים נוספים באקוסיסטם של אפליקציות AI.1
קחו את ההשוואה הזאת כפשוטה, לא כמחמאה. לפני הפרוטוקול ההוא, תמיכה בשפה בתוך עורך דרשה plugin לכל עורך; אחריו, צוות שפה שלח שרת אחד וכל עורך קיבל אותו. מדד ההצלחה לא היה אלגנטיות, אלא זה שמספר האינטגרציות הפסיק להתרבות. אותו הדבר נובע כאן: הערך נמצא במספר המימושים, לא בעיצוב. פרוטוקול ששני מוצרים מדברים הוא פורמט נתונים עם טקסיות עודפת.
מה באמת עובר על ה-wire
קישור למקטע: מה באמת עובר על ה-wireהודעות MCP הן JSON-RPC 2.0. בקשה היא אובייקט עם jsonrpc, id, method ו-params אופציונלי; תגובה נושאת את אותו id ואת result או error; notification היא בקשה בלי id ולא מקבלת תשובה. המפרט מוסיף מעל זה שלושה אילוצים: ה-id חייב להיות מחרוזת או מספר ואסור לו להיות null, אסור לו להתנגש בבקשה אחרת שעדיין בטיסה, וכל result חייב לשאת שדה resultType.2
ב-stdio transport — זה שהפקודה למעלה השתמשה בו — כלל המסגור הוא שורה אחת לכל הודעה:
הודעות מופרדות באמצעות שורות חדשות, ואסור שיכילו שורות חדשות משובצות. […] השרת חייב שלא לכתוב ל-
stdoutשלו שום דבר שאינו הודעת MCP תקפה.3
הסעיף האחרון הוא הדרך הנפוצה ביותר שבה שרת ביתי נשבר, והוא נשבר בשקט: console.log תועה, סרגל התקדמות, אזהרת deprecation מתלות, וה-line parser של הלקוח נתקל במשהו שאינו JSON. פתח המילוט נמצא באותו סעיף — השרת רשאי לכתוב כל דבר שירצה ל-stderr, והלקוח לא אמור להתייחס לזה כשגיאה. שרת הייחוס למעלה מדפיס Starting default (STDIO) server... בכל הפעלה, על stderr, ולכן ה-pipe עדיין עבד.
ה-transport התקני האחר הוא Streamable HTTP: כל הודעה היא POST ל-endpoint יחיד, והתשובה היא או אובייקט JSON או זרם Server-Sent Events scoped לבקשה — פורמט ה-wire שפרק 14 פענח ידנית. הסמנטיקה זהה בשניהם, כי transport הוא binding: הוא מגדיר מסגור ומסירה, לא משמעות.4
הדבר הראשון שהיה שגוי: לא הייתה גרסה
קישור למקטע: הדבר הראשון שהיה שגוי: לא הייתה גרסההפקודה למעלה שלחה tools/list ולא שום דבר אחר. תחת הגרסה הנוכחית הבקשה הזאת malformed, ושרת תואם חייב לדחות אותה.
מאז 2026-07-28, MCP הוא פרוטוקול stateless, והמפרט אומר זאת בלי הסתייגות:
Model Context Protocol (MCP) הוא פרוטוקול stateless: כל המידע הדרוש לעיבוד בקשה נמצא בבקשה עצמה. שרת מעבד כל בקשה באופן עצמאי; אין להסיק מצב מבקשות קודמות, גם כאלה שעל אותו חיבור או stream.2
לכן כל בקשה נושאת את גרסת הפרוטוקול שלה ואת יכולות הלקוח שלה, בתוך אובייקט שמור _meta בתוך params. שניים מהשדות האלה נדרשים בכל בקשה ובקשה; בקשה שחסר בה אחד מהם malformed והשרת חייב לענות -32602:2
מפתח _meta | נדרש | מה זה |
|---|---|---|
io.modelcontextprotocol/protocolVersion | כן | הגרסה שהבקשה הזאת מדברת, למשל "2026-07-28" |
io.modelcontextprotocol/clientCapabilities | כן | מה הלקוח יכול לעשות עבור השרת בבקשה הזאת |
io.modelcontextprotocol/clientInfo | לא (אבל אמור) | שם וגרסת הלקוח, לתצוגה וללוגים בלבד |
io.modelcontextprotocol/logLevel | לא | רמת הלוג המינימלית שהשרת אמור לפלוט עבור הבקשה הזאת |
בכתיבה מלאה, tools/list נכון נראה כך — וזאת הפעם האחרונה שהפרק מציג את המטא-דאטה במלואו, כי הוא נמצא על כל בקשה מכאן והלאה:
{"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"}}}}אובייקט ה-capabilities הוא המשא ומתן. כבר אין שלב משא ומתן נפרד: הלקוח מצהיר מה הוא יכול לעשות בכל בקשה, השרת מצהיר מה הוא יכול לעשות ב-result, ואף צד אינו רשאי להשתמש בפיצ׳ר שהצד השני לא טען שיש לו. שרת שזקוק ל-capability שהלקוח לא הצהיר עליו חייב לענות -32021 ולציין את ה-capability החסר ב-data.requiredCapabilities. שרת שאינו מדבר את הגרסה המבוקשת חייב לענות -32022 ולמנות את הגרסאות שהוא כן מדבר.2
לקוחות שרוצים את התשובה מראש יכולים לבקש אותה: server/discover הוא RPC חובה שמחזיר גרסאות נתמכות, capabilities, זהות ובלוק אופציונלי של instructions ב-round trip אחד.5 הקריאה אליו אופציונלית. המימוש שלו לא.
הדבר השני שהיה שגוי: השרת היה legacy
קישור למקטע: הדבר השני שהיה שגוי: השרת היה legacyהפקודה עבדה. תחת הגרסה הנוכחית היא לא הייתה אמורה לעבוד, והסיבה שכן שווה מדידה יותר מפסקה, כי היא מצב האקוסיסטם כולו בשורה אחת.
בדקו את שרת הייחוס בדרך שבה המפרט אומר ללקוח מודרני לבדוק:
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":"…"}}הלקוח ביקש 2026-07-28 והשרת ענה 2025-11-25. ב-7 בספטמבר 2026, שרת הייחוס הרשמי — חבילת npm @modelcontextprotocol/server-everything, גרסה 2026.8.31, שפורסמה ב-31 באוגוסט 2026 — אינו מממש את הגרסה הנוכחית. גם TypeScript SDK שעליו הוא בנוי לא, לפי התאריכים: release 1.30.0 יצא ב-27 ביולי 2026, יום לפני הגרסה.
קראו את ההשלכה, לא את הרכילות. כמעט כל מה שנכתב על MCP מתאר פרוטוקול עם handshake של initialize, session, בקשת roots/list שהשרת שולח ללקוח, ו-HTTP+SSE transport. כל הארבעה נעלמו או בדרך החוצה. כשאתם קוראים משהו על MCP, כולל העמוד הזה, הדבר הראשון שצריך לחפש הוא מספר גרסה.
והסיבה שהפקודה הראשונה ממש עבדה מופיעה במפרט כסכנה, לא כפיצ׳ר:
חלק משרתי legacy אינם מוודאים שבקשה מגיעה אחרי
initializeוהיו מעבדים מתודה עמומת-תקופה (כמוtools/call) תחת סמנטיקה legacy. probing מייצר כישלון דטרמיניסטי במקום זאת.3
נמדד: שליחת tools/list לשרת הזה בלי handshake בכלל מחזירה את הקטלוג המלא. מתודה שהייתה אמורה להידחות הוגשה, וזו בדיוק הסיבה שהמפרט אומר לבצע probe עם server/discover קודם, גם כשאתם תומכים רק בגרסאות מודרניות.
שלושה תפקידים, והמשפט שצריך לצטט מכל המסמך
קישור למקטע: שלושה תפקידים, והמשפט שצריך לצטט מכל המסמךל-MCP יש שלושה צדדים, וההבחנה בין שני הראשונים היא זו שאנשים ממוטטים:
Host. האפליקציה: מוצר הצ׳אט, העורך, ה-agent. הוא הבעלים של השיחה, המודל, האישורים וההסכמה של המשתמש. הוא יוצר לקוחות ואוכף את גבול האבטחה ביניהם.
Client. מחבר בתוך ה-host. כל client מדבר עם שרת אחד בדיוק — קשר 1:1 קפדני — ומצמיד את גרסת הפרוטוקול וה-capabilities לכל בקשה שהוא מנתב.
Server. תהליך או שירות שחושף משאבים, כלים ו-prompts. הוא יכול להיות מקומי או מרוחק, הוא פועל באופן עצמאי, וכל תפקידו הוא תחום ממוקד אחד.6
כלל ״שרת אחד בדיוק״ אינו הנהלת חשבונות. הוא מה שהופך את עקרון העיצוב הבא לבר-מימוש, וזה המשפט לקחת מהמפרט אם אתם לוקחים רק אחד:
שרתים לא אמורים להיות מסוגלים לקרוא את כל השיחה, או ״להציץ לתוך״ שרתים אחרים. שרתים מקבלים רק מידע contextual נחוץ. היסטוריית השיחה המלאה נשארת אצל ה-host. כל שרת שומר על בידוד. אינטראקציות בין שרתים נשלטות על ידי ה-host.6
זה הופך את המודל המנטלי שרוב האנשים מגיעים איתו. שרת מזג אוויר שאתם מחברים לעוזר שלכם לא רואה מה שאלתם. הוא רואה tools/call עם הארגומנטים שהמודל בחר, ושום דבר נוסף — לא התורות הקודמים, לא ה-system prompt שלכם, לא התוצאות ששרת היומן החזיר לפני רגע. אם שני שרתים צריכים לשתף פעולה, ה-host נושא ערך מאחד לשני, בכוונה, כי המודל ביקש ממנו. לכן בידוד הוא מאפיין האבטחה שפרק 30 נשען עליו: לשרת שנפרץ יש blast radius קטן ומוגדר, והגדלתו דורשת מה-host לשתף פעולה.
הדבר השלישי: שלושה primitives, ממוינים לפי מי שולט
קישור למקטע: הדבר השלישי: שלושה primitives, ממוינים לפי מי שולטהפקודה הראשונה ביקשה מהשרת כלים וקיבלה שלושה-עשר. שאלו אותו את שתי השאלות האחרות והוא עונה גם עליהן: resources/list מחזירה שבעה, prompts/list מחזירה ארבעה. אף אחד מהם לא הופיע, כי שום דבר לא ביקש. וזה מביא אותנו לעמוד השדרה הפדגוגי של MCP, שיושב במפרט כטבלה שכמעט אף אחד לא מצטט:
| Primitive | שליטה | תיאור | דוגמה |
|---|---|---|---|
| Prompts | בשליטת המשתמש | תבניות אינטראקטיביות שמופעלות לפי בחירת המשתמש | פקודות slash, אפשרויות תפריט |
| Resources | בשליטת האפליקציה | נתוני context שמוצמדים ומנוהלים על ידי ה-client | תוכני קבצים, היסטוריית git |
| Tools | בשליטת המודל | פונקציות שנחשפות ל-LLM כדי לבצע פעולות | בקשות API POST, כתיבת קבצים |
לא ״שלוש דרכים לחשוף capability״. שלוש תשובות לשאלה מי מחליט שזה קורה. המודל מחליט לקרוא לכלי. האפליקציה מחליטה להצמיד משאב. האדם מחליט להריץ prompt. טעו בזה והפיצ׳ר עדיין עובד, אבל הוא עובד ברגע הלא נכון ומהסיבה הלא נכונה.
הדרך הברורה ביותר להרגיש את זה היא יומן. הנה שרת שחושף את אותו יומן שלוש פעמים, פעם אחת בתור כל primitive, במאה שורות Node פשוטות בלי dependencies:
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, עטוף כאן לטובת העמוד, עם ה-_meta של הבקשה ובלוק הזהות של השרת מושמטים:
→ 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, היא אינרטית, והאפליקציה מחליטה אם להצמיד אותה לשיחה. אין שום דבר בפרוטוקול שמאפשר למודל להגיע אליה בכוחות עצמו. ה-result נושא ttlMs ו-cacheScope, חדשים בגרסה הזאת, כדי שהלקוח יוכל לשמור את השבוע ב-cache לדקה במקום לבצע polling.
יצירת אירוע היא כלי
קישור למקטע: יצירת אירוע היא כלייש לה schema, יש לה תופעות לוואי, והמודל מחליט מתי לקרוא לה. ה-result שלה נושא isError, שהוא השדה שפרק 18 טען בעדו: כשל validation חוזר כ-tool result שהמודל יכול לקרוא ולתקן, לא כשגיאת פרוטוקול.
״הכן לי את השבוע״ הוא prompt
קישור למקטע: ״הכן לי את השבוע״ הוא promptזוהי תבנית בעלת שם, שמקבלת ארגומנטים, שהאדם מפעיל — פקודת ה-slash בתפריט. היא מחזירה הודעות, לא תשובה. זו דרך עבור מחבר שרת לשלוח את הניסוח שעובד עם הכלים שלו, שזה בדיוק הידע שיש למחבר השרת ואין למשתמש.
כמעט כולם הופכים את שלושתם לכלים. התוצאה היא קטלוג שבו קריאה שהאפליקציה הייתה אמורה להצמיד בשקט מתחרה על attention של המודל עם כתיבה שדורשת אישור, ושבו הדבר היחיד שאדם רצה עבורו כפתור קבור בתוך schema. לא עולה כלום לעשות את זה נכון, וזה מוכרע לפני שאתם כותבים שורה.
השרת לא יכול לקרוא לכם
קישור למקטע: השרת לא יכול לקרוא לכםלכלי היומן יש ארגומנט נדרש אחד, title, ו-startsAt אופציונלי. בקשו ממנו ליצור אירוע בלי תאריך, ומשהו מעניין חוזר:
→ 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=="}השרת לא שלח בקשה. הוא ענה לבקשה שקיבל, עם resultType: "input_required" ותיאור של מה שהוא עדיין צריך. הלקוח אוסף את התשובה מהאדם, ואז שולח מחדש את הקריאה המקורית — עם id חדש, כשהיא נושאת inputResponses ומהדהדת בחזרה את ה-requestState האטום:
→ 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, שהוצג בגרסה הנוכחית, והוא החליף את העיצוב הישן שבו שרתים שלחו בקשות JSON-RPC חזרה ללקוחות. מפרט ה-transport קובע עכשיו את הכלל באופן חד: ״שרתים אינם יוזמים בקשות JSON-RPC ולקוחות אינם שולחים תגובות JSON-RPC״.4 יש כיוון יוזמה אחד, והוא שייך ל-host.
שני פיצ׳רים בצד הלקוח רוכבים על המנגנון הזה, ולאחד מהם יש שם שיכול להכשיל אתכם.
Elicitation הוא השרת שמבקש משהו מהאדם: טופס עם JSON Schema מוגבל בכוונה — אובייקטים שטוחים, מאפיינים פרימיטיביים, בלי nesting — כדי שכל לקוח יוכל לרנדר אותו בלי מנוע layout. הוא נושא כלל קשיח: שרתים חייבים שלא להשתמש במצב טופס כדי לבקש ״סיסמאות, מפתחות API, access tokens או פרטי תשלום״, וחייבים להשתמש במצב URL עבור אלה, ששולח את המשתמש לעמוד שהלקוח לעולם לא קורא.7
Sampling הוא השרת שמבקש מהמודל של ה-host generation, כדי ששרת יוכל להיות אינטליגנטי בלי להחזיק מפתח API. וכאן אזהרת אוצר המילים, כי למילה הזאת כבר יש משמעות אחרת בקורס הזה: זה לא ה-sampling של פרק 17. שום דבר כאן לא עוסק בטמפרטורה, top-p או צורה של התפלגות הסתברות. זו קריאת מודל מקוננת שנוסעת אחורה דרך פרוטוקול.
יש סיבה שנייה לא למהר להשתמש בזה: נכון לגרסה הזאת, sampling הוא deprecated, לצד roots ו-logging, תחת SEP-2577, עם הצעת migration בוטה — ״להשתלב ישירות עם APIs של ספקי LLM במקום Sampling״.8 הרעיון לא נכשל טכנית; הוא נכשל בהצדקת שטח הפנים שלו, ופרוטוקול שיכול להסיר דברים בריא יותר מפרוטוקול שלא יכול.
לשבור בכוונה: חיבורים אינם sessions
קישור למקטע: לשבור בכוונה: חיבורים אינם sessionsStatelessness נשמע כמו פרט של wire-format עד שבודקים אותו. קחו את חילופי שלוש ההודעות למעלה והריצו כל הודעה בתהליך נפרד — node calendar.mjs טרי, בלי זיכרון משותף, בלי שום דבר שעובר הלאה:
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)תהליך B, שמעולם לא ראה את השאלה, השלים קריאת multi-round-trip שתהליך A התחיל. זו הנקודה של requestState: ההמשך נוסע בהודעה, כך ששום דבר לא תלוי בכך שהתהליך יהיה אותו תהליך.
תהליך C הוא הכישלון. האירוע נוצר והוא לא שם — כי שרת הצעצוע שומר את EVENTS במערך ברמת module, ומערך ברמת module הוא מצב חיבור. הערת המפרט קוראת לטעות בשם המדויק שלה:
חיבור פתוח, כמו תהליך STDIO, אינו שיחה או session: לקוחות עשויים לשלב בקשות לא קשורות על אותו transport, ושרת חייב שלא להתייחס לזהות חיבור או תהליך כ-proxy להמשכיות שיחה או session.2
התיקון שנקבע אינו session. הוא handle מפורש: כלי יצירה מחזיר מזהה אטום, וכל קריאה מאוחרת יותר מקבלת אותו כארגומנט רגיל. לפרוטוקול אין שום מושג עליו — ״מנקודת המבט של ה-wire, handle הוא מחרוזת רגילה ב-tool result וארגומנט רגיל לקריאות כלי עוקבות״.9 זה שם את המודל כאחראי לשאת אותו, ואת השרת כאחראי לוודא שלקורא הזה מותר להשתמש בו בכל קריאה וקריאה, כי handle הוא שם ולא הרשאה.
מה שרת עולה לפני שהוא עושה משהו
קישור למקטע: מה שרת עולה לפני שהוא עושה משהוכל כלי ששרת חושף הוא schema שנכנס ל-prompt שלכם בכל בקשה, ופרק 24 מדד מה זה עושה ל-window. MCP מוסיף סעיף עלות שני שקל לפספס, ולכן כדאי לספור את שניהם על שרת הייחוס למעלה.
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שתי תצפיות. הראשונה היא חשבון: חברו חמישה שרתים בגודל הזה וכשמונה אלף tokens מה-window שלכם תפוסים בכל turn, לנצח, בין שהמודל משתמש במשהו מהם ובין שלא — וזה המנגנון מאחורי ההפחתה מ-150,000 ל-2,000 שפרק 24 ציטט, והסיבה שקיים גילוי כלים just-in-time.
השנייה היא הערת אבטחה בתחפושת של הנהלת חשבונות. instructions הוא טקסט בשפה טבעית, שנכתב על ידי מחבר השרת, ונוחת ב-prompt של ה-host, וכך גם תיאורי הכלים שלידו. המפרט אומר מה לעשות עם זה בעקרונות האבטחה שלו: annotations ותיאורים של כלים ״should be considered untrusted, unless obtained from a trusted server״, ו-hosts ״must obtain explicit user consent before invoking any tool״.1 חיבור שרת MCP אינו הוספת dependency. הוא מתן 1,619 tokens מתוך ה-system prompt שלכם לאדם זר, ואת הזכות להיקרא. פרק 30 הוא מה שקורה כשהזר הזה עוין.
סעיף מתוארך: גרסת 2026-07-28, ומה היא שוברת
קישור למקטע: סעיף מתוארך: גרסת 2026-07-28, ומה היא שוברתכל מה שבסעיף הזה נכון לגבי גרסת הפרוטוקול 2026-07-28, הנוכחית, כפי שנקראה ב-7 בספטמבר 2026. גרסאות מתוארכות כ-YYYY-MM-DD והתאריך הוא הפעם האחרונה שבה נעשה שינוי שאינו תואם לאחור.10 המסמך הנורמטיבי הוא קובץ TypeScript, schema/2026-07-28/schema.ts; ה-JSON Schema שלצידו נוצר ממנו, ולכן המפרט נקרא כאן ב-TypeScript ולכן ללמד MCP מכל דבר אחר הוא ללמד תרגום.
| מה השתנה | היה | עכשיו | שובר |
|---|---|---|---|
| ה-handshake | initialize + notifications/initialized, פעם אחת לכל חיבור | הוסר; כל בקשה נושאת גרסת _meta ו-capabilities | כל client שנכתב לפני הגרסה הזאת |
| Sessions | header של Mcp-Session-Id, מצב scoped לחיבור | הוסר; מצב נוסע ב-handles מפורשים שהשרת הנפיק | endpoints של רשימה שהשתנו לפי חיבור |
| Discovery | הוסק מה-result של initialize | server/discover, ששרתים חייבים לממש | כלום, אבל עכשיו חובה לממש אותו |
| קריאות משרת ללקוח | השרת שלח roots/list, sampling/createMessage, elicitation/create | InputRequiredResult ו-retry של הלקוח | כל שרת שדחף בקשה ללקוח |
| צורת result | כל אובייקט | נדרש resultType: "complete" או "input_required" | כלום: שדה חסר חייב להיקרא כ-"complete" |
| Subscriptions | stream של HTTP GET, resources/subscribe | stream אחד של subscriptions/listen עם סוגים ב-opt-in | endpoint ה-GET נעלם |
| חידוש stream | replay של Last-Event-ID ב-Streamable HTTP | הוסר; stream שנשבר מאבד את הבקשה, שלחו מחדש עם id חדש | לקוחות שסמכו על redelivery |
| Roots | פיצ׳ר לקוח ששרתים יכלו לבקש | deprecated (SEP-2577); העבירו paths כארגומנטים לכלים או כ-resource URIs | עדיין כלום — חלון של שנים-עשר חודשים |
| Sampling ו-logging | פיצ׳רים של לקוח | deprecated (SEP-2577) | עדיין כלום — חלון של שנים-עשר חודשים |
| HTTP+SSE transport | deprecated מאז 2025-03-26 | Deprecated תחת מדיניות lifecycle (SEP-2596) | לעבור ל-Streamable HTTP |
| רישום לקוח | OAuth 2.0 Dynamic Client Registration, RFC 7591 | deprecated לטובת Client ID Metadata Documents | נשמר עבור שרתי authorization שאין להם אותם |
| קודי שגיאה | -32002 עבור resource not found | -32602; -32020–-32099 שמורים למפרט | קודים חדשים -32020, -32021, -32022 |
שינוי הממשל שמתחת לטבלה חשוב יותר מכל שורה בודדת. הגרסה הזאת אימצה מדיניות lifecycle ו-deprecation של פיצ׳רים: פיצ׳רים הם Active, Deprecated או Removed, פיצ׳ר deprecated מתעד את נתיב ה-migration שלו ונשאר במפרט לפחות שנים-עשר חודשים לפני שהוא כשיר להסרה, ויש registry שמונה את כל מה שנמצא כרגע במצב Deprecated.8 לפני המדיניות הזאת, ״deprecated״ בפרוטוקול AI פירושו היה מה שהפוסט האחרון בבלוג אמר. עכשיו זה אומר תאריך.
הצגת פרטים
Extensions, החלק שאף אחד עוד לא כתב עליו.
מעבר לליבה, MCP מגדיר extensions אופציונליים — ״תמיד opt-in ודורשים תמיכה מפורשת הן מה-client והן מה-server״, שמוצהרים דרך שדה extensions ב-capabilities של הלקוח והשרת.1 שלושה כדאי להכיר בשם:
- Tasks (
io.modelcontextprotocol/tasks), שהועברו מליבת הפרוטוקול אל extension רשמי בגרסה הזאת: ביצוע אסינכרוני של פעולות ארוכות, עם polling דרךtasks/get, קלט באמצע הריצה דרךtasks/update, ו-handles עמידים. זו התשובה לכלי שלוקח עשרים דקות, שפרק 23 טיפל בו עם אירוע התקדמות ו-signal שמגיע לכלי. - Skills over MCP, קבוצת עבודה שהופכת agent skills — הנושא של פרק 28 — לניתנות לגילוי ולצריכה דרך הפרוטוקול.
- MCP Apps, ממשק אינטראקטיבי שמרונדר inline בתוך השיחה: תרשימים, טפסים, נגני וידאו.
ושימו לב מה ״negotiated״ אומר עכשיו: אין initialization שבו מנהלים משא ומתן, ולכן extension מוצהר לכל בקשה כמו כל דבר אחר.
איפה MCP יושב, מול כל מה שמבלבלים איתו
קישור למקטע: איפה MCP יושב, מול כל מה שמבלבלים איתוזה אוצר המילים של כל הבלוק במקום אחד.
| מה זה | מי מדבר עם מי | מתי זו התשובה | |
|---|---|---|---|
| API רגיל | ממשק עבור תוכנה | הקוד שלכם ↔ שירות | אתם כותבים את הקורא. אתם שולטים ב-schema, ב-auth ובטיפול בשגיאות, ואין בעיית discovery לפתור. |
| MCP | פרוטוקול לחשיפת כלים, נתונים ותבניות לאפליקציית AI | host ↔ server, client אחד לכל אחד | מישהו אחר כתב את ה-capability והרבה hosts אמורים להיות מסוגלים להשתמש בו בלי אינטגרציה bespoke. |
| RAG | טכניקה למציאת טקסט והכנסתו ל-prompt | הקוד שלכם ↔ האינדקס שלכם | המודל צריך לדעת משהו. פרק 19. MCP הוא דרך לספק retriever; הוא לא retriever. |
| Agent skills | תיקייה עם SKILL.md שהמודל קורא | model ↔ מסמך | הידע הוא פרוצדורלי — איך אנחנו עושים את זה — והוא פרוזה, לא פונקציה. פרק 28. |
| A2A | פרוטוקול לשיתוף פעולה בין agents כשווים | agent ↔ agent | הצד השני חושב, מתכנן ומחזיק מצב לאורך משימה ארוכה, במקום לענות לקריאה. |
| ACP | היה פרוטוקול נפרד לתקשורת agents | — | זו כבר לא השוואה חיה. ראו בהמשך. |
שניים מאלה ראויים למשפט כל אחד, כי שם הבלבול באמת חי.
MCP מול A2A אינו יריבות, ושני המפרטים אומרים זאת. תיעוד A2A מותח את הקו לפי מה שנמצא בצד השני: MCP ״defines how an AI agent interacts with and utilizes individual tools and resources, such as a database or an API״, כאשר כלי מבצע ״specific, often stateless, functions״; A2A עוסק ב-agents, ״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 כדי להגיע ל-agents אחרים, וכל agent משתמש ב-MCP כדי להגיע לכלים שלו. פרק 25 שרטט את הקו הזה בתוך תהליך אחד, בין לבקש מ-sub-agent לבין למסור לו את השיחה; A2A משרטט אותו בין ארגונים.
MCP מול ACP הוא השוואה עם הנחת יסוד שהתיישנה, וזו בדיוק הסיבה שכדאי לענות עליה. Agent Communication Protocol היה תקן פתוח נפרד להודעות agent-to-agent. התיעוד שלו עצמו נפתח עכשיו בהודעה: ״ACP is now part of A2A under the Linux Foundation!״12 התשובה הכנה ל-״MCP או ACP?״ בספטמבר 2026 היא שלשאלה יש אפשרות אחת פחות מכפי שהעמודים שמדורגים עליה מציעים.
וההשוואה שאנשים מבקשים הכי הרבה, mcp vs api, מקבלת את התשובה הכי פחות מעניינת: MCP הוא API. מה שהוא מוסיף אינו כוח, אלא מוסכמות — קבוצה קבועה של שמות מתודות, קריאת discovery, היררכיית שליטה על ה-primitives, ומודל בידוד. אתם מוותרים על החופש לעצב את הממשק שלכם ומקבלים כל host שמדבר את הפרוטוקול, וזה הטרייד שכל פרוטוקול הציע מאז ומעולם.
לאן זה ממשיך
קישור למקטע: לאן זה ממשיךעכשיו אתם יכולים לקרוא את המפרט בלי מתרגם, להבדיל בין resource לכלי ל-prompt לפי מי ששולט בו, להקליד בקשה ידנית כשספריית client משקרת לכם, ולתארך כל מאמר MCP שאתם קוראים לפי אילו פיצ׳רים deprecated הוא עדיין מלמד כעדכניים.
מה שעוד לא עשיתם הוא לשלוח אחד לפרודקשן. פרק 27 כותב את אותו שרת פעמיים — TypeScript ו-Python, זה לצד זה, כי MCP הוא הטריטוריה הדו-לשונית באמת היחידה בקורס הזה והמספרים אומרים זאת בשני הכיוונים. הוא מכסה כמו שצריך את שני ה-transports החיים, את ה-inspector, packaging, ואת החצי של הפרוטוקול שהפרק הזה השאיר בכוונה בצד: authorization. כי ברגע שהשרת שלכם מרוחק ולא subprocess על הלפטופ שלכם, client של זר יציג token, והכלל של המפרט לגבי מה שמותר לכם לעשות איתו מחמיר באופן חריג.
וזה מעלה את השאלה שהפרק הבא חייב לענות עליה, והיא לא שאלה ידידותית: אם token מגיע לשרת שלכם והוא הונפק עבור audience של מישהו אחר, מה בדיוק מונע מכם להעביר אותו הלאה?
מקורות ושיטה
קישור למקטע: מקורות ושיטהכל ציטוט, שם מתודה, קוד שגיאה וכלל בפרק הזה נקראו ממפרט Model Context Protocol, גרסה 2026-07-28, ב-7 בספטמבר 2026. כל trace הופק מקומית על Node 22: שרת היומן הצעצועי הוא 101 שורות בלי dependencies, ושרת הייחוס הוא חבילת npm שפורסמה ושמה מופיע למטה. לא נקרא שום API בתשלום כדי לכתוב את הפרק הזה — שום דבר כאן לא צריך מודל, וזו בעצמה הנקודה.
המדידות: @modelcontextprotocol/server-everything@2026.8.31, פורסם ב-31 באוגוסט 2026, בנוי על @modelcontextprotocol/sdk@1.30.0, שפורסם ב-27 ביולי 2026 — יום אחד לפני הגרסה שהפרק הזה מתאר. הוא עונה ל-server/discover עם -32601, מנהל משא ומתן על 2025-11-25 כשמבקשים 2026-07-28, ומגיש tools/list בלי handshake בכלל. הקטלוג שלו הוא 13 כלים ב-7,663 בתים; ספירות token הן o200k_base דרך tiktoken, על פני name, description ו-inputSchema של כל הגדרה, וזה מה שספק מרנדר לתוך ה-prompt שלכם ולא מה ששוקלת מסגרת JSON-RPC.
Anthropic, Code execution with MCP: building more efficient agents, 4 בנובמבר 2025, הוא מקור הנתון 150,000-ל-2,000, שצוטט ונעשה בו שימוש בפרק 24 ורק מוזכר כאן.
הפניות
קישור למקטע: הפניות-
מפרט,
modelcontextprotocol.io/specification/latest(מפנה אל/2026-07-28), נקרא ב-7 בספטמבר 2026. מקור ההשוואה ל-Language Server Protocol; ההצהרה שהמפרט ״based on the TypeScript schema inschema.ts״; תקציר פרוטוקול הבסיס (״Stateless, self-contained requests״, ״Per-request capability negotiation״); רשימת ה-extensions (Tasks, Skills over MCP, MCP Apps) וההצהרה ש-extensions ״are always opt-in and require explicit support from both client and server״; ועקרונות Security and Trust & Safety, כולל ״Hosts must obtain explicit user consent before invoking any tool״ והטיפול ב-tool annotations כלא-מהימנות. ↩ ↩2 ↩3 -
פרוטוקול בסיס,
modelcontextprotocol.io/specification/2026-07-28/basic. מקור אילוצי JSON-RPC (id שאינו null, אין שימוש חוזר ב-id,resultTypeנדרש); סעיף Statelessness וההערה שלו שתהליך stdio פתוח אינו session; טבלת המפתחות השמורים_metaומעמד החובה/אופציונלי של כל שדה לכל בקשה; כלל-32602עבור שדה נדרש חסר; כללMissingRequiredClientCapability(-32021); ומדיניות הקצאת קודי השגיאה. ↩ ↩2 ↩3 ↩4 ↩5 -
stdio transport,
modelcontextprotocol.io/specification/2026-07-28/basic/transports/stdio. מקור כללי המסגור המופרד בשורות חדשות, דרישת הטוהר שלstdout, ההיתר ל-stderr, וה-probe לשלוש תוצאות של תאימות לאחור — כולל האזהרה שחלק משרתי legacy מעבדים מתודות עמומות-תקופה בלי handshake, שהמדידה בפרק הזה משחזרת. ↩ ↩2 ↩3 -
סקירת transports,
modelcontextprotocol.io/specification/2026-07-28/basic/transports. מקור המסגור ״a transport is a binding״ וההצהרה ששרתים אינם יוזמים בקשות JSON-RPC ולקוחות אינם שולחים תגובות JSON-RPC. ↩ ↩2 -
Discovery,
modelcontextprotocol.io/specification/2026-07-28/server/discover. מקור מעמד החובה שלserver/discover, הצורה שלDiscoverResult, ושדהinstructionsהמתואר כ-״optional natural-language guidance for LLMs on how to use this server effectively״. ↩ -
ארכיטקטורה,
modelcontextprotocol.io/specification/2026-07-28/architecture. מקור הגדרות ה-host/client/server, כלל ה-1:1 בין client ל-server, ארבעת עקרונות העיצוב, שמתוכם עקרון הבידוד מצוטט כאן ללא הבולט החמישי שלו, ״Host process enforces security boundaries״, וסעיף capability-negotiation. ↩ ↩2 -
Elicitation,
.../client/elicitation, ו-Sampling,.../client/sampling. מקור שני מצבי elicitation וה-schema המוגבל שלהם; האיסור לבקש אישורים דרך מצב טופס; הגדרת sampling, דרישת human-in-the-loop שלו, ואזהרת ה-deprecation שמוצמדת אליו. ↩ -
שינויים עיקריים,
modelcontextprotocol.io/specification/2026-07-28/changelog, ו-מדיניות lifecycle ו-deprecation של פיצ׳רים,.../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); הסיווג מחדש של HTTP+SSE (SEP-2596); ה-deprecation של Dynamic Client Registration לטובת Client ID Metadata Documents; מספור קודי השגיאה מחדש; וחלון deprecation של שנים-עשר חודשים. ↩ ↩2 -
Tools,
modelcontextprotocol.io/specification/2026-07-28/server/tools, ו-Server Features,.../server. מקור טבלת היררכיית השליטה ששוחזרה למעלה; הצורותtools/listו-tools/call; הבחנתisErrorבין שגיאות פרוטוקול לבין שגיאות ביצוע כלי; כללי שמות הכלים והערת ה-namespace שממליצה על ״prefixing tool names with a server identifier״; וההנחיה הלא-נורמטיבית ״Stateful Tools״ לגבי handles מפורשים. ↩ -
Versioning,
modelcontextprotocol.io/specification/versioning. מקור סכמתYYYY-MM-DD, מצבי הגרסה Draft/Current/Final, האישור ש-2026-07-28 היא current, וכללי המשא ומתן לכל בקשה. טבלת שכבות ה-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— המפרט והעמוד A2A and MCP: Relationship and Distinction, נקראו ב-7 בספטמבר 2026. מקור ההבחנה בין כלים ל-agents, ההצהרה ששני הפרוטוקולים ״address distinct but highly complementary needs״, וניסוח ה-partnering/using. ↩ -
Agent Communication Protocol,
agentcommunicationprotocol.dev, נקרא ב-7 בספטמבר 2026: ״ACP is now part of A2A under the Linux Foundation!״, באנר שנוסף מעל מפרט שעדיין מוגש במלואו — architecture, agent manifest, agent discovery, message structure, stateful agents, run lifecycle ורשימת REST endpoints כולם עדיין עונים 200. המפרט לא נעלם; הפרויקט כן. ↩