Complete the key fields in a tools/list tool object and a tools/call request
A tools/list tool carries name, description, and inputSchema; a tools/call request sends name plus arguments and gets back a content array with optional isError.
Think of a restaurant menu. Each dish has a name, a short description so you know what it is, and a list of choices you can customize, like spice level or sides. That menu is what tools/list returns: every tool's name, its description, and its inputSchema describing valid options. When you order, you don't recite the whole menu. You just say the dish name plus your choices, which is exactly what tools/call sends: name and arguments. The kitchen then hands back your plate, the content array, and if something went wrong it tells you, the isError flag. The menu lets you browse; the order form lets you act.
Concept explanation~2 min read
Everything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example. Click to expand.
Concept explanation~2 min read
Everything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example. Click to expand.
The MCP tools primitive is built on a clean separation: first you discover what a server can do, then you invoke it. tools/list is the discovery method. tools/call is the invocation method. Getting the field names right for each is a favorite interview probe because it reveals whether a candidate has actually read the spec or just heard the elevator pitch.
The shapes are deliberately asymmetric. The list response is rich, because the model has to understand a tool well enough to decide whether and how to use it. The call request is minimal, because by then the only open questions are which tool and what arguments.
This deep dive walks through both methods field by field, explains the result shape including the often-missed isError contract, and shows how a host stitches the two together with a model's function-calling format.
The tools/list response, field by field
When a host calls tools/list, the server returns a tools array. Each element is a tool descriptor with three required fields.
nameis a unique string that identifies the tool, likesearch_docsorread_file. It is the dispatch key the host uses later to route atools/call.descriptionis human-readable text. It is the most behavior-critical field, because it is the only signal the model has when deciding whether to pick this tool. A vague description causes the model to skip a useful tool or misuse it.inputSchemais a JSON Schema object describing the accepted arguments: their names, types, which are required, and any constraints.
Newer spec revisions add optional fields like title (a display name) and annotations (hints such as whether the tool is read-only or destructive), but the three above are the load-bearing core.
It is worth dwelling on why all three live in the list response rather than being fetched lazily. The model needs the full picture in one shot. It cannot decide whether a tool is relevant without the description, and it cannot form a syntactically valid call without the schema. So MCP front-loads everything into discovery. There is no separate tools/describe round-trip per tool. The host caches the whole catalog and the model reasons over it inside its context window. The cost is context budget: a server exposing fifty richly-described tools can consume a meaningful slice of the prompt, which is why hosts sometimes filter or paginate the tool set they surface.
{
"name": "search_docs",
"description": "Search the documentation corpus and return matching passages.",
"inputSchema": {
"type": "object",
"properties": {
"query": { "type": "string" }
},
"required": ["query"]
}
}Situations where this technique stops working.
2–4 min · Everything important, quickly.
| Aspect | tools/list | tools/call |
|---|---|---|
| Direction | Host asks, server answers | Host invokes, server runs |
| Key fields | name, description, inputSchema | name, arguments |
| Returns | Array of tool descriptors | content array (+ optional isError) |
| When called | Once at discovery time | Every time the model picks a tool |
| Failure signal | JSON-RPC error if not supported | isError true inside the result |
Real products, models, and research that use this idea.
- Claude Code calls `tools/list` on every configured MCP server at session start, then maps each descriptor into an Anthropic tool definition.
- The official filesystem MCP server publishes tools like `read_file` with an `inputSchema` requiring a `path` string argument.
What an interviewer would ask next. Try answering before peeking at the approach.
QWhy does MCP put tool execution failures in the result via isError instead of the JSON-RPC error channel?
The model needs to read and reason over the failure text to retry; transport errors are for the host, not the model. Separating the two keeps the recovery loop inside the model turn.
Red flags & common mistakes
The phrases that signal junior thinking. Click to expand.
Red flags & common mistakes
The phrases that signal junior thinking. Click to expand.
Confusing the list shape with the call shape. tools/list returns descriptors; tools/call sends only name plus arguments, then receives a content array.
60 second bullets to scan on the way to the call.
The three required fields on a tools/list descriptor
Why description is load-bearing for tool selection
Primary sources. Browse if you want the original framing.
Same topic, related formats. Practice these next.