Schema Form
A form generated from a JSON Schema, so a person can invoke a tool by hand. The counterpart to Tool Schema: that one explains the parameters, this one collects them — together they are how you test an MCP tool without writing a client.
src/components/ui/schema-form.tsxAbout
From the component's own source, where it was written.
A form generated from a JSON Schema, so a person can invoke a tool by hand.
The counterpart to ToolSchema: that one explains the parameters, this one collects them. Together they are how you test an MCP tool without writing a client — which is the first thing anyone wants when a server misbehaves.
**Validation is reported, not enforced by disabling submit.** A disabled button with no explanation is the worst version of a form: you cannot submit and you are not told why. Missing required fields are listed, and submit stays live so the error surfaces on the field.
It handles the schema subset that tool definitions actually use — string, number, integer, boolean, enum, and string arrays entered one per line. Nested objects are deliberately out of scope: a generated form for a deep schema is worse than a JSON editor, and CodeBlock already is one.
Install
npx astralyx-ui add schema-form
Usage
import { SchemaForm } from '@/components/ui/schema-form'
<SchemaForm
schema={tool.inputSchema}
value={args}
onChange={setArgs}
onSubmit={(args) => callTool(tool.name, args)}
/>Composer
Change the props and the source below follows.
No props to configure.
<SchemaForm
schema={tool.inputSchema}
value={args}
onChange={setArgs}
onSubmit={(args) => callTool(tool.name, args)}
/>Examples
Calling read_file by hand
<SchemaForm schema={tool.inputSchema} value={args} onChange={setArgs} onSubmit={call} />API
Generated from the source, so it cannot fall behind the code. One table per exported component, then hooks, functions and types.
SchemaForm
Extends Omit<ComponentProps<'form'>, 'onSubmit' | 'onChange'>.
| Prop | Type | Default | Description |
|---|---|---|---|
| schema | JsonSchema | required | Handles the subset tool definitions actually use: string, number, integer, boolean, enum, and string arrays entered one per line. |
| value | SchemaFormValue | required | — |
| onChange | (next: SchemaFormValue) => void | required | — |
| onSubmit | (value: SchemaFormValue) => void | — | — |
| submitLabel | ReactNode | 'Run' | — |
| busy | boolean | false | Disables every control while the call is in flight. |
| missingLabel | (fields: string[]) => ReactNode | (fields) => `Required: ${fields.join(', ')}` | Names the fields that are required but empty. |
| emptyLabel | string | 'This tool takes no parameters.' | — |
| arrayHint | string | 'One per line.' | Hint under an array field. |
Functions
| Function | Signature | Description |
|---|---|---|
| schemaFormMissing | (schema: JsonSchema, value: SchemaFormValue) => string[] | Required, and either absent or an empty string. |
Types
| Type | Definition | Description |
|---|---|---|
SchemaFormValue | Record<string, unknown> | A form generated from a JSON Schema, so a person can invoke a tool by hand. |
Behaviour
| Topic | Detail | Description |
|---|---|---|
| nested objects | out of scope | Deliberately. A generated form for a deep schema is worse than a JSON editor, and CodeBlock already is one. |
| validation | reported, not enforced | Submit is never disabled for missing fields. A dead button that will not say why is the worst version of a form — the missing names are listed instead. |