הבעיה
ולידציה של ארגומנטים לכלי MCP נתפסת כחריגה ב-error tracking, ומגיעה לשם במצב שאי אפשר לפעול לפיו.
ToolError (issue 01a05ec6-5dfa-7eb3-8c10-391ce3a772a0), 4 הופעות בשני סשנים, 2–3 בספטמבר. סוכן העביר lines שגוי פעמיים:
codekeeper_get_repo_file · lines.0 · input_value=True, input_type=bool
codekeeper_get_file · lines.1 · input_value='9', input_type=str
Pydantic דחה, FastMCP עטף ב-ToolError, ו-enable_exception_autocapture שלח את זה כאירוע $exception.
למה זו לא תקלה
StrictLines (mcp_server/handlers.py:43) עשה בדיוק את מה שהוא נועד לעשות. ההערה בשורה 64 מסבירה למה הוא קיים: bool הוא תת-מחלקה של int בפייתון, ולכן בלי strict=True הערך lines=[true, 50] היה עובר ולידציה בשקט והופך ל-lines=[1, 50] — הסוכן היה מקבל טווח שגוי בלי ששום דבר נכשל.
הדחייה היא ההגנה עובדת, לא כשל.
למה האירוע ב-error tracking חסר ערך
אין ולו מסגרת אחת מהקוד שלנו. כל המסגרות הן mcp/server/fastmcp/ ו-posthog/mcp/. הוולידציה קורית לפני שהפונקציה שלנו רצה. PostHog עצמו מציג Hide 2 vendor frames — אין שם מה להסתיר משלנו.
והטקסט מוסתר. _redact_exception_values מחליף את $exception_list ב-_EXCEPTION_VALUE_PLACEHOLDER, כמתוכנן. כלומר האירוע מגיע בלי סיבה ובלי קוד שלנו.
ואותו כשל כבר נרשם בערוץ אחר, עם פרטים. $mcp_tool_call עם $mcp_is_error=true נושא את $mcp_error_message המלא — שם השדה, הערך שנדחה והטיפוס — כי _ALLOWED_BY_ERROR_TYPE פותח אותו במפורש ל-ValidationError. משם הגיעו שתי השורות למעלה.
שני ערוצים לאותו אירוע. אחד שימושי, אחד לא. השני מייצר התראות.
התיקון המוצע
ב-scrub_mcp_payload (mcp_server/analytics.py:227): להחזיר None לאירוע $exception שסוגו ValidationError, כך שהוא לא נשלח כלל.
האירוע לא נעלם — הוא כבר קיים בערוץ ה-MCP, עם יותר מידע ממה שיש ב-$exception אחרי ההסתרה.
מה לשים לב אליו
זו הרחבה מ"מה מוסתר" ל"מה נזרק", וזה שער אחר. הפונקציה כבר מחזירה None בכשל, ולכן המנגנון קיים — אבל היום זה קורה רק כשההסתרה עצמה נכשלת. כאן זו זריקה מכוונת של אירוע תקין, וההנמקה צריכה להיכתב ליד הקוד.
הגידור חייב להיות צר. הזריקה חלה רק על ValidationError שמקורו בוולידציית ארגומנטים של כלי. אם ValidationError יכול לצוץ בשירות ממקום אחר — לא מוולידציית ארגומנטים — הוא חייב להמשיך לעבור, אחרת נסתיר תקלה אמיתית.
חצי מההופעות לא נושאות $mcp_error_type. שתיים מארבע חזרו עם $mcp_error_message ריק, כי _ALLOWED_BY_ERROR_TYPE נפתח רק כשהערך הוא בדיוק ValidationError. אם הזריקה תסתמך על אותו מבחין, היא תפספס את אותן שתיים. שווה לבדוק על מה בדיוק להסתעף לפני שכותבים את התנאי.
טסטים
- אירוע
$exception עם ValidationError → נזרק (None)
- אירוע
$exception עם סוג אחר → עובר, עם $exception_list מוסתר כמו היום
$mcp_tool_call עם $mcp_is_error ו-$mcp_error_type="ValidationError" → עובר עם $mcp_error_message מלא, בלי שינוי
$mcp_parameters נשאר חסום בכל המסלולים
מוטציה לכל אחד: הסרת התנאי צריכה להפיל את הראשון; הרחבתו לכל החריגות צריכה להפיל את השני.
מה לא לעשות
לא להוסיף הגנה נוספת ל-lines ולא לשנות את StrictLines. הוא עובד. הבעיה היא בערוץ הדיווח, לא בוולידציה.
הבעיה
ולידציה של ארגומנטים לכלי MCP נתפסת כחריגה ב-error tracking, ומגיעה לשם במצב שאי אפשר לפעול לפיו.
ToolError(issue01a05ec6-5dfa-7eb3-8c10-391ce3a772a0), 4 הופעות בשני סשנים, 2–3 בספטמבר. סוכן העבירlinesשגוי פעמיים:Pydantic דחה, FastMCP עטף ב-
ToolError, ו-enable_exception_autocaptureשלח את זה כאירוע$exception.למה זו לא תקלה
StrictLines(mcp_server/handlers.py:43) עשה בדיוק את מה שהוא נועד לעשות. ההערה בשורה 64 מסבירה למה הוא קיים:boolהוא תת-מחלקה שלintבפייתון, ולכן בליstrict=Trueהערךlines=[true, 50]היה עובר ולידציה בשקט והופך ל-lines=[1, 50]— הסוכן היה מקבל טווח שגוי בלי ששום דבר נכשל.הדחייה היא ההגנה עובדת, לא כשל.
למה האירוע ב-error tracking חסר ערך
אין ולו מסגרת אחת מהקוד שלנו. כל המסגרות הן
mcp/server/fastmcp/ו-posthog/mcp/. הוולידציה קורית לפני שהפונקציה שלנו רצה. PostHog עצמו מציגHide 2 vendor frames— אין שם מה להסתיר משלנו.והטקסט מוסתר.
_redact_exception_valuesמחליף את$exception_listב-_EXCEPTION_VALUE_PLACEHOLDER, כמתוכנן. כלומר האירוע מגיע בלי סיבה ובלי קוד שלנו.ואותו כשל כבר נרשם בערוץ אחר, עם פרטים.
$mcp_tool_callעם$mcp_is_error=trueנושא את$mcp_error_messageהמלא — שם השדה, הערך שנדחה והטיפוס — כי_ALLOWED_BY_ERROR_TYPEפותח אותו במפורש ל-ValidationError. משם הגיעו שתי השורות למעלה.שני ערוצים לאותו אירוע. אחד שימושי, אחד לא. השני מייצר התראות.
התיקון המוצע
ב-
scrub_mcp_payload(mcp_server/analytics.py:227): להחזירNoneלאירוע$exceptionשסוגוValidationError, כך שהוא לא נשלח כלל.האירוע לא נעלם — הוא כבר קיים בערוץ ה-MCP, עם יותר מידע ממה שיש ב-
$exceptionאחרי ההסתרה.מה לשים לב אליו
זו הרחבה מ"מה מוסתר" ל"מה נזרק", וזה שער אחר. הפונקציה כבר מחזירה
Noneבכשל, ולכן המנגנון קיים — אבל היום זה קורה רק כשההסתרה עצמה נכשלת. כאן זו זריקה מכוונת של אירוע תקין, וההנמקה צריכה להיכתב ליד הקוד.הגידור חייב להיות צר. הזריקה חלה רק על
ValidationErrorשמקורו בוולידציית ארגומנטים של כלי. אםValidationErrorיכול לצוץ בשירות ממקום אחר — לא מוולידציית ארגומנטים — הוא חייב להמשיך לעבור, אחרת נסתיר תקלה אמיתית.חצי מההופעות לא נושאות
$mcp_error_type. שתיים מארבע חזרו עם$mcp_error_messageריק, כי_ALLOWED_BY_ERROR_TYPEנפתח רק כשהערך הוא בדיוקValidationError. אם הזריקה תסתמך על אותו מבחין, היא תפספס את אותן שתיים. שווה לבדוק על מה בדיוק להסתעף לפני שכותבים את התנאי.טסטים
$exceptionעםValidationError→ נזרק (None)$exceptionעם סוג אחר → עובר, עם$exception_listמוסתר כמו היום$mcp_tool_callעם$mcp_is_errorו-$mcp_error_type="ValidationError"→ עובר עם$mcp_error_messageמלא, בלי שינוי$mcp_parametersנשאר חסום בכל המסלוליםמוטציה לכל אחד: הסרת התנאי צריכה להפיל את הראשון; הרחבתו לכל החריגות צריכה להפיל את השני.
מה לא לעשות
לא להוסיף הגנה נוספת ל-
linesולא לשנות אתStrictLines. הוא עובד. הבעיה היא בערוץ הדיווח, לא בוולידציה.