Skip to content

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 →