Input Definitions
When to Use
Use this when declaring what a tool accepts. Inputs are typed-data definitions; they drive validation, the Explorer form, the config schema suggestion, and the JSON Schema that AI and MCP callers see.
Version: applies to
drupal/tool1.0.0-beta11 (beta; no security advisory coverage). Paths are undermodules/contrib/tool/.
Classes
All live in Drupal\tool\TypedData and implement InputDefinitionInterface.
| Class | Use for | Constructor (copied from tool 1.0.0-beta11) |
|---|---|---|
InputDefinition |
A scalar or any typed-data type | ($data_type, $label, $description, $required = TRUE, $multiple = FALSE, $default_value = NULL, ?array $constraints = [], bool $locked = FALSE, array $examples = []) |
EntityInputDefinition |
An entity | ($data_type, $label, $description, $required = TRUE, $multiple = FALSE, $default_value = NULL, array $constraints = [], bool $locked = FALSE, array $examples = []); a bare 'node' becomes 'entity:node' |
ListInputDefinition |
A repeated value | ($label, $description, $required = TRUE, $default_value = NULL, array $constraints = [], ?InputDefinitionInterface $item_definition = NULL, bool $locked = FALSE); no item definition means items of type any |
MapInputDefinition |
An object with named properties | ($label, $description, $required = TRUE, $multiple = FALSE, $default_value = NULL, array $constraints = [], array $property_definitions = [], bool $locked = FALSE); every property must be an InputDefinitionInterface |
label and description have no default. required defaults to TRUE.
Data Types and Constraints
data_type is any core typed-data type ID: string, integer, float, decimal, boolean, email, uri, timestamp, datetime_iso8601, map, list, any, entity, entity:<type>. The module adds a text data type (tool 1.0.0-beta11 src/Plugin/DataType/TextData.php).
constraints takes any validation constraint by plugin name, for example ['Choice' => ['choices' => ['ASC', 'DESC']]]. The module adds DateTime, DateOnly, FieldExists, GreaterThan, GreaterThanOrEqual, LessThan, LessThanOrEqual, IdenticalTo and PositiveOrZero (tool 1.0.0-beta11 src/Plugin/Validation/Constraint/).
Enums in the JSON Schema. Choice and AllowedValues become a JSON Schema enum and are never limited. Enums derived from site state (PluginExists, EntityBundleExists) are left out entirely when they would exceed 50 entries; they are not truncated (DERIVED_ENUM_LIMIT in src/Normalizer/ContextDefinitionNormalizer.php).
Pattern
A list input, from the shipped agent skill reference (tool 1.0.0-beta11 .agents/skills/create-tool-plugins/references/anatomy.md):
new ListInputDefinition(
label: new TranslatableMarkup('Tags'),
description: new TranslatableMarkup('...'),
required: FALSE,
constraints: ['Count' => ['max' => 10]], // binds the list
item_definition: new InputDefinition(
data_type: 'string',
label: '',
description: '',
constraints: ['Length' => ['max' => 64]], // binds each value
),
);
Input Semantics
- Required means present and not NULL. An empty list
[]or map{}passesrequired. AddNotBlankorCountto demand content (tool 1.0.0-beta11docs/developers/input-output-definitions.md). - An unset input takes the definition default. A required input explicitly set to NULL, with a NULL default, is reported by
validateInputs(). Ifaccess()orexecute()runs withoutvalidateInputs()first,resolveDefaultValue()throwsContextException, which is not an\InvalidArgumentException.access()catches only\InvalidArgumentException, so it throws the exception uncaught.execute()reports aRuntimefailure with only the class name (tool 1.0.0-beta11src/TypedInputsTrait.php,src/Tool/ToolBase.php). The JSON Schema lists every required input underrequired, defaults or not. - Value order: locked default, then explicit input, then configuration value, then definition default (tool 1.0.0-beta11
src/TypedInputsTrait.php,getExecutableValue()). locked: TRUEfixes the value to the default.setInputValue()on it throwsInputException"The @name input is locked and cannot be changed." Locked inputs are hidden fromgetInputDefinitions()unless you passTRUE.- Absent map properties are left unchanged. A required property that is absent is a violation.
- List items cannot be NULL.
setInputValue()throws "The @name input must not contain NULL items." - Coercion.
InputTypeCoercionSubscriberruns at priority 50 on every value passed tosetInputValue(). It runs after invoker-specific subscribers (the invoker is the caller identity passed tocreateInstance(); see Calling a Tool from PHP), such as handle resolution (100), and before the recursive subscriber (-100). Configuration values and defaults are not coerced. It changes only unambiguous values: JSON strings to maps or lists, a scalar to a one-item list,"true"toTRUE,"5"to5, near-miss enum casing (tool 1.0.0-beta11src/EventSubscriber/InputTypeCoercionSubscriber.php). - Validation is by shape. Lists are validated per item and maps per property against their definitions; declared list and map constraints run separately (tool 1.0.0-beta11
src/TypedInputsTrait.php,validateInputValue()). - The root schema rejects unknown names.
normalizeInputSchema()emitsadditionalProperties: FALSEat the root only; maps stay open (tool 1.0.0-beta11src/Normalizer/ToolDefinitionSerializer.php). examplesare emitted as JSON Schemaexamplesand never validated.
Refiners
A refiner narrows one input from the values of others, for example a bundle list that depends on entity_type_id. Declare input_definition_refiners: ['field_name' => ['entity']] and implement Drupal\tool\TypedData\InputDefinitionRefinerInterface::refineInputDefinition($name, $definition, $values). The refiner runs only when every dependency has a non-NULL, valid value. A refinement that changes the data type or multiplicity throws \LogicException (tool 1.0.0-beta11 src/TypedInputsTrait.php, assertRefinementNarrows()). Real example: tool_belt:field_set_value (tool_belt 1.0.0-alpha6 modules/tool_belt_content/src/Plugin/tool/Tool/FieldSetValue.php).
Common Mistakes
- Forgetting
required: FALSEon optional inputs → every input is required by default; callers get validation failures - Using
multiple: TRUE→ deprecated in beta10, removed in rc1; declare aListInputDefinition - A write tool that accepts a required map and saves it →
{}passesrequiredand can wipe config; addNotBlank - Putting item constraints on a
ListInputDefinition→ they bind the list; put them onitem_definition - Expecting a refiner to widen a type → it can only narrow; widen in the declaration
See Also
- Output Definitions → the output side
- Entity Inputs and Handles → entity inputs
- Reference:
modules/contrib/tool/src/TypedData/,modules/contrib/tool/src/TypedInputsTrait.php,modules/contrib/tool/docs/developers/input-output-definitions.md