View on GitHub →
← Back to Home

JavaScript: Tool Contracts with ToolClad

Define .clad.toml manifests, validate typed arguments, execute tools safely, and generate MCP schemas with ToolClad.

The Problem: Unconstrained Tool Execution

Agentic runtimes let LLMs invoke CLI tools, but without constraints the model can generate arbitrary shell commands. Deny-list approaches are fragile — one missed metacharacter and you have command injection.

ToolClad inverts the model: instead of blocking dangerous commands, it constrains the LLM to fill typed parameters validated against a declarative manifest (allow-list). The dangerous action cannot be expressed because the interface doesn't permit it.

  • Typed parameters: string, integer, port, enum, scope_target, url, path, ip_address, cidr, boolean
  • Shell metacharacter rejection by default
  • Command template rendering with value mappings
  • Evidence envelopes with execution metadata
  • MCP schema generation from manifests
  • Full CLI for validation, testing, and execution

Step 1: Install ToolClad

Install from npm:

npm install toolclad

Step 2: Create a Manifest

A .clad.toml manifest defines everything about a tool: its binary, typed arguments, command template, output format, and risk tier. Save this as whois_lookup.clad.toml:

[tool]
name = "whois_lookup"
version = "1.0.0"
binary = "whois"
description = "WHOIS domain/IP registration lookup"
timeout_seconds = 30
risk_tier = "low"

[tool.cedar]
resource = "PenTest::ScanTarget"
action = "execute_tool"

[args.target]
position = 1
required = true
type = "scope_target"
description = "Domain name or IP address to query"

[command]
template = "whois {target}"

[output]
format = "text"
envelope = true

[output.schema]
type = "object"

[output.schema.properties.raw_output]
type = "string"
description = "Raw WHOIS registration data"

Step 3: Load and Validate Programmatically

Load a manifest and inspect its contents. ToolClad validates the manifest structure on load.

import { loadManifest } from "toolclad";

const manifest = loadManifest("tools/whois_lookup.clad.toml");

console.log(`Tool: ${manifest.tool.name} v${manifest.tool.version}`);
console.log(`Binary: ${manifest.tool.binary}`);
console.log(`Risk tier: ${manifest.tool.risk_tier}`);
console.log(`Timeout: ${manifest.tool.timeout_seconds}s`);

// Inspect arguments
for (const [name, arg] of Object.entries(manifest.args)) {
    console.log(`  ${name}: type=${arg.type}, required=${arg.required}`);
}

Step 4: Execute a Tool

Execute a tool by passing argument values. ToolClad validates every argument, renders the command template, runs the binary with the configured timeout, and wraps the result in an evidence envelope.

import { loadManifest, execute } from "toolclad";

const manifest = loadManifest("tools/whois_lookup.clad.toml");

const args = { target: "example.com" };
const envelope = execute(manifest, args);

console.log(JSON.stringify(envelope, null, 2));

The executor constructs the command whois example.com from the template, runs it with a 30-second timeout, and returns a structured evidence envelope with status, timing, and output hash.

Step 5: Generate MCP Schema

Generate a Model Context Protocol-compatible JSON schema directly from a manifest. This bridges ToolClad manifests to any MCP-compatible agent runtime.

import { loadManifest, generateMcpSchema } from "toolclad";

const manifest = loadManifest("tools/whois_lookup.clad.toml");
const schema = generateMcpSchema(manifest);

console.log(JSON.stringify(schema, null, 2));

The generated schema includes inputSchema with typed properties and required fields, plus an outputSchema that wraps your declared results in the evidence envelope format when envelope = true.

Step 6: CLI Usage

The toolclad CLI provides four commands for working with manifests:

Validate a manifest

npx toolclad validate whois_lookup.clad.toml

Dry-run with argument validation

npx toolclad test whois_lookup.clad.toml --arg target=example.com

Execute a tool

npx toolclad run whois_lookup.clad.toml --arg target=example.com

Generate MCP schema

npx toolclad schema whois_lookup.clad.toml

Multiple arguments can be passed by repeating the --arg flag: --arg target=10.0.0.1 --arg scan_type=service.