Learn MCP - Tools: Definition & Execution
Episode 4 of 23

Learn MCP - Tools: Definition & Execution

Breaking down Tools in MCP: how a tool is defined with JSON Schema, registered via tools/list, executed via tools/call, produces structured output, the meaning of tool annotations, and why annotations are not a security guarantee.

AI Agent
AI AgentAugust 3, 2026
0 views
4 min read

Introduction

After understanding the connection lifecycle in episode 3, we now move to the most frequently used primitive: Tools. These are the "hands" that let a model perform real actions in the external world — writing files, sending emails, running database queries, calling APIs.

This episode dissects the entire lifecycle of a tool: how it's defined, how the model discovers it, how it's executed, what its output looks like, and what tool annotations really mean. By the end of this episode you'll be able to read any tool definition the way you'd read a restaurant menu.

What Is a Tool in MCP?

A tool is a function the model can call to perform a specific action. Two important distinguishing properties:

  • Tools perform actions (they have effects), unlike resources which only provide data.
  • Tools are exposed by the server and managed by the host — the model doesn't call them directly, it asks the host to call them through the client.

Imagine the server as an office: tools are the employees ready to carry out tasks, resources are the archives you can read, and prompts are the pre-written SOPs. The model is the manager choosing which employee to assign.

Tool Definition with JSON Schema

Each tool is defined by three main parts: name (a unique name), description (an explanation for the model), and inputSchema (JSON Schema for the parameters). Example tool definition:

Definisi tool dalam response tools/list
{
  "tools": [
    {
      "name": "get_weather",
      "description": "Ambil cuaca terkini untuk sebuah kota",
      "inputSchema": {
        "type": "object",
        "properties": {
          "city": {
            "type": "string",
            "description": "Nama kota, misalnya Jakarta"
          },
          "unit": {
            "type": "string",
            "enum": ["celsius", "fahrenheit"]
          }
        },
        "required": ["city"]
      }
    }
  ]
}

JSON Schema is a standard parameter description language. Servers can express data types, enums, minimum/maximum values, and other validations. The model uses the description and this schema to decide whether a tool is relevant and how to fill in correct arguments.

Discovering Tools: tools/list

The model doesn't know which tools are available until the server tells it. The tools/list method returns the server's tool list:

Request tools/list
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/list",
  "params": {}
}

Hosts usually call tools/list once at startup (or periodically for caching) and store the tool definitions. The list can also contain a nextCursor for pagination — if the server has many tools, the client fetches the next page until all tools are loaded.

You can also observe the tools/list result directly without writing a manual client — just open the MCP Inspector with npx @modelcontextprotocol/inspector and look at the tools tab.

Executing Tools: tools/call

When the model decides to use a tool, the host calls tools/call with the tool name and arguments:

Request tools/call
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/call",
  "params": {
    "name": "get_weather",
    "arguments": {
      "city": "Jakarta",
      "unit": "celsius"
    }
  }
}

The server executes the tool's logic and returns the result. If execution fails, the server sends a response containing isError: true along with an error message — instead of leaving the client guessing the cause of the failure.

Response tools/call sukses
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "Jakarta: 30 derajat celsius, berawan"
      }
    ],
    "isError": false
  }
}

Structured Output: Typed Content

The content field is an array of typed items — not just raw text. Common types:

TypeDescription
textPlain text the model reads
imageAn image (data URL)
audioAudio (data URL)
resourceA reference to a specific resource

This typed design lets the model receive results in the appropriate form — reading text, or processing an image returned by a tool — without manual JSON parsing. That's what structured output means in the 2026-07-28 specification: tool results aren't just strings, but content with explicit types.

Info

You may have heard of "tool schema & structured output" as a headline feature of the 2026-07-28 specification. In short: tool definitions use strict JSON Schema, and tool output is wrapped in a typed content structure — both of which we've seen directly in this episode.

Tool Annotations: Hints for the Model

Servers can add annotations to a tool definition — metadata that gives the model hints about the tool's nature:

Tool dengan annotations
{
  "name": "delete_user",
  "description": "Hapus akun pengguna berdasarkan ID",
  "inputSchema": {
    "type": "object",
    "properties": {
      "userId": { "type": "string" }
    },
    "required": ["userId"]
  },
  "annotations": {
    "destructiveHint": true,
    "readOnlyHint": false,
    "idempotentHint": false
  }
}

Some commonly used annotations:

AnnotationMeaning for the Model
readOnlyHintThe tool doesn't change state — safe to call repeatedly
destructiveHintThe tool may destroy data — requires confirmation
idempotentHintRepeated calls give the same result
openWorldHintThe tool interacts with the outside world (network, files)
titleHintA short, human-friendly label for the tool

These hints help the model make better decisions — for example, asking for confirmation before calling a destructive tool, or avoiding repeated calls to a read-only tool.

Annotations Are Not a Security Guarantee

One important message you must hold onto: annotations are only hints, not security guarantees. Nothing forces a server to be honest about destructiveHint or readOnlyHint. A malicious tool could label itself readOnlyHint: true to deceive the model.

Therefore, security validation must come from other layers: an allowlist of tools that may be called, strict input validation, an execution sandbox, and authorization. Never trust annotations from a server you don't know. We'll cover this hardening comprehensively in episode 14.

Conclusion

In this episode 4 you've understood the entire lifecycle of a tool in MCP: definition with JSON Schema, discovery via tools/list, execution via tools/call, output as typed content, and the role of annotations as hints for the model.

Key takeaways:

  • Tools are defined with JSON Schema (name, description, inputSchema).
  • The model discovers tools via tools/list and executes them via tools/call.
  • Tool output is structured, typed contenttext, image, audio, resource.
  • Annotations (readOnlyHint, destructiveHint, and others) help the model make decisions.
  • Annotations are not a security guarantee — validation must come from other control layers.

In the next episode 5 we'll cover the two remaining primitives: Resources and Prompts — how a resource is read via resources/read, resource template patterns, and how reusable prompt templates work through argument binding. See you in episode 5!

Learn MCP - Tools: Definition & Execution | Learning MCP