feat(mcp): תחבורת streamable-http לצד stdio (#231.1) #425
Reference in New Issue
Block a user
Delete Branch "worktree-mcp-http-transport"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
למה
סוכני הפלטפורמה מקבלים את שרתי ה-MCP שלהם מהלקוח בפתיחת הסשן, והערוץ הזה מקבל שרתי HTTP בלבד — כל שרת מוזרק כ-
{type:"http", name, url, headers:[Bearer]}. לשרת stdio אין מסלול לשם כלל, ומכאן שכל 108 הכלים נעדרו מהסוכנים מאז שמנוע-ההרצה שלהם השתנה (TaskMaster #231).זהו שלב 1 מתוך 5 בתכנית שב-#231.
מה
MCP_TRANSPORTבוחר תחבורה, ברירת-מחדלstdio.שרת אחד, שתי תחבורות — לא מימוש שני (G2). מרשם-הכלים, השירותים ובריכת-ה-DB משותפים מילולית; רק פרוטוקול-החוט משתנה, כך שכלי לא יכול להתקיים בתחבורה אחת ולא באחרת.
stdioנשאר ברירת-המחדל — כל סשן אינטראקטיבי מגיע דרכו מ-~/.claude.json. שינוי ברירת-המחדל היה שובר את כולם.מלכודת שהתגלתה בהרצה — ולכן לא הסתמכתי על ה-env של FastMCP
ל-
FastMCP.__init__יש ברירות-מחדל מפורשות (host="127.0.0.1",port=8000) שמועברות ל-Settings(**settings). בפידנטיק ארגומנטים מפורשים גוברים על משתני-סביבה — כך ש-FASTMCP_PORTמתעלמים ממנו והשרת נקשר ל-8000 בכל מקרה.על המכונה הזו 8000 תפוס (Coolify), ולכן זה נכשל ברעש במקרה ולא בזכות תכנון. משם
MCP_HTTP_HOST/MCP_HTTP_PORTנקראים אצלנו ומועברים לבנאי.אבטחה
ברירת-מחדל loopback (
127.0.0.1:8790). התחבורה עדיין ללא אימות, ובמרשם יש כלים הרסניים (case_delete,precedent_library_delete). שער ה-Bearer הוא #231.2 והוא חייב לנחות לפני חשיפה כלשהי מחוץ למארח.אימות end-to-end
הורץ בפועל, לא רק נבדק תחבירית:
שם הכלי זהה בדיוק ל-stdio. כלומר 66 ההענקות, כל הוראות-הסוכנים,
web/paperclip_client.pyושערagent_tool_grants_guard.pyממשיכים לעבוד בלי שינוי.Invariants
web/agent_platform_port.py; המודול נותר נקי מסמלי-פלטפורמה.leak_guard.pyירוק (השער תפס ניסוח מוקדם שלי והנוסח תוקן).agent_tool_grants_guard.pyירוק (7 סוכנים, 66 הענקות, 108 כלים).הבא בתור
#231.2 — שער Bearer. זהו הצוואר האמיתי של הפרויקט, לא השמות.
סוכני הפלטפורמה מקבלים את שרתי ה-MCP שלהם מהלקוח בפתיחת הסשן, והערוץ הזה מקבל שרתי HTTP בלבד: כל שרת מוזרק כ- {type:"http", name, url, headers:[Bearer]}. לשרת stdio אין מסלול לשם בכלל — ומכאן שכל 108 הכלים נעדרו מהסוכנים מאז שמנוע-ההרצה שלהם השתנה. שרת אחד, שתי תחבורות — לא מימוש שני (G2). מרשם-הכלים, השירותים ובריכת ה-DB משותפים מילולית; רק פרוטוקול-החוט משתנה, כך שכלי לא יכול להתקיים בתחבורה אחת ולא באחרת. - MCP_TRANSPORT בוחר תחבורה, ברירת-מחדל stdio. ערך לא-חוקי נכשל ברעש (SystemExit) ולא נופל בשקט חזרה ל-stdio — אחרת ה-listener נעדר בעוד שהכול "נראה" תקין (כלל-הנדסה §6). - stdio נשאר ברירת-המחדל: כל סשן אינטראקטיבי מגיע דרכו מ-~/.claude.json. מלכודת שהתגלתה בהרצה: אי-אפשר להסתמך על FASTMCP_HOST/FASTMCP_PORT. ל-FastMCP.__init__ יש ברירות-מחדל מפורשות (host="127.0.0.1", port=8000) שמועברות ל-Settings(**settings), ובפידנטיק ארגומנטים מפורשים גוברים על env — כך ש-FASTMCP_PORT מתעלמים ממנו והשרת נקשר ל-8000 בכל מקרה. על המכונה הזו 8000 תפוס, כך שזה נכשל ברעש במקרה ולא בזכות תכנון. לכן MCP_HTTP_HOST/MCP_HTTP_PORT נקראים אצלנו ומועברים לבנאי. ברירת-מחדל loopback (127.0.0.1:8790): התחבורה עדיין ללא אימות, ובמרשם יש כלים הרסניים (case_delete, precedent_library_delete). שער ה-Bearer הוא #231.2 והוא חייב לנחות לפני חשיפה מחוץ למארח. אומת end-to-end: claude התחבר ל-http://127.0.0.1:8791/mcp וקיבל 108 כלים בשם mcp__legal-ai__case_get — זהה בדיוק ל-stdio. כלומר 66 ההענקות, הוראות-הסוכנים, web/paperclip_client.py ושער INV-AG3 ממשיכים לעבוד. invariants: G2 — מקיים (שרת אחד, שתי תחבורות, מרשם משותף). G12 — מקיים; חיווט צד-הפלטפורמה נשאר מאחורי web/agent_platform_port.py, והמודול הזה נותר נקי מסמלי-פלטפורמה (leak_guard ירוק). INV-AG3 — לא נגוע, השער ירוק. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>