.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 2.\d+.\d+ (semver, major must be 2). |
root | string | Base URL for all routes. Must start with https:// (no trailing slash). |
routes | object | Route definitions. Keys are camelCase route names. Maximum 8 routes. |
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 routes. |
sharedLists | object[] | [] | Shared list references. See Shared Lists. |
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):
Route Definition
Each key inroutes is the route name in camelCase. The route name becomes part of the fully qualified tool name (namespace/schemaFile::routeName).
Route 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 route does. Appears in tool description. |
parameters | array | Yes | Input parameter definitions. Can be empty []. |
tests | array | Yes | Executable test cases. At least 1 per route. See Route 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. Routes 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 |
| Route 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 routes per schema | 8 | Keeps schemas focused. Split large APIs into multiple schemas. |
| Version major | 2 | Must match 2.\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. |