Deterministic static auditDraft revision · 26 Aug 2026

Tool Contract Workbench

Find weak contracts before an agent does.

Paste imperative WebMCP code or declarative markup. The audit checks current draft syntax, Chrome guidance, privacy risks, runtime validation seams, and lifecycle cleanup—without sending code to a model.

Input

Paste HTML or JavaScript

Local analysis

Remove secrets and customer data. Tool contracts should never contain credentials.

Draft conformance

Current global, names, schema closure, and runtime validation seams.

Security signals

Annotations, metadata budgets, data minimization, and verifiability.

Lifecycle hygiene

AbortSignal-based cleanup for route and component ownership.

Audit ledger

1 tool contract detected

search_catalog

Current feature detection

Uses the current document.modelContext surface.

draft

No obsolete navigator global

No navigator.modelContext reference was found.

draft

Imperative registration

An imperative tool registration is source-visible.

draft

Tool names are valid and compact

1 tool name detected. The draft permits 1–128 ASCII letters, numbers, underscore, hyphen, and period; Chrome recommends about 30 characters.

draft

Closed input schemas

At least one schema rejects undeclared properties.

project rule

Runtime input validation

A runtime validation seam is source-visible.

draft

Registration lifecycle cleanup

Registration uses an AbortSignal so route or component teardown can unregister the tool.

draft

Behavior annotations are explicit

A read-only behavior hint is source-visible. Confirm it matches the actual effect.

draft

Untrusted output is labeled

Tool output is marked as untrusted.

chrome guidance

Metadata stays within current guidance

Detected descriptions fit the current non-normative Chrome character budgets.

chrome guidance

Parameter minimization

No common demographic or profiling fields were detected by this static check.

draft

Results support state verification

A structured result or verification field is source-visible.

project rule

Quick fix

Reference implementation

const registration = new AbortController();

if (typeof document.modelContext?.registerTool === "function") {
  await document.modelContext.registerTool({
    name: "search_catalog",
    title: "Search catalog",
    description: "Find public catalog items that match explicit filters.",
    inputSchema: {
      type: "object",
      properties: {
        query: {
          type: "string",
          maxLength: 120,
          description: "Product words to search for."
        },
        max_price: {
          type: "number",
          minimum: 0,
          description: "Maximum price in USD."
        }
      },
      additionalProperties: false
    },
    annotations: {
      readOnlyHint: true,
      untrustedContentHint: true
    },
    async execute(input, { signal }) {
      const filters = validateSearchInput(input);
      const items = await catalog.search(filters, { signal });
      return { items, count: items.length };
    }
  }, { signal: registration.signal });
}

// Keep this callback and invoke it only on route change or component unmount.
const unregisterPageTools = () => registration.abort();