Tool schema interoperability
Use Standard Schema validators and JSON Schema converters with typed tool handlers.
tool() validates inputs through Standard Schema
and publishes model-facing inputs through
Standard JSON Schema. These are separate
interfaces: validation returns the value your handler receives, while JSON Schema
describes the input the model should send.
Zod and ArkType
Schemas that implement both interfaces work directly:
import { tool } from "@trycereal/sdk"
import { z } from "zod"
import { type } from "arktype"
const lookup = tool({
name: "lookup",
input: z.object({ sourceId: z.string() }),
handler: ({ sourceId }) => ({ sourceId })
})
const search = tool({
name: "search",
input: type({ query: "string" }),
handler: ({ query }) => ({ query })
})The integration tests exercise Zod 4.2+ and ArkType with the official MCP client. The SDK has no runtime import of either validation library.
Valibot and explicit converters
For a validator with a separate JSON Schema converter, pass inputJsonSchema:
import { tool } from "@trycereal/sdk"
import * as v from "valibot"
import { toJsonSchema } from "@valibot/to-json-schema"
const input = v.object({ count: v.pipe(v.string(), v.transform(Number)) })
const count = tool({
name: "count",
input,
inputJsonSchema: () => toJsonSchema(input, { typeMode: "input" }),
handler: ({ count }) => ({ doubled: count * 2 })
})The model sends a string; the handler receives the validated, transformed number.
A converter must describe the input, and tool input schemas must have
type: "object" at the root. inputJsonSchema can also be a plain JSON Schema
object. It controls the published schema; the input validator remains the
runtime authority.
Any Standard Schema validator can use this path, including asynchronous
validators. Failed validation produces an MCP tool error without calling your
handler. A validator without JSON Schema conversion fails at tool() definition
time with instructions to supply inputJsonSchema.
Reuse tool implementations and MCP results
tool() retains its inferred handler type, so application code can reuse
lookup.handler(input, context) with a ToolContext. Direct handler calls are
ordinary function calls: validate untrusted input before invoking them. Validation
runs automatically when the tool is called through Cereal's MCP endpoint.
Handlers can return strings, objects, arrays, or native MCP results with
content, structuredContent, and isError. Plain objects are returned as both
JSON text and structured content; arrays are returned as JSON text. Native MCP
results pass through unchanged. Thrown errors become MCP tool errors.
Use context.signal when calling fetch or another cancellable API so request
cancellation can stop work. Tool context is scoped to each request, including
verified session identity and metadata.