Přeskočit na obsah
27/30Kapitola 27 z 30

Nasazení MCP serveru: TypeScript a Python pod měřením

Tentýž server napsaný dvakrát: tři tools, resource a prompt. 94 balíčků proti 28 a cold start 145 ms proti 709.

Na této stránce

Tady je celý jazykový spor, změřený ještě předtím, než padne jediné slovo.

spawn → tools/list answered, median of 25 launchesTEXT
node ./incidents.js         144.5 ms
python incidents.py         709.4 ms
npx incidents-mcp           712.6 ms

První dva řádky jsou srovnání, které chce každý vidět. Třetí řádek je tentýž TypeScript server z prvního řádku, spuštěný způsobem, jakým by se skutečně distribuoval — a končí tři milisekundy od Pythonu.

Kapitola 26 četla Model Context Protocol proti jeho vlastní specifikaci přes syrové JSON-RPC, protože syrové JSON-RPC nemá žádný jazyk. Tahle kapitola má dva a váha argumentu leží tady: tentýž server, napsaný dvakrát. Tři tools, jeden resource, jeden prompt, obě SDK, bez zkratek na kterékoli straně. Pak transporty, inspector, 401 a čísla, která dosud nikdo nezveřejnil.

Server a proč je v něm právě těchto pět věcí

Odkaz na sekci: Server a proč je v něm právě těchto pět věcí

Incident log. Tři tools, protože rozdělení mezi čtením a zápisem z kapitoly 18 musí být vidět: search_incidents čte, open_incident zapisuje a vrací handle, resolve_incident ten handle vezme a uzavře. Jeden resource, incidents://open, protože čtení aktuálního seznamu je něco, co připojuje aplikace. Jeden prompt, postmortem, protože „napiš tohle“ je slash command člověka. To je hierarchie řízení z kapitoly 26 — model, aplikace, člověk — převedená do pěti registrací.

Na handlu záleží víc, než se zdá. Kapitola 26 rozbila hračkový kalendář tím, že jeho stav držela v poli na úrovni modulu: protocol nemá session, takže creační tool vrátí opaque identifikátor a každý pozdější call ho bere jako obyčejný argument. Nic v žádném souboru nepředpokládá, že volající je proces, který ho otevřel.

Tady je tentýž tool v obou jazycích, registrovaný vedle sebe:

incidents.tsTS
server.registerTool(
  "resolve_incident",
  {
    description:
      "Close an incident by handle and record its cause.",
    inputSchema: {
      id: z.string().describe(
        "The handle returned by open_incident, e.g. INC-3."),
      cause: z.string().describe(
        "One sentence. What actually broke."),
    },
    annotations: {
      readOnlyHint: false,
      destructiveHint: true,
      idempotentHint: true,
    },
  },
  async ({ id, cause }) => {
    const at = OPEN.findIndex((i) => i.id === id);
    if (at < 0) {
      return { isError: true, content: [{ type: "text",
        text: `No open incident ${id}. ` +
              `Call search_incidents first.` }] };
    }
    const [done] = OPEN.splice(at, 1);
    return { content: [{ type: "text",
      text: JSON.stringify({ ...done, cause }) }] };
  },
);
incidents.pyPYTHON
@server.tool(
    description=
      "Close an incident by handle and record its cause.",
    annotations=ToolAnnotations(
        readOnlyHint=False,
        destructiveHint=True,
        idempotentHint=True,
    ),
)
def resolve_incident(
    id: Annotated[str, Field(description=
        "The handle returned by open_incident, e.g. INC-3.")],
    cause: Annotated[str, Field(description=
        "One sentence. What actually broke.")],
) -> Incident:
    for at, i in enumerate(OPEN):
        if i["id"] == id:
            done = OPEN.pop(at)
            return {**done, "cause": cause}
    raise ValueError(
        f"No open incident {id}. Call search_incidents first.")

Nejprve si přečtěte, co je stejné, protože to je zjištění. Oba deklarují název, popis, dva popsané string argumenty a tři anotace; oba jsou jedna funkce; ani jeden nezmiňuje JSON-RPC, framing, stdout ani verzi protocol. Obě SDK se sběhla do stejného tvaru, což je přesně to, co má „Tier 1“ znamenat.1

