Parámetros de encabezado
Traducción automática
Esta página se tradujo automáticamente a partir de la documentación en inglés, y la página en inglés es la versión de referencia. Si algo no se lee bien, Traducciones explica cómo avisarnos.
La mayoría de los servidores nunca necesita esto.
Un gateway o un balanceador de carga delante del servidor solo puede enrutar según lo que puede leer sin analizar el cuerpo. Marca un argumento de una herramienta con x-mcp-header y los clientes de la versión del protocolo 2026-07-28 envían su valor también como encabezado HTTP.
Marcar un argumento
La marca es una clave adicional en el JSON Schema del argumento. En MCPServer, Field la pone ahí:
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}."
- Con Streamable HTTP en
2026-07-28, el cliente envíaMcp-Param-Regionjunto con el cuerpo, y el servidor rechaza una llamada en la que los dos no coinciden. - Un cliente que no ha listado la herramienta nunca ha visto la marca: no envía ningún encabezado y la llamada se rechaza. El
Clientde este SDK lista entonces las herramientas y reenvía la llamada una vez, así que listar primero solo ahorra una ida y vuelta. - Cualquier otra conexión ignora la anotación.
Tu función no cambia: region sigue llegando como argumento.
Qué se puede marcar
Los argumentos str, int y bool. Cualquier otra cosa se rechaza al registrar la herramienta, con InvalidSignature.
Eso incluye str | None, que no tiene un tipo único. Un argumento opcional necesita su esquema escrito de forma explícita, con WithJsonSchema de Pydantic:
region: Annotated[str | None, WithJsonSchema({"type": "string", "x-mcp-header": "Region"})] = None
En el Server de bajo nivel
Ahí escribes input_schema a mano, así que la clave va directamente dentro:
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()
- Nada verifica la anotación por ti: una no válida se sirve tal cual, y los clientes
2026-07-28dejan la herramienta fuera de su listado.
Esquemas por nombre
Para verificar el encabezado, el SDK necesita el esquema de entrada de la herramienta antes de despachar la llamada. Sin get_tool_input_schema, lo obtiene ejecutando tu handler on_list_tools en cada llamada que lleva argumentos, haya o no alguna herramienta marcada.
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()
- Pasa la función para responder a partir de lo que ya tienes.
- Devuelve
Nonepara una herramienta que no tiene nada que verificar.
Resumen
x-mcp-headeren un argumento de una herramienta hace que los clientes2026-07-28lo repitan como encabezado HTTPMcp-Param-*.- El servidor rechaza una llamada cuyo encabezado y cuerpo no coinciden.
- Solo se pueden marcar argumentos
str,intybool.MCPServerlanzaInvalidSignaturepara cualquier otra cosa. - El
Serverde bajo nivel no verifica nada, y los clientes descartan una herramienta cuya anotación no es válida. get_tool_input_schemaevita que elServerde bajo nivel ejecuteon_list_toolsen cada llamada.
El resto de la API escrita a mano de Server está en El Server de bajo nivel.