Skip to main content
This guide covers migrating schemas between FlowMCP versions. Both migration paths are documented below.
The full migration specification is maintained at github.com/FlowMCP/flowmcp-spec. This page provides a practical walkthrough.

v2 to v3 Migration

The v3.0.0 release renames routes to tools and adds two new MCP primitives: Resources (SQLite-based read-only data) and Skills (reusable AI agent instructions).

What Changed

v2v3Description
main.routesmain.toolsPrimary key rename — routes accepted as deprecated alias
version: '2.0.0'version: '3.0.0'Version field update
namespace/file.mjs::routeNamenamespace/file.mjs::tool::routeNameType discriminator in group references
prompts (in groups)skills (in groups)Group prompts renamed to group skills
main.resourcesNew: SQLite-based read-only data
main.skillsNew: AI agent instruction files
includeSchemaSkillsNew: Auto-include schema skills in groups

Automated Migration

Use the flowmcp migrate command to upgrade schemas automatically:
# Migrate a single schema
flowmcp migrate ./schemas/coingecko/Ping.mjs

# Migrate all schemas in a directory
flowmcp migrate --all ./schemas/

# Preview changes without writing (dry run)
flowmcp migrate --dry-run ./schemas/coingecko/Ping.mjs
The migration tool:
  1. Reads the v2 schema file
  2. Renames routes to tools
  3. Updates version from 2.x.x to 3.0.0
  4. Writes the updated schema in-place (or to a new file with --dry-run)
  5. Runs validation on the result
Use --dry-run first to preview what changes will be made without modifying any files.

Manual Migration Steps

If you prefer to migrate manually:
1

Rename routes to tools

The primary change — rename the routes key to tools:Before (v2):
export const main = {
    namespace: 'coingecko',
    name: 'Ping',
    version: '2.0.0',
    root: 'https://api.coingecko.com/api/v3',
    routes: {
        ping: {
            method: 'GET',
            path: '/ping',
            description: 'Check API status',
            parameters: []
        }
    }
}
After (v3):
export const main = {
    namespace: 'coingecko',
    name: 'Ping',
    version: '3.0.0',
    root: 'https://api.coingecko.com/api/v3',
    tools: {
        ping: {
            method: 'GET',
            path: '/ping',
            description: 'Check API status',
            parameters: []
        }
    }
}
2

Update version field

BeforeAfter
version: '2.0.0'version: '3.0.0'
3

Update group references (if applicable)

If your project uses groups in .flowmcp/groups.json, update tool references to use type discriminators:Before:
"tools": [
    "etherscan/contracts.mjs::getContractAbi"
]
After:
"tools": [
    "etherscan/contracts.mjs::tool::getContractAbi"
]
The old format without ::tool:: is still accepted but will produce warnings.
4

Add resources (optional)

If your schema benefits from local data lookups, add a resources block:
resources: {
    verifiedContracts: {
        description: 'Lookup verified contracts',
        source: 'sqlite',
        database: 'contracts.db',
        queries: {
            byAddress: {
                description: 'Find by address',
                sql: 'SELECT * FROM contracts WHERE address = ?',
                parameters: [
                    { key: 'address', type: 'string', description: 'Contract address', required: true }
                ]
            }
        }
    }
}
See Resources for the full specification.
5

Add skills (optional)

If your schema benefits from AI agent workflows, add a skills array and create skill files:
skills: [
    { name: 'contract-audit', file: 'contract-audit.mjs', description: 'Full contract audit' }
]
See Skills for the full specification.
6

Run validation

flowmcp validate <schema-path>
Verify the migrated schema passes all validation rules.

Deprecation Timeline

Versionroutes Behavior
v3.0.0routes accepted as silent alias for tools — schemas work without changes
v3.1.0routes accepted with loud deprecation warning on every load
v3.2.0routes rejected with error — schemas must use tools

Backward Compatibility

Featurev2 Schema on v3 Runtimev3 Schema on v3 Runtime
routes keyAccepted (alias)Use tools instead
version: '2.x.x'Accepted with infoMust be 3.x.x
Group ::routeNameAcceptedUse ::tool::routeName
ResourcesNot availableFully supported
SkillsNot availableFully supported

v1 to v2 Migration

This section covers the earlier migration from v1.2.0 to v2.0.0 format.

