Free

Claude bitten, das MCP von vor 6 Tagen neu zu schreiben

Smithery hat fast-mcp abgewiesen. Claude hat den kompletten MCP-Server in einer halben Stunde auf das offizielle SDK gehoben — billig, weil die erste Schicht dünn war.


Im smarts-Projekt habe ich vor sechs Tagen MCP angebunden. Ich ließ Claude Code mit dem Gem fast-mcp drei Tools aufsetzen:

  • get_contract_info(chain, address) — Vertragsname, Protocol-Adapter-Tag, Function-/Event-Counts
  • read_contract_state(chain, address, function_name, args?) — einzelner View-/Pure-Aufruf, 60s-Cache
  • get_uniswap_v3_pool(chain, address) — vollständiges V3-Panel: Preis in beide Richtungen, Liquidity, Tick, USD-TVL

Dieser Commit war 27ca82e feat(mcp): serve live contract data over MCP via fast-mcp, am 2026-04-21 um 1:37 Uhr. Etwa 30 Minuten. Lief glatt.

Sechs Tage später, heute Abend — 2026-04-27 um 20:24 — habe ich einen weiteren Commit gepusht: 4df08fa feat(mcp): switch to official mcp gem with Streamable HTTP transport.

Was ist dazwischen passiert?

Smithery hat fast-mcp abgewiesen

Ich habe smarts bei Smithery (ein Verzeichnis für MCP-Server) zur Registrierung eingereicht. Deren Scanner hat sofort 405 zurückgegeben:

POST /mcp/sse → 405 Method Not Allowed

Ich brauchte kurz, bis ich es hatte: fast-mcp 1.6.0 (das aktuelle Release) implementiert weiterhin den HTTP+SSE-Transport des MCP-Spec 2024-11-05. Moderne MCP-Clients sind aber schon auf den Streamable HTTP des Spec 2025-03-26 umgestiegen — ein einziger Endpoint, POST + DELETE auf derselben URL, kein separater /sse-Pfad.

Anders gesagt: der Spec ist einen Schritt weiter, das in der Community dominante Gem hat noch nicht nachgezogen.

Ich wollte nicht auf fast-mcp warten. Die MCP-Server-Schicht existiert, damit Clients sie konsumieren — Spec-Kompatibilität wiegt mehr als die Frage, welches Gem sich am angenehmsten schreibt.

Fundament tauschen, ~30 Minuten

fast-mcp durch Anthropics offizielles mcp-Gem 0.14.0 ersetzt. Diese Runde habe ich in Amp einen neuen Thread aufgemacht (darunter läuft weiter Claude Opus, dasselbe Modell wie bei Claude Code).

Was die Migration brachte:

Transport neu verlegt

# Alt: fast-mcp mountet automatisch auf /mcp, mit /sse
# Neu: explizites Mount, Endpoint einzeln
mount StreamableHTTPTransport.new(server, stateless: true), at: "/mcp"

stateless: true ist der entscheidende Punkt. Der Server hält keinen per-Session-State im Speicher, sodass Puma mit workers > 0 laufen und horizontal skalieren kann — ohne Sticky Sessions.

Tool-API umgebaut

Alte fast-mcp-Form:

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

  def call(chain:, address:)
    # Geschäftslogik
  end
end

Das offizielle Gem verlagert die SDK-Verkabelung in die Basisklasse:

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:)
    # Geschäftslogik, gibt ein Hash zurück
  end
end

Subklassen kümmern sich nur darum, welches Hash payload(**args) zurückgibt; die Basisklasse wickelt das in einen JSON-encoded Text Block innerhalb von MCP::Tool::Response. Zwei Vorteile:

  1. SDK-Verkabelung verteilt sich nicht mehr über jede Tool-Klasse
  2. Tests können direkt auf dem Hash von Tool.payload(chain:, address:) asserten — kein Abblättern des Protokoll-Envelopes

Den dry-schema-DSL habe ich durch raw JSON-Schema-Literale ersetzt. Sieht wie ein Rückschritt aus, aber input_schema ist genau das, was Clients aus dem MCP-Spec direkt konsumieren — als Spec-Primitive zu schreiben ist ehrlicher.

Tests umgezogen

433 Tests, von Tool.new.call(...) auf Tool.payload(...) umgestellt. Alles grün.

Discovery / Docs synchronisiert

  • .well-known/mcp.json mit transport: "streamable-http", protocol_version: "2025-03-26"
  • README, llms.txt, smithery.yaml — alle auf https://smarts.md/mcp aktualisiert
  • claude mcp add-Flag von --transport sse auf --transport http umgestellt
  • Im CLAUDE.md-Tech-Stack-Abschnitt jetzt mcp als primary, fast-mcp als legacy/deprecated

„Bereit zu sein, neu zu schreiben" ist der eigentliche Hebel

Die erste MCP-Integration hat 30 Minuten gedauert. Die Neufassung etwa genauso. Dazwischen sechs Tage.

Was mir aufgefallen ist: in einem jungen Ökosystem wie MCP hinken Gems dem Spec hinterher. fast-mcp ist nicht schlecht — der Maintainer ist aktiv. Das Problem ist, dass das Protokoll schneller iteriert als Drittanbieter-Implementierungen. Ein Gem, das dieses Jahr stabil aussieht, kann in sechs Monaten „das von der alten Spec" sein.

Hätte ich vor sechs Monaten zehntausend Zeilen Geschäftslogik auf fast-mcp geschrieben, wäre ich heute höchstwahrscheinlich an die alte Spec gefesselt — weil die Kosten der Neufassung so hoch wären, dass ich mich nicht aufraffen würde.

Tatsächlich war es aber so: die fast-mcp-Schicht war von Anfang an nur ein dünner Wrapper. Geschäftslogik wohnte in den ApplicationTool-Subklassen. Die echten Kosten des Neuschreibens waren also:

  • Basisklasse ändern (einmal)
  • Den Schema-DSL in jeder der 4 Tool-Klassen umschreiben (je ~10 Zeilen)
  • Test-Aufrufstil anpassen (mechanisch)
  • Eine Mount-Zeile in routes ändern
  • Docs-URL via Search-and-Replace

Teuer ist die Geschäftslogik. Protokoll-Wrapper sollten billig und neu schreibbar sein. Das ist der größte Gefallen, den Claude Code mir vor sechs Tagen getan hat — er hat die Geschäftslogik nicht in fast-mcp-Callbacks gestopft, sondern eine saubere ApplicationTool-Abstraktion gebaut, die das SDK aufnimmt. Deshalb erforderte der SDK-Tausch sechs Tage später nur Basisklasse + Schema.

Was mich in 6 Tagen von „erste Integration" zu „Spec-Upgrade und Neufassung" gebracht hat, ist die Stabilität von Claude als zugrunde liegendem Modell — in welcher Agent-Shell ich war, ist relativ egal.

Quellcode: https://github.com/defi-io/smarts