Saltar a contenido

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í:

server.py
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ía Mcp-Param-Region junto 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 Client de 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:

server.py
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-28 dejan 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.

server.py
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 None para una herramienta que no tiene nada que verificar.

Resumen

  • x-mcp-header en un argumento de una herramienta hace que los clientes 2026-07-28 lo repitan como encabezado HTTP Mcp-Param-*.
  • El servidor rechaza una llamada cuyo encabezado y cuerpo no coinciden.
  • Solo se pueden marcar argumentos str, int y bool. MCPServer lanza InvalidSignature para cualquier otra cosa.
  • El Server de bajo nivel no verifica nada, y los clientes descartan una herramienta cuya anotación no es válida.
  • get_tool_input_schema evita que el Server de bajo nivel ejecute on_list_tools en cada llamada.

El resto de la API escrita a mano de Server está en El Server de bajo nivel.