Aller au contenu

Paramètres d’en-tête

Traduction automatique

Cette page a été traduite automatiquement à partir de la documentation en anglais, et la page en anglais fait foi. Si quelque chose vous semble incorrect, la page Traductions explique comment le signaler.

La plupart des serveurs n’en ont jamais besoin.

Une passerelle ou un répartiteur de charge placé devant votre serveur ne peut router que d’après ce qu’il lit sans analyser le corps. Marquez un argument d’outil avec x-mcp-header, et les clients en version du protocole 2026-07-28 envoient aussi sa valeur sous forme d’en-tête HTTP.

Marquer un argument

La marque est une clé supplémentaire dans le schéma JSON de l’argument. Avec MCPServer, c’est Field qui l’y place :

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}."
  • Sur Streamable HTTP en version 2026-07-28, un client envoie Mcp-Param-Region en plus du corps, et le serveur rejette tout appel où les deux ne concordent pas.
  • Un client qui n’a pas listé l’outil n’a jamais vu la marque : il n’envoie aucun en-tête, et l’appel est rejeté. Le Client de ce SDK liste alors les outils et renvoie l’appel une seule fois ; lister d’abord ne fait donc qu’économiser un aller-retour.
  • Toutes les autres connexions ignorent l’annotation.

Votre fonction ne change pas : region arrive toujours sous forme d’argument.

Ce qui peut être marqué

Les arguments str, int et bool. Tout le reste est refusé à l’enregistrement de l’outil, avec InvalidSignature.

Cela vaut aussi pour str | None, qui n’a pas de type unique. Pour un argument facultatif, il faut écrire son schéma explicitement, avec WithJsonSchema de Pydantic :

region: Annotated[str | None, WithJsonSchema({"type": "string", "x-mcp-header": "Region"})] = None

Avec le Server de bas niveau

Là, vous écrivez input_schema à la main ; la clé s’y place donc directement :

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()
  • Rien ne vérifie l’annotation à votre place : une annotation invalide est servie telle quelle, et les clients en version 2026-07-28 omettent l’outil de leur liste.

Schémas par nom

Pour vérifier l’en-tête, le SDK a besoin du schéma d’entrée de l’outil avant d’acheminer l’appel. Sans get_tool_input_schema, il l’obtient en exécutant votre gestionnaire on_list_tools à chaque appel comportant des arguments, qu’un outil soit marqué ou non.

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()
  • Passez cette fonction pour répondre à partir de ce que vous avez déjà.
  • Renvoyez None pour un outil qui n’a rien à vérifier.

Récapitulatif

  • x-mcp-header sur un argument d’outil amène les clients en version 2026-07-28 à le répéter dans un en-tête HTTP Mcp-Param-*.
  • Le serveur rejette tout appel dont l’en-tête et le corps ne concordent pas.
  • Seuls les arguments str, int et bool peuvent être marqués. MCPServer lève InvalidSignature pour tout le reste.
  • Le Server de bas niveau ne vérifie rien, et les clients écartent tout outil dont l’annotation est invalide.
  • get_tool_input_schema évite au Server de bas niveau d’exécuter on_list_tools à chaque appel.

Le reste de l’API du Server écrit à la main est décrit dans Le Server de bas niveau.