Skip to content
Star -

Type System

Related Topics: Endpoints (use types in definitions) | Policies (filter by type) | YAML Schemas (complete field reference) | Testing (validate types)

MXCP’s type system provides robust data validation for endpoint parameters and return values. It combines JSON Schema compatibility with DuckDB type mapping, ensuring type safety across your entire application.

Why types matter:

  • Validation - Invalid data is rejected before execution
  • Documentation - LLMs understand what values are expected
  • SQL Safety - Parameters are properly typed in queries
  • Policy Filtering - Sensitive fields can be automatically filtered

MXCP supports six base types:

TypeDescriptionExampleDuckDB Type
stringText values"hello"VARCHAR
numberFloating-point3.14DOUBLE
integerWhole numbers42INTEGER
booleanTrue/falsetrueBOOLEAN
arrayOrdered list[1, 2, 3]ARRAY
objectKey-value structure{"key": "value"}STRUCT

String types can have format annotations for specialized handling:

FormatDescriptionExampleDuckDB Type
emailEmail address"user@example.com"VARCHAR
uriURL/URI"https://example.com"VARCHAR
dateISO 8601 date"2024-01-15"DATE
timeISO 8601 time"14:30:00"TIME
date-timeISO 8601 timestamp"2024-01-15T14:30:00Z"TIMESTAMP WITH TIME ZONE
durationISO 8601 duration"P1DT2H"VARCHAR
timestampUnix timestamp1705329000TIMESTAMP
parameters:
- name: email
type: string
format: email
description: User's email address
- name: start_date
type: string
format: date
description: Start date (YYYY-MM-DD)
- name: created_at
type: string
format: date-time
description: Creation timestamp

Format annotations are validated automatically when values are passed to endpoints.

Available for all types:

AnnotationDescription
descriptionHuman-readable description
defaultDefault value if not provided
examplesExample values for documentation
enumList of allowed values
parameters:
- name: status
type: string
description: Order status
enum: ["pending", "shipped", "delivered"]
default: "pending"
examples: ["pending", "shipped"]

Parameters are required by default. A parameter becomes optional when it has a default value:

parameters:
# Required - must be provided
- name: user_id
type: integer
description: User ID
# Optional - uses default if not provided
- name: limit
type: integer
description: Maximum results
default: 10
AnnotationDescription
minLengthMinimum string length
maxLengthMaximum string length
formatSpecialized format
- name: username
type: string
minLength: 3
maxLength: 50
description: Username (3-50 characters)
AnnotationDescription
minimumMinimum value (inclusive)
maximumMaximum value (inclusive)
exclusiveMinimumMinimum value (exclusive)
exclusiveMaximumMaximum value (exclusive)
multipleOfValue must be multiple of this
- name: age
type: integer
minimum: 0
maximum: 150
description: Age in years
- name: quantity
type: integer
minimum: 1
multipleOf: 5
description: Quantity (must be multiple of 5)
- name: price
type: number
minimum: 0
exclusiveMaximum: 1000000
description: Price in dollars

Note: multipleOf works reliably with integers. For decimal precision (e.g., currency), use integer cents instead of multipleOf: 0.01 due to floating-point precision limitations.

AnnotationDescription
itemsSchema for array items
minItemsMinimum array length
maxItemsMaximum array length
uniqueItemsItems must be unique
- name: tags
type: array
items:
type: string
minItems: 1
maxItems: 10
uniqueItems: true
description: List of tags (1-10 unique strings)
AnnotationDescription
propertiesSchema for object properties
requiredList of required properties
additionalPropertiesAllow (and preserve) undefined properties. Default: true (if omitted). Use false to reject unknown keys.
- name: address
type: object
properties:
street:
type: string
city:
type: string
zip:
type: string
required: ["street", "city"]

Types can be nested to any depth:

return:
type: array
description: List of users
items:
type: object
properties:
id:
type: integer
name:
type: string
email:
type: string
format: email
return:
type: object
properties:
user:
type: object
properties:
id:
type: integer
name:
type: string
orders:
type: array
items:
type: object
properties:
order_id:
type: string
amount:
type: number

Mark fields containing sensitive data with sensitive: true. The sensitive flag can be applied to any type - strings, numbers, integers, booleans, arrays, or objects:

