Smithery a rejeté fast-mcp. Claude a déplacé tout le serveur MCP vers le SDK officiel en une demi-heure — la réécriture a coûté peu parce que la première version était fine.
Le projet smarts a intégré MCP il y a six jours. J'avais demandé à Claude Code de mettre en place trois tools avec le gem fast-mcp :
get_contract_info(chain, address) — nom du contract, tag de l'adapter de protocole, comptes de function / eventread_contract_state(chain, address, function_name, args?) — un seul appel view / pure, cache de 60sget_uniswap_v3_pool(chain, address) — panneau V3 complet : prix bidirectionnel, liquidity, tick, TVL en USDCe commit-là, c'était 27ca82e feat(mcp): serve live contract data over MCP via fast-mcp, le 2026-04-21 à 1h37. Une trentaine de minutes. Tout roulant.
Six jours plus tard, ce soir — 2026-04-27 à 20h24 — j'ai poussé un autre commit : 4df08fa feat(mcp): switch to official mcp gem with Streamable HTTP transport.
Qu'est-ce qui s'est passé entre les deux ?
J'ai soumis smarts à Smithery (un annuaire de MCP servers) pour l'enregistrer. Leur scanner m'a balancé 405 direct :
POST /mcp/sse → 405 Method Not Allowed
J'ai mis un peu de temps à comprendre : fast-mcp 1.6.0 (la dernière release) implémente toujours le transport HTTP+SSE de la MCP spec 2024-11-05. Les clients MCP modernes ont déjà basculé sur le Streamable HTTP de la spec 2025-03-26 — endpoint unique, POST + DELETE sur la même URL, pas de chemin /sse séparé.
Autrement dit : la spec a avancé, et le gem dominant de la communauté n'a pas suivi.
Pas question d'attendre fast-mcp. La couche serveur MCP existe pour être consommée par les clients — la compatibilité de spec pèse plus que le gem qui vous plaît à écrire.
J'ai remplacé fast-mcp par le gem officiel mcp 0.14.0 d'Anthropic. Pour cette manche, j'ai ouvert un nouveau thread dans Amp (avec Claude Opus en dessous, le même que Claude Code).
Ce qui a atterri pendant la migration :
Transport, recâblé
# Ancien : fast-mcp monte automatiquement sur /mcp avec /sse
# Nouveau : mount explicite, endpoint unique
mount StreamableHTTPTransport.new(server, stateless: true), at: "/mcp"
stateless: true est la clé. Le serveur ne garde plus d'état per-session en mémoire, ce qui permet à Puma de tourner avec workers > 0 et de scaler horizontalement sans sticky session.
Restructuration de la Tool API
L'ancienne forme fast-mcp :
class GetContractInfoTool < ApplicationTool
arguments do
required(:chain).filled(:string)
required(:address).filled(:string)
end
def call(chain:, address:)
# logique métier
end
end
Le gem officiel pousse la plomberie SDK dans la classe de 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:)
# logique métier, renvoie un Hash
end
end
Les sous-classes ne s'occupent que du Hash que renvoie payload(**args) ; la classe de base l'enveloppe dans un text block JSON-encoded au sein de MCP::Tool::Response. Deux gains :
Tool.payload(chain:, address:), sans dépiauter l'enveloppe de protocoleLe DSL dry-schema a été remplacé par des littéraux JSON Schema bruts. À première vue ça ressemble à un retour en arrière, mais input_schema est ce que les clients lisent littéralement dans la MCP spec — écrire à la primitive de la spec est plus honnête.
Tests, déménagement
433 tests, basculés de Tool.new.call(...) à Tool.payload(...). Tous au vert.
Synchronisation discovery / docs
.well-known/mcp.json avec transport: "streamable-http", protocol_version: "2025-03-26"https://smarts.md/mcpclaude mcp add passé de --transport sse à --transport httpmcp comme primary et fast-mcp comme legacy/deprecatedLa première intégration MCP m'a pris 30 minutes. La réécriture, à peu près pareil. Six jours d'écart.
Ce qui m'a frappé : dans un écosystème jeune comme MCP, les gems sont en retard sur la spec. fast-mcp n'est pas mauvais — son mainteneur est actif. Le problème, c'est que le protocole itère plus vite que les implémentations tierces. Un gem qui paraît solide cette année peut être « celui de l'ancienne spec » dans six mois.
Si j'avais écrit dix mille lignes de logique métier sur fast-mcp il y a six mois, aujourd'hui je serais cloué à l'ancienne spec — parce que le coût de réécriture serait trop élevé pour que je m'y attelle.
Mais voilà ce qui s'est passé : la couche fast-mcp a toujours été un thin wrapper. La logique métier vivait dans les sous-classes de ApplicationTool. Du coup le coût réel de la réécriture a été :
Le cher, c'est la logique métier. Les wrappers de protocole devraient être bon marché et réécrissables. C'est le plus grand service que Claude Code m'a rendu il y a six jours — il n'a pas fourré la logique métier dans les callbacks fast-mcp. Il a construit une abstraction ApplicationTool propre qui absorbait le SDK. Du coup, six jours plus tard, l'échange de SDK n'a demandé que la classe de base + le schema.
Ce qui m'a permis d'aller de « première intégration » à « upgrade de spec et réécriture » en 6 jours, c'est la stabilité de Claude comme modèle de fond — peu importe dans quel shell d'agent j'étais.
Source : https://github.com/defi-io/smarts