Skip to content

How to Build Your Own MCP Server (Node + TypeScript)

Build a minimal MCP server from scratch with the official TypeScript SDK, expose one tool over stdio, connect it to Claude Code, and test it end to end.

MGMCSA Guru Team January 8, 2026 5 min read
A minimal TypeScript MCP server exposing a single tool, connected to Claude Code in a terminal

The fastest way to understand MCP is to build a server. You don’t need a database or a network service to start — a single tool that does one small thing is enough to see the whole loop: define a capability, connect a transport, and watch Claude Code call it.

This walkthrough builds a minimal MCP server in Node and TypeScript with the official SDK, exposes one tool, wires it into Claude Code, and tests it. If the protocol concepts are still fuzzy, read the Model Context Protocol explained first — this assumes you know what tools, resources, and transports are.

What you’ll build

A server with one tool that takes two numbers and returns their sum. Trivial on purpose: the point is the wiring, not the logic. Once the loop works, swapping in a real tool — a database query, an internal API call — is the same shape.

Before you start

  • Node.js installed (a current LTS release).
  • Claude Code installed and working.
  • A terminal — PowerShell on Windows or bash in WSL.
  • Basic comfort with TypeScript and npm.

Set up the project

Create a folder and initialize it:

mkdir add-server
cd add-server
npm init -y

Install the official TypeScript SDK and the tooling to build and validate input:

npm install @modelcontextprotocol/sdk zod
npm install -D typescript @types/node

zod defines and validates the tool’s input schema. Add a minimal tsconfig.json:

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "Node16",
    "moduleResolution": "Node16",
    "outDir": "dist",
    "strict": true
  },
  "include": ["src/**/*.ts"]
}

Write the server

Create src/index.ts. The structure is always the same: make a server, register capabilities, connect a transport.

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: "add-server",
  version: "1.0.0",
});

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

const transport = new StdioServerTransport();
await server.connect(transport);

Three things are happening. The McpServer declares the server’s name and version. registerTool adds the add tool with a description and an input schema — the description and schema are what the model reads to decide when and how to call it. Then connect attaches a stdio transport so Claude Code can launch the server as a subprocess and exchange messages over stdin/stdout.

Note the .js extensions on the SDK imports — that’s required under Node16 module resolution even though the source is TypeScript. Exact export names can shift between SDK versions, so if an import fails, check the current SDK reference rather than guessing.

Build it

Add a build script to package.json:

{
  "scripts": {
    "build": "tsc"
  }
}

Compile:

npm run build

That produces dist/index.js, the file Claude Code will run.

The three primitives, briefly

You just registered a tool. The SDK lets you register the other two MCP primitives the same way, and it’s worth seeing them side by side so you know what’s available when your server grows past a single action.

MCP primitives in the SDK

Primitive What it does
Tool An action the model can invoke
Resource Read-only data the server exposes
Prompt A reusable template the user invokes

Most servers start with one tool and add more over time. Resources and prompts are optional — reach for them when the model needs to read context or when you want to offer a canned workflow as a slash command.

Connect it to Claude Code

Register the built server with claude mcp add, pointing the command at dist/index.js. In WSL:

claude mcp add add-server -- node /home/you/add-server/dist/index.js

On native Windows, run node through the command interpreter to avoid the shim issue that bites npm-installed launchers:

claude mcp add add-server -- cmd /c node C:\Users\YourName\add-server\dist\index.js

That cmd /c wrapper and the Windows path differences are covered in depth in the Windows and WSL MCP setup guide — worth a read if the connection fails.

Test it

Start Claude Code and check the server is live:

/mcp

You should see add-server connected with one tool, add. Now ask the agent to use it:

Use the add tool to add 21 and 21.

Claude Code calls your tool, your handler returns 42, and the result comes back into the conversation. That round trip — request out over stdio, your code runs, result back — is the entire protocol in action.

Where to take it

Replace the add handler with something real and you have a useful server. A few directions:

  • Wrap an internal API so the agent can query a service you own.
  • Expose read-only data as resources — config files, logs, a status endpoint.
  • Add input validation with richer zod schemas so bad arguments fail clearly.

Keep tool descriptions specific. The model decides whether to call a tool based on its description, so “run a read-only SQL query against the analytics DB” beats “database tool” every time.

Wrapping up

A working MCP server is genuinely small: create the server, register one tool with a schema, connect a stdio transport, build, and add it to Claude Code. Everything beyond that — more tools, resources, prompts, a remote HTTP transport — is layered on the same foundation you just built.

From here, see which servers other people have already built in the best MCP servers for Claude Code roundup, so you don’t reinvent something that exists. And keep the MCP explainer handy as a reference for the primitives.

Frequently asked questions

What do I need to build an MCP server?

Node.js, the official MCP SDK for your language (TypeScript here), and a tool you want to expose. A minimal server is under 40 lines: create the server, register one tool with an input schema, and connect it to a stdio transport.

Which language should I write an MCP server in?

The official SDKs cover several languages including TypeScript and Python. TypeScript is a common pick because most local servers run via Node and npx, and the typing helps you define tool input schemas clearly.

How does Claude Code talk to my server?

Over stdio by default. Claude Code launches your server as a subprocess and exchanges JSON-RPC messages over standard input and output. You add it with claude mcp add and point the command at your built server file.

Why isn't my tool showing up in Claude Code?

Common causes: the server didn't build, the command in claude mcp add points at the wrong file, or you logged to stdout. With stdio transport, stdout is reserved for protocol messages, so any debug output must go to stderr or it corrupts the stream.

What's the difference between a tool, a resource, and a prompt?

A tool is an action the model can call, a resource is read-only data the server exposes, and a prompt is a reusable template. You can implement any combination; this guide focuses on a single tool, which is the most common starting point.

Can I write debug logs in an MCP server?

Yes, but write them to stderr, not stdout. Under stdio transport stdout carries the JSON-RPC messages, so console.log will break the connection. Use console.error or a logger configured to stderr.

Sources & further reading

Official vendor documentation referenced while writing this guide.

MG

MCSA Guru Team

IT & Systems Administration

We are working IT pros and system administrators who spend our days in Windows Server, Microsoft 365, and the wider Microsoft stack. MCSA Guru is where we write down the fixes and walkthroughs we wish we had found the first time.

MCSA Guru provides independent, educational IT guidance. Microsoft, Windows, Windows Server, Microsoft 365, Exchange, and Microsoft Teams are trademarks of Microsoft Corporation; Docker is a trademark of Docker, Inc. MCSA Guru is not affiliated with or endorsed by Microsoft or Docker. Always test changes in a safe environment before applying them in production.

Related guides

Fixing something right now?

Jump straight into the guide library or search for the exact error or task you are dealing with.