S'inscrire

Tools in MCP

This article is not available in French yet. It is shown in English.

A tool in the Model Context Protocol (MCP) is a function that a server exposes so that a language model can call it through the host: search a bug tracker, query a database, send a message, call an external API. Each tool has a unique name, a description and a JSON Schema of its input parameters. The client gets the list of tools with tools/list and invokes a tool with tools/call.

Tools have been part of MCP since the first published version of the specification, 2024-11-05. Later revisions added annotations, structured results, icons, rules for names and caching hints. This article follows the current version of the specification, 2026-07-28. The basic concepts of the protocol (host, client, server, primitives) are described in the article What is MCP.

Overview

Property Value
Kind Server primitive
Who decides to call The model, under the control of the host and the user
Methods tools/list, tools/call
Notification notifications/tools/list_changed
Server capability tools, optional listChanged
Definition fields name, title, description, icons, inputSchema, outputSchema, annotations, _meta
Result fields content, structuredContent, isError
Schema dialect JSON Schema 2020-12 by default
Specification 2026-07-28

The problem tools solve

A language model produces text. To act on the outside world it needs functions that an application executes on its behalf. Model APIs support this through function calling: the application sends descriptions of functions with a request, and the model returns a request to call one of them.

Function calling does not say where the functions come from. An MCP tool moves the description to the side of the service. The server author describes the tool once, and any host that supports MCP receives the description at runtime through tools/list.

The specification calls tools model-controlled: the model decides when to call them, based on the context and the request of the user. The protocol does not prescribe a user interface, but recommends a human in the loop who can deny a call.

History

The table lists the changes to tools in each version of the specification.

Date Event
November 2024 First version of the specification, 2024-11-05: tools/list, tools/call, text, image and embedded resource results, isError, notifications/tools/list_changed
March 2025 Specification 2025-03-26: tool annotations, audio content
June 2025 Specification 2025-06-18: title, structured results with outputSchema and structuredContent, resource links in results
November 2025 Specification 2025-11-25: icons (SEP-973), guidance on tool names (SEP-986), input validation errors as tool execution errors (SEP-1303), JSON Schema 2020-12 as the default dialect (SEP-1613)
28 July 2026 Specification 2026-07-28: x-mcp-header (SEP-2243), caching hints (SEP-2549), deterministic order of the list, change notifications through subscriptions/listen, any JSON Schema 2020-12 keywords in schemas and any JSON value in structuredContent (SEP-2106)

Tool definition

A tool definition is a JSON object. The example shows the main fields:

JSON
{
  "name": "search_issues",
  "title": "Search issues",
  "description": "Search issues in the bug tracker by text and status. Use it to check for an existing issue before creating a new one. Returns at most 20 issues, newest first. Does not return comments or attachments.",
  "inputSchema": {
    "type": "object",
    "properties": {
      "query": {
        "type": "string",
        "description": "Words to look for in the issue title and description"
      },
      "status": {
        "type": "string",
        "enum": ["open", "in_progress", "closed"],
        "description": "Only issues with this status. All statuses if omitted"
      }
    },
    "required": ["query"],
    "additionalProperties": false
  },
  "outputSchema": {
    "type": "object",
    "properties": {
      "issues": {
        "type": "array",
        "items": {
          "type": "object",
          "properties": {
            "id": { "type": "string" },
            "title": { "type": "string" },
            "status": { "type": "string" }
          },
          "required": ["id", "title", "status"]
        }
      }
    },
    "required": ["issues"]
  },
  "annotations": {
    "readOnlyHint": true,
    "openWorldHint": false
  },
  "icons": [
    { "src": "https://tracker.example.com/icons/search.png", "mimeType": "image/png", "sizes": ["48x48"] }
  ]
}

The table shows the purpose of each field in the 2026-07-28 schema.

