Tool Schema Builder — C 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 C implementation — the same logic the interactive tool runs, in a shareable, citable form.
/*
* Tool Schema Builder — strict-mode validation of function-calling / MCP
* tool definitions. C11 — C has no stdlib JSON, so the definition is modeled
* as native structs; the rule walk mirrors src/lib/tool-schema.ts (the
* canonical TypeScript lib). CosmoDev polyglot showcase port.
*/
#include <stdio.h>
#include <string.h>
typedef struct prop {
const char *key, *type, *description, *def;
const char *enum_kinds; /* NULL: no enum; "": empty; else one char per value (s/n/b) */
int has_items; /* arrays: items object present */
const struct prop *nested; /* objects: nested properties */
int nested_n, nested_strict;
} prop;
typedef struct {
const char *name, *description;
int strict; /* additionalProperties === false */
const char *const *required;
int required_n;
const prop *props;
int props_n;
} tool_def;
static void check(const char *rule, const char *path) {
printf("%-26s %s\n", rule, path);
}
/* The recursive strict-mode walk — every object nests the same rules. */
static void check_object(const char *path, const prop *props, int props_n,
const char *const *required, int required_n, int strict) {
static const char *types[] = {"string", "number", "integer", "boolean", "object", "array"};
if (!strict) check("no-additional-properties", path);
int missing = 0;
for (int i = 0; i < props_n; i++) {
int listed = 0;
for (int r = 0; r < required_n; r++)
if (strcmp(required[r], props[i].key) == 0) listed = 1;
if (!listed) missing++;
}
if (missing > 0) check("all-required", path);
for (int i = 0; i < props_n; i++) {
const prop *pr = &props[i];
char p[128];
snprintf(p, sizeof p, "%s.properties.%s", path, pr->key);
if (pr->def) check("no-defaults", p);
if (!pr->description || !pr->description[0]) check("description-present", p);
int type_ok = 0;
if (pr->type)
for (int t = 0; t < 6; t++)
if (strcmp(pr->type, types[t]) == 0) type_ok = 1;
if (!type_ok) check("typed-properties", p);
if (pr->enum_kinds) {
int mixed = 0;
for (const char *k = pr->enum_kinds; k[0] && k[1]; k++)
if (k[0] != k[1]) mixed = 1;
if (!pr->enum_kinds[0] || mixed) check("enum-values", p);
}
if (pr->type && strcmp(pr->type, "array") == 0 && !pr->has_items) check("array-items", p);
if (pr->nested_n > 0) check_object(p, pr->nested, pr->nested_n, NULL, 0, pr->nested_strict);
}
}
int main(void) {
/* Demo: validate a small broken definition and print the issues. */
const prop props[] = {
{"city", "string", NULL, "Paris", NULL, 0, NULL, 0, 0},
{"unit", "string", "celsius or fahrenheit", NULL, "sn", 0, NULL, 0, 0},
{"tags", "array", NULL, NULL, NULL, 0, NULL, 0, 0},
};
static const char *const req[] = {"city"};
tool_def broken = {"Get_Weather", NULL, 0, req, 1, props, 3};
size_t n = strlen(broken.name);
if (n < 1 || n > 64 || strspn(broken.name, "abcdefghijklmnopqrstuvwxyz0123456789_-") != n)
check("non-empty-name", "name: must be 1-64 chars of [a-z0-9_-]");
if (!broken.description || !broken.description[0])
check("description-present", "description: the tool needs a description");
check_object("input_schema", broken.props, broken.props_n, broken.required, broken.required_n, broken.strict);
return 0;
}
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 →