Zum Inhalt springen

Server-Integration

Docs > Guides

FlowMCP-Schemas koennen als MCP-Tools ueber zwei Transport-Modi bereitgestellt werden: stdio fuer lokale KI-Anwendungen wie Claude Desktop und HTTP/SSE fuer Remote-Webanwendungen. Diese Anleitung behandelt beide Ansaetze.

Der Integrationspfad haengt von deinem Anwendungsfall ab:

TransportAnwendungsfallProtokoll
stdioClaude Desktop, Claude Code, lokale KI-AppsStandard Input/Output
HTTP/SSEWeb-Services, Remote-Clients, Multi-TenantServer-Sent Events ueber HTTP
CLISchnelles Testen, Agent-Modusflowmcp run

Das v4-Core stellt drei statische Bausteine bereit — FlowMCP.loadSchema, FlowMCP.prepareServerTool und FlowMCP.fetch. Du laedst ein Schema einmal und registrierst dann jedes seiner Tools auf einem MCP-Server. Es gibt keinen einzelnen “Aktivieren”-Aufruf: die Registrierung ist eine explizite Schleife, die dir Kontrolle pro Tool gibt.

Der stdio-Transport wird fuer lokale KI-Anwendungen verwendet, die den MCP-Server als Subprocess starten. Dies ist der Standardansatz fuer die Claude-Desktop-Integration.

import { FlowMCP } from 'flowmcp-core'
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
// MCP-Server erstellen
const server = new McpServer(
{ name: 'my-flowmcp-server', version: '1.0.0' }
)
// Server-Parameter (API-Schluessel aus Umgebung)
const serverParams = {
ETHERSCAN_API_KEY: process.env.ETHERSCAN_API_KEY
}
// Ein Schema laden und jedes deklarierte Tool als MCP-Tool registrieren
async function registerSchema( { filePath } ) {
const { status, main, handlerMap, messages } = await FlowMCP
.loadSchema( { filePath } )
if( !status ) {
console.error( `Failed to load ${filePath}:`, messages )
return
}
Object.keys( main.tools )
.forEach( ( routeName ) => {
const { toolName, description, zod, func } = FlowMCP
.prepareServerTool( { main, handlerMap, serverParams, routeName } )
server.registerTool(
toolName,
{ description, inputSchema: zod },
async ( args ) => {
const { status: ok, data, dataAsString } = await func( args )
return {
content: [ { type: 'text', text: dataAsString ?? JSON.stringify( data ) } ],
isError: !ok
}
}
)
} )
}
await registerSchema( { filePath: './schemas/coingecko-ping.mjs' } )
await registerSchema( { filePath: './schemas/etherscan-gas.mjs' } )
// Via stdio verbinden
const transport = new StdioServerTransport()
await server.connect( transport )

Fuer Webanwendungen und Remote-Zugriff den SSE-Transport mit einem HTTP-Server verwenden. Der registerSchema-Helfer aus dem stdio-Beispiel wird unveraendert wiederverwendet — nur der Transport unterscheidet sich:

import express from 'express'
import { FlowMCP } from 'flowmcp-core'
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js'
const app = express()
// MCP-Server erstellen
const server = new McpServer(
{ name: 'my-remote-server', version: '1.0.0' }
)
const serverParams = {
ETHERSCAN_API_KEY: process.env.ETHERSCAN_API_KEY
}
// Schema laden und registrieren (dieselbe loadSchema -> prepareServerTool -> registerTool-Schleife)
const { main, handlerMap } = await FlowMCP
.loadSchema( { filePath: './schemas/etherscan-gas.mjs' } )
Object.keys( main.tools )
.forEach( ( routeName ) => {
const { toolName, description, zod, func } = FlowMCP
.prepareServerTool( { main, handlerMap, serverParams, routeName } )
server.registerTool(
toolName,
{ description, inputSchema: zod },
async ( args ) => {
const { status, data, dataAsString } = await func( args )
return {
content: [ { type: 'text', text: dataAsString ?? JSON.stringify( data ) } ],
isError: !status
}
}
)
} )
// SSE-Endpunkt
app.get( '/sse', async ( req, res ) => {
const transport = new SSEServerTransport( '/messages', res )
await server.connect( transport )
} )
// Message-Endpunkt
app.post( '/messages', async ( req, res ) => {
await transport.handlePostMessage( req, res )
} )
app.listen( 3000, () => {
console.log( 'MCP server running on http://localhost:3000' )
} )

Der schnellste Weg, Schemas bereitzustellen, ist ueber die CLI. flowmcp run startet einen MCP-Server (stdio-Transport), der jedes Tool aus den in schemaFolders[] konfigurierten Schema-Ordnern bereitstellt — ohne Aktivierungsschritt pro Tool:

