flowmcp validate <schema-path>.
This page covers all validation rules from the formal specification. Rules are enforced at load-time and during CLI validation.
Severity Levels
| Severity | Description | Effect |
|---|---|---|
error | Must fix before use | Schema cannot be loaded |
warning | Should fix | Schema loads with warnings |
info | Nice to have | Informational only |
Validation Output
Rules by Category
Schema Structure Rules (VAL001-VAL005)
Schema Structure Rules (VAL001-VAL005)
| Code | Severity | Rule |
|---|---|---|
| VAL001 | error | Schema must export main as named export |
| VAL002 | error | main must be an object |
| VAL003 | error | main must not contain unknown fields |
| VAL004 | error | handlers (if exported) must be a function |
| VAL005 | warning | handlers function must return an object with keys matching tool names |
Main Block - Required Fields (VAL010-VAL016)
Main Block - Required Fields (VAL010-VAL016)
| Code | Severity | Rule |
|---|---|---|
| VAL010 | error | main.namespace is required and must be a string |
| VAL011 | error | main.namespace must match ^[a-z]+$ |
| VAL012 | error | main.name is required and must be a string |
| VAL013 | error | main.description is required and must be a string |
| VAL014 | error | main.version is required and must match ^3\.\d+\.\d+$ |
| VAL015 | error | main.root is required and must be a valid URL |
| VAL016 | error | main.tools is required and must be a non-empty object |
Main Block - Optional Fields (VAL020-VAL026)
Main Block - Optional Fields (VAL020-VAL026)
| Code | Severity | Rule |
|---|---|---|
| VAL020 | error | main.docs (if present) must be an array of strings |
| VAL021 | error | main.tags (if present) must be an array of strings |
| VAL022 | error | main.requiredServerParams (if present) must be an array of strings |
| VAL023 | error | main.headers (if present) must be a plain object |
| VAL024 | error | main.sharedLists (if present) must be an array of objects |
| VAL025 | error | main.requiredLibraries (if present) must be an array of strings |
| VAL026 | error | Each entry in requiredLibraries must be on the runtime allowlist |
Tool Rules (VAL030-VAL037)
Tool Rules (VAL030-VAL037)
| Code | Severity | Rule |
|---|---|---|
| VAL030 | error | Tool name must match ^[a-z][a-zA-Z0-9]*$ |
| VAL031 | error | Maximum 8 tools per schema |
| VAL032 | error | tool.method is required and must be GET, POST, PUT, or DELETE |
| VAL033 | error | tool.path is required and must be a string starting with / |
| VAL034 | error | tool.description is required and must be a string |
| VAL035 | error | tool.parameters is required and must be an array |
| VAL036 | warning | tool.output is recommended for new schemas |
| VAL037 | info | tool.async is a reserved field (not executed in v3.0.0) |
Parameter Rules (VAL040-VAL050)
Parameter Rules (VAL040-VAL050)
| Code | Severity | Rule |
|---|---|---|
| VAL040 | error | Each parameter must have position and z objects |
| VAL041 | error | position.key is required and must be a string |
| VAL042 | error | position.value is required and must be a string |
| VAL043 | error | position.location must be insert, query, or body |
| VAL044 | error | z.primitive is required and must be a valid primitive type |
| VAL045 | error | z.options must be an array of strings |
| VAL046 | error | enum() values must not be empty |
| VAL047 | error | Shared list interpolation {{listName:fieldName}} is only allowed in enum() |
| VAL048 | error | Referenced shared list must be declared in main.sharedLists |
| VAL049 | error | Referenced field must exist in the shared list’s meta.fields |
| VAL050 | error | insert parameters must have a corresponding {{key}} in tool.path |
Output Schema Rules (VAL060-VAL065)
Output Schema Rules (VAL060-VAL065)
| Code | Severity | Rule |
|---|---|---|
| VAL060 | error | output.mimeType must be a supported MIME type |
| VAL061 | error | output.schema must be a valid schema definition |
| VAL062 | error | output.schema.type must match MIME type expectations |
| VAL063 | warning | Nested depth should not exceed 4 levels |
| VAL064 | error | properties is only valid when type is object |
| VAL065 | error | items is only valid when type is array |
Shared List Reference Rules (VAL070-VAL075)
Shared List Reference Rules (VAL070-VAL075)
Security Rules (SEC001-SEC005)
Security Rules (SEC001-SEC005)
| Code | Severity | Rule |
|---|---|---|
| SEC001 | error | Forbidden pattern found in schema file — no import statements allowed |
| SEC002 | error | main block contains non-serializable value (function, symbol, etc.) |
| SEC003 | error | Shared list file contains forbidden pattern |
| SEC004 | error | Shared list file contains executable code |
| SEC005 | error | requiredLibraries contains unapproved package |
Shared List Validation Rules (LST001-LST011)
Shared List Validation Rules (LST001-LST011)
Group Validation Rules (GRP001-GRP006)
Group Validation Rules (GRP001-GRP006)
| Code | Severity | Rule |
|---|---|---|
| GRP001 | error | Group name must match ^[a-z][a-z0-9-]*$ |
| GRP002 | error | Maximum 50 tools per group |
| GRP003 | error | Tool reference must follow namespace/file::type::name format |
| GRP004 | error | All referenced tools must be resolvable |
| GRP005 | error | Duplicate tool references are forbidden |
| GRP006 | error | Group hash must match calculated hash |
Test Requirements (TST001-TST008)
Test Requirements (TST001-TST008)
| Code | Severity | Rule |
|---|---|---|
| TST001 | error | Each tool must have at least 1 test |
| TST002 | error | Each test must have a _description field of type string |
| TST003 | error | Each test must provide values for all required {{USER_PARAM}} parameters |
| TST004 | error | Test parameter values must pass the corresponding z validation |
| TST005 | error | Test objects must be JSON-serializable |
| TST006 | error | Test objects must only contain keys matching {{USER_PARAM}} parameter keys or _description |
| TST007 | warning | Tools with enum or chain parameters should test multiple enum values |
| TST008 | info | Consider adding tests that demonstrate optional parameter usage |
Skill Validation Rules (PRM001-PRM008)
Skill Validation Rules (PRM001-PRM008)
| Code | Severity | Rule |
|---|---|---|
| PRM001 | error | Skill name must match ^[a-z][a-z0-9-]*$ |
| PRM002 | error | File must exist at declared path |
| PRM003 | error | File must have # Title (first line) |
| PRM004 | error | File must have ## Workflow section |
| PRM005 | warning | Tool references must resolve in group |
| PRM006 | error | Group must have at least one tool |
| PRM007 | error | No duplicate skill names within a group |
| PRM008 | error | Filename must match skill name |
Resource Validation Rules (RES001-RES023)
Resource Validation Rules (RES001-RES023)
| Code | Severity | Rule |
|---|---|---|
| RES001 | error | resources (if present) must be an object |
| RES002 | error | Resource name must match ^[a-z][a-zA-Z0-9]*$ |
| RES003 | error | Maximum 2 resources per schema |
| RES004 | error | resource.description is required and must be a string |
| RES005 | error | resource.source must be 'sqlite' |
| RES006 | error | resource.database is required and must be a string ending in .db |
| RES007 | error | resource.queries is required and must be a non-empty object |
| RES008 | error | Maximum 4 queries per resource |
| RES009 | error | Query name must match ^[a-z][a-zA-Z0-9]*$ |
| RES010 | error | query.description is required and must be a string |
| RES011 | error | query.sql is required and must be a string |
| RES012 | error | SQL must start with SELECT (read-only enforcement) |
| RES013 | error | SQL must not contain blocked patterns (ATTACH DATABASE, LOAD_EXTENSION, PRAGMA, etc.) |
| RES014 | error | SQL must use ? placeholders (no string interpolation) |
| RES015 | error | Number of ? placeholders must match number of parameters |
| RES016 | error | query.parameters (if present) must be an array |
| RES017 | error | Each query parameter must have key, type, and description |
| RES018 | error | Query parameter type must be string, number, or boolean |
| RES019 | error | Query parameter key must match ^[a-z][a-zA-Z0-9]*$ |
| RES020 | error | No duplicate parameter keys within a query |
| RES021 | error | Database file must exist at schema-relative path (runtime check) |
| RES022 | warning | Consider adding tests to resource queries |
| RES023 | error | SQL must not contain subqueries with write operations |
Schema-Level Skill Validation Rules (SKL001-SKL025)
Schema-Level Skill Validation Rules (SKL001-SKL025)
| Code | Severity | Rule |
|---|---|---|
| SKL001 | error | skills (if present) must be an array |
| SKL002 | error | Maximum 4 skills per schema |
| SKL003 | error | Each skill entry must have name, file, and description |
| SKL004 | error | Skill name must match ^[a-z][a-z0-9-]*$ |
| SKL005 | error | Skill file must end in .mjs |
| SKL006 | error | Skill file must exist at schema-relative path |
| SKL007 | error | Skill file must export skill as named export |
| SKL008 | error | skill.name must match the name in main.skills entry |
| SKL009 | error | skill.version must be 'flowmcp-skill/1.0.0' |
| SKL010 | error | skill.description is required and must be a string |
| SKL011 | error | skill.content is required and must be a non-empty string |
| SKL012 | error | skill.requires must be an object with tools, resources, and external arrays |
| SKL013 | error | Each requires.tools entry must match a tool name in the schema |
| SKL014 | error | Each requires.resources entry must match a resource name in the schema |
| SKL015 | error | skill.input (if present) must be an array |
| SKL016 | error | Each input must have key, type, description, and required fields |
| SKL017 | error | Input key must match ^[a-z][a-zA-Z0-9]*$ |
| SKL018 | error | Input type must be string, number, or boolean |
| SKL019 | error | No duplicate input keys within a skill |
| SKL020 | error | skill.output (if present) must be a string |
| SKL021 | warning | {{tool:x}} placeholders should reference tools in requires.tools |
| SKL022 | warning | {{resource:x}} placeholders should reference resources in requires.resources |
| SKL023 | warning | {{input:x}} placeholders should reference input keys |
| SKL024 | error | {{skill:x}} placeholders must reference other skills in the schema |
| SKL025 | error | No circular skill references via {{skill:x}} placeholders |
Deprecation Rules (DEP001-DEP004)
Deprecation Rules (DEP001-DEP004)
| Code | Severity | Rule |
|---|---|---|
| DEP001 | warning | main.routes is deprecated — use main.tools instead (v3.0.0: alias, v3.1.0: loud warning, v3.2.0: error) |
| DEP002 | info | Legacy ::routeName format in groups — use ::tool::routeName discriminator |
| DEP003 | warning | prompts key in groups.json — renamed to skills |
| DEP004 | info | version: '2.x.x' detected — run flowmcp migrate to upgrade |