Tool Schema Builder — Java 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 Java 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 (OpenAI strict mode / MCP inputSchema contract).
// CosmoDev polyglot showcase port, from src/lib/tool-schema.ts (the canonical
// TypeScript lib). Java 17; no stdlib JSON, so the definition arrives as the
// Map<String,Object> a Jackson/org.json parse would produce; only the parse differs.
import java.util.*;
public class ToolSchema {
static final Set<String> SUPPORTED = Set.of("string", "number", "integer", "boolean", "object", "array");
record Issue(String rule, String path) {}
@SuppressWarnings("unchecked")
static Map<String, Object> obj(Object v) { return v instanceof Map ? (Map<String, Object>) v : null; }
static Map<String, Object> map(Object... kv) {
Map<String, Object> m = new LinkedHashMap<>();
for (int i = 0; i + 1 < kv.length; i += 2) m.put((String) kv[i], kv[i + 1]);
return m;
}
// The recursive strict-mode walk — every object nests the same rules.
static void checkObject(String path, Map<String, Object> o, List<Issue> issues) {
if (!Boolean.FALSE.equals(o.get("additionalProperties"))) issues.add(new Issue("no-additional-properties", path));
Map<String, Object> props = obj(o.get("properties"));
if (props == null) return;
List<String> required = o.get("required") instanceof List<?> l ? (List<String>) l : List.of();
String missing = props.keySet().stream()
.filter(k -> !required.contains(k)).reduce((a, b) -> a + ", " + b).orElse(null);
if (missing != null) issues.add(new Issue("all-required", path + ": required missing " + missing));
for (var e : props.entrySet()) {
Map<String, Object> prop = obj(e.getValue());
if (prop == null) continue;
String p = path + ".properties." + e.getKey();
if (prop.containsKey("default")) issues.add(new Issue("no-defaults", p));
if (!(prop.get("description") instanceof String d) || d.isBlank())
issues.add(new Issue("description-present", p));
if (!(prop.get("type") instanceof String t) || !SUPPORTED.contains(t))
issues.add(new Issue("typed-properties", p + ": must be one of " + String.join(" | ", SUPPORTED)));
if (prop.get("enum") instanceof List<?> en) {
Set<String> kinds = new HashSet<>();
for (Object v : en) kinds.add(v == null ? "null" : v.getClass().getSimpleName());
boolean primitive = kinds.stream().allMatch(k -> k.equals("String") || k.equals("Integer")
|| k.equals("Long") || k.equals("Double") || k.equals("Boolean"));
if (en.isEmpty() || kinds.size() > 1 || !primitive) issues.add(new Issue("enum-values", p));
}
if ("array".equals(prop.get("type")) && obj(prop.get("items")) == null)
issues.add(new Issue("array-items", p));
if ("object".equals(prop.get("type")) && obj(prop.get("properties")) != null)
checkObject(p, prop, issues);
}
}
// Validate a parsed tool definition ({name, description, input_schema}).
static List<Issue> validate(Map<String, Object> root) {
List<Issue> issues = new ArrayList<>();
if (!(root.get("name") instanceof String n) || !n.matches("^[a-z0-9_-]{1,64}$"))
issues.add(new Issue("non-empty-name", "name: must be 1-64 chars of [a-z0-9_-]"));
if (!(root.get("description") instanceof String d) || d.isBlank())
issues.add(new Issue("description-present", "description: the tool needs a description"));
Map<String, Object> schema = obj(root.get("input_schema"));
if (schema != null && "object".equals(schema.get("type"))) checkObject("input_schema", schema, issues);
else issues.add(new Issue("json-parseable", "input_schema: must be an object with type: \"object\""));
return issues;
}
public static void main(String[] args) {
// Demo: validate a small broken definition and print the issues.
Map<String, Object> broken = map(
"name", "Get_Weather",
"input_schema", map(
"type", "object",
"properties", map(
"city", map("type", "string", "default", "Paris"),
"unit", map("type", "string", "description", "celsius or fahrenheit", "enum", List.of("c", 2)),
"tags", map("type", "array")),
"required", List.of("city")));
for (Issue i : validate(broken)) System.out.println(i.rule() + " " + i.path());
}
}
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 →