---
title: Quickstart
description: Check one tool schema against all four providers, then compile it — about five minutes, no API key.
url: https://pr-2-390be2854416.thally.app/quickstart
lastVerified: 2026-08-20T00:00:00.000Z
verifiedVersion: 0.1.0
---

# Quickstart

Check one tool schema against all four providers, then compile it — about five minutes, no API key.

In five minutes you will take one canonical tool schema, find out what OpenAI,
Anthropic, Gemini and MCP each do with it, and write four provider-native
definitions plus a manifest. Nothing here touches the network.

**Before you start:** a working `schemaport` command. See
[Installation](/installation) — the packages are not on npm yet, so this is a
workspace build, and `schemaport …` below means `node cli/dist/cli.js …` unless
you linked the binary.

#### Point at a schema

A canonical tool is plain JSON: a `name`, an optional `description`, and an
`inputSchema` that is a JSON Schema object. Put one in a `tools/` directory.

```json wrap title="tools/refund-order.json"
{
  "name": "refund_order",
  "description": "Refunds all or part of an order",
  "inputSchema": {
    "type": "object",
    "properties": {
      "orderId": { "type": "string", "description": "The order to refund" },
      "amount": { "type": "number", "minimum": 0, "description": "Amount to refund. Omit to refund the full order." },
      "refundMethod": { "type": "string", "description": "How to return the funds", "enum": ["original_payment", "store_credit", "bank_transfer"] }
    },
    "required": ["orderId"]
  }
}
```