Dva rozdíly jsou skutečné a oba se vrátí později. TypeScript popisuje argumenty knihovnou pro schema — tady Zod — a schema je hodnota, kterou napíšete. Python je popisuje vlastními type hints funkce a čte je při importu, a proto o funkci ví věci, které mu TypeScript soubor nikdy neřekl. A cesta chyb: TypeScript vrací tool result s isError, Python vyhazuje výjimku. To si zapamatujte.

Další čtyři registrace se strukturálně neliší v ničem. Resource je server.registerResource("open-incidents", "incidents://open", …) proti @server.resource("incidents://open", …); prompt je registerPrompt proti @server.prompt. Poslední řádek každého souboru je transport: await server.connect(new StdioServerTransport()) proti server.run().

Celé soubory: 81 neprázdných řádků a 3 060 bajtů TypeScriptu proti 63 a 2 555. Berte to s patřičnou rezervou — počty řádků měří formatter stejně jako jazyk, a proto není ani jedno číslo v hlavní tabulce níže.

Důkaz, že jazyk je neviditelný, je jeden client spuštěný dvakrát, v jedenácti řádcích:

client.tsTS
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";

const client = new Client({ name: "incident-cli", version: "1.0.0" });
await client.connect(new StdioClientTransport({
  command: process.argv[2], args: process.argv.slice(3) }));

const { tools } = await client.listTools();
console.log("tools:", tools.map((t) => t.name).join(", "));

const opened = await client.callTool({ name: "open_incident",
  arguments: { title: "Queue backed up", severity: "sev2" } });
console.log("open_incident ->", JSON.stringify(opened.content));

Namiřte ho postupně na každý server. Skutečný výstup, zkrácený:

TEXT
$ node client.ts node incidents.ts
tools: search_incidents, open_incident, resolve_incident
open_incident -> [{"type":"text","text":"{\"id\":\"INC-3\"}"}]

$ node client.ts ./py/.venv/bin/python ./py/incidents.py
tools: search_incidents, open_incident, resolve_incident
open_incident -> [{"type":"text","text":"{\n  \"id\": \"INC-3\"\n}"}]

Stejné tools, stejné pořadí, stejný handle. TypeScript client nepozná, v čem je server napsaný, a nikdy se neptá. To je celý slib protocol — a drží.

Teď se podívejte na whitespace ve druhém výsledku, protože není kosmetický: Python SDK serializuje payloady s pydantic_core.to_json(result, fallback=str, indent=2). Při čtení resource se dvěma incidenty v seznamu má TypeScript body 136 znaků a 37 o200k_base tokens; Python body má 185 a 62. O šedesát osm procent víc tokens pro identické řádky, placených tím, kdo resource čte do prompt, pokaždé.

Catalogue vypráví stejný příběh s větší příčinou. Oba servery, stejné tři tools, tools/list zvážené klíč po klíči:

keyTypeScriptPython
name2121
description4646
annotations4646
inputSchema211192
outputSchema187
execution27
total342480

Pythoní input schemata jsou levnější — TypeScriptový můstek Zod razítkuje na každé $schema a additionalProperties. Celá 138tokenová mezera je output schema, které nikdo nenapsal. resolve_incident je anotované jako -> Incident, takže SDK odvodilo JSON Schema pro návratový typ a odeslalo ho. Je to skutečně užitečné — právě díky tomu může client validovat structuredContent — a je to 187 tokens vašeho context window, které dorazí kvůli type hint. Pravidlo z kapitoly 24 o definicích vytlačujících materiál, na kterém záleží, platí i pro schemata, o kterých jste nevěděli, že je máte.

Rozbijte to schválně: chybová zpráva, která unikla

Odkaz na sekci: Rozbijte to schválně: chybová zpráva, která unikla

Ty dvě chybové cesty výše nejsou otázka stylu. Dejte každému serveru tool, který selže tak, jak selhává skutečná integrace, a přečtěte si, co doputuje k modelu.

tools/call on a tool that raisesTEXT
TypeScript  {"content":[{"type":"text","text":
              "connect ECONNREFUSED 10.0.3.7:5432 (db-prod-eu, user=reporting)"}],
             "isError":true}

Python      {"content":[{"text":"Error executing tool boom","type":"text"}],
             "isError":true}

TypeScript SDK vložilo do context modelu interní adresu, port, název databáze a service account. Python SDK tam nevložilo nic z toho; traceback šel do stderr a zůstal na serveru.

