ποΈ Anatomy of an MCP Server
An MCP server is a process that speaks JSON-RPC over stdio (or HTTP). At a minimum, it needs to respond to two methods: initialize (handshake) and tools/list (list tools). When the client calls a tool, the server receives it via tools/call and returns the result.
In practice, the SDK abstracts all of this. You just define the tools and their handlers. But understanding the anatomy helps you debug when something goes wrong.
In one sentence: an MCP server = a process that speaks JSON-RPC and exposes tools with schemas.
π¦ TypeScript SDK
The package @modelcontextprotocol/sdk is the fastest way to create an MCP server. With 30 lines, you have a working server. The main class is McpServer, which you instantiate, register tools with, and connect to a transport.
Installation: npm init -y && npm install @modelcontextprotocol/sdk zod. Zod is used to validate tool inputs in a type-safe way.
mkdir my-mcp-server && cd my-mcp-server npm init -y npm install @modelcontextprotocol/sdk zod touch index.ts
In one sentence: TypeScript SDK = create a working MCP server in 30 lines.
π§ Defining Tools and Input Schemas
Each tool has: name (single string), description (what it does, in natural language), and inputSchema (parameters via Zod or JSON Schema). A clear, descriptive schema is the difference between the agent getting it right on the first try and guessing.
Tip: write the description as if you were explaining it to a junior developer. The agent uses this text to decide when and how to call the tool.
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
const server = new McpServer({ name: "my-server", version: "1.0.0" });
server.tool("greet", "Say hello to someone by name", {
name: z.string().describe("The person's name")
}, async ({ name }) => ({
content: [{ type: "text", text: `Hello, ${name}!` }]
}));
const transport = new StdioServerTransport();
await server.connect(transport);In one sentence: tool = name + clear description + Zod/JSON Schema inputSchema.
β‘ Handlers and Responses
The handler is the async function that receives the validated arguments and returns a CallToolResult. The result is an array of content items, which can be text, images, or embedded resources. Errors are returned with isError: true.
Basic pattern: receive args -> run logic -> return {{ content: [{{ type: 'text', text: resultado }}] }}. For errors, return the error message in the content with isError: true.
In one sentence: handler = async function that receives args, runs logic, and returns content.
π§ͺ Testing Your Server
O MCP Inspector is the official tool for testing MCP servers. Run npx @modelcontextprotocol/inspector node index.js and it opens a web UI where you can list tools, call them with parameters, and see the responses.
Beyond the Inspector, test by integrating directly into Claude Code: add it to the local settings.json and ask the agent to use it. If it can call the tool and receive a result, itβs working.
# Testar com o MCP Inspector npx @modelcontextprotocol/inspector node index.js
In one sentence: MCP Inspector + testing in Claude Code = complete server validation.
π€ Packaging and Distribution
To share your server: (1) publish it to npm with npm publish, (2) make sure it works via npx (configure the bin in package.json), (3) optionally, list it on Smithery.ai for visibility.
If the server has heavy dependencies, consider a Docker image. This ensures it works on any machine without dependency conflicts.
In one sentence: npm publish + npx entry point + optional Smithery listing = distribution.
π§Ύ Module Summary
Next module:
3.6 β Ecosystem and Marketplace: where to find and evaluate MCPs.