Traverse vs AI Function Calling: Contracts vs Definitions

Function calling gives AI agents a list of functions to invoke. Traverse gives agents contracts with preconditions, postconditions, enforcement, and trace artifacts. A meaningful difference when the function matters.

What function calling solves

Function calling lets LLMs invoke external tools. The model sees a list of function definitions, picks the right one, produces the arguments, and the calling code runs the function and returns the result.

This works well for simple integrations: look up a user record, send a notification, query a search index. The model handles intent and argument construction. Your code handles execution.

It is the foundation of most AI agent tooling today. It is well supported across OpenAI, Anthropic, Google, and the MCP ecosystem.

Problems with function calling alone

Function calling works. But when the function being called is a business capability with rules, preconditions, and compliance requirements, the bare function definition model has gaps.

  • 01
    No preconditions A function signature says what parameters to pass. It does not say what must be true before calling. The agent learns about failures by calling the function and getting an error back — often after side effects have already started.
  • 02
    No enforcement If the agent passes invalid inputs, the function decides what to do. Maybe it throws. Maybe it silently accepts them. Behavior is up to the implementation. The agent cannot verify correctness before calling.
  • 03
    No audit trail You know a function was called. You may have a log entry. But you do not have a structured, queryable record of the inputs, outputs, which version ran, and whether all conditions were met. Compliance teams ask for exactly this.
  • 04
    Definitions go stale Function definitions in a system prompt or tool list are text. When the underlying function changes, the definition may not be updated. Agents trained or prompted on stale definitions call capabilities that have changed or no longer exist.

What Traverse adds on top

Traverse does not replace function calling. It governs the capabilities that function calling invokes. The agent still calls a function. That function is now backed by a contract and a runtime that enforces it.

  • pre
    Preconditions The contract declares what must be true before the capability can run. The runtime checks this before execution. The agent can read the contract and know what is required before calling.
  • post
    Postconditions The contract declares what the output will look like and what must be true after execution. The runtime validates the output before returning it. The agent can trust the output shape.
  • run
    Runtime enforcement Validation happens at the runtime level, not inside the function. This is not a convention or a doc string. The capability cannot run if preconditions are unmet. Full stop.
  • log
    Trace artifacts Every execution produces a structured trace: inputs, outputs, contract version, timestamp, and result. Queryable. Replayable. Ready for compliance review without extra instrumentation.
  • ver
    Versioned contracts The capability registry always reflects what actually runs. Agents resolve capabilities by name and version. A stale definition is a contract mismatch the registry catches at load time, not at runtime surprise.

Side-by-side: raw function definition vs Traverse contract

The same capability — checking promotion eligibility — defined two ways.

Raw function definition (OpenAI tool format)
// What the agent sees { "name": "check_promo_eligibility", "description": "Check if a promo code is valid for a customer", "parameters": { "type": "object", "properties": { "customer_id": { "type": "string" }, "promo_code": { "type": "string" }, "cart_total": { "type": "number" } }, "required": ["customer_id", "promo_code"] } } // What happens if cart_total is missing? // What must be true about customer_id? // What does the response look like? // Which version of this logic ran? // Was it audited? // Nobody knows.
Traverse contract
[capability] name = "promotions.check-eligibility" version = "2.1.0" placement = ["browser", "edge", "cloud", "ai-pipeline"] [preconditions] # Enforced before execution. Cannot be bypassed. customer_id = "non-empty string, max 64 chars" promo_code = "non-empty string, alphanumeric" cart_total = "float, >= 0.0" region = "ISO 3166-1 alpha-2" [postconditions] # Enforced after execution. Output shape guaranteed. eligible = "boolean" discount_pct = "float, 0.0..100.0 when eligible" reason = "string when !eligible" expires_at = "RFC3339 timestamp" [trace] emit = true # Trace includes: inputs, outputs, version, timestamp, # precondition results, postcondition results.

The Traverse contract is not documentation. The runtime reads it and refuses to execute if any condition is unmet. The agent can load the contract and know exactly what is required before calling.

Using them together via MCP

Traverse and function calling are not mutually exclusive. You can expose Traverse capabilities as MCP tools. The agent calls them through standard function calling. The capabilities just come with contracts and traces attached.

mcp-server/tools.ts
import { TraverseRuntime } from '@traverse-framework/runtime'; import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; const runtime = await TraverseRuntime.init({ registry: process.env.REGISTRY_URL }); const server = new McpServer({ name: 'traverse-capabilities', version: '1.0.0' }); // Expose Traverse capability as an MCP tool. // The agent calls it like any function. The runtime enforces the contract. server.tool( 'check-promo-eligibility', 'Check promotion eligibility. Contract-enforced. Produces a trace.', { customer_id: z.string(), promo_code: z.string(), cart_total: z.number(), region: z.string(), }, async ({ customer_id, promo_code, cart_total, region }) => { const result = await runtime.execute( 'promotions.check-eligibility@2.1.0', { customer_id, promo_code, cart_total, region } ); // result.trace_id links this AI call to every other system // that ran this capability for the same transaction return { content: [{ type: 'text', text: JSON.stringify({ ...result.output, trace_id: result.trace_id, })}], }; } );
What the agent gets: the same function-calling interface it already knows. What your system gets: contract enforcement, versioned execution, and a trace that links every AI call to the same capability your browser and backend use.

The verdict

Use function calling to let AI agents invoke tools. Use Traverse to ensure the tools worth invoking have enforced contracts and produce auditable traces.

Not every function needs a Traverse contract. A search tool, a calculator, a timezone lookup — raw function calling is fine. But pricing logic, eligibility checks, compliance validations? Those are capabilities worth governing. Traverse is built for exactly that.

The two compose cleanly. Expose Traverse capabilities as MCP tools. Your agent gets function calling that happens to come with enforcement and traceability baked in.

Give your AI agents governed capabilities.
Contract-enforced. Traceable. Versioned.
Quickstart GitHub →