return:
type: object
properties:
username:
type: string
password:
type: string
sensitive: true
balance:
type: number
sensitive: true # Numbers can also be sensitive
config:
type: object
properties:
host:
type: string
api_key:
type: string
sensitive: true # Nested sensitive field

Sensitive fields are:

  • Redacted in audit logs - Replaced with [REDACTED]
  • Filterable by policies - Can be removed with filter_sensitive_fields action
  • Documented as sensitive - Clear indication in schemas

You can mark entire objects as sensitive:

return:
type: object
properties:
public_data:
type: object
properties:
name:
type: string
credentials:
type: object
sensitive: true
properties:
access_token:
type: string
refresh_token:
type: string

The filter_sensitive_fields policy action automatically removes all fields marked as sensitive:

policies:
output:
- condition: "user.role != 'admin'"
action: filter_sensitive_fields
reason: "Non-admin users cannot see sensitive data"

This is more maintainable than filter_fields as sensitive fields are defined once in the schema rather than repeated in policies.

Parameters defined in your YAML are available in SQL queries using $parameter_name syntax:

parameters:
- name: user_id
type: integer
- name: status
type: string
enum: ["active", "inactive"]
SELECT * FROM users
WHERE id = $user_id
AND status = $status

The type system ensures parameters are properly escaped and typed when passed to DuckDB.

MXCP automatically handles type conversion between:

  1. JSON/YAML input → Python types
  2. Python types → DuckDB types
  3. DuckDB results → Python types
  4. Python types → JSON/YAML output
Python TypeDuckDB Type
strVARCHAR
intINTEGER
floatDOUBLE
boolBOOLEAN
listARRAY
dictSTRUCT
datetimeTIMESTAMP
dateDATE
timeTIME

Here’s a complete parameter definition showcasing various type features:

parameters:
- name: user_id
type: integer
description: Unique user identifier
minimum: 1
examples: [1, 42, 100]
- name: email
type: string
format: email
description: User's email address
examples: ["user@example.com"]
- name: role
type: string
description: User role
enum: ["admin", "user", "guest"]
default: "user"
- name: tags
type: array
items:
type: string
minItems: 0
maxItems: 5
description: User tags
- name: preferences
type: object
description: User preferences
properties:
theme:
type: string
enum: ["light", "dark", "auto"]
default: "auto"
notifications:
type: boolean
default: true
language:
type: string
default: "en"
required: ["theme"]
- name: created_after
type: string
format: date-time
description: Filter users created after this time

MXCP intentionally restricts schema complexity:

Not supported:

  • $ref - No schema references
  • allOf, oneOf, anyOf - No union types
  • pattern, patternProperties - No regex-based constraints
  • Conditional schemas (if/then)

These restrictions ensure:

  • Static, serializable schemas
  • SQL-compatible types
  • AI tooling compatibility
  • Simpler validation and testing

MXCP provides clear error messages:

Error: Invalid email format: not-an-email
Error: Value must be >= 0
Error: String must be at least 3 characters long
Error: Missing required properties: name, email
Error: Value 'invalid' not in enum: ['admin', 'user', 'guest']

Every parameter and return field should have a description:

- name: user_id
type: integer
description: Unique identifier for the user

Specify formats for specialized strings:

- name: email
type: string
format: email # Validates email format

Make optional parameters explicit:

- name: limit
type: integer
default: 10 # Optional - uses 10 if not provided

Constrain to valid options:

- name: status
type: string
enum: ["active", "inactive", "pending"]

Protect sensitive information:

- name: api_key
type: string
sensitive: true # Redacted in logs, filterable by policies

Always specify return schemas with required fields:

return:
type: object
properties:
id:
type: integer
name:
type: string
required: ["id", "name"]

Include examples for documentation and testing:

- name: region
type: string
examples: ["North", "South", "East", "West"]

Define array and numeric constraints:

- name: items
type: array
items:
type: string
minItems: 1
maxItems: 100

Use mxcp validate to check type definitions before deployment:

Terminal window
mxcp validate

Consider putting all sensitive fields in a dedicated object that can be marked sensitive as a whole:

return:
type: object
properties:
public:
type: object
properties:
name: { type: string }
secrets:
type: object
sensitive: true
properties:
token: { type: string }
key: { type: string }