Smithery ha respinto fast-mcp. Claude ha spostato l'intero server MCP sul SDK ufficiale in mezz'ora — la riscrittura è costata poco perché il primo strato era sottile.
Il progetto smarts ha integrato MCP sei giorni fa. Avevo chiesto a Claude Code di tirare su tre tool col gem fast-mcp:
get_contract_info(chain, address) — nome del contract, tag dell'adapter di protocollo, conteggi di function/eventread_contract_state(chain, address, function_name, args?) — singola chiamata view/pure, cache da 60sget_uniswap_v3_pool(chain, address) — pannello V3 completo: prezzo bidirezionale, liquidity, tick, TVL in USDQuel commit era 27ca82e feat(mcp): serve live contract data over MCP via fast-mcp, il 2026-04-21 all'1:37. Una trentina di minuti. Filato.
Sei giorni dopo, stasera — 2026-04-27 alle 20:24 — ho pushato un altro commit: 4df08fa feat(mcp): switch to official mcp gem with Streamable HTTP transport.
Cosa è successo in mezzo?
Ho mandato smarts su Smithery (una directory per server MCP) per registrarlo. Il loro scanner mi ha sparato un 405 subito:
POST /mcp/sse → 405 Method Not Allowed
Ho impiegato un attimo a capire: fast-mcp 1.6.0 (latest release) implementa ancora l'HTTP+SSE transport della MCP spec 2024-11-05. I client MCP moderni si sono già spostati allo Streamable HTTP della spec 2025-03-26 — endpoint unico, POST + DELETE sulla stessa URL, niente percorso /sse separato.
Tradotto: la spec è andata avanti, e il gem dominante della community non l'ha ancora seguita.
Non avevo intenzione di aspettare fast-mcp. Il layer del server MCP esiste perché i client lo consumino — la compatibilità con la spec pesa più di quale gem ti piaccia di più scrivere.
Ho sostituito fast-mcp con il gem ufficiale mcp 0.14.0 di Anthropic. Per questo giro ho aperto un nuovo thread su Amp (sotto gira sempre Claude Opus, lo stesso di Claude Code).
Cosa ha portato la migrazione:
Transport, nuovo cablaggio
# Vecchio: fast-mcp monta automaticamente su /mcp con /sse
# Nuovo: mount esplicito, endpoint unico
mount StreamableHTTPTransport.new(server, stateless: true), at: "/mcp"
stateless: true è il punto. Il server non tiene stato per-sessione in memoria, e così Puma può girare con workers > 0 e scalare orizzontalmente senza sticky session.
Ristrutturazione della Tool API
La forma vecchia di fast-mcp:
class GetContractInfoTool < ApplicationTool
arguments do
required(:chain).filled(:string)
required(:address).filled(:string)
end
def call(chain:, address:)
# logica di business
end
end
Il gem ufficiale spinge l'idraulica del SDK nella classe base:
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:)
# logica di business, ritorna un Hash
end
end
Le sottoclassi pensano solo a quale Hash ritorni payload(**args); la classe base lo avvolge in un text block JSON-encoded dentro MCP::Tool::Response. Due vantaggi:
Tool.payload(chain:, address:), senza scartare l'envelope di protocolloIl DSL di dry-schema l'ho cambiato in literal raw JSON Schema. Sembra un passo indietro, ma input_schema è ciò che il client legge letteralmente dalla MCP spec — scriverlo come primitiva della spec è più onesto.
Trasloco dei test
433 test, passati da Tool.new.call(...) a Tool.payload(...). Tutti verdi.
Sincronizzazione discovery / docs
.well-known/mcp.json con transport: "streamable-http", protocol_version: "2025-03-26"https://smarts.md/mcpclaude mcp add cambiato da --transport sse a --transport httpmcp come primary e fast-mcp come legacy/deprecatedLa prima integrazione MCP è costata 30 minuti. La riscrittura più o meno lo stesso. Sei giorni di distanza.
Quello che ho realizzato: in un ecosistema giovane come MCP, i gem sono indietro rispetto alla spec. fast-mcp non è male — il maintainer è attivo. Il problema è che il protocollo itera più veloce delle implementazioni di terzi. Un gem che quest'anno sembra solido può diventare "quello della vecchia spec" tra sei mesi.
Se sei mesi fa avessi scritto diecimila righe di logica di business sopra fast-mcp, oggi sarei probabilmente bloccato sulla vecchia spec — perché il costo della riscrittura sarebbe troppo alto per decidermi a pagarlo.
Ma in realtà è andata così: il layer fast-mcp è sempre stato un thin wrapper. La logica di business viveva nelle sottoclassi di ApplicationTool. Il costo reale della riscrittura quindi è stato:
Il costoso è la logica di business. I wrapper di protocollo dovrebbero essere economici e riscrivibili. È il favore più grosso che Claude Code mi ha fatto sei giorni fa — non ha infilato la logica di business nei callback di fast-mcp. Ha costruito un'astrazione ApplicationTool pulita che assorbe il SDK. Per questo sei giorni dopo lo scambio di SDK ha richiesto solo classe base + schema.
Quello che mi ha portato da "prima integrazione" a "upgrade di spec e riscrittura" in 6 giorni è la stabilità di Claude come modello di fondo — in quale shell di agent fossi conta poco.
Sorgente: https://github.com/defi-io/smarts