Free

מבקש מ-Claude לכתוב מחדש את ה-MCP שהקמתי לפני 6 ימים

Smithery דחה את fast-mcp. Claude העביר את כל ה-MCP server ל-SDK הרשמי בחצי שעה — הכתיבה מחדש הייתה זולה כי השכבה הראשונה הייתה דקה.


בפרויקט smarts חיברנו MCP לפני שישה ימים. ביקשתי מ-Claude Code להעלות שלושה tools באמצעות ה-gem fast-mcp:

  • get_contract_info(chain, address) — שם החוזה, תג של מתאם פרוטוקול, ספירת function / event
  • read_contract_state(chain, address, function_name, args?) — קריאה אחת view / pure, cache של 60 שניות
  • get_uniswap_v3_pool(chain, address) — פאנל V3 מלא: מחיר דו-כיווני, liquidity, tick, TVL בדולרים

ה-commit ההוא היה 27ca82e feat(mcp): serve live contract data over MCP via fast-mcp, ב-2026-04-21 ב-1:37 לפנות בוקר. בערך 30 דקות. עבר חלק.

שישה ימים אחר כך, הערב — 2026-04-27 ב-20:24 — דחפתי commit נוסף: 4df08fa feat(mcp): switch to official mcp gem with Streamable HTTP transport.

מה קרה בין שני ה-commits האלה?

Smithery דחה את fast-mcp

הגשתי את smarts ל-Smithery (אינדקס של MCP servers) לרישום. הסורק שלהם זרק 405 מיד:

POST /mcp/sse → 405 Method Not Allowed

לקח לי קצת זמן להבין: fast-mcp 1.6.0 (latest release) עדיין מיישם את HTTP+SSE transport של MCP spec 2024-11-05. אבל לקוחות MCP מודרניים כבר עברו ל-Streamable HTTP של spec 2025-03-26 — endpoint יחיד, POST + DELETE על אותו URL, בלי נתיב נפרד של /sse.

במילים אחרות: ה-spec זז קדימה, וה-gem הדומיננטי בקהילה עוד לא הדביק.

לא התכוונתי לחכות ל-fast-mcp. שכבת ה-MCP server קיימת בשביל שהלקוחות יצרכו אותה — תאימות ל-spec שוקלת יותר מאיזה gem נעים יותר לכתוב.

להחליף את היסודות, בערך 30 דקות

החלפתי את fast-mcp ב-gem הרשמי של Anthropic — mcp 0.14.0. בסיבוב הזה פתחתי thread חדש ב-Amp (מתחת עדיין רץ Claude Opus, אותו אחד כמו ב-Claude Code).

מה נחת במהלך ההגירה:

Transport מחווט מחדש

# ישן: fast-mcp עושה mount אוטומטי על /mcp עם /sse
# חדש: mount מפורש, endpoint יחיד
mount StreamableHTTPTransport.new(server, stateless: true), at: "/mcp"

stateless: true הוא העיקר. ה-server לא מחזיק state per-session בזיכרון, מה שמאפשר ל-Puma לרוץ עם workers > 0 ולעלות בקנה מידה אופקי בלי sticky session.

שינוי מבנה של Tool API

הצורה הישנה של fast-mcp:

class GetContractInfoTool < ApplicationTool
  arguments do
    required(:chain).filled(:string)
    required(:address).filled(:string)
  end

  def call(chain:, address:)
    # לוגיקת ביזנס
  end
end

ה-gem הרשמי דוחף את הצנרת של ה-SDK למחלקת הבסיס:

class ApplicationTool < MCP::Tool
  def self.call(**args, server_context: nil)
    hash = payload(**args)
    MCP::Tool::Response.new([{ type: "text", text: hash.to_json }])
  end
end

class GetContractInfoTool < ApplicationTool
  input_schema(
    properties: {
      chain:   { type: "string" },
      address: { type: "string" }
    },
    required: %w[chain address]
  )

  def self.payload(chain:, address:)
    # לוגיקת ביזנס, מחזיר Hash
  end
