What Is MCP, Really? A Real Server, Tested Against the Actual Protocol
Description and use
MCP enables a tool to be exposed as a server that any client can use without additional integration code. The article demonstrates a weather server tested against the real protocol and fixes a top‑level await issue.
Problem
Tools were duplicated across projects, requiring manual sync of function, schema, and description.
Outcome
The MCP server correctly lists tools and returns weather data for Dhaka, demonstrating that the protocol works in a real subprocess environment.
Workflow
- Define weather data and create an MCP server with a get_weather tool.
- Register the tool with title, description, and Zod input schema.
- Wrap server startup in an async main() to support top‑level await.
- Spawn the server as a subprocess via StdioServerTransport.
- Create an MCP client with StdioClientTransport pointing to the server process.
- List available tools and call get_weather with a city argument.
- Close the client connection.
Evidence
Every tool in this series so far was wired directly into one project. Fine once — until a second project wants the same tool, and you're copying the function, schema, and description, keeping both in sync by hand.
Anthropic introduced MCP in November 2024. OpenAI and Google both adopted it within months. In December 2025, Anthropic donated the protocol to the Agentic AI Foundation, a vendor-neutral Linux Foundation project co-founded with Block and OpenAI.
Same name, same description, same one field as the get_weather tool from the tool-calling post — inputSchema just takes Zod validators instead of hand-written JSON Schema, and the SDK converts it.
This spawns the server as a real subprocess and does the actual MCP handshake — not a mock.
The first version ended with a bare top-level await server.connect(transport). Type-checked fine. The client connection closed immediately on run. The cause: this file's execution transforms it to a module format that doesn't support top-level await, crashing the process before the server could listen — nothing to do with MCP itself, but exactly where an MCP server's entrypoint sits. Wrapping it in an async main() fixed it completely.
- Record date: 2026-10-16T15:40:59.888Z