MCP as the tool boundary
A tool is a named schema plus a call, and the protocol standardising that boundary also writes down where human approval belongs — which is a UI requirement stated in a spec, not a nice-to-have.
Everything so far has been a framework’s opinion. Nodes, edges, checkpointers and interrupts are LangGraph’s vocabulary, and a portfolio company that picked something else gets a different set of nouns for the same jobs. This lesson is the exception. The boundary where an agent reaches out and touches the world has a written specification, and that specification contains requirements addressed to the thing you build.
That is unusual enough to be worth using. In most design arguments you are asserting that a confirmation step is a good idea. Here you can point at a normative document and say the specification says applications should provide one.
A tool is a name and a schema
The Tools section of the specification defines the data type a server publishes. The fields, with the ones your UI actually renders marked:
| Field | Required | What it is for |
|---|---|---|
name | Yes | The identifier a call is made against. |
title | Optional | A human-facing label. This is the one your UI should show. |
description | Yes | Prose written by the server author, primarily for the model. |
icons | Optional | Server-supplied iconography. |
inputSchema | Yes | Valid JSON Schema, non-null. This is the shape of the arguments, and therefore the shape of anything you render for review. |
outputSchema | Optional | The declared shape of the result, where a server states one. |
annotations | Optional | Optional properties describing tool behaviour. See the warning below before you trust one. |
{
"name": "send_email",
"title": "Send Email",
"description": "Sends an email on the user's behalf",
"inputSchema": {
"type": "object",
"properties": { "to": { "type": "string" } },
"required": ["to"]
},
"annotations": { "destructiveHint": true }
}Fields are the specification’s; the annotation value in that example is illustrative rather than quoted. Note what the shape gives you for free: inputSchema is required and must be valid JSON Schema, so a review surface for “here is what the agent is about to do” can be generated from the tool definition rather than hand-built per tool. That is the practical reason a standardised boundary matters to a UI architect. One renderer, every tool.
The paragraph to quote in a design review
Under user interaction, the specification states:
“For trust & safety and security, there SHOULD always be a human in the loop with the ability to deny tool invocations.” (MCP, Tools)
And three requirements addressed to applications, verbatim:
- “Provide UI that makes clear which tools are being exposed to the AI model”
- “Insert clear visual indicators when tools are invoked”
- “Present confirmation prompts to the user for operations, to ensure a human is in the loop”
Read those as a specification of three distinct surfaces, because they are: a capability disclosure that exists before anything runs, an activity indicator during the run, and a confirmation at the moment of the call. Teams routinely build the third and skip the first, which is how a user ends up approving a call to a tool they did not know the agent had.
One thing the specification carefully does not say: that MCP performs any of this. It standardises where the responsibility lands, on the application, which is the client, which is you. There is no protocol message that pauses a call while a human thinks. The mechanism is yours to build.
Annotations are hostile input
The specification is unambiguous: clients MUST consider tool annotations to be untrusted unless they come from trusted servers. So readOnlyHint is a claim, not a fact, and a UI that dims the confirm dialog because a tool called itself harmless has taken a server’s word for the one thing the confirmation existed to check. The same applies to description and title: they are text an untrusted party wrote, rendered into your interface, next to a button that does something real.
A second kind of pause, from a different layer
The interrupt module taught one way an agent stops for a human: the graph throws, the runtime checkpoints, and a later invocation resumes it with a Command. The tools specification documents a different one, at the protocol layer, and the two are easy to conflate.
A tool result carries a resultType. It is either "complete" or "input_required". In the second case, the server has not finished: it responds mid-call with an elicitation/create request embedded in inputRequests, and the client answers by retrying the same call with inputResponses and an opaque requestState token that the server issued.
| Question | Graph interrupt | MCP input-required |
|---|---|---|
| Who paused | The node, by throwing | The server, inside a tool call |
| What holds the pause | A checkpoint, on a thread | An opaque requestState token |
| How it continues | A second invocation carrying { resume } | A retry of the call carrying inputResponses |
| Survives the user closing the tab | Yes, that is what the checkpointer is for | Only as far as the token remains valid, which the specification does not put a number on |
The comparison in that table is this course’s, not a claim made by either document; each side of it comes from its own specification. The design point it produces is worth the table though. Both mechanisms can put the same modal on the same screen, and only one of them gives you a durable state to come back to. If you are designing a “we saved your place” experience, you need to know which layer the pause came from before you promise it.
Two pieces of context from the specification revision, both fetched for this course on 2026-09-02. Elicitation carries more weight now than it did in 2025-era material: sampling and roots are deprecated as of this revision, leaving elicitation as the client primitive. And the protocol is stateless — there is no initialize handshake, and capabilities travel as per-request metadata. Material written against the older revision is describing a different protocol, which is the same trap the stale reference site sets in the LangGraph docs.
One more thing to know exists rather than to learn now: an x-mcp-header extension lets specific tool-call parameters be mirrored into HTTP headers on Streamable HTTP transport. Relevant if you are debugging a call and wondering why an argument is showing up twice.
Check your recall
Answer from memory — no scrolling back.
Retrieval check
You are asked to justify a confirmation step that the team considers friction. You have thirty seconds. What do you say, and what do you not overclaim?
Check your answer
Say: the Model Context Protocol’s tools specification states there should always be a human in the loop with the ability to deny tool invocations, and lists presenting confirmation prompts as something applications should do. It is a normative document, not a blog post, and originated at Anthropic rather than with a vendor selling a review product.
Do not overclaim two things. It is a SHOULD, not a MUST, so a team can meet the specification and still argue about scope. And MCP does not implement any of it — it says where the responsibility sits, which is with the application. The work is still yours, the specification just settles whose work it is.
The strongest version of the argument is not the quote. It is pointing out that the confirmation is the only place a person can catch a tool description written by a server nobody on the team reviewed.
Hands on
Spec one tool-approval surface against a written standard
Done when: ARTIFACT.md’s module 4 section contains a one-page approval spec for the single side-effecting step in your parser graph, with each of the specification’s three application requirements met by a named surface, and an explicit line saying which pause mechanism backs it.
- Name the one step in your graph that touches the world: writes a record, sends something, charges something. If your teaching rebuild has none, invent the most plausible one rather than skipping this.
- Write its tool definition as an MCP
Tool:name,title,description, and a realinputSchema. Then sketch the review surface generated from that schema rather than hand-drawn, and note what the schema alone does not tell you. - Cover the three application requirements with three named surfaces: where the user learns which tools exist, what changes on screen when one fires, and what the confirmation looks like. Any requirement you cannot name a surface for is a gap, and writing “gap” is a valid answer.
- Write the sentence that appears in your confirmation when the tool description came from a server your team does not control. It has to be honest without being useless.
- State which mechanism backs the pause: a graph interrupt with a checkpoint behind it, or a protocol-level input-required round trip. Then say, in one line, what happens if the user closes the tab. If the two answers differ, your UI copy has to differ too.
What this does not cover
This lesson treated the pause as a UI event. What makes a pause durable — the checkpoint, the thread, the state you read back afterwards — is the checkpointers-and-threads lesson, and the payload design for the answer a human gives is the decision-surface lesson. Neither is replaced by anything here.
Nothing here tells you how to find the tool boundary in a codebase you have never opened, which is a different skill from knowing what the boundary owes a user. That, plus the state schema, the routing and the stream, is the repeatable pass in the reading-an-unfamiliar-stack lesson, which closes the course.
Read this next — primary source
Model Context Protocol — Tools (revision 2026-07-28)Model Context Protocol, originated by Anthropic — modelcontextprotocol.io, fetched 2026-09-05. Normative specification, not vendor documentation
This lesson takes the tool data type, the user-interaction requirements, and the input-required result flow. Read the page in full because it is short, normative, and one of the few documents in this field that tells you what your interface owes a user rather than what a framework can do. What it will not give you is any of the design: it says a confirmation belongs there, not what it should say or how a person should be able to decline.
Stuck, curious, or think this lesson is wrong? Ask your teaching agent. The lessons are the scaffold; the conversation is where the learning gets unstuck.