Schema Categories

Existing schemas fall into three categories based on migration effort:
Category% of SchemasMigration EffortDescription
Pure declarative~60%AutomaticNo handlers, no imports. Only URL construction and parameters.
With handlers~30%Semi-automaticHas preRequest/postRequest handlers but no imports.
With imports~10%Manual reviewImports shared data that must become shared list references.

Migration Steps

1

Wrap existing fields in main block

The biggest structural change — fields move into a main export, and handlers become a separate factory function.Before (v1.2.0):
export const schema = {
    namespace: 'etherscan',
    name: 'SmartContractExplorer',
    flowMCP: '1.2.0',
    root: 'https://api.etherscan.io/v2/api',
    requiredServerParams: [ 'ETHERSCAN_API_KEY' ],
    routes: { /* ... */ },
    handlers: { /* ... */ }
}
After (v2.0.0):
export const main = {
    namespace: 'etherscan',
    name: 'SmartContractExplorer',
    version: '2.0.0',
    root: 'https://api.etherscan.io/v2/api',
    requiredServerParams: [ 'ETHERSCAN_API_KEY' ],
    requiredLibraries: [],
    routes: { /* ... */ }
}

export const handlers = ( { sharedLists, libraries } ) => ({
    /* ... */
})
Key changes:
  • Two separate named exports: main (static) and handlers (factory function)
  • flowMCP: '1.2.0' becomes version: '2.0.0'
  • handlers is now a factory function receiving { sharedLists, libraries }
  • New field requiredLibraries declares needed npm packages
  • Zero import statements
2

Update version field

BeforeAfter
flowMCP: '1.2.0'version: '2.0.0'
The version field moves inside main and follows semver starting with 2..
3

Convert imports to shared list references

Before (v1.2.0):
import { evmChains } from '../_shared/evm-chains.mjs'

export const schema = {
    namespace: 'etherscan',
    handlers: {
        getContractAbi: {
            preRequest: async ( { struct, payload } ) => {
                const chain = evmChains
                    .find( ( c ) => c.alias === payload.chainName )
                // ...
            }
        }
    }
}
After (v2.0.0):
export const main = {
    namespace: 'etherscan',
    sharedLists: [
        { ref: 'evmChains', version: '1.0.0' }
    ],
    routes: { /* ... */ }
}

export const handlers = ( { sharedLists } ) => ({
    getContractAbi: {
        preRequest: async ( { struct, payload } ) => {
            const chain = sharedLists.evmChains
                .find( ( c ) => c.alias === payload.chainName )
            return { struct, payload }
        }
    }
})
Key changes:
  • Remove import statement entirely (zero imports policy)
  • Add sharedLists reference in main
  • Access list data via sharedLists.evmChains (injected by factory function)
4

Add output schemas (optional but recommended)

New in v2.0.0 — declare expected response shapes:
routes: {
    getContractAbi: {
        // ... existing fields ...
        output: {
            mimeType: 'application/json',
            schema: {
                type: 'object',
                properties: {
                    abi: { type: 'string', description: 'Contract ABI as JSON string' }
                }
            }
        }
    }
}
5

Run validation

flowmcp validate <schema-path>
Checks required fields, namespace format, version format, tool count (max 8), parameter definitions, output schema validity.

Common Migration Issues

IssueCauseFix
SEC001: Forbidden pattern "import"Import statement still presentConvert to sharedLists reference
VAL003: "flowMCP" is not a valid fieldOld version fieldChange to version inside main
DEP001: main.routes is deprecatedv2 schema on v3 runtimeRename routes to tools, update version to 3.0.0

Migration Checklist

Per schema (v1 to v2):
  • Fields wrapped in main block
  • flowMCP: '1.2.0' changed to version: '2.0.0' inside main
  • handlers at top level (sibling of main)
  • All import statements removed
  • Imported data converted to sharedLists references
  • Handler code uses sharedLists via factory injection
  • requiredLibraries declared (can be empty [])
  • Full validation passes (flowmcp validate)
Per schema (v2 to v3):
  • routes renamed to tools
  • version changed from 2.x.x to 3.0.0
  • Group references updated with type discriminators (optional in v3.0.0)
  • Resources added if applicable
  • Skills added if applicable
  • Full validation passes (flowmcp validate)