feat(mcp): תחבורת streamable-http לצד stdio (#231.1) #425

Merged
chaim merged 1 commits from worktree-mcp-http-transport into main 2026-08-05 07:42:22 +00:00
Owner

למה

סוכני הפלטפורמה מקבלים את שרתי ה-MCP שלהם מהלקוח בפתיחת הסשן, והערוץ הזה מקבל שרתי HTTP בלבד — כל שרת מוזרק כ-{type:"http", name, url, headers:[Bearer]}. לשרת stdio אין מסלול לשם כלל, ומכאן שכל 108 הכלים נעדרו מהסוכנים מאז שמנוע-ההרצה שלהם השתנה (TaskMaster #231).

זהו שלב 1 מתוך 5 בתכנית שב-#231.

מה

MCP_TRANSPORT בוחר תחבורה, ברירת-מחדל stdio.

שרת אחד, שתי תחבורות — לא מימוש שני (G2). מרשם-הכלים, השירותים ובריכת-ה-DB משותפים מילולית; רק פרוטוקול-החוט משתנה, כך שכלי לא יכול להתקיים בתחבורה אחת ולא באחרת.

  • stdio נשאר ברירת-המחדל — כל סשן אינטראקטיבי מגיע דרכו מ-~/.claude.json. שינוי ברירת-המחדל היה שובר את כולם.
  • ערך לא-חוקי נכשל ברעש ולא נופל בשקט חזרה ל-stdio — אחרת ה-listener נעדר בעוד שהכול "נראה" תקין (כלל-הנדסה §6).

מלכודת שהתגלתה בהרצה — ולכן לא הסתמכתי על ה-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

הורץ בפועל, לא רק נבדק תחבירית:

[legal_mcp] Serving MCP over streamable-http on 127.0.0.1:8791
Uvicorn running on http://127.0.0.1:8791

$ claude -p --strict-mcp-config --mcp-config '{"legal-ai":{"type":"http","url":"http://127.0.0.1:8791/mcp"}}'
→ `mcp__legal-ai__case_get` — 108 כלים זמינים

שם הכלי זהה בדיוק ל-stdio. כלומר 66 ההענקות, כל הוראות-הסוכנים, web/paperclip_client.py ושער agent_tool_grants_guard.py ממשיכים לעבוד בלי שינוי.

Invariants

  • G2 — מקיים. שרת אחד בשתי תחבורות, מרשם משותף; לא מסלול מקביל שיתפצל.
  • G12 — מקיים. חיווט צד-הפלטפורמה נשאר מאחורי web/agent_platform_port.py; המודול נותר נקי מסמלי-פלטפורמה. leak_guard.py ירוק (השער תפס ניסוח מוקדם שלי והנוסח תוקן).
  • INV-AG3 — לא נגוע; agent_tool_grants_guard.py ירוק (7 סוכנים, 66 הענקות, 108 כלים).

הבא בתור

#231.2 — שער Bearer. זהו הצוואר האמיתי של הפרויקט, לא השמות.

## למה סוכני הפלטפורמה מקבלים את שרתי ה-MCP שלהם **מהלקוח** בפתיחת הסשן, והערוץ הזה מקבל **שרתי HTTP בלבד** — כל שרת מוזרק כ-`{type:"http", name, url, headers:[Bearer]}`. לשרת **stdio אין מסלול לשם כלל**, ומכאן שכל 108 הכלים נעדרו מהסוכנים מאז שמנוע-ההרצה שלהם השתנה (TaskMaster **#231**). זהו **שלב 1 מתוך 5** בתכנית שב-#231. ## מה `MCP_TRANSPORT` בוחר תחבורה, ברירת-מחדל `stdio`. **שרת אחד, שתי תחבורות — לא מימוש שני (G2).** מרשם-הכלים, השירותים ובריכת-ה-DB משותפים מילולית; רק פרוטוקול-החוט משתנה, כך שכלי לא יכול להתקיים בתחבורה אחת ולא באחרת. - `stdio` נשאר ברירת-המחדל — כל סשן אינטראקטיבי מגיע דרכו מ-`~/.claude.json`. שינוי ברירת-המחדל היה שובר את כולם. - ערך לא-חוקי **נכשל ברעש** ולא נופל בשקט חזרה ל-stdio — אחרת ה-listener נעדר בעוד שהכול "נראה" תקין (כלל-הנדסה §6). ## מלכודת שהתגלתה בהרצה — ולכן לא הסתמכתי על ה-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 הורץ בפועל, לא רק נבדק תחבירית: ``` [legal_mcp] Serving MCP over streamable-http on 127.0.0.1:8791 Uvicorn running on http://127.0.0.1:8791 $ claude -p --strict-mcp-config --mcp-config '{"legal-ai":{"type":"http","url":"http://127.0.0.1:8791/mcp"}}' → `mcp__legal-ai__case_get` — 108 כלים זמינים ``` **שם הכלי זהה בדיוק ל-stdio.** כלומר 66 ההענקות, כל הוראות-הסוכנים, `web/paperclip_client.py` ושער `agent_tool_grants_guard.py` ממשיכים לעבוד בלי שינוי. ## Invariants - **G2** — מקיים. שרת אחד בשתי תחבורות, מרשם משותף; לא מסלול מקביל שיתפצל. - **G12** — מקיים. חיווט צד-הפלטפורמה נשאר מאחורי `web/agent_platform_port.py`; המודול נותר נקי מסמלי-פלטפורמה. `leak_guard.py` ירוק (השער תפס ניסוח מוקדם שלי והנוסח תוקן). - **INV-AG3** — לא נגוע; `agent_tool_grants_guard.py` ירוק (7 סוכנים, 66 הענקות, 108 כלים). ## הבא בתור #231.2 — שער Bearer. זהו הצוואר האמיתי של הפרויקט, לא השמות.
chaim added 1 commit 2026-08-05 07:40:44 +00:00
feat(mcp): תחבורת streamable-http לצד stdio — פותח את הדרך להזרקת השרת לסשני ACP (#231.1)
All checks were successful
INV-AG3 Agent Tool Grants / agent-tool-grants (pull_request) Successful in 42s
G12 Leak-Guard / leak-guard (pull_request) Successful in 4s
Lint — undefined names / undefined-names (pull_request) Successful in 11s
81ea43a70a
סוכני הפלטפורמה מקבלים את שרתי ה-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>
chaim merged commit 6aac4a73f6 into main 2026-08-05 07:42:22 +00:00
chaim deleted branch worktree-mcp-http-transport 2026-08-05 07:42:22 +00:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: ezer-mishpati/legal-ai#425