Skip to content

Tool Schema Builder — SQL source

Build function-calling and MCP tool schemas that pass strict mode on the first try, and lint pasted ones against the strict-mode contract — additionalProperties, required-sync, defaults, enums — with one-click autofix for every mechanical violation. Runs entirely in your browser.

This is the SQL implementation — the same logic the interactive tool runs, in a shareable, citable form.

-- Tool Schema Builder — the nine strict-mode rules as DDL, plus a
-- CHECK-constraint flavored validation demo.
--
-- Language: SQL (SQLite dialect — Cloudflare D1)
-- Source:   CosmoDev polyglot showcase port, from src/lib/tool-schema.ts
--           (the canonical TypeScript lib). The rule ids mirror the tool
--           README one-to-one — the lint output IS the answer surface.

CREATE TABLE IF NOT EXISTS tool_schema_rule (
  id INTEGER PRIMARY KEY,       -- lint order
  rule TEXT NOT NULL UNIQUE,    -- the Issue.rule ids, verbatim
  applies_to TEXT NOT NULL,     -- 'input' | 'tool' | 'object' | 'property'
  summary TEXT NOT NULL
);

INSERT INTO tool_schema_rule (id, rule, applies_to, summary) VALUES
  (1, 'json-parseable',          'input',    'input parses and input_schema is an object with type: "object"'),
  (2, 'non-empty-name',          'tool',     'name is 1-64 chars of [a-z0-9_-] (the get_weather convention)'),
  (3, 'description-present',     'tool',     'the tool and every property carry a description'),
  (4, 'no-additional-properties','object',   'every object sets additionalProperties: false'),
  (5, 'all-required',            'object',   'required lists every property — optionality is semantics, not schema'),
  (6, 'no-defaults',             'property', 'strict mode rejects defaults — remove the key'),
  (7, 'typed-properties',        'property', 'type is one of string|number|integer|boolean|object|array'),
  (8, 'enum-values',             'property', 'enum is non-empty and all values share one primitive type'),
  (9, 'array-items',             'property', 'arrays declare items with a type');

-- The rules as the engine itself enforces them. A definition row is only
-- insertable when it satisfies the tool-level rules (2, 3):
CREATE TABLE IF NOT EXISTS tool_definition (
  name        TEXT PRIMARY KEY,
  description TEXT NOT NULL,
  CHECK (length(name) BETWEEN 1 AND 64 AND name GLOB '[a-z0-9_-]*'), -- non-empty-name
  CHECK (description <> '')                                          -- description-present
);

-- ...and a property row only when it satisfies rules 3, 6, 7, 8, 9:
CREATE TABLE IF NOT EXISTS tool_property (
  tool_name   TEXT NOT NULL,
  path        TEXT NOT NULL,     -- e.g. 'input_schema.properties.city'
  type        TEXT NOT NULL,
  description TEXT NOT NULL,
  has_default INTEGER NOT NULL DEFAULT 0,
  enum_kinds  TEXT,              -- DISTINCT typeof() of enum values; NULL = no enum
  items_type  TEXT,              -- arrays only
  PRIMARY KEY (tool_name, path),
  CHECK (type IN ('string','number','integer','boolean','object','array')),     -- typed-properties
  CHECK (description <> ''),                                                    -- description-present
  CHECK (has_default = 0),                                                      -- no-defaults
  CHECK (enum_kinds IS NULL OR (enum_kinds <> '' AND enum_kinds NOT LIKE '%,%')), -- enum-values
  CHECK (type <> 'array' OR items_type IS NOT NULL)                             -- array-items
);

-- Demo: inserting the broken definition's rows fires the CHECKs.
-- city has a default -> no-defaults rejects it:
INSERT INTO tool_property VALUES
  ('get_weather', 'input_schema.properties.city', 'string', 'City name', 1, NULL, NULL);
-- unit's enum mixes text and integer -> enum-values rejects it:
INSERT INTO tool_property VALUES
  ('get_weather', 'input_schema.properties.unit', 'string', 'celsius or fahrenheit', 0, 'text,integer', NULL);
-- tags is an array without items -> array-items rejects it:
INSERT INTO tool_property VALUES
  ('get_weather', 'input_schema.properties.tags', 'array', 'Tags to filter by', 0, NULL, NULL);

-- The compliant row inserts cleanly:
INSERT INTO tool_property VALUES
  ('get_weather', 'input_schema.properties.city', 'string', 'City name', 0, NULL, NULL);

-- Rule 4 and 5 (additionalProperties, required) are structural — they
-- constrain the shape of the definition, not a column — so they stay in
-- the rule table above, enforced by the application-side walk.

Also available in 13 other languages

Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →