Skip to content

Parameters

Each parameter in a FlowMCP tool describes where a value is placed in the API request (position) and how it is validated (z). Both blocks are required.

{
position: {
key: 'address',
value: '{{USER_PARAM}}',
location: 'query'
},
z: {
primitive: 'string()',
options: [ 'min(42)', 'max(42)' ]
}
}

The position block controls where the parameter’s value is placed in the HTTP request.

FieldTypeRequiredDescription
keystringYesParameter name. For user-facing parameters, this is the input field name exposed to the AI client.
valuestringYes{{USER_PARAM}} for user input, {{SERVER_PARAM:KEY_NAME}} for server params, or a fixed string.
locationstringYesWhere the value is placed: insert, query, or body.
LocationDescriptionExample
insertInserted into the URL path at the {{key}} placeholder/api/v1/{{address}}/txs becomes /api/v1/0xABC.../txs
queryAdded as a URL query parameter?address=0xABC...&module=contract
bodyAdded to the JSON request body{ "address": "0xABC..." }
  1. insert parameters require a matching {{key}} placeholder in the tool’s path.
  2. query parameters are appended to the URL in array order.
  3. body parameters are only valid for POST and PUT tools. A body parameter on a GET or DELETE tool causes a load-time error.
  4. Multiple locations in the same tool are valid.
Value PatternDescriptionVisible to User
{{USER_PARAM}}Value provided by the user at call-timeYes
{{SERVER_PARAM:KEY_NAME}}Value injected from server environmentNo
Any other stringFixed value, sent automaticallyNo

The z block defines validation constraints enforced before the API request is made. The name references Zod, the validation library used by the runtime.

FieldTypeRequiredDescription
primitivestringYesBase type declaration with optional inline values.
optionsstring[]YesArray of validation constraints. Can be empty [].
PrimitiveDescriptionZod EquivalentExample
string()Any string valuez.string()'string()'
number()Numeric valuez.number()'number()'
boolean()True or falsez.boolean()'boolean()'
enum(A,B,C)One of the listed valuesz.enum(['A','B','C'])'enum(mainnet,testnet)'
array()Array of valuesz.array()'array()'
object()Nested objectz.object()'object()'

Options are applied in array order after the primitive type check:

OptionDescriptionApplies ToExample
min(n)Minimum value or minimum lengthnumber, string'min(1)'
max(n)Maximum value or maximum lengthnumber, string'max(100)'
length(n)Exact length or exact item countstring, array'length(42)'
optional()Parameter is not requiredall'optional()'
default(value)Default value when omitted (implies optional())all'default(100)'

Option rules:

  • min() and max() constrain the numeric value for number(), or string length for string().
  • Multiple options combine with AND logic: [ 'min(1)', 'max(100)' ] means value must be >= 1 AND <= 100.
  • Regular expressions are intentionally excluded — type-level validation with min()/max()/length() covers most use cases.

Resource query parameters use a simplified format compared to tool parameters. Since resources are local SQLite queries (not HTTP requests), there is no location field in the position block:

resources: {
verifiedContracts: {
source: 'sqlite',
database: 'contracts.db',
queries: {
byAddress: {
description: 'Find contract by address',
sql: 'SELECT * FROM contracts WHERE address = ?',
parameters: [
{ key: 'address', type: 'string', description: 'Contract address', required: true }
]
}
}
}
}

Resource parameters have a flat structure with key, type, description, and required fields. They do not use the position/z blocks because there is no HTTP request to construct.

Skills define their input parameters with a similar flat format:

input: [
{ key: 'address', type: 'string', description: 'Ethereum contract address', required: true },
{ key: 'chain', type: 'string', description: 'Chain name', required: false }
]

Skill inputs are used as template variables in the skill content via {{input:key}} placeholders.

When a parameter’s enum values come from a shared list, use the {{listName:fieldName}} syntax inside enum():

{
position: {
key: 'chainName',
value: '{{USER_PARAM}}',
location: 'query'
},
z: {
primitive: 'enum({{evmChains:etherscanAlias}})',
options: []
}
}

At load-time, the runtime resolves {{evmChains:etherscanAlias}} by:

  1. Finding the shared list named evmChains (declared in main.sharedLists)
  2. Applying any filter defined in the shared list reference
  3. Extracting the etherscanAlias field from each entry
  4. Replacing the placeholder with comma-separated values

The result at runtime is equivalent to:

primitive: 'enum(ETHEREUM_MAINNET,POLYGON_MAINNET,ARBITRUM_MAINNET,OPTIMISM_MAINNET)'
  1. {{listName:fieldName}} is only allowed inside enum(). Using it in other primitives is an error.
  2. The referenced list must be declared in main.sharedLists.
  3. If the shared list reference has a filter, only matching entries are used.
  4. The fieldName must exist in the list’s meta.fields.
  5. Interpolation happens at load-time, not call-time. Shared list updates require a schema reload.
  6. Mixed static and interpolated values are allowed: enum(custom,{{evmChains:etherscanAlias}}).

Parameters with a fixed value (not {{USER_PARAM}} and not {{SERVER_PARAM:...}}) are invisible to the user and sent automatically:

{
position: {
key: 'module',
value: 'contract',
location: 'query'
},
z: {
primitive: 'string()',
options: []
}
}

Fixed parameters are common for APIs that use query parameters for routing (like Etherscan’s module and action parameters).

API keys are injected via the {{SERVER_PARAM:KEY_NAME}} syntax:

{
position: {
key: 'apikey',
value: '{{SERVER_PARAM:ETHERSCAN_API_KEY}}',
location: 'query'
},
z: {
primitive: 'string()',
options: []
}
}
  1. The KEY_NAME must be declared in main.requiredServerParams.
  2. Server parameters are invisible to the AI client.
  3. The runtime resolves the value from the environment variable. If unset, the tool is hidden.
  4. Server parameter values are never logged.
Value PatternVisible to AI ClientAppears in Input SchemaSource
{{USER_PARAM}}YesYesUser provides at call-time
{{SERVER_PARAM:KEY}}NoNoEnvironment variable
Fixed stringNoNoHardcoded in schema
{
position: { key: 'contractAddress', value: '{{USER_PARAM}}', location: 'query' },
z: { primitive: 'string()', options: [ 'min(42)', 'max(42)' ] }
}
{
position: { key: 'chain', value: '{{USER_PARAM}}', location: 'query' },
z: { primitive: 'enum({{evmChains:slug}})', options: [ 'default(ethereum)' ] }
}
[
{
position: { key: 'version', value: '2', location: 'body' },
z: { primitive: 'string()', options: [] }
},
{
position: { key: 'query', value: '{{USER_PARAM}}', location: 'body' },
z: { primitive: 'object()', options: [] }
},
{
position: { key: 'limit', value: '{{USER_PARAM}}', location: 'body' },
z: { primitive: 'number()', options: [ 'optional()', 'default(100)', 'min(1)', 'max(1000)' ] }
}
]