Skip to content

MCP Server Integration

FlowMCP schemas can be served as MCP tools through two transport modes: stdio for local AI applications like Claude Desktop, and HTTP/SSE for remote web applications. This guide covers both approaches.

The integration path depends on your use case:

TransportUse CaseProtocol
stdioClaude Desktop, Claude Code, local AI appsStandard input/output
HTTP/SSEWeb services, remote clients, multi-tenantServer-Sent Events over HTTP
CLIQuick testing, agent modeflowmcp run

The stdio transport is used for local AI applications that launch the MCP server as a subprocess. This is the standard approach for Claude Desktop integration.

import { FlowMCP } from 'flowmcp-core'
import { Server } from '@modelcontextprotocol/sdk/server/index.js'
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
// Import your schemas
import { main as coingeckoMain } from './schemas/coingecko-ping.mjs'
import { main as etherscanMain, handlers as etherscanHandlers } from './schemas/etherscan-gas.mjs'
// Create MCP server
const server = new Server(
{ name: 'my-flowmcp-server', version: '1.0.0' },
{ capabilities: { tools: {} } }
)
// Server params (API keys from environment)
const serverParams = {
ETHERSCAN_API_KEY: process.env.ETHERSCAN_API_KEY
}
// Load and activate schemas
const { status: s1, main: m1, handlerMap: h1 } = await FlowMCP.loadSchema( {
filePath: './schemas/coingecko-ping.mjs'
} )
const { status: s2, main: m2, handlerMap: h2 } = await FlowMCP.loadSchema( {
filePath: './schemas/etherscan-gas.mjs'
} )
// Activate all schema routes as MCP tools
FlowMCP.activateServerTools( { server, schema: m1, serverParams, validate: true } )
FlowMCP.activateServerTools( { server, schema: m2, serverParams, validate: true } )
// Connect via stdio
const transport = new StdioServerTransport()
await server.connect( transport )

For web applications and remote access, use the SSE transport with an HTTP server:

import express from 'express'
import { FlowMCP } from 'flowmcp-core'
import { Server } from '@modelcontextprotocol/sdk/server/index.js'
import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js'
const app = express()
// Create MCP server
const server = new Server(
{ name: 'my-remote-server', version: '1.0.0' },
{ capabilities: { tools: {} } }
)
const serverParams = {
ETHERSCAN_API_KEY: process.env.ETHERSCAN_API_KEY
}
// Load and activate schemas
const { main } = await FlowMCP.loadSchema( {
filePath: './schemas/etherscan-gas.mjs'
} )
FlowMCP.activateServerTools( { server, schema: main, serverParams } )
// SSE endpoint
app.get( '/sse', async ( req, res ) => {
const transport = new SSEServerTransport( '/messages', res )
await server.connect( transport )
} )
// Message endpoint
app.post( '/messages', async ( req, res ) => {
await transport.handlePostMessage( req, res )
} )
app.listen( 3000, () => {
console.log( 'MCP server running on http://localhost:3000' )
} )

The fastest way to serve schemas is through the CLI:

Terminal window
# Serve default group as MCP server (stdio)
flowmcp run
# Serve specific group
flowmcp run --group crypto

This starts the CLI in MCP server mode using stdio transport. Configure it in your AI application’s MCP settings.

To use FlowMCP schemas in Claude Desktop, add your server to claude_desktop_config.json:

{
"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", "--group", "crypto" ]
}
}
}

The config file is located at:

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

When serving many schemas, use filtering to expose only the tools you need:

import { FlowMCP } from 'flowmcp-core'
const allSchemas = [ schema1, schema2, schema3, schema4 ]
// Filter by namespace
const { filteredArrayOfSchemas } = FlowMCP.filterArrayOfSchemas( {
arrayOfSchemas: allSchemas,
includeNamespaces: [ 'coingecko', 'etherscan' ],
excludeNamespaces: [],
activateTags: []
} )
// Filter by tags
const { filteredArrayOfSchemas: defiSchemas } = FlowMCP.filterArrayOfSchemas( {
arrayOfSchemas: allSchemas,
includeNamespaces: [],
excludeNamespaces: [],
activateTags: [ 'defi' ]
} )
// Filter specific routes
const { filteredArrayOfSchemas: specific } = FlowMCP.filterArrayOfSchemas( {
arrayOfSchemas: allSchemas,
includeNamespaces: [],
excludeNamespaces: [],
activateTags: [
'coingecko.getPrice', // Include only getPrice from coingecko
'etherscan.!getBalance' // Exclude getBalance from etherscan
]
} )
// Activate filtered schemas
specific.forEach( ( schema ) => {
FlowMCP.activateServerTools( { server, schema, serverParams } )
} )

Server parameters (API keys, tokens) are injected at runtime and never exposed to the AI client. Declare them in the schema’s requiredServerParams and pass them when activating tools:

// Schema declares what it needs
export const main = {
// ...
requiredServerParams: [ 'ETHERSCAN_API_KEY', 'MORALIS_API_KEY' ],
// ...
}
// Server provides the values
const serverParams = {
ETHERSCAN_API_KEY: process.env.ETHERSCAN_API_KEY,
MORALIS_API_KEY: process.env.MORALIS_API_KEY
}
FlowMCP.activateServerTools( { server, schema: main, serverParams } )

For fine-grained control, activate individual routes instead of entire schemas:

// Activate a single route as an MCP tool
const { toolName, mcpTool } = FlowMCP.activateServerTool( {
server,
schema: main,
routeName: 'getGasOracle',
serverParams,
validate: true
} )
console.log( `Activated: ${toolName}` )
// Output: "Activated: etherscan_getGasOracle"

Use prepareServerTool to inspect a tool configuration without registering it:

const toolConfig = FlowMCP.prepareServerTool( {
schema: main,
serverParams,
routeName: 'getGasOracle',
validate: true
} )
console.log( 'Tool name:', toolConfig.toolName )
console.log( 'Description:', toolConfig.description )
console.log( 'Zod schema:', toolConfig.zod )
// Execute manually if needed
const result = await toolConfig.func( { chainName: 'ETH' } )