Lesson 16 built a working MCP server in Python: FastMCP, Pydantic models, decorators, a docstring that doubled as the tool's description. The protocol that server speaks — JSON-RPC over stdio, tools with a name and a JSON-Schema input, structured results — is identical no matter which SDK emits it. This lesson builds the same tickets server again, this time in TypeScript, and the point is not to relearn what a tool or a transport is.
The point is what genuinely changes when the implementation language changes. Zod replaces Pydantic as the input contract, but with a sharper edge: `z.infer` derives the handler's parameter type directly from the schema object, so there is no second place for the type to quietly disagree with the validation. The TypeScript SDK does not read your handler's JSDoc comment the way FastMCP reads a Python docstring — description is a field you set explicitly, or it ships empty. And a `npm run build` step exists that Python's interpreter never gives you: a schema and a handler that no longer agree is a compile error, not a runtime surprise months later.
By the end of this lesson you will have written `SearchTicketsInputSchema` as a Zod object and derived its TypeScript type from it, registered a tool with `registerTool` carrying an explicit description and all four annotation hints, returned both `content` and `structuredContent` from the same handler, wired stdio transport with the `console.error` logging rule strictly observed, and compiled and inspected the result with the official tools rather than guessing at correctness.