Back to all posts

Developer & technical insights October 10, 2026 5 min read

What Are Tool Contracts in AI Agents?

Teal header titled What Are Tool Contracts in AI Agents?

TL;DR: A tool contract is the agreement between an agent and the software it can operate. It defines inputs, outputs, preconditions, side effects, and failure. The model can propose an action. The harness decides whether that action is valid, and whether it actually happened.

What Are Tool Contracts in AI Agents?

Giving an AI agent access to tools is easy.

Giving it access to tools reliably is much harder.

A tool might let an agent look up an order, update a CRM record, create a support ticket, search company knowledge, book an appointment, send a message, or trigger an external API.

The model needs to know that the tool exists and when to use it.

But that’s only part of the problem.

Your application also needs to know exactly what the tool accepts, what it returns, when it is allowed to run, and what should happen when something goes wrong.

That definition is the tool contract. It sits inside the agent harness, which is the system around the model, not the model itself.

A Tool Is Not Just a Function

Imagine giving an agent this function:

Pythondef schedule_appointment(contact_id, start_time):
    ...

Technically, the agent has a scheduling tool.

But there are still a lot of unanswered questions.

Can start_time be any string?

Which timezone does it use?

Can the customer book an unavailable slot?

Can the function be called twice?

What happens if Google Calendar times out?

How does the agent know whether the appointment was actually created?

Can the agent tell the customer they’re booked before the function succeeds?

Those questions are part of the contract.

For production agents, the function itself is often the easy part. The small Python harness starts to show this the moment a tool can change something.

What Should a Tool Contract Define?

At minimum, I would define five things.

1. Inputs

The model should not invent arbitrary arguments.

A tool should define exactly what it accepts.

Pythonfrom pydantic import BaseModel

class ScheduleAppointmentInput(BaseModel):
    contact_id: str
    appointment_type_id: str
    start_time: str
    timezone: str

Now your runtime can validate the request before anything happens.

If the model omits appointment_type_id, the tool doesn’t run.

If it sends malformed data, the tool doesn’t run.

The model can propose an action.

Software decides whether that action is valid.

2. Outputs

Outputs should be structured too.

Instead of returning “looks like it worked,” return something explicit:

Python{
    "ok": True,
    "appointment_id": "apt_91821",
    "start_time": "2026-10-12T14:00:00",
    "timezone": "America/Toronto",
}

And on failure:

Python{
    "ok": False,
    "error_code": "SLOT_UNAVAILABLE",
    "message": "The requested time is no longer available.",
}

Structured outputs give the agent evidence it can reason from.

They also make verification much easier.

3. Preconditions

Some tools should only be callable after certain conditions have been satisfied.

Suppose an agent can cancel an order.

You might require that the customer has been identified, the order belongs to that customer, the order has not shipped, and cancellation is allowed under company policy.

You can tell the model all of this in a prompt.

You should probably enforce it in code too.

Pythonif not customer_verified:
    return {
        "ok": False,
        "error_code": "CUSTOMER_NOT_VERIFIED",
    }

This is one of the biggest differences between a demo agent and a production one.

Important rules should not depend entirely on the model remembering them.

4. Side effects

Reading information and changing information are not the same thing.

get_order_status is relatively safe.

refund_order can move money.

Your harness should know the difference.

A useful tool contract can include metadata such as:

Python{
    "name": "refund_order",
    "side_effect": True,
    "critical": True,
    "requires_verification": True,
}

That lets your runtime treat consequential actions differently from simple lookups.

You may require additional validation, approval, logging, or policy checks.

5. Failure behavior

Tools fail.

APIs time out.

Calendar providers return errors.

CRMs reject requests.

Network calls die halfway through.

A production agent needs to understand the difference between the action succeeding, the action failing, the outcome being unknown, the action being safe to retry, and the action that must not be retried.

That last one matters more than people realize.

Imagine a payment tool times out after the payment was actually processed.

Automatically retrying could charge the customer twice.

This is why concepts like idempotency belong in the tool contract too.

The Agent Should Never Confuse Intent With Success

This is one of the most important rules we enforce in Myna.

Suppose the agent decides it should book Tuesday at 2 PM.

That’s intent.

It calls the scheduling tool.

The tool fails.

The agent cannot then say the customer is booked for Tuesday at 2 PM.

Nothing was booked.

It sounds obvious, but language models are very good at continuing the conversation as though their intended action happened.

A strong harness uses the tool result as evidence.

No successful tool result means no success claim. The runtime reference is that rule written as one turn: approved tool calls, confirmed state, then a reply.

Tool Contracts Reduce Prompt Engineering

Without proper contracts, developers often compensate by adding more instructions.