Field Required Purpose
name Yes Unique identifier of the tool within the server
title No Display name for people
description No Text for the model: what the tool does and when to use it
inputSchema Yes JSON Schema of the arguments
outputSchema No JSON Schema of the structured result
annotations No Hints about the behavior of the tool
icons No Icons for the user interface
_meta No Additional metadata, for example of extensions

Name, title and description

name is the identifier that the client passes in tools/call. title is meant for the user interface. A display name is chosen in this order: title, then annotations.title, then name. The schema describes description as a hint to the model about the purpose of the tool. The field is formally optional, but without it the model sees only the name and the schema.

Input schema

inputSchema defines the arguments of the tool. Arguments are always a JSON object, so the root of the schema has "type": "object". Since 2026-07-28 any JSON Schema 2020-12 keyword may appear next to it, including oneOf, anyOf, if/then/else and $ref with $defs.

A schema without a $schema field follows JSON Schema 2020-12; another dialect is declared in $schema. The schema must be a valid object, not null. For a tool without parameters the specification recommends { "type": "object", "additionalProperties": false }, which accepts only an empty object. Implementations must not automatically dereference a $ref that points to a network URI.

Output schema

outputSchema describes the structured result of the tool and can be any valid JSON Schema 2020-12, including an array schema. If a tool declares an output schema, the server must return structured results that conform to it, and the client should validate them.

Annotations

Annotations describe the behavior of a tool for the client. The table lists the fields of ToolAnnotations and their default values.

Field Meaning Default
title Human-readable title None
readOnlyHint The tool does not modify its environment false
destructiveHint The tool may perform destructive updates; meaningful only when readOnlyHint is false true
idempotentHint Repeated calls with the same arguments have no additional effect; meaningful only when readOnlyHint is false false
openWorldHint The tool interacts with an open world of external entities, such as the web true

All annotations are hints and are not guaranteed to describe the tool faithfully. Clients must treat annotations as untrusted unless they come from trusted servers.

Icons and metadata

icons is an array of icons, each with a src (an HTTPS URL or a data: URI) and optional mimeType, sizes and theme. Clients that render icons must support at least PNG and JPEG.

_meta carries metadata outside the core fields. Extensions use it: in MCP Apps, _meta.ui.resourceUri of a tool points to a ui:// resource with an interactive interface. Extensions are described in the article Extensions in MCP.

Tool names

The specification gives recommendations for names (SHOULD, not MUST):

  • a name is 1 to 128 characters long and case-sensitive;
  • only Latin letters A-Z and a-z, digits 0-9, _, - and . are used, without spaces or commas;
  • a name is unique within a server.

Uniqueness is limited to one server. A host that connects several servers can receive two tools named search. The specification recommends that such hosts and proxies disambiguate names, for example with a prefix that identifies the server. The server name from serverInfo is not guaranteed to be unique and should not be used for this.

The rules of model APIs can be narrower. In the Claude API a tool name must match ^[a-zA-Z0-9_-]{1,128}$, which does not allow a dot. The MCP specification does not define how a host converts names for the API of its model.

Listing tools

The client requests the list with tools/list. If the result contains nextCursor, the client requests the next page with this value in cursor.

JSON
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/list",
  "params": {
    "_meta": {
      "io.modelcontextprotocol/protocolVersion": "2026-07-28",
      "io.modelcontextprotocol/clientInfo": { "name": "example-client", "version": "1.0.0" },
      "io.modelcontextprotocol/clientCapabilities": {}
    }
  }
}
JSON
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "resultType": "complete",
    "tools": [
      {
        "name": "get_issue",
        "title": "Get issue",
        "description": "Get one issue by its identifier, with status, assignee and description.",
        "inputSchema": {
          "type": "object",
          "properties": {
            "id": { "type": "string", "description": "Issue identifier, for example BUG-142" }
          },
          "required": ["id"]
        },
        "annotations": { "readOnlyHint": true }
      }
    ],
    "nextCursor": "page-2",
    "ttlMs": 300000,
    "cacheScope": "public"
  }
}

