.mjs file with two separate named exports: a static main block and an optional handlers factory function. This separation enables integrity hashing, security scanning, and dependency injection.
This page covers the schema format from the formal specification. See Parameters for parameter details and Security Model for security constraints.
The Two-Export Pattern
Why Two Separate Exports
maincan be hashed without calling any function. The runtime reads the static export, serializes it viaJSON.stringify(), and computes its hash.- Handlers receive all dependencies through injection. Schema files have zero
importstatements. The runtime resolves shared lists, loads approved libraries, and passes them into thehandlers()factory. requiredLibrariesdeclares what npm packages the schema needs. The runtime loads them from a security allowlist and injects them.
The main Export
All fields in main must be JSON-serializable. No functions, no dynamic values, no imports. Everything must survive a JSON.parse( JSON.stringify( main ) ) roundtrip.
Required Fields
| Field | Type | Description |
|---|---|---|
namespace | string | Provider identifier, lowercase letters only (/^[a-z]+$/). |
name | string | Schema name in PascalCase (e.g. SmartContractExplorer). |
description | string | What this schema does, 1-2 sentences. |
version | string | Must match 3.\d+.\d+ (semver, major must be 3). |
root | string | Base URL for all tools. Must start with https:// (no trailing slash). |
tools | object | Tool definitions. Keys are camelCase tool names. Maximum 8 tools. |
Optional Fields
| Field | Type | Default | Description |
|---|---|---|---|
docs | string[] | [] | Documentation URLs for the API provider. |
tags | string[] | [] | Categorization tags for tool discovery. |
requiredServerParams | string[] | [] | Environment variable names needed at runtime. |
requiredLibraries | string[] | [] | npm packages needed by handlers (must be on allowlist). |
headers | object | {} | Default HTTP headers applied to all tools. |
sharedLists | object[] | [] | Shared list references. See Shared Lists. |
resources | object | {} | SQLite-based read-only data resources. See Resources. |
skills | array | [] | AI agent skill references. See Skills. |
The key
routes is accepted as a deprecated alias for tools. Schemas using routes will work in v3.0.0 but will produce warnings in v3.1.0 and errors in v3.2.0. Use flowmcp migrate to update automatically.Field Details
namespace
Only lowercase ASCII letters. No numbers, hyphens, or underscores:
root
Must use HTTPS with no trailing slash:
requiredServerParams
Declares environment variables that must exist at runtime. Values are injected via {{SERVER_PARAM:KEY_NAME}} syntax:
requiredLibraries
Declares npm packages that handlers need. Must be on the runtime allowlist (see Security Model):
Tool Definition
Each key intools is the tool name in camelCase. The tool name becomes part of the fully qualified name (namespace/schemaFile::tool::toolName).
Tool Fields
| Field | Type | Required | Description |
|---|---|---|---|
method | string | Yes | HTTP method: GET, POST, PUT, DELETE. |
path | string | Yes | URL path appended to root. May contain {{key}} placeholders. |
description | string | Yes | What this tool does. Appears in tool description. |
parameters | array | Yes | Input parameter definitions. Can be empty []. |
tests | array | Yes | Executable test cases. At least 1 per tool. See Tests. |
output | object | No | Output schema. See Output Schema. |
preload | object | No | Cache configuration. See Preload. |
HTTP Methods
| Method | Body Allowed | Typical Use |
|---|---|---|
GET | No | Read operations, queries |
POST | Yes | Create operations, complex queries |
PUT | Yes | Update operations |
DELETE | No | Delete operations |
Path Templates
The path supports{{key}} placeholders that are replaced by insert parameters:
{{key}} placeholder must have a corresponding parameter with location: 'insert'.
The handlers Export
The handlers export is a factory function receiving injected dependencies:
Injected Dependencies
| Parameter | Type | Description |
|---|---|---|
sharedLists | object | Resolved shared list data, keyed by list name. Deep-frozen (read-only). |
libraries | object | Loaded npm packages from requiredLibraries, keyed by package name. |
Handler Types
| Handler | When | Input | Must Return |
|---|---|---|---|
preRequest | Before the API call | { struct, payload } | { struct, payload } |
postRequest | After the API call | { response, struct, payload } | { response } |
Handler Rules
- Handlers are optional. Tools without handlers make direct API calls.
- Zero import statements. All dependencies are injected through the factory function.
- No restricted globals.
fetch,fs,process,eval,Function,setTimeoutare forbidden. sharedListsis read-only. Deep-frozen viaObject.freeze(). Mutations throwTypeError.- Handlers must be pure transformations. No side effects, no state mutations, no logging.
- Return shape must match.
preRequestreturns{ struct, payload }.postRequestreturns{ response }.
Runtime Loading Sequence
Naming Conventions
| Element | Convention | Pattern | Example |
|---|---|---|---|
| Namespace | Lowercase letters only | ^[a-z]+$ | etherscan |
| Schema name | PascalCase | ^[A-Z][a-zA-Z0-9]*$ | SmartContractExplorer |
| Schema filename | PascalCase .mjs | ^[A-Z][a-zA-Z0-9]*\.mjs$ | SmartContractExplorer.mjs |
| Tool name | camelCase | ^[a-z][a-zA-Z0-9]*$ | getContractAbi |
| Parameter key | camelCase | ^[a-z][a-zA-Z0-9]*$ | contractAddress |
| Tag | lowercase with hyphens | ^[a-z][a-z0-9-]*$ | smart-contracts |
Constraints
| Constraint | Value | Rationale |
|---|---|---|
| Max tools per schema | 8 | Keeps schemas focused. Split large APIs into multiple schemas. |
| Max resources per schema | 2 | Resources are supplementary data, not primary output. |
| Max skills per schema | 4 | Skills compose tools; keep schemas focused. |
| Version major | 3 | Must match 3.\d+.\d+. |
| Namespace pattern | ^[a-z]+$ | Letters only. No numbers, hyphens, or underscores. |
| Root URL protocol | https:// | HTTP is not allowed. |
| Root URL trailing slash | Forbidden | root must not end with /. |
main export | JSON-serializable | Must survive JSON.parse( JSON.stringify() ) roundtrip. |
| Schema file imports | Zero | All dependencies are injected. |