Terminal-Fenster
# Den kompletten konfigurierten schemaFolders[]-Katalog als MCP-Server bereitstellen (stdio)
flowmcp run

Um FlowMCP-Schemas in Claude Desktop zu nutzen, fuege deinen Server zur claude_desktop_config.json hinzu:

{
"mcpServers": {
"flowmcp-crypto": {
"command": "node",
"args": [ "/path/to/your/server.mjs" ],
"env": {
"ETHERSCAN_API_KEY": "your-key-here",
"COINGECKO_API_KEY": "your-key-here"
}
}
}
}
{
"mcpServers": {
"flowmcp": {
"command": "flowmcp",
"args": [ "run" ]
}
}
}

Speicherort der Konfigurationsdatei:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json

Wenn du deinen eigenen Server baust, entscheidest du an zwei Stellen, welche Tools den KI-Client erreichen: welche Schema-Dateien du laedst und welche Routen du registrierst. In v4 gibt es keine separate Filter-API — du ueberspringst einfach die Routen, die du nicht willst, innerhalb der Registrierungs-Schleife:

// Nur eine Teilmenge der Tools eines Schemas freigeben
const exposeOnly = [ 'getGasOracle', 'getBalance' ]
const { main, handlerMap } = await FlowMCP
.loadSchema( { filePath: './schemas/etherscan-gas.mjs' } )
Object.keys( main.tools )
.filter( ( routeName ) => exposeOnly.includes( routeName ) )
.forEach( ( routeName ) => {
const { toolName, description, zod, func } = FlowMCP
.prepareServerTool( { main, handlerMap, serverParams, routeName } )
server.registerTool(
toolName,
{ description, inputSchema: zod },
async ( args ) => {
const { status, data, dataAsString } = await func( args )
return {
content: [ { type: 'text', text: dataAsString ?? JSON.stringify( data ) } ],
isError: !status
}
}
)
} )

Fuer den CLI-Weg sind die entsprechenden Stellschrauben die schemaFolders[]-Konfiguration (welche Schemas existieren) und benannte Selections (flowmcp selection).

Server-Parameter (API-Schluessel, Tokens) werden zur Laufzeit injiziert und niemals dem KI-Client offengelegt. Deklariere sie in requiredServerParams des Schemas und uebergib sie an prepareServerTool, wenn du jedes Tool registrierst:

// Schema deklariert, was es braucht
export const main = {
// ...
requiredServerParams: [ 'ETHERSCAN_API_KEY', 'MORALIS_API_KEY' ],
// ...
}
// Server stellt die Werte bereit
const serverParams = {
ETHERSCAN_API_KEY: process.env.ETHERSCAN_API_KEY,
MORALIS_API_KEY: process.env.MORALIS_API_KEY
}
// serverParams fliesst in jeden prepareServerTool-Aufruf
const { toolName, description, zod, func } = FlowMCP
.prepareServerTool( { main, handlerMap, serverParams, routeName } )

Fuer feinkoernige Kontrolle registrierst du eine Route, statt ueber das ganze Schema zu iterieren:

const { main, handlerMap } = await FlowMCP
.loadSchema( { filePath: './schemas/etherscan-gas.mjs' } )
// Ein einzelnes Tool vorbereiten
const { toolName, description, zod, func } = FlowMCP
.prepareServerTool( { main, handlerMap, serverParams, routeName: 'getGasOracle' } )
console.log( `Registering: ${toolName}` )
// Output: "Registering: get_gas_oracle_etherscan"
server.registerTool(
toolName,
{ description, inputSchema: zod },
async ( args ) => {
const { status, data, dataAsString } = await func( args )
return {
content: [ { type: 'text', text: dataAsString ?? JSON.stringify( data ) } ],
isError: !status
}
}
)

prepareServerTool gibt ein einfaches Objekt zurueck, du kannst also eine Tool-Konfiguration inspizieren, ohne sie zu registrieren — und sie sogar ueber das zurueckgegebene func direkt ausfuehren:

const { toolName, description, zod, func } = FlowMCP
.prepareServerTool( { main, handlerMap, serverParams, routeName: 'getGasOracle' } )
console.log( 'Tool name:', toolName ) // z. B. "get_gas_oracle_etherscan"
console.log( 'Description:', description )
console.log( 'Zod input shape:', zod ) // Raw-Shape { param: ZodType }
// Bei Bedarf manuell ausfuehren
const { status, data, dataAsString } = await func( { chainName: 'ETH' } )