The specification sets rules for the content of the list:

  • The list contains the tools currently available to the requesting client. It may be empty and may change over time.
  • The list must not vary per connection or as a side effect of other requests.
  • The list may vary by the authorization of the request, for example by the scopes of the token.
  • The server should return tools in a deterministic order, which helps clients cache the list.

Calling a tool

The client calls a tool with tools/call, passing the name of the tool and its arguments:

JSON
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/call",
  "params": {
    "name": "search_issues",
    "arguments": { "query": "login timeout", "status": "open" },
    "_meta": {
      "io.modelcontextprotocol/protocolVersion": "2026-07-28",
      "io.modelcontextprotocol/clientInfo": { "name": "example-client", "version": "1.0.0" },
      "io.modelcontextprotocol/clientCapabilities": {}
    }
  }
}

Over Streamable HTTP the request also carries the headers Mcp-Method: tools/call and Mcp-Name: search_issues. The transports are described in the article Transports in MCP.

The server answers with the final result (resultType: "complete") or with a result of type input_required if it needs additional input, for example from the user. In the second case the client repeats the call with a new id and the answers in inputResponses. This mechanism, Multi Round-Trip Requests (MRTR), is described in the article Stateless MCP.

Tool results

A result can contain unstructured content, structured content or both.

Unstructured content

Unstructured content is the content array, which can hold several items of different types. The table lists the content types of the 2026-07-28 schema.

Type Fields What it carries
text text Text
image data, mimeType Image in Base64
audio data, mimeType Audio in Base64
resource_link uri, name and optional fields of a resource Link to a resource that the client can read
resource resource with uri and text or blob Contents of a resource embedded in the result

All content types support optional annotations: audience, priority and lastModified. A resource link returned by a tool is not guaranteed to appear in resources/list. Resources and annotations are described in the article Resources and resource templates in MCP.

JSON
{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "resultType": "complete",
    "content": [
      { "type": "text", "text": "Issue BUG-142 has a log file attached." },
      {
        "type": "resource_link",
        "uri": "tracker://issues/BUG-142/attachments/server.log",
        "name": "server.log",
        "mimeType": "text/plain"
      }
    ]
  }
}

Structured content

Structured content is a JSON value in the structuredContent field. Since 2026-07-28 it can be any JSON value, not only an object. If the tool declares outputSchema, the value must conform to it. For backward compatibility a tool that returns structured content should also return the serialized JSON in a text block.

The specification notes that structuredContent is unrelated to the structured outputs of models.

JSON
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "resultType": "complete",
    "content": [
      { "type": "text", "text": "{\"issues\": [{\"id\": \"BUG-142\", \"title\": \"Login times out\", \"status\": \"open\"}]}" }
    ],
    "structuredContent": {
      "issues": [{ "id": "BUG-142", "title": "Login times out", "status": "open" }]
    }
  }
}

Two kinds of errors

Tools report errors in two ways. The table shows which errors fall into each.

Kind Examples How it is returned Passed to the model
Protocol error Unknown tool, request that does not match the CallToolRequest schema, server failure JSON-RPC error The client may pass it
Tool execution error API failure, input validation error (date in a wrong format, value out of range), business logic error Result with isError: true and an explanation The client should pass it
JSON
{
  "jsonrpc": "2.0",
  "id": 4,
  "error": {
    "code": -32602,
    "message": "Unknown tool: search_isues"
  }
}
JSON
{
  "jsonrpc": "2.0",
  "id": 5,
  "result": {
    "resultType": "complete",
    "content": [
      { "type": "text", "text": "Invalid status \"done\". Use one of: open, in_progress, closed." }
    ],
    "isError": true
  }
}

The difference matters because a model can correct its call only if it sees the error. Protocol errors are usually handled by the application, while tool execution errors return to the context of the model.

