πŸ€– HarDojo
Log in Sign up

Your First MCP Server (TypeScript)

Build a working MCP server in ~40 lines with the official SDK.

Let's build a tiny MCP server that exposes one tool: a calculator the AI can call. We'll use the official TypeScript SDK.

Setup

mkdir my-mcp && cd my-mcp
npm init -y
npm install @modelcontextprotocol/sdk zod
npm install -D typescript tsx @types/node

The server

Create index.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: "calc", version: "1.0.0" });

server.tool(
  "multiply",
  "Multiply two numbers",
  { a: z.number(), b: z.number() },
  async ({ a, b }) => ({
    content: [{ type: "text", text: String(a * b) }],
  })
);

await server.connect(new StdioServerTransport());

Run it: npx tsx index.ts (it waits silently on stdin β€” that's correct).

Register it in a client

{
  "mcpServers": {
    "calc": {
      "command": "npx",
      "args": ["tsx", "/full/path/to/index.ts"]
    }
  }
}

Now ask your client: "Use the calculator to multiply 24 by 7." The model calls multiply({a:24, b:7}) and gets 168.

What just happened

  1. McpServer declares our server and its capabilities.
  2. server.tool(...) registers a tool with a name, description, and a JSON schema (zod β†’ schema).
  3. The handler returns content β€” the text the model receives.
  4. StdioServerTransport speaks MCP over stdin/stdout.

Why descriptions matter

The model reads the tool name and description to decide when to call it. A tool called calc with no description will almost never be used correctly. Write descriptions for humans, because the model reads them like documentation.

You just built real infrastructure. From here, swap the calculator for a database query or an HTTP call β€” the shape is identical.
";