Build an MCP Server in TypeScript: A Guide

An MCP server is a program that exposes tools, data, and prompts to AI clients over the Model Context Protocol, a standard built on JSON-RPC. Because the protocol is consistent, any compatible client, Claude Code included, can discover and use your server without custom integration code. It is often described as a USB-C port for AI applications.
Start a Node project and install two packages: the official MCP SDK for TypeScript and a schema library such as Zod for validating inputs. The SDK provides a server object and a set of transports, while Zod lets you describe each tool's arguments in a shape the SDK turns into a schema the client can read.
Begin with the stdio transport while developing locally. It launches your server as a child process of the client with no networking to configure, so the first working version is quick to reach. Switch to the Streamable HTTP transport later, when the server must be reached over a network rather than launched locally.
Register it with the claude mcp add command, pointing it at the command that launches your server; other clients keep the same information in a configuration file. Once registered, the client starts the server and lists its tools automatically. Before that, test the server in isolation with the MCP Inspector to catch schema errors cheaply.
Only if you treat inputs as untrusted. An MCP server runs with whatever privileges you give it and executes on arguments the model chooses, so validate every input at the boundary, never pass it straight into a shell or query, and scope the server's access to only what it truly needs.

Key Takeaway
The Model Context Protocol lets you expose your own tools, data, and prompts to AI clients like Claude over a standard interface. Building a server in TypeScript takes only the official SDK, a transport, and a handful of typed handlers. This guide walks from an empty project to a running server a client can call.
The Model Context Protocol, or MCP, is an open standard for connecting AI clients to external tools and data through one consistent interface. Instead of writing a bespoke integration for every assistant, you build one MCP server and any compatible client, Claude Code included, can use it. It is often described as a USB-C port for AI applications.
This guide builds a small server in TypeScript from scratch. We will scaffold the project with the official SDK, expose a typed tool, connect the server to a client, and cover what changes when you move from a local prototype to something others depend on.
An MCP server is a program that exposes capabilities to AI clients over a structured protocol built on JSON-RPC. The client and server exchange messages in a defined shape, so the model can discover what the server offers and call into it without any custom glue on the client side.
You would build one when you want an assistant to reach something it cannot see on its own:
Start a Node project and install two packages: the official MCP SDK for TypeScript and a schema library such as Zod for validating inputs. The SDK gives you a server object and a set of transports; Zod lets you describe each tool's arguments in a way the SDK turns into a schema the client can read.
A minimal server that registers one tool and speaks over standard input and output looks like this:
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: "weather",
version: "1.0.0",
});
server.tool(
"get_forecast",
"Get a short weather forecast for a city",
{ city: z.string().describe("City to look up") },
async ({ city }) => ({
content: [
{ type: "text", text: "Forecast for " + city + ": sunny, 27C" },
],
})
);
const transport = new StdioServerTransport();
await server.connect(transport);Begin with the stdio transport while you develop locally. It launches the server as a child process of the client with no networking to configure, which makes the first working version far quicker to reach than a networked setup.
A tool is an action the model can choose to call. Each one needs four things, and getting them right is what makes the tool usable rather than a source of confusion.
With the server built, register it with a client. In Claude Code you add a server with the claude mcp add command, pointing it at the command that launches your server; other clients keep the same information in a configuration file. Once registered, the client starts the server and lists its tools automatically.
Before wiring it into a real assistant, test the server in isolation with the MCP Inspector, a standalone tool that connects to your server and lets you list and call its capabilities by hand. Catching a broken schema in the Inspector is far cheaper than debugging it through a chat interface.
An MCP server runs with whatever privileges you give it and executes on inputs the model chooses, so treat every argument as untrusted. Validate inputs at the boundary, never pass them straight into a shell or query, and scope the server's access to only what it truly needs.
A stdio server on your laptop is the start, not the finish. Moving to something shared or remote brings a few decisions that the local version let you ignore.
Building an MCP server in TypeScript is mostly about three moves: scaffold with the official SDK, describe each tool with a strict input schema, and pick the transport that matches where the server runs. Start local over stdio, validate every input, and you have a reusable bridge any MCP client can plug into.