The current classification comes from SEP-1303 (created on 5 August 2025, status Final), which entered the specification in version 2025-11-25. Before it, "invalid arguments" were listed among protocol errors and "invalid input data" among tool execution errors. SEP-1303 moved all input validation errors to tool execution errors. The 2026-07-28 schema still lists invalid tool arguments among the uses of code -32602, so the schema and the tools page are not fully consistent on this point. How errors are tested is described in the article Testing MCP servers.

State between calls

MCP has no protocol session, so a server cannot relate calls through the connection. The specification gives non-normative guidance for tools that need state, such as a shopping cart or a database transaction. A creation tool returns an explicit handle, for example basket_id, and the following tools accept it as an argument.

According to the guidance, an authenticated server checks the authorization of the caller against the handle on every call. Handles are opaque, their lifetime is stated in the description of the creation tool, and a call with an expired handle returns a tool execution error that says so.

x-mcp-header

x-mcp-header is an extension property inside the schema of a tool parameter. It tells the client to copy the value of the parameter into the HTTP header Mcp-Param-{name} when the call goes over Streamable HTTP; the value of the property is the name part of the header. Load balancers, proxies and web application firewalls can then route requests by the parameter without parsing the body. The property was introduced in version 2026-07-28 by SEP-2243, created on 4 February 2026 by the MCP Transports Working Group.

JSON
{
  "name": "execute_sql",
  "description": "Execute SQL in the database of the given region",
  "inputSchema": {
    "type": "object",
    "properties": {
      "region": {
        "type": "string",
        "description": "The region to execute the query in",
        "x-mcp-header": "Region"
      },
      "query": { "type": "string", "description": "The SQL query to execute" }
    },
    "required": ["region", "query"]
  }
}

A call with "region": "us-west1" gets the header Mcp-Param-Region: us-west1:

HTTP
POST /mcp HTTP/1.1
Content-Type: application/json
MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/call
Mcp-Name: execute_sql
Mcp-Param-Region: us-west1

The property is optional for servers, but clients must support it. Its value is not empty, follows the token syntax of HTTP field names (RFC 9110), contains no control characters and is unique within the schema, case-insensitively. It is applied only to parameters of type string, integer or boolean, and only to properties reachable from the root through a chain of properties keys, without items, composition keywords or $ref.

A client on Streamable HTTP excludes a tool that violates these constraints from the result of tools/list and should log a warning. Clients on other transports may ignore the property. A value that cannot be sent as plain ASCII is encoded in Base64 in the form =?base64?{value}?=. If the parameter is absent or null, the header is omitted.

A server that processes the body checks that the headers match the arguments. On a mismatch it returns HTTP 400 and JSON-RPC error -32020 (HeaderMismatch). Header values are visible to network intermediaries, so the specification recommends against marking passwords, keys, tokens and personal data with x-mcp-header.

List changes and caching

A server that reports changes to its list declares "tools": { "listChanged": true }. Since 2026-07-28 the notification notifications/tools/list_changed reaches only clients that have opened a subscriptions/listen stream with toolsListChanged: true:

JSON
{
  "jsonrpc": "2.0",
  "id": 7,
  "method": "subscriptions/listen",
  "params": {
    "_meta": {
      "io.modelcontextprotocol/protocolVersion": "2026-07-28",
      "io.modelcontextprotocol/clientInfo": { "name": "example-client", "version": "1.0.0" },
      "io.modelcontextprotocol/clientCapabilities": {}
    },
    "notifications": { "toolsListChanged": true }
  }
}

After the notification the client requests tools/list again. The subscription mechanism is common to all primitives and is described in the article Resources and resource templates in MCP.

Each complete result of tools/list carries two caching hints. ttlMs is the time in milliseconds during which the result may be considered fresh, similar to Cache-Control: max-age in HTTP. cacheScope is public if the result contains no user data and may be shared, including by gateways, or private if it may be reused only with the same authorization, for example the same access token. A list change notification invalidates a cached list at once, even before its TTL expires. The result of tools/call carries no caching hints.