Ani jedno není bug. Obojí jsou rozhodnutí a to pythoní je zapsané přímo ve vlastním docstringu: ToolError je „selhání, které jste očekávali“ a jeho zpráva se vrací „v content, aby si ji model přečetl“; cokoli jiného „se bere jako crash: model vidí jen Error executing tool <name> a server loguje traceback na ERROR“. Třída pro crash case říká zbytek nahlas — „nic z původního se nedostane ke client“.

Obě chování jsou v polovině případů špatně. Kapitola 18 tvrdila, že validační chyba se má vrátit jako tool result, který model dokáže přečíst a opravit, protože to je ve většině integrací řádek s nejvyšší pákou; na straně Pythonu to vyžaduje explicitně vyhodit ToolError a holé ValueError užitečnou větu zahodí. Argument kapitoly 30 míří opačně: všechno, co tool vrátí, přistane v context, ze kterého se to pozdější prompt injection může pokusit přečíst zpět, a nerevidovaný text výjimky je nejméně auditovaný text ve vašem systému.

Pravidlo, které přežije obojí: rozhodněte u každého tool, co smí selhání říct, a ten řetězec napište sami. Nikdy nenechte výchozí text výjimky rozhodovat, v žádném jazyce.

Rozbijte to schválně: jeden řádek na standardní výstup

Odkaz na sekci: Rozbijte to schválně: jeden řádek na standardní výstup

Oficiální tutorial uvádí pravidlo bez uhýbání: „Pro servery založené na STDIO: nikdy nepište na stdout. Zápis na stdout poškodí JSON-RPC messages a rozbije váš server. Funkce print() ve výchozím nastavení píše na stdout, takže ji ze STDIO serveru držte úplně pryč.“1 Kapitola 26 citovala normativní verzi — server „MUST NOT zapisovat do svého stdout nic, co není validní MCP message“.2

Přidejte do každého serveru jeden řádek a přečtěte raw stream:

raw stdout, first two linesTEXT
TypeScript  incidents server starting
            {"result":{"protocolVersion":"2025-11-25", … },"jsonrpc":"2.0","id":1}

Python      {"jsonrpc":"2.0","id":1,"result":{ … }}
            incidents server starting

Pythoní varianta je horší a důvodem není MCP. Proces, jehož stdout je pipe místo terminálu, dostane block-buffered stream, takže zbloudilý řádek se flushne, kdykoli se buffer rozhodne — tady při ukončení, po odpovědi, před kterou byl zapsán. Poškození se neobjeví tam, kde je bug. Přidejte flush=True nebo knihovnu, která flushuje, a přesune se.

Pak část, která vysvětluje, proč se to dostane do provozu. Pošlete rozbitý server třem client:

TEXT
naive parser, dirty server   SyntaxError: Unexpected token 'i',
                             "incidents "... is not valid JSON
SDK client, dirty server     tools: search_incidents, open_incident, resolve_incident
MCP Inspector, dirty server  full catalogue, no warning

Sedmiřádkový parser umře okamžitě. Oficiální client i Inspector pokrčí rameny — řádek přeskočí a pokračují. Pravidlo, které rozbije jen client, které nikdo nepoužívá, je pravidlo, které se do produkce dostane neporušené, a proto stojí za to rozbít ho schválně tady, ne v logu zákazníka.

CLI režim Inspectoru je polovina, na kterou se zapomíná: npx @modelcontextprotocol/inspector --cli <command> --method tools/list vytiskne catalogue a skončí, díky čemuž je skriptovatelný způsobem, kterým browser UI není.3

Obě SDK se nainstalovala čistě, do vlastních adresářů, nic sdíleného:

TypeScriptPython
package@modelcontextprotocol/sdk 1.30.0 + zod 3.25.76mcp 2.1.1
latest protocol revision implemented2025-11-252026-07-28
transitive packages installed9428
installed size13,9 MiB44,3 MiB
files on disk3 3862 018
third-party packages loaded to serve stdio8 z 9418 z 28
bare interpreter start, median19,4 ms11,1 ms
spawn → tools/list answered, median of 25144,5 ms709,4 ms
tools/list catalogue, o200k_base tokens342480

Každý řádek překvapí jiným směrem, a proto má smysl srovnání spustit, ne ho předpokládat.

TypeScript instaluje víc než třikrát tolik balíčků a méně než třetinu bajtů. 94 dependencies je npm ekosystém ve své přirozené podobě — fast-deep-equal, es-errors, dunder-proto. Pythoních 28 je méně a obrovských: cryptography, pydantic-core a uvicorn jsou kompilované artefakty. Pokud máte instinkt, že problémem je počet dependencies, tenhle řádek je protipříklad.

