Start learning free

LESSON 56 OF 129 · AI ENGINEERING: MCP

Ask Before a Tool Changes Something

Practice

Your assistant runs every tool the model asks for, at once. That is fine for a tool that only reads, like lookup_order. But start_return changes an order, and a model can ask for a change the customer never wanted.

Annotations: an MCP server can say what kind each tool is. read_only_hint=True marks a tool that only reads, and destructive_hint=True marks one whose change is not easy to take back. On a notes server it looks like this:

@mcp.tool(annotations=ToolAnnotations(destructive_hint=True))
def delete_note(note_id: int) -> dict:
    "Delete one note by its id."
    notes.pop(note_id)
    return {"deleted": note_id}

An annotation is only a hint: it stops nothing by itself. The client reads it from tool.annotations (which is None when the server gave none) and decides what to do. A careful assistant asks the customer before a destructive call. On a no, it skips the call and sends the model a tool result that says so, marked as an error, so the model doesn't claim the change was made.

The customer writes: "I want to return order 4. And where is my order 7?" The model asks for a return of both orders, and the customer says no to the second one. Your program and the check must print:

Tool: lookup_order {'order_id': 4}
Tool: lookup_order {'order_id': 7}
Ask the customer: run start_return with {'order_id': 4}? Customer: yes
Tool: start_return {'order_id': 4}
Ask the customer: run start_return with {'order_id': 7}? Customer: no
Answer: I started the return for order 4. Order 7 is paid and not shipped yet; I left it as it is.
Tools on the server: 2
- lookup_order: read-only
- start_return: destructive
What the model was told about its tool calls:
- lookup_order {"order_id": 4}: ok
- lookup_order {"order_id": 7}: ok
- start_return {"order_id": 4}: ok
- start_return {"order_id": 7}: error
Order 4 in the database: return started
Order 7 in the database: paid

Your task: on the server, mark lookup_order as read-only and start_return as destructive. In the assistant, collect the names of the destructive tools, call the ready-made customer_confirms before running one, and on a no append an error tool result and continue, so the server is never called.


Assignment
Follow the Coding Tutorial to mark the shop's tools and make the assistant ask before a destructive call.


Hint
Asking is not enough: an if not allowed: must act on the answer. Every tool request needs a tool result, also the ones you skip.


STEP 1 OF 9
    Ctrl + Enter to check