How the description affects the choice of a tool

The model does not see the code of a tool. It sees what the host puts into its context: the name, the description and the input schema. For example, the Claude API builds a special system prompt from the tool definitions passed with a request. From this text the model decides whether a tool is needed, which one, and how to fill in its arguments. An inaccurate description leads to missed calls, calls of the wrong tool or wrong arguments, even when the tool works correctly.

The documentation of the Claude API calls detailed descriptions by far the most important factor in tool performance. It recommends at least three or four sentences per description: what the tool does, when it should and should not be used, what each parameter means, and which information the tool does not return.

The article "Writing effective tools for agents" (Anthropic, 11 September 2025) adds several practices:

  • Unambiguous parameter names, such as user_id instead of user.
  • Namespacing with common prefixes, such as asana_search and jira_search. According to the authors, the choice between prefixes and suffixes noticeably affects evaluation results, and the effect differs between models.
  • Fewer, broader tools. Tools that merely wrap existing API endpoints are described as a common error.
  • Meaningful results, with readable names instead of opaque identifiers and a choice of a concise or detailed response.
  • Limited response size, with pagination, filtering and truncation. Claude Code limits tool responses to 25,000 tokens by default.
  • Actionable errors that say what to change in the call, instead of opaque codes or stack traces.

Instructions hidden in a description from an untrusted server also reach the model; this attack, tool poisoning, and the security requirements for tools are described in the article Security of MCP. Whether descriptions lead models to the right calls is checked by running models on sets of tasks, as described in the article Evaluating MCP servers with models. How to choose and describe tools over an existing API is covered in the article MCP server for an existing API.

MCP tool and function calling definition

A host passes MCP tools to its model through the function calling of the model API. The table compares an MCP tool definition with a client tool definition in the Claude API, as an example of such an API.

MCP tool Claude API client tool
Who writes the definition Author of the MCP server Developer of the application
How it reaches the model tools/list, then the host In each API request
Name Recommended 1-128 characters: letters, digits, _, -, . Required pattern ^[a-zA-Z0-9_-]{1,128}$
Input schema inputSchema input_schema
Output schema outputSchema Not among the documented fields
Behavior hints annotations Not among the documented fields
Usage examples No such field input_examples
Who executes the call MCP server Application

The two definitions work at different levels. Function calling defines how the model asks for a call. An MCP tool definition defines how a server publishes a function so that any host can find it, show it to the user and call it.

Part of the MCP definition is meant for the host rather than the model. The MCP specification does not define which of these fields a host passes to the model.

Terms

Term Meaning
Tool Function that a server exposes for the model to call through the host
Tool annotations Hints about the behavior of a tool, such as read-only or destructive; untrusted unless the server is trusted
Structured content JSON value in structuredContent that conforms to the output schema of the tool
Protocol error JSON-RPC error: unknown tool, malformed request, server failure
Tool execution error Tool result with isError: true: invalid input, API failure, business logic error
x-mcp-header Property in a parameter schema that copies its value into the Mcp-Param-{name} HTTP header
Handle Identifier that a tool returns and later calls accept, to keep state between calls
Caching hints ttlMs and cacheScope in cacheable results, such as lists: how long the result is fresh and who may reuse it

Sources

Series

Model Context Protocol (MCP)
  1. What is MCP (Model Context Protocol)
  2. Tools in MCPCurrent
  3. Resources and resource templates in MCP
  4. Prompts in MCP
  5. MCP transports: stdio and Streamable HTTP
  6. Stateless MCP: changes in 2026-07-28
  7. Authorization in MCP
  8. MCP security
  9. MCP extensions
  10. MCP server over an existing API
  11. Testing MCP servers: the basics
  12. Evaluating an MCP server with models
  13. Regression testing of an MCP server
  14. Publishing an MCP server to the MCP Registry

Wiki articles are written and maintained by the ComplexQA team.