A tool call is a request
An assistant can draft a refund request from a customer message. That does not mean it should be able to issue a refund whenever a page, email, or model response tells it to.
Function calling gives a model a way to ask your application to run a function. Your application receives the call, checks it, executes permitted code, and sends a result back. The model can then answer or request another tool. Your server remains responsible for access and business rules throughout that loop.
Draw the trust boundary first
List the actor, the data each actor may access, and the actions each role may perform. A customer, support operator, and administrator may all use the same interface while having different permissions.
Document text, search results, email bodies, and tool outputs are untrusted input. They can contain instructions aimed at redirecting an agent. Keep those inputs out of privileged developer instructions, and do not let them authorize a tool call or set the acting user’s identity.
- Authenticate the user before the agent runs.
- Resolve account and tenant identifiers on the server.
- Expose only the tools needed for the task.
- Separate read-only lookup from an action that changes data.
Define a narrow tool contract
A tool schema tells the model what arguments to return. OpenAI recommends strict mode for function calls; the documented strict schema requires additionalProperties to be false on objects and every property to be listed as required. A nullable type can represent an optional value.
This example defines a request for a refund review, not an instruction to execute a refund. It shows the tool definition that would be supplied to the Responses API. The specific business workflow and permitted values need to be designed for your application.
const requestRefundReview = {
type: "function",
name: "request_refund_review",
description: "Prepare a refund request for review; does not issue a refund.",
strict: true,
parameters: {
type: "object",
properties: {
order_id: { type: "string", description: "Order to review" },
reason: { type: "string", description: "Customer’s stated reason" }
},
required: ["order_id", "reason"],
additionalProperties: false
}
};
// Supply this definition in the Responses API tools array.
// Your application must handle, validate, and authorize any returned call.Validate and authorize on the server
Strict schema output reduces malformed arguments. It cannot establish that an order exists, belongs to the signed-in user, falls within a policy, or has already been refunded. Check those facts against your own records after receiving the call.
Bind the operation to the authenticated session, not an account ID invented or supplied by the model. Reject unexpected tool names and arguments. Return a clear denial or validation error without leaking records from another tenant.
- Check the order exists and the user may access it.
- Apply the actual refund policy and any spending limits.
- Use an idempotency key or equivalent duplicate protection for actions that may be retried.
- Record the decision and outcome without logging credentials or unnecessary customer data.
Make approval a separate step
For a consequential action, show a human the proposed change, the relevant evidence, and the scope before execution. A review request is not a completed refund. The approval should identify the exact action and should be checked again at execution time if the underlying state or permissions may have changed.
For MCP connections, the platform safety guidance recommends keeping tool approvals enabled. Apply your own organization’s access and approval requirements to every integration, including reads of sensitive information.
Return the tool result to the model
After a permitted tool runs, send its output back through the documented tool-calling flow. The model can use that result to explain what happened or ask for the next step. A refusal, timeout, or validation failure should remain a failure in the user interface; do not convert it into a success message.
Treat the returned content as data as well. If a tool fetches a third-party page, a sentence in that page should not be able to grant access or change your application’s rules.
Test the boundary, not only the happy path
Create tests where the user is allowed to request a review, is denied access to a different account, submits a malformed order ID, repeats an action, or changes the order between review and execution. Add a retrieved document that contains an instruction to reveal information and verify the agent does not follow it.
Record whether the correct policy was applied and whether any unauthorized call reached execution. Review tool-call traces, failure reasons, and approval decisions. A passing schema check alone is not evidence that the workflow is secure.
- Ordinary request: allowed user, valid order, no side effect until review.
- Cross-account request: deny without disclosing order details.
- Repeated call: prevent duplicate execution.
- Stale approval: re-check relevant state before acting.
- Prompt injection: ignore instructions embedded in retrieved data.
Before you enable a write tool
Start read-only, then add a single well-defined action with a named owner, server-side checks, an approval path, and a rollback or recovery procedure. Re-run the tests when a tool, permission rule, model, or prompt changes.
Sources and further reading
Documentation reviewed November 9, 2026. Verify current model support, limits and pricing before implementation.