This is `examples/refund-order/v1/refund-order.json` from the
[`cli`](https://github.com/schemaport/cli) repository. Copy it, or point the
commands at that file directly — the reports below are that one tool.

Every command accepts a `.json` file or a directory of them. A directory is read
recursively, skipping `node_modules`, `dist`, `coverage` and dot-directories, so
pointing at `examples/refund-order/v1` instead would load `search_orders` too
and print a longer report.

#### Run check

```bash
schemaport check tools/
```

`check` runs every selected provider's rules over every tool. With no
`--targets`, that is all four.

It reports one block per finding, grouped by provider under `Tool: refund_order`.
Here is everything it printed, with the `✗` and `⚠` markers from your terminal.

#### OpenAI

3 errors{" "}2 warnings

| | Finding | Path | What `compile` does |
|---|---|---|---|
| ✗ | Strict mode requires `additionalProperties: false` on every object schema. | `inputSchema.additionalProperties` | Adds `additionalProperties: false`. |
| ✗ | Optional property `amount` is not allowed in strict mode; every property must be listed in `required`. | `inputSchema.properties.amount` | Emits `amount` as required and nullable. |
| ✗ | Optional property `refundMethod` is not allowed in strict mode; every property must be listed in `required`. | `inputSchema.properties.refundMethod` | Emits `refundMethod` as required and nullable. |
| ⚠ | After compilation the model may send `amount: null` instead of omitting the property. Treat `null` as "not supplied". | `inputSchema.properties.amount` | Adds `"null"` to the type; the key is always present. |
| ⚠ | After compilation the model may send `refundMethod: null` instead of omitting the property. | `inputSchema.properties.refundMethod` | Adds `"null"` to the type; the key is always present. |

Rules from [structured outputs](https://developers.openai.com/api/docs/guides/structured-outputs)
and [function calling](https://developers.openai.com/api/docs/guides/function-calling).

#### Anthropic

2 warnings

| | Finding | Path | What `compile` does |
|---|---|---|---|
| ⚠ | Anthropic accepts this schema in full but does not validate tool inputs against it by default, so Claude may return mistyped values or omit required properties. | `inputSchema` | Emits the default (non-strict) tool definition, preserving the schema verbatim. |
| ⚠ | `minimum` is never enforced. It is ignored in default tool use and is on the documented "Not supported" list for `strict: true`. | `inputSchema.properties.amount.minimum` | Preserved verbatim in `input_schema`. |

Rules from [strict tool use](https://platform.claude.com/docs/en/agents-and-tools/tool-use/strict-tool-use)
and [JSON Schema limitations](https://platform.claude.com/docs/en/build-with-claude/structured-outputs#json-schema-limitations).

#### Gemini

1 warning

| | Finding | Path | What `compile` does |
|---|---|---|---|
| ⚠ | `minimum` is sent to Gemini, but only `FunctionCallingConfig.mode = VALIDATED` is documented to validate calls with constrained decoding. Under the default `AUTO` mode it guides the model rather than binding it. | `inputSchema.properties.amount` | Emits the constraint unchanged. |

Rules from [function calling](https://ai.google.dev/gemini-api/docs/function-calling).

#### MCP

Compatible

No findings. MCP defers to JSON Schema, so this tool needs nothing changed.

The run ends with the summary line:

```console
Result: 3 errors, 5 warnings
```

#### Read the result

The command exits **1**. That is the expected result here, and it is the whole
demonstration — not a problem with your setup.

Exit 1 means at least one `error`-severity diagnostic was found, and an `error`
means *this canonical schema cannot be handed to that provider directly*. It
does not mean you are stuck. Each of the three OpenAI errors is followed by
`SchemaPort can compile this:` and the exact fix, so the failure and the
remedy arrive together.

Read the four sections as four different answers to the same question:

| Target | Verdict |
|---|---|
| OpenAI | Rejected as written. Strict mode has no optional properties and wants every object closed. All three errors are fixable by `compile`. |
| Anthropic | Accepted in full — but not enforced. `minimum` is preserved in the output and still never binds. |
| Gemini | Accepted. Whether `minimum` binds depends on `FunctionCallingConfig.mode`. |
| MCP | `✓ Compatible` — zero diagnostics, nothing to change. |

`✓ Compatible` is printed only when a target produced no diagnostics at all, so
it never hides a provider that would accept your schema after quietly dropping
part of it.

> **Tip:**
`--fail-on warning` makes those warnings fail the command too;
`--fail-on never` reports without ever exiting 1. See
[`check`](/commands/check).

#### Run compile

```bash
schemaport compile tools/ --out generated/
```

Each provider reports the file it wrote, every transformation it applied, and any
warning that survived. The CLI marks transformations `[safe]` or `[lossy]`; every
one here is `[safe]`.

#### OpenAI

Wrote `generated/openai/refund-order.json`.

| | Transformation | Path | What changed |
|---|---|---|---|
| `[safe]` | `renamed-input-schema-to-parameters` | `inputSchema` | Emitted `inputSchema` as the OpenAI `parameters` field. |
| `[safe]` | `enabled-strict-mode` | `inputSchema` | Emitted `strict: true` so OpenAI enforces the schema instead of best-effort matching. |
| `[safe]` | `converted-optional-property-to-nullable` | `inputSchema.properties.amount` | Made `amount` required and added `"null"` to its type; strict mode has no optional properties. |
| `[safe]` | `converted-optional-property-to-nullable` | `inputSchema.properties.refundMethod` | Made `refundMethod` required and added `"null"` to its type; strict mode has no optional properties. |
| `[safe]` | `added-additional-properties-false` | `inputSchema.additionalProperties` | Added `additionalProperties: false`, which strict mode requires on every object. |

2 warnings survived

| | Warning | Path |
|---|---|---|
| ⚠ | After compilation the model may send `amount: null` instead of omitting the property. Treat `null` as "not supplied". | `inputSchema.properties.amount` |
| ⚠ | After compilation the model may send `refundMethod: null` instead of omitting the property. | `inputSchema.properties.refundMethod` |

#### Anthropic

Wrote `generated/anthropic/refund-order.json`.

| | Transformation | Path | What changed |
|---|---|---|---|
| `[safe]` | `renamed-input-schema-field` | `inputSchema` | Emitted the canonical `inputSchema` as the Messages API field `input_schema`. |

2 warnings survived

| | Warning | Path |
|---|---|---|
| ⚠ | Anthropic accepts this schema in full but does not validate tool inputs against it by default, so Claude may return mistyped values or omit required properties. | `inputSchema` |
| ⚠ | `minimum` is never enforced. It is ignored in default tool use and is on the documented "Not supported" list for `strict: true`. | `inputSchema.properties.amount.minimum` |

#### Gemini

Wrote `generated/gemini/refund-order.json`.

| | Transformation | Path | What changed |
|---|---|---|---|
| `[safe]` | `added-enum-format` | `inputSchema.properties.refundMethod.format` | Added `format: "enum"`, which the Gemini reference uses to mark an enumerated field. |
| `[safe]` | `renamed-input-schema-to-parameters` | `inputSchema` | Emitted `inputSchema` as `FunctionDeclaration.parameters`. |
| `[safe]` | `normalized-type-case` | `inputSchema` | Emitted 4 `type` values as Gemini `Type` enum names (`string` -> `STRING`). |

1 warning survived

| | Warning | Path |
|---|---|---|
| ⚠ | `minimum` is sent to Gemini, but only `FunctionCallingConfig.mode = VALIDATED` is documented to validate calls with constrained decoding. Under the default `AUTO` mode it guides the model rather than binding it. | `inputSchema.properties.amount` |

#### MCP

Wrote `generated/mcp/refund-order.json`. No transformations, no warnings.

```console
Result: 4 files written to generated, 0 refusals
```

This time the command exits **0**. Every transformation is marked `[safe]`,
meaning no canonical constraint stopped being enforced, so nothing needed your
permission. Had any transformation been `[lossy]`, that tool/target pair would
have been refused and written nothing — see
[Safe and lossy compilation](/concepts/safe-and-lossy-compilation).

The warnings survive compilation. Losing nothing is not the same as changing
nothing: `amount` really will arrive as `null` now.

#### Look at the output

```text
generated/
├── manifest.json
├── anthropic/refund-order.json
├── gemini/refund-order.json
├── mcp/refund-order.json
└── openai/refund-order.json
```

Each file is the provider-native tool definition, ready to send. Here is the
OpenAI one — required-and-nullable optionals, a closed object, `strict: true`,
and `minimum: 0` still intact:

```json title="generated/openai/refund-order.json"
{
  "type": "function",
  "name": "refund_order",
  "description": "Refunds all or part of an order",
  "parameters": {
    "type": "object",
    "properties": {
      "orderId": {
        "type": "string",
        "description": "The order to refund"
      },
      "amount": {
        "type": [
          "number",
          "null"
        ],
        "description": "Amount to refund. Omit to refund the full order.",
        "minimum": 0
      },
      "refundMethod": {
        "type": [
          "string",
          "null"
        ],
        "description": "How to return the funds",
        "enum": [
          "original_payment",
          "store_credit",
          "bank_transfer"
        ]
      }
    },
    "required": [
      "orderId",
      "amount",
      "refundMethod"
    ],
    "additionalProperties": false
  },
  "strict": true
}
```

The three schema paths OpenAI rejected are exactly the three that changed, and
nothing else did. `manifest.json` records the same story in machine-readable
form — where each output came from, every transformation with its `lossy` flag,
and every warning that survived:

```json wrap title="generated/manifest.json (openai section of refund_order)"
{
  "output": "openai/refund-order.json",
  "transformations": [
    {
      "code": "converted-optional-property-to-nullable",
      "path": "inputSchema.properties.amount",
      "detail": "Made `amount` required and added `\"null\"` to its type; strict mode has no optional properties.",
      "lossy": false
    }
  ],
  "warnings": [
    {
      "code": "openai/nullable-instead-of-omitted",
      "path": "inputSchema.properties.amount",
      "message": "After compilation the model may send `amount: null` instead of omitting the property. Treat `null` as \"not supplied\" in the handler for `refund_order`."
    }
  ]
}
```

One transformation and one warning are shown; the real entry lists all five
transformations and both warnings from the run above. The full document is
described in [Manifest](/reference/manifest).

## What you just proved

The canonical schema stayed the source of truth, `check` found the three places
OpenAI would reject it before a single API call, and `compile` produced output
for all four providers without dropping `minimum: 0` anywhere.

Compiled output is derived, never authoritative, and compiling the same
canonical schema always produces byte-identical files — so you can commit
`generated/` and review it in a pull request, or regenerate it during a build.

## Next

#### [Canonical schemas](/concepts/canonical-schemas)

    What the input format is, and why `inputSchema` must be an object schema.

#### [Safe and lossy compilation](/concepts/safe-and-lossy-compilation)

    What happens when a transformation *would* weaken your schema.

#### [diff](/commands/diff)

    Catch a new required property before it breaks existing callers.

#### [Continuous integration](/guides/ci)

    Wire `check` and `diff` into a pipeline using their exit codes.