Cereal docs
Tools and integrations

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.

On this page