end

תת-המחלקות אכפת להן רק איזה Hash מחזיר payload(**args); מחלקת הבסיס עוטפת אותו ב-text block JSON-encoded בתוך MCP::Tool::Response. שני יתרונות:

  1. צנרת ה-SDK מפסיקה להתפזר על כל מחלקת tool
  2. הטסטים יכולים לטעון ישירות על ה-Hash של Tool.payload(chain:, address:), בלי לקלף את envelope הפרוטוקול

את ה-DSL של dry-schema החלפתי בליטרלים גולמיים של JSON Schema. נראה כמו צעד אחורה, אבל input_schema הוא בדיוק מה שלקוח קורא ישירות מ-MCP spec — לכתוב כמו פרימיטיב ה-spec יותר ישר.

טסטים בהעברה

433 טסטים, הוחלפו מ-Tool.new.call(...) ל-Tool.payload(...). כולם ירוקים.

סנכרון discovery / docs

  • .well-known/mcp.json עם transport: "streamable-http", protocol_version: "2025-03-26"
  • README, llms.txt, smithery.yaml — כולם עודכנו ל-https://smarts.md/mcp
  • ה-flag של claude mcp add שונה מ---transport sse ל---transport http
  • ב-CLAUDE.md סקציית ה-tech stack מסמנת עכשיו mcp כ-primary ו-fast-mcp כ-legacy/deprecated

"מוכנות לכתוב מחדש" היא המנוף האמיתי

האינטגרציה הראשונה של MCP לקחה 30 דקות. הכתיבה מחדש בערך אותו דבר. שישה ימים בין השניים.

מה שהתבהר לי: באקוסיסטם צעיר כמו של MCP, gems מפגרים אחרי ה-spec — זו נורמה. fast-mcp לא רע — המתחזק שלו פעיל. הבעיה היא שהפרוטוקול עצמו מתקדם מהר יותר ממימושי צד שלישי. gem שנראה יציב השנה, יכול להיות "זה של ה-spec הישן" בעוד חצי שנה.

לו לפני חצי שנה הייתי כותב עשרת אלפי שורות לוגיקת ביזנס מעל fast-mcp, היום הייתי תקוע על ה-spec הישן — כי עלות הכתיבה מחדש הייתה גבוהה מדי בשבילי להתגייס אליה.

אבל מה שקרה באמת: שכבת fast-mcp הייתה מההתחלה wrapper דק. לוגיקת הביזנס חיה בתת-מחלקות של ApplicationTool. לכן עלות הכתיבה מחדש האמיתית הייתה:

  • לשנות את מחלקת הבסיס (פעם)
  • לכתוב מחדש את DSL של ה-schema בכל אחת מ-4 מחלקות ה-tool (~10 שורות לכל אחת)
  • לשנות את סגנון הקריאה בטסטים (מכני)
  • לשנות שורת mount אחת ב-routes
  • search-and-replace ל-URL ב-docs

היקר זה לוגיקת הביזנס. עוטפי פרוטוקול אמורים להיות זולים וניתנים לכתיבה מחדש. זה הטובה הכי גדולה ש-Claude Code עשה לי לפני שישה ימים — הוא לא דחף את לוגיקת הביזנס לתוך callbacks של fast-mcp. הוא בנה הפשטה נקייה של ApplicationTool שבולעת את ה-SDK. בגלל זה שישה ימים אחר כך החלפת SDK הצריכה רק מחלקת בסיס + schema.

מה שאפשר לי לעבור ב-6 ימים מ"אינטגרציה ראשונה" ל"שדרוג spec וכתיבה מחדש" זה היציבות של Claude כמודל הבסיסי — באיזה agent shell ספציפי הייתי, פחות משנה.

קוד מקור: https://github.com/defi-io/smarts