Параметри в заголовках
Машинний переклад
Цю сторінку перекладено автоматично з англомовної документації, і основною версією є англомовна сторінка. Якщо щось читається неправильно, на сторінці Переклади пояснено, як про це повідомити.
Більшості серверів це ніколи не знадобиться.
Шлюз або балансувальник навантаження перед сервером може маршрутизувати запити лише за тим, що здатен прочитати, не розбираючи тіло. Позначте аргумент інструмента ключем x-mcp-header, і клієнти на версії протоколу 2026-07-28 надсилатимуть його значення ще й як HTTP-заголовок.
Позначення аргументу
Позначка — це один додатковий ключ у JSON-схемі аргументу. У MCPServer його туди додає Field:
from typing import Annotated
from pydantic import Field
from mcp.server import MCPServer
mcp = MCPServer("Bookshop")
@mcp.tool()
def check_stock(
title: str,
region: Annotated[str, Field(json_schema_extra={"x-mcp-header": "Region"})],
) -> str:
"""Count the copies of a book in one region's warehouses."""
return f"{title}: 3 copies in {region}."
- Через Streamable HTTP на версії
2026-07-28клієнт надсилає заголовокMcp-Param-Regionразом із тілом, а сервер відхиляє виклик, у якому вони розходяться. - Клієнт, який не отримував цей інструмент у списку, позначки ніколи не бачив: заголовка він не надсилає, і такий виклик буде відхилено. Клас
Clientіз цього SDK після цього отримує список інструментів і один раз надсилає виклик повторно, тож якщо спершу отримати список, це лише заощадить один раунд обміну. - Усі інші з'єднання ігнорують цю анотацію.
Сама функція не змінюється: region, як і раніше, надходить як аргумент.
Що можна позначати
Аргументи типів str, int і bool. Для всього іншого реєстрація інструмента завершується винятком InvalidSignature.
Це стосується й str | None, що не має єдиного типу. Для необов'язкового аргументу схему потрібно прописати явно — за допомогою WithJsonSchema з Pydantic:
region: Annotated[str | None, WithJsonSchema({"type": "string", "x-mcp-header": "Region"})] = None
У низькорівневому класі Server
Там input_schema ви пишете вручну, тож ключ просто вписуєте в схему:
from mcp.server import Server, ServerRequestContext
from mcp.types import (
CallToolRequestParams,
CallToolResult,
ListToolsResult,
PaginatedRequestParams,
TextContent,
Tool,
)
CHECK_STOCK = Tool(
name="check_stock",
description="Count the copies of a book in one region's warehouses.",
input_schema={
"type": "object",
"properties": {
"title": {"type": "string"},
"region": {"type": "string", "x-mcp-header": "Region"},
},
"required": ["title", "region"],
},
)
async def list_tools(ctx: ServerRequestContext, params: PaginatedRequestParams | None) -> ListToolsResult:
return ListToolsResult(tools=[CHECK_STOCK])
async def call_tool(ctx: ServerRequestContext, params: CallToolRequestParams) -> CallToolResult:
args = params.arguments or {}
text = f"{args['title']}: 3 copies in {args['region']}."
return CallToolResult(content=[TextContent(type="text", text=text)])
server = Server("Bookshop", on_list_tools=list_tools, on_call_tool=call_tool)
app = server.streamable_http_app()
- Анотацію за вас ніхто не перевіряє: некоректну сервер теж віддає, а клієнти на
2026-07-28не включають такий інструмент до свого списку.
Схеми за назвою
Щоб перевірити заголовок, SDK потребує вхідної схеми інструмента ще до того, як передасть виклик на виконання. Без get_tool_input_schema SDK отримує її, запускаючи обробник on_list_tools під час кожного виклику з аргументами, незалежно від того, чи позначено хоч один інструмент.
from typing import Any
from mcp.server import Server, ServerRequestContext
from mcp.types import (
CallToolRequestParams,
CallToolResult,
ListToolsResult,
PaginatedRequestParams,
TextContent,
Tool,
)
CHECK_STOCK = Tool(
name="check_stock",
description="Count the copies of a book in one region's warehouses.",
input_schema={
"type": "object",
"properties": {
"title": {"type": "string"},
"region": {"type": "string", "x-mcp-header": "Region"},
},
"required": ["title", "region"],
},
)
TOOLS = {CHECK_STOCK.name: CHECK_STOCK}
async def list_tools(ctx: ServerRequestContext, params: PaginatedRequestParams | None) -> ListToolsResult:
return ListToolsResult(tools=list(TOOLS.values()))
async def call_tool(ctx: ServerRequestContext, params: CallToolRequestParams) -> CallToolResult:
args = params.arguments or {}
text = f"{args['title']}: 3 copies in {args['region']}."
return CallToolResult(content=[TextContent(type="text", text=text)])
def tool_input_schema(name: str) -> dict[str, Any] | None:
tool = TOOLS.get(name)
return tool.input_schema if tool else None
server = Server(
"Bookshop",
on_list_tools=list_tools,
on_call_tool=call_tool,
get_tool_input_schema=tool_input_schema,
)
app = server.streamable_http_app()
- Передайте функцію, щоб відповідати з того, що вже маєте.
- Для інструмента, в якому нічого перевіряти, поверніть
None.
Підсумки
- Ключ
x-mcp-headerна аргументі інструмента змушує клієнтів на2026-07-28дублювати цей аргумент у HTTP-заголовкуMcp-Param-*. - Сервер відхиляє виклик, у якому заголовок і тіло розходяться.
- Позначати можна лише аргументи типів
str,intіbool. Для всього іншогоMCPServerвикидає винятокInvalidSignature. - Низькорівневий клас
Serverнічого не перевіряє, а клієнти відкидають інструмент із некоректною анотацією. - Завдяки
get_tool_input_schemaнизькорівневий класServerне запускаєon_list_toolsпід час кожного виклику.
Решту API класу Server, де все пишеться вручну, описано на сторінці Низькорівневий Server.