The two methods the whole agent economy runs on — tools/list and tools/call — decoded from real traffic.
In Lesson 1 you opened a session. Everything below
reuses that same open session: the Mcp-Session-Id and
MCP-Protocol-Version headers ride along on every request, but we'll stop drawing
them so you can focus on the payloads. Two methods do all the work.
A tool call is a two-step conversation. tools/list asks
"what can you do, and what shape are the arguments?" — the server answers with machine-readable
schemas. tools/call then says "do this one with
these arguments." The schema from step one is what lets a model fill in step two
correctly.spec
tools/list — discoveryThe request is almost nothing — just the method:
The reply is a result with a tools array. Here is one real entry
in full — the echo tool — because this object is the entire contract a
model needs to call it:
It's a JSON Schema object describing the arguments: their types, which are
required, and (here) additionalProperties: false meaning "no extra
keys allowed." This is how an LLM knows to send {"message": "..."} and not guess.
If no $schema is given, MCP assumes JSON Schema draft 2020-12; this server pins
draft-07 explicitly.spec
Pagination: tools/list may return a
nextCursor string. If present, send it back as params.cursor to fetch
the next page. Our server's list is short, so no cursor appears — but real servers with hundreds
of tools page this way.
Our server returned 13 tools. Their names alone:
tools/call — invocationTo run one, name it and pass arguments that satisfy its inputSchema:
The result is a content array. It's an array because one call can return
several blocks of mixed media — each block has a type: text,
image, audio, resource_link, or an embedded
resource.spec
This is the "unstructured" channel — text and media meant for a human or the model to read.
structuredContent + outputSchemaText is fine for a model to read, but a program wants typed data. A tool can declare an
outputSchema and return a parallel structuredContent object. Watch
get-structured-content return both — the same data twice:
The structuredContent object is the typed answer; the content text
block is the same JSON serialized as a string. The spec says a tool returning structured
content SHOULD also mirror it as text, so older clients that only read
content still work. If the tool declared an outputSchema, the server
MUST make structuredContent conform to it, and clients SHOULD validate it.spec
This is the subtlest, most useful part of the whole tools model. MCP has two separate error channels, and which one fires changes what an agent should do.spec
isError: trueThe call reached the tool, but the tool failed. It comes back as a successful
JSON-RPC result — just with isError: true and an explanatory text block
the model can read and retry against. On this server, even an unknown tool name and a
type mismatch arrive this way:
errorThe request itself was structurally wrong — here, an unknown method (not an unknown
tool). There is no result at all; instead a JSON-RPC error object with a
numeric code. A model usually can't "retry" its way out of this — it's a wiring bug:
The spec lets a server report an unknown tool as a protocol error. But
this server (like most SDKs) deliberately funnels unknown-tool and bad-argument failures into the
isError: true result channel — so the model gets a readable message and can
self-correct, rather than a dead-end error. The reliable rule when reading traffic: a
top-level error key = protocol failure; a result with
isError = the tool ran and failed. Don't judge by the -32602
number — judge by which key it's under.
Session still open from Lesson 1 (re-run bash assets/mcp-curl.sh init if needed).
Use the helper's call verb — call NAME '<args-json>':
Predict before you run each one: will the failure come back under
result.isError or under a top-level error? Then try
call get-env '{}' and read what a server can expose — a nice preview of why the auth
lessons matter.
inputSchema on a listed tool actually for?result object containing isError: true. What happened?get-structured-content return the same data in two places?MCP Specification 2025-11-25 — Server / Tools.
Read the "Tool Result" and "Error Handling" sections: you've now seen content,
structuredContent, outputSchema, and both error channels on the wire —
the page formalises exactly what you observed.