MCP in Depth: build MCP servers in TypeScript · Part 1 of 9

What is MCP? Model Context Protocol explained

The video for this part is on its way to the channel. The written lesson comes first so you can start now.

Every AI app that wants to touch your files, your database or your tickets used to need its own custom integration. MCP is the attempt to replace that with one shared plug. If you want the comparison with regular APIs first, read MCP vs API: what is the difference?.

The three roles#

  • Host: the AI app a person uses, for example a desktop chat app, a terminal agent or an IDE.
  • Client: a connection manager inside the host. The host creates one client per server.
  • Server: a small program that offers capabilities. It can run on your machine or remotely.

A server can offer tools (the model calls them), resources (the app reads them as context) and prompts (the user picks them). This part uses tools only.

Set up#

You need Node.js 20 or newer. Create a folder and install the SDK, zod for the input schema, and tsx to run TypeScript directly:

bash
mkdir repopilot && cd repopilot
npm init -y
npm pkg set type=module
npm i @modelcontextprotocol/sdk zod
npm i -D tsx typescript

Your first server#

One tool, add. It is deliberately boring so the protocol is the only new thing:

ts
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: "repopilot", version: "0.1.0" });

server.registerTool(
  "add",
  {
    description: "Add two numbers.",
    inputSchema: { a: z.number(), b: z.number() },
  },
  async ({ a, b }) => ({
    content: [{ type: "text", text: String(a + b) }],
  }),
);

await server.connect(new StdioServerTransport());

Save it as server.ts. Three things worth noticing:

  1. The description is for the model. It is the only thing telling it when to use the tool.
  2. The input schema is zod. The SDK turns it into JSON Schema and validates every call for you.
  3. The result is a list of content blocks, not a bare value.

Run it in the Inspector#

Do not wire a server into an AI app before you have seen it work alone. The MCP Inspector is a small web UI that acts as a client:

bash
npx @modelcontextprotocol/inspector npx tsx server.ts

Open the URL it prints, connect, open the Tools tab, run add with a = 2 and b = 3. You should get 5.

The stdio rule. With stdio, stdout is the protocol. A stray console.log breaks the connection in confusing ways. Log with console.error, which goes to stderr.

Register it in an AI app#

In Claude Code, one command registers a local stdio server:

bash
claude mcp add repopilot -- npx tsx /absolute/path/to/server.ts

Other apps take the same command and arguments in their MCP settings file. Ask the app to add two numbers and watch it pick your tool.

What you learned#

  • MCP has three roles: host, client and server.
  • A tool is a name, a description for the model, an input schema and a handler.
  • stdio servers must keep stdout clean.
  • Test with the Inspector before connecting an app.

Next up: real tools for RepoPilot, starting with git_log and git_diff.

Frequently asked questions

What does MCP stand for?

Model Context Protocol.

What is the difference between an MCP host, client and server?

The host is the AI app the user talks to. It creates one client per server connection. The server is the program that offers tools, resources and prompts.

Why must an MCP stdio server never print to stdout?

With the stdio transport, stdout carries the protocol messages. Anything else written there corrupts the stream. Log to stderr with console.error instead.