Header-Parameter
Maschinelle Übersetzung
Diese Seite wurde automatisch aus der englischen Dokumentation übersetzt, und die englische Seite ist die maßgebliche Fassung. Wenn sich etwas falsch liest, erklärt Übersetzungen, wie du es melden kannst.
Die meisten Server brauchen das nie.
Ein Gateway oder Load Balancer vor deinem Server kann nur anhand dessen routen, was er lesen kann, ohne den Body zu parsen. Markiere ein Tool-Argument mit x-mcp-header, und Clients mit der Protokollversion 2026-07-28 senden seinen Wert zusätzlich als HTTP-Header.
Ein Argument markieren
Die Markierung ist ein zusätzlicher Schlüssel im JSON Schema des Arguments. Bei MCPServer setzt Field ihn dort:
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}."
- Über Streamable HTTP mit
2026-07-28sendet ein ClientMcp-Param-Regionzusätzlich zum Body, und der Server lehnt einen Aufruf ab, bei dem beide nicht übereinstimmen. - Ein Client, der das Tool nicht aufgelistet hat, hat die Markierung nie gesehen: Er sendet keinen Header, und der Aufruf wird abgelehnt. Der
Clientdieses SDK listet dann die Tools auf und sendet den Aufruf einmal erneut. Vorher aufzulisten spart also nur einen Roundtrip. - Jede andere Verbindung ignoriert die Annotation.
Deine Funktion ändert sich nicht: region kommt weiterhin als Argument an.
Was sich markieren lässt
Argumente vom Typ str, int und bool. Alles andere wird beim Registrieren des Tools mit InvalidSignature abgewiesen.
Das gilt auch für str | None, das keinen einzelnen Typ hat. Ein optionales Argument braucht ein ausgeschriebenes Schema, mit WithJsonSchema von Pydantic:
region: Annotated[str | None, WithJsonSchema({"type": "string", "x-mcp-header": "Region"})] = None
Beim Low-Level-Server
Dort schreibst du input_schema von Hand, der Schlüssel kommt also direkt hinein:
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()
- Nichts prüft die Annotation für dich: Eine ungültige wird ausgeliefert, und
2026-07-28-Clients lassen das Tool aus ihrer Auflistung weg.
Schemas nach Namen
Um den Header zu prüfen, braucht das SDK das Eingabeschema des Tools, bevor es den Aufruf weiterleitet. Ohne get_tool_input_schema holt es sich das Schema, indem es bei jedem Aufruf mit Argumenten deinen on_list_tools-Handler ausführt – egal, ob überhaupt ein Tool markiert ist.
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()
- Übergib die Funktion, um aus dem zu antworten, was du schon hast.
- Gib
Nonefür ein Tool zurück, bei dem es nichts zu prüfen gibt.
Zusammenfassung
x-mcp-headeran einem Tool-Argument sorgt dafür, dass2026-07-28-Clients es als HTTP-HeaderMcp-Param-*wiederholen.- Der Server lehnt einen Aufruf ab, bei dem Header und Body nicht übereinstimmen.
- Nur Argumente vom Typ
str,intundboollassen sich markieren. Bei allem anderen löstMCPServerInvalidSignatureaus. - Der Low-Level-
Serverprüft nichts, und Clients verwerfen ein Tool mit ungültiger Annotation. get_tool_input_schemaverhindert, dass der Low-Level-Serverbei jedem Aufrufon_list_toolsausführt.
Der Rest der handgeschriebenen Server-API steht in Der Low-Level-Server.