The system prompt gradually becomes a list of warnings: never call this tool before X, always check Y, do not call it twice, if it returns Z do not say the action succeeded, make sure field A is present, never use value B.

Some of those instructions are still useful.

But many of them belong in software.

If appointment_type_id is required, make it a required schema field.

If refunds above $500 require approval, enforce that outside the model.

If the same request cannot execute twice, add idempotency.

Don’t make the LLM your only enforcement mechanism. The loop chooses the action. The harness executes it.

Good Tool Names Matter Too

Tool design also affects how well the agent reasons.

Compare do_customer_action with create_support_ticket, update_contact_email, lookup_order_status, and schedule_appointment.

Specific tools are usually easier for the model to choose correctly.

Descriptions matter too.

A tool definition should explain when to use it, not just what API endpoint it calls.

“Calls the appointments endpoint” is a weak description.

“Creates a new appointment after the customer has agreed to a specific available time” tells the model the business meaning.

Myna tools are contracts for that reason. The protocol carries the action. The contract says what the action means.

Don’t Give Every Agent Every Tool

Another common mistake is creating one giant tool registry and exposing everything to every agent.

A customer-support agent probably shouldn’t automatically receive delete customer, unrestricted refunds, billing-plan changes, an export of all contacts, or the ability to send an arbitrary campaign.

Tool availability itself is a permission boundary.

At Myna, tools can be scoped according to what the agent actually needs to accomplish.

Fewer relevant tools also make selection easier for the model.

Tool Contracts Make Agents Easier to Debug

When an agent makes a mistake, structured contracts make it much easier to determine what happened.

You can inspect which tool was selected, which arguments were supplied, whether validation passed, which policy checks ran, what the external service returned, whether the operation succeeded, and what evidence the agent saw afterward.

Without that structure, debugging often becomes “the AI did something weird.”

That’s not useful.

An Example Tool Contract

A simplified contract might look like this:

Python{
    "name": "schedule_appointment",
    "description": (
        "Book an appointment after the customer agrees "
        "to a specific available time."
    ),
    "input_schema": {
        "contact_id": "string",
        "appointment_type_id": "string",
        "start_time": "datetime",
        "timezone": "string",
    },
    "output_schema": {
        "ok": "boolean",
        "appointment_id": "string | null",
        "error_code": "string | null",
    },
    "side_effect": True,
    "requires": [
        "customer_identified",
        "time_confirmed",
    ],
    "idempotent": True,
}

Your implementation will probably look different.

The important part is the mindset.

The tool is not merely an API the model can call.

It is a controlled capability with a defined contract.

Why Tool Contracts Matter More as Agents Become More Autonomous

The more an agent can do, the more important this becomes.

A knowledge chatbot that chooses the wrong search query may produce a bad answer.

An agent with access to business systems can create a bad outcome.

It can book the wrong appointment, modify the wrong contact, create duplicate tickets, send something it shouldn’t, trigger a workflow twice, or claim something happened when it didn’t.

Better models help.

But better reasoning does not eliminate the need for reliable execution.

That is what the harness is for.

How We Think About Tools in Myna

Myna treats tools as capabilities with contracts rather than loose functions attached to a chatbot.

The model can decide that an action is appropriate.

The harness still controls inputs, execution, policies, critical conditions, side effects, results, and verification.

That allows the conversational part of the agent to remain flexible without making business operations equally flexible.

And that’s the balance production agents need.

The conversation can be probabilistic.

Your database doesn’t have to be.

The Short Answer

A tool contract defines the agreement between an AI agent and the software it is allowed to operate.

It specifies what the tool does, when it should be used, what inputs it accepts, what output it returns, what conditions must be satisfied, what side effects it creates, and how failures are represented.

If you’re building an AI agent with real-world tools, this shouldn’t be an afterthought.

Tool calling makes an AI agent capable.

Tool contracts make that capability reliable.


Read the runtime reference →


Related:

Frequently asked questions

What is a tool contract in an AI agent?

A tool contract is the agreement between the model and your software. It defines what the tool does, when it should be used, which inputs it accepts, what it returns, which conditions must already be true, what side effects it creates, and how failure is reported.

Why isn't a Python function enough?

A function can book an appointment. It does not, by itself, say which timezone applies, whether an unavailable slot can be booked, what happens if the calendar times out, or whether the agent may tell the customer they are booked before the call succeeds. Those rules belong in the contract.

Should tool rules live in the system prompt?

Some instructions still belong in the prompt, especially when the tool should be used. Required fields, approval limits, and rules against running the same charge twice should be enforced in software. The model can propose an action. The runtime decides whether it is valid.

What is the difference between intent and success?

Intent is the model deciding it should book Tuesday at 2 PM. Success is a tool result that says the appointment was created. If the tool fails, the agent should not tell the customer they are booked.

Sign up free