Pythoní interpret startuje rychleji než Node, a ne o málo — 11,1 ms proti 19,4 ms na prázdném programu. Takže těch 565 ms v řádku cold-start není jazyk. Je to SDK a řádek načtených balíčků říká proč:

third-party modules loaded to answer one tools/list over stdioTEXT
TypeScript   8 of 94   sdk, zod, zod-to-json-schema, ajv, ajv-formats,
                       fast-deep-equal, fast-uri, json-schema-traverse

Python      18 of 28   mcp, mcp_types, pydantic, pydantic_core, anyio,
                       starlette, uvicorn, sse_starlette, httpx2,
                       cryptography, _cffi_backend, opentelemetry, click, …

Server, jehož jediné I/O je pipe, importuje ASGI web server, HTTP client a TLS knihovnu dřív, než přečte první řádek. TypeScript SDK také dodává Express, Hono, jose a eventsource — leží na disku nepřečtené, protože hranice balíčku je drží mimo import server/stdio.js. Pythoní package je jeden import graph, takže import mcp je všechno: python -X importtime připisuje 727 ms import mcp.server.mcpserver — číslo měřené pod import profilerem, a proto vychází nad 709 ms, které neprofilovaný běh potřebuje od spawn po odpověď — a 269 z nich samotnému subtree mcp.types — wire typy jsou Pydantic modely, jedna třída na protocol message na revision, a jejich sestavení je práce udělaná při importu. To je designový trade-off, ne nedbalost — eager imports jsou důvod, proč vám Python SDK umí na dalším řádku dát run(transport="streamable-http") bez druhé instalace.

A pak poslední řádek úvodního bloku celý argument zruší. Zabalte TypeScript server správně — entry bin, shebang, npm link, nic ke stažení — a spusťte ho přes npx s --no-install, což je způsob, jakým se publikovaný stdio server skutečně startuje:

median of 25, spawn → tools/list answeredTEXT
node ./incidents.js       144.5 ms
npx incidents-mcp         712.6 ms      (+568.1 ms of launcher)
python incidents.py       709.4 ms

Launcher stojí 568 ms na start — čtyřapůlkrát víc než celý import TypeScript SDK — a platí se při každém spuštění, protože MCP host startuje stdio server spuštěním toho příkazu. Poctivá podoba výroku „TypeScript startuje pětkrát rychleji“ tedy je: ano, dokud ho nedistribuujete obvyklým způsobem. Stejná výhrada pravděpodobně platí pro uvx; na tomto stroji nebyl nainstalovaný žádný uv, takže takový řádek neexistuje. Nic nezměřeného do tabulky nepatří.

Kapitola 26 pokryla framing stdio. Dvě věci nechala sem.

První: spuštění serveru přes npx nebo uvx je stdio transport. Neexistuje samostatný „package mode“. Konfigurace hosta jmenuje příkaz a argumenty; host ho spawnne a mluví přes pipes. Proto jsou lokálně otázky „jak to distribuovat“ a „kterým transportem to mluví“ jedna otázka, a proto náklad launcheru patří do kapitoly o shipping.

Druhá: stdio nemá žádnou sekci authorization a specifikace to říká jedním řádkem — implementace používající stdio „SHOULD NOT follow this specification, and instead retrieve credentials from the environment“.4 Jeho bezpečnostní model je bezpečnostní model operačního systému a stejný je i jeho limit: lokální subprocess obslouží přesně jeden stroj a jednoho uživatele.

Druhý živý transport je Streamable HTTP: jeden endpoint, který přijímá POST, jeden HTTP request na JSON-RPC message a hlavička Accept, která musí uvádět jak application/json, tak text/event-stream, protože server si u každého request vybírá, kterým z těch dvou odpoví.5 Kapitola 14 ten event stream parsovala ručně, takže ve wire formátu není nic nového — jen to, co ho obaluje. Tři povinnosti aktuální revision se snadno přehlédnou a všechny tři jsou testovatelné:

Hlavička verze musí souhlasit s body

Odkaz na sekci: Hlavička verze musí souhlasit s body

Každý POST nese MCP-Protocol-Version a její hodnota musí odpovídat protocolVersion uvnitř vlastního _meta requestu. Nesoulad je 400 s chybou header-mismatch, ne pokrčení rameny.5

Pro compliance jsou vyžadovány další dvě hlavičky

Odkaz na sekci: Pro compliance jsou vyžadovány další dvě hlavičky

Mcp-Method zrcadlí method na každém request; Mcp-Name zrcadlí params.name nebo params.uri na tools/call, resources/read a prompts/get. Existují proto, aby proxy mohla routovat bez parsování bodies.5

Staré tvary jsou pryč a odpovídají odmítnutím

Odkaz na sekci: Staré tvary jsou pryč a odpovídají odmítnutím

GET stream, Mcp-Session-Id a resumption Last-Event-ID byly odstraněny. Server, který mluví jen touto revision, má na GET nebo DELETE odpovědět 405 Method Not Allowed, ignorovat session header bez mintování nové a ignorovat Last-Event-ID.5

Teď měření, které přerámuje celou kapitolu. Pošlete request aktuální revision na každý server přes HTTP.

POST /mcp, MCP-Protocol-Version: 2026-07-28TEXT
Python   200  {"result":{"resultType":"complete","cacheScope":"private","ttlMs":0,
              "tools":[…],"_meta":{"io.modelcontextprotocol/serverInfo":{…}}}}

TypeScript    {"error":{"code":-32000,"message":"Bad Request: Unsupported protocol
              version: 2026-07-28 (supported versions: 2025-11-25, 2025-06-18,
              2025-03-26, 2024-11-05, 2024-10-07)"}}

Konstanty souhlasí s chováním: pythoní LATEST_PROTOCOL_VERSION SDK čte 2026-07-28, TypeScriptové čte 2025-11-25. Pošlete header-mismatch request z kroku výše a Python server odpoví 400 s chybou -32020 a zprávou „mcp-protocol-version header does not match the request envelope's protocol version“; TypeScript SDK takový kód nemá, protože neimplementuje revision, která ho definuje.

Stránka, která obě uvádí na Tier 1, také říká „Each SDK provides the same functionality“.1 K níže uvedenému datu je pro aktuální revision tahle věta aspirativní. Zkontrolujte LATEST_PROTOCOL_VERSION v SDK, které se chystáte nainstalovat; je to jeden řádek a jediné tvrzení v této kapitole, na kterém bude za rok ještě záležet.

Přesuňte server z laptopu a objeví se client cizího člověka s token. Tohle je polovina, kterou kapitola 26 nechala stranou, a polovina, kterou multi-user produkt nemůže přeskočit.

Specifikace staví MCP server do role OAuth 2.1 a pojmenovává ji: chráněný MCP server je resource server, client je OAuth client a authorization server je problém někoho jiného.4 Z této role plynou čtyři povinné klauzule, citované celé, protože jejich parafrázování je přesně cesta k chybě:

MCP servers, acting in their role as an OAuth 2.1 resource server, MUST validate access tokens as described in OAuth 2.1 Section 5.2. MCP servers MUST validate that access tokens were issued specifically for them as the intended audience, according to RFC 8707 Section 2. […] MCP clients MUST NOT send tokens to the MCP server other than ones issued by the MCP server's authorization server. MCP servers MUST only accept tokens that are valid for use with their own resources. MCP servers MUST NOT accept or transit any other tokens.4

„Must not accept or transit“ je pravidlo proti passthrough a právě kvůli němu existuje celý aparát audience. Server, který přehraje bearer token, který dostal, na third-party API, je confused deputy: propůjčuje vlastní důvěru tomu, kdo ho zavolal. Pravidlo zakazuje reuse, nejen ukládání.

Aby to bylo vynutitelné, jsou potřeba čtyři RFC, každé s jednou úlohou.6 RFC 9728 říká, jak client vůbec najde authorization server: MCP server poskytne protected-resource-metadata dokument a 401 na něj ukazuje. RFC 8707 je parametr resource — client musí poslat kanonické URI serveru v authorization request i v token request, „regardless of whether authorization servers support it“, aby vydaný token jmenoval svou audience. RFC 9207 uzavírá smyčku z druhé strany: client si před redirect zaznamená issuer a vrácené iss porovná přesným stringem, bez normalizace — žádné case folding, žádné vypuštění defaultního portu, žádné trailing slash. A RFC 7591, Dynamic Client Registration, je teď deprecated ve prospěch Client ID Metadata Documents, „retained for backwards compatibility with authorization servers that do not support“ them.4

Zapojte to na obou serverech s token verifier, který nedělá nic než kontrolu audience. TypeScriptový žebřík:

POST /mcp — TypeScript, with requireBearerAuthTEXT
no token            401  WWW-Authenticate: Bearer error="invalid_token",
                         error_description="Missing Authorization header",
                         scope="incidents:read",
                         resource_metadata="…/.well-known/oauth-protected-resource/mcp"
aud=other server    401  error_description="token audience is not this server"
no exp claim        401  error_description="Token has no expiration time"
right aud, no scope 403  error="insufficient_scope", scope="incidents:read"
right aud + scope   200  {"result":{"tools":[…]}}
GET /.well-known/oauth-protected-resource/mcpTEXT
{"resource":"http://127.0.0.1:8931/mcp",
 "authorization_servers":["https://auth.example.com/"],
 "scopes_supported":["incidents:read","incidents:write"],
 "resource_name":"Incidents"}

Obě SDK ten dokument servírují a obě na něj míří 401, což je celý discovery příběh: client, který váš server nikdy neviděl, se z odmítnutí dozví, kde se authenticate. 403 je jiné zvíře — token je v pořádku, scope ne — a challenge jmenuje, co chybí, aby client mohl přidat úroveň, ne začínat znovu.

Dvě příčky se liší a žádný rozdíl není ve specifikaci. TypeScript SDK odmítne token s chybějícím expiry claim; pythoní vrátí 200, protože expires_at je na jeho AccessToken volitelné a None znamená „bez názoru“. A pythoní 403 nese error_description="Required scope: incidents:read" bez parametru scope, který by podle specifikace měly servery zahrnovat. Verifier není místo, kde přijímat default knihovny: kontrola audience je v obou jazycích vaše práce, stejně jako expiry.

Jedna poctivá drobnost ze stejného běhu. GET na endpoint odpověděl 404 na Express zapojení a 400 Bad Request: Missing session ID na pythoním, kde specifikace žádá 405 Method Not Allowed a kde „session ID“ je slovník, který tahle revision odstranila. Ani jedno není nebezpečné; obojí je tvar ekosystému uprostřed migrace.

Poslední část shipping je místo publikování a má odpověď s číslem. Dnes procházeno: každý server v oficiálním registru v nejnovější verzi:7

servers
total (latest version, not deleted)28 170
active / deprecated27 853 / 317
ship at least one installable package13 065
remote only — a URL, nothing to install14 696
npm8 275
PyPI3 603
OCI images867
mcpb bundles706
NuGet / Cargo107 / 43

Dvě čtení, mířící opačnými směry. Podle publikovaných serverů vede npm 2,3 ku 1 — číslo, které lidé citují, když říkají, že ekosystém je TypeScript. Podle downloads vede Python: za posledních třicet dní vzalo mcp 286,7 milionu proti @modelcontextprotocol/sdk na 194,7 milionu, před přičtením fastmcp na 72,1 milionu.7 Obojí je Tier 1, normativní schema je schema.ts a oficiální tutorial „Build an MCP server“ začíná na záložce Python.1 Ať jste měli v hlavě kteroukoli polovinu, pravdivá je i ta druhá.

A řádek, na kterém záleží víc než na obou: víc než polovina registru — 14 696 z 28 170 — nemá nic k instalaci. To jsou webové služby. Počty transportů souhlasí z druhé strany: z 14 290 package entries deklaruje 13 787 stdio; z 16 640 remote entries deklaruje 15 570 Streamable HTTP a 1 070 stále deklaruje deprecated HTTP+SSE. Takže „MCP server je subprocess na vašem laptopu“ popisuje zmenšující se menšinu a každý jeden z těch 14 696 potřebuje sekci výše, ne environment variable.

Zobrazit podrobnosti

Záměrně dvojjazyčné a precedent k tomu.

Tohle je jediná dvojjazyčná kapitola v kurzu, protože poctivá odpověď se štěpí: registry je npm-first a downloads jsou Python-first, zároveň, dnes. Napsat jen jednu z obou variant by znamenalo vzdát se poloviny otázky a přitom špatně popsat ekosystém. Precedent existuje otevřeně — Hugging Face MCP Course uvádí mezi prerequisites „Experience with at least one programming language (Python or TypeScript examples will be shown)“ a učí obojí.8 Protocol, jehož celá hodnota stojí na počtu implementací, je špatné místo pro monolingual přístup.

Datovaná sekce: všechno výše, co má trvanlivost

Odkaz na sekci: Datovaná sekce: všechno výše, co má trvanlivost

Čteno a měřeno 7. září 2026 proti protocol revision 2026-07-28.

value
@modelcontextprotocol/sdk1.30.0, publikováno 27. července 2026; 4 322 438 bajtů rozbaleno, 693 souborů, 17 direct dependencies
latest revision it implements2025-11-25
mcp (PyPI)2.1.1, publikováno 25. srpna 2026; wheel o 357 912 bajtech plus mcp-types 2.1.1 o 69 656 bajtech
latest revision it implements2026-07-28
SDK tiersTypeScript, Python, C#, Go, Rust na Tier 1; Java, Ruby na Tier 2; Swift, PHP, Kotlin na Tier 3
registry servers28 170
downloads, last 30 daysmcp 286 653 871 · fastmcp 72 097 269 · @modelcontextprotocol/sdk 194 679 333

Jedna migrační poznámka, která není číslem. V mcp 2.x bylo FastMCP přejmenováno na MCPServer a skoro každý online tutorial pořád začíná starým importem. SDK dodává modul, jehož jediným účelem je to vysvětlit, což je nejohleduplnější deprecation v této kapitole:

from mcp.server.fastmcp import FastMCPTEXT
ModuleNotFoundError: No module named 'mcp.server.fastmcp'. This is mcp 2.x,
where FastMCP was renamed to MCPServer (from mcp.server.mcpserver import
MCPServer) and other APIs changed; see the migration guide … or pin 'mcp<2'
to keep running v1 code.

S tabulkou před očima je doporučení nudné, což je dobré znamení.

Pokud server žije uvnitř webové aplikace, kterou už provozujete, napište ho v TypeScriptu. Stejný proces, stejný deploy, stejný request handler; Streamable HTTP je endpoint, který přidáte vedle ostatních; a 13,9 MiB i 145 ms jsou zdarma, protože runtime už běžel. To je většina z 14 696 remote serverů.

Pokud server obaluje data tooling, napište ho v Pythonu. To, co vystavujete, je pandas, warehouse client, notebook transformací a server v jiném jazyce by byl subprocess call převlečený za schema. Sedm set milisekund importu ve službě, která startuje jednou, není náklad; v subprocessu, který host restartuje celý den, je.

A prozatím oba argumenty přebíjí řádek revision. Pokud potřebujete 2026-07-28 — multi-round-trip requests, resultType, cache hints, server/discover — jedno z těch dvou SDK to dnes má a druhé ne.

Teď můžete nasadit tentýž server v kterémkoli jazyce, obhájit volbu tabulkou místo preference, spustit ho přes oba živé transporty a předat mu token, který odmítne.

To, co jste postavili, je pořád function: schema, endpoint, deterministická věc, kterou model vyvolává. Celá třída znalostí se do toho tvaru nevejde — jak my píšeme postmortem, která pole naše incident reports potřebují, v jakém pořadí věci děláme a proč. Je to procedura, je to próza, a nutit to do popisu tool je způsob, jak system prompts narostou na dva tisíce tokens placených v každém jednotlivém turn, ať se konverzace incidentů týká, nebo ne.

Kapitola 28 je druhá odpověď: složka s SKILL.md uvnitř, kterou model čte místo volání, načtená ve třech úrovních tak, že referenční materiál nestojí skoro nic až do turn, kdy je potřeba. Nemá hlavní jazyk, a to je první věc, kterou učí.


Všechno zde bylo měřeno 7. září 2026 na Node 22.22.3 a Python 3.14.4 proti @modelcontextprotocol/sdk 1.30.0 s zod 3.25.76 a mcp 2.1.1, každé nainstalované do vlastního zahazovacího adresáře. Časy jsou mediány 25 spuštění, wall clock od spawn po řádek nesoucí odpověď tools/list; počty token jsou o200k_base přes tiktoken nad JSON každé definice. Nebylo voláno žádné placené API: nic zde nepotřebuje model.

Dva servery mají 81 a 63 neprázdných řádků; jeden z jejich tří tools je výše reprodukován v obou jazycích a další čtyři registrace se liší jen popsaným způsobem. Python SDK error-disclosure policy je citovaná z docstrings ToolError a UnexpectedToolError v mcp/server/mcpserver/exceptions.py; pretty-printing default je pydantic_core.to_json(result, fallback=str, indent=2) v mcp/server/mcpserver/resources/types.py a utilities/func_metadata.py. Konstanty protocol-version jsou LATEST_PROTOCOL_VERSION v mcp_types/version.py a v TypeScript SDK types.js, obojí čtené z nainstalovaných packages, ne z changelog.

  1. SDKs, modelcontextprotocol.io/docs/sdk, a Build an MCP server, modelcontextprotocol.io/docs/develop/build-server, obojí čteno 7. září 2026. Zdroj tier table, věty „Each SDK provides the same functionality but follows the idioms and best practices of its language“, pořadí jazykových záložek v tutorialu (Python, TypeScript, Java, Kotlin, C#, Ruby, Rust, Go) a citovaného logging rule o print() a stdout. 2 3 4

  2. stdio transport, .../basic/transports/stdio. Zdroj newline framingu a pravidla purity stdout. Kapitola 26 čte tuto stránku celou; tady je citovaná kvůli řádku, který rozbitý server porušuje.

  3. MCP Inspector, modelcontextprotocol.io/docs/2026-07-28/tools/inspector, čteno 7. září 2026. Jeden package, tři clients za jedním binary — web, --cli a --tui — sdílející jedno core, jednu sadu transportů a jeden OAuth state na disku. CLI vyprodukovalo catalogue traces zde.

  4. Authorization, modelcontextprotocol.io/specification/2026-07-28/basic/authorization, čteno 7. září 2026. Zdroj role resource-server; čtyř plně citovaných klauzulí pro nakládání s token; požadavku, aby servery implementovaly RFC 9728 a clients ho používaly pro discovery; pravidel parametru resource a definice kanonického URI; tabulky validace issuer; deprecation Dynamic Client Registration; tabulky 401/403/400 a challenge insufficient_scope; a výjimky pro stdio: „Implementations using an STDIO transport SHOULD NOT follow this specification, and instead retrieve credentials from the environment.“ 2 3 4

  5. Streamable HTTP, .../basic/transports/streamable-http, a Transports overview, .../basic/transports. Zdroj pravidla POST na jeden endpoint, dvojitého požadavku Accept, hlavičky MCP-Protocol-Version a jejího pravidla must-match-the-body, hlaviček Mcp-Method a Mcp-Name popsaných jako „REQUIRED for compliance“, odstranění GET stream, sessions a Last-Event-ID, guidance 405, povinné validace Origin a klasifikace transportu HTTP+SSE z 2024-11-05 jako Deprecated pod SEP-2596. 2 3 4

  6. Čtyři RFC, o která se specifikace opírá, s draftem, který profiluje: The OAuth 2.1 Authorization Framework, draft-ietf-oauth-v2-1-13. Campbell, B., Bradley, J. and Tschofenig, H., Resource Indicators for OAuth 2.0, RFC 8707, únor 2020 — parametr resource a audience, kterou váže. Jones, M.B., Hunt, P. and Parecki, A., OAuth 2.0 Protected Resource Metadata, RFC 9728, duben 2025 — dokument, na který ukazuje 401. Meyer zu Selhausen, K. and Fett, D., OAuth 2.0 Authorization Server Issuer Identification, RFC 9207, březen 2022 — parametr iss a porovnání přesným stringem. Richer, J. (ed.) et al., OAuth 2.0 Dynamic Client Registration Protocol, RFC 7591, červenec 2015, deprecated pro toto použití. A Jones, M. and Hardt, D., The OAuth 2.0 Authorization Framework: Bearer Token Usage, RFC 6750, říjen 2012, sekce 3, pro tvar challenge WWW-Authenticate výše.

  7. Oficiální MCP registry, registry.modelcontextprotocol.io/v0/servers, crawled 7. září 2026 pomocí version=latest: 282 stránek, 28 170 serverů, sečteno podle registryType nad distinct server names. Download figures: api.npmjs.org/downloads/point/last-month pro @modelcontextprotocol/sdk (194 679 333 za 8. srpna – 6. září 2026) a pypistats.org/api/packages/<name>/recent pro mcp a fastmcp, obojí čteno tentýž den. Package sizes pocházejí z npm registry document a PyPI JSON API. 2

  8. MCP Course, Hugging Face, huggingface.co/learn/mcp-course, unit 0, čteno 7. září 2026: mezi prerequisites „Experience with at least one programming language (Python or TypeScript examples will be shown)“.

Necháte výběr modelu na LIA?

Tvořte se všemi modely AI na jednom místě – začněte ještě dnes zdarma.