How to Build an MCP Server in TypeScript

Install the official package @modelcontextprotocol/server and Zod, create an McpServer with a name and version, register each tool with registerTool, a description and a Zod input schema, then connect a StdioServerTransport. Run npx @modelcontextprotocol/inspector to call your tools by hand before any AI application touches them.

The pieces you need
PieceWhere it comes fromWhat it does
McpServer@modelcontextprotocol/serverHolds your tools and answers protocol requests
registerToolMethod on McpServerAdds one tool: name, description, input schema, handler
StdioServerTransport@modelcontextprotocol/server/stdioTalks to the host over standard input and output
z.object(...)zod/v4Describes and validates the tool's arguments
Inspectornpx @modelcontextprotocol/inspectorLets you list and call tools by hand

Updated

Tick off each step as you go. The checklist keeps your place, and every step has the exact command or file you need. The finished server searches a small list of notes, which is enough to see every moving part without a database.

Build checklist

  1. Make a project folder and a package.json
    mkdir notes-server && cd notes-server
  2. Install the SDK, Zod and a TypeScript runner
    npm install @modelcontextprotocol/server zod
    npm install --save-dev tsx typescript
  3. Write server.ts with one tool
    server.registerTool('notes_search', { ... }, handler)
  4. Start the server once to check it does not crash
    npx tsx server.ts
  5. Open the Inspector and connect to your server
    npx @modelcontextprotocol/inspector
  6. List tools and call notes_search by hand
    tools/list, then tools/call with { "query": "invoice" }

The complete server

Two files. Change the notes array to whatever your server should search.

package.json

type module lets the ES import syntax run directly; the start script uses tsx so you skip a build step.

{
  "name": "notes-server",
  "version": "1.0.0",
  "type": "module",
  "scripts": { "start": "tsx server.ts" }
}

server.ts

One tool with a Zod schema, a plain search function and a stdio connection. Logging goes to stderr so it never mixes with protocol messages.

import { McpServer } from '@modelcontextprotocol/server';
import { StdioServerTransport } from '@modelcontextprotocol/server/stdio';
import * as z from 'zod/v4';

const notes = [
  { title: 'Invoice March', body: 'Sent to the printer, paid on the 12th' },
  { title: 'Invoice April', body: 'Waiting on the client' },
  { title: 'Team lunch', body: 'Friday at noon' },
];

function search(query: string) {
  const q = query.toLowerCase();
  return notes.filter((n) => (n.title + ' ' + n.body).toLowerCase().includes(q));
}

const server = new McpServer({ name: 'notes-server', version: '1.0.0' });

server.registerTool(
  'notes_search',
  {
    description: 'Find notes whose title or text contains a word. Use it before answering questions about the notes.',
    inputSchema: z.object({ query: z.string().min(1) }),
  },
  async ({ query }) => {
    const hits = search(query);
    const text = hits.length
      ? `${hits.length} notes match: ${hits.map((n) => n.title).join(', ')}`
      : `No notes contain "${query}".`;
    return { content: [{ type: 'text', text }] };
  },
);

async function main() {
  await server.connect(new StdioServerTransport());
  console.error('notes-server running on stdio');
}

main();

Test it with the Inspector

The Inspector has three modes. The web UI is the easiest place to start; the CLI mode suits scripts and CI.

Inspector modes

In the web UI, connect with the command that starts your server (npx tsx server.ts), then open the tools list.

npx @modelcontextprotocol/inspector         # web UI
npx @modelcontextprotocol/inspector --cli   # command line
npx @modelcontextprotocol/inspector --tui   # terminal UI

Why stdio first

A stdio server is just a program the host starts. There is no port, no hosting and no login, which makes it the quickest route to a working tool you can test on your own machine.

Once the tools behave, moving to Streamable HTTP changes the transport line and the hosting, not the tool code. That separation is the main reason to keep business logic in plain functions the handlers call.

Designing the handler's answer

A handler returns an object with a content array. Text items are the common case, and short, specific text works best: say what matched and how many, rather than dumping a whole record set.

When nothing matches, return a sentence that says so. An empty string leaves the model guessing whether the call failed or the search was simply empty.

How it works

  1. Create a folder, add the package.json shown below and install the two dependencies.
  2. Paste server.ts and change the notes array to your own data or an API call.
  3. Start the Inspector and point it at the command that runs your server.
  4. List the tools, call notes_search with a word and confirm the text that comes back.

Tips

Frequently asked questions

Which npm package do I install?

For SDK version 2, install @modelcontextprotocol/server for servers and @modelcontextprotocol/client for clients. The older v1 package, @modelcontextprotocol/sdk, lives on a v1.x branch and gets bug and security fixes for at least six months after the v2 release.

Do I need Zod?

The v2 README uses Zod v4 for input schemas and imports it from zod/v4, and it says other Standard Schema libraries such as Valibot and ArkType also work. Install whichever you choose alongside the SDK.

Can the server run on Bun or Deno?

The SDK README says it runs on Node.js, Bun and Deno. The Inspector is a separate Node tool and its README asks for Node 22.19.0 or newer.

How do I make the server available remotely?

Swap the stdio transport for Streamable HTTP and host the process somewhere reachable. Add authentication before you expose any tool that changes data, since anyone who can reach the URL can send requests.

How do I know an AI application will understand my tool?

Read your description and schema as if you knew nothing else about the project. If a stranger could not tell when to call the tool and what to pass, a model will guess too. The Inspector shows exactly what a host will see.

Related: What is an MCP server?, How to build an AI agent, JSON Schema generator, Install Node and npm on a Mac, TypeScript vs JavaScript.

Start for free or see all free tools. We.Inc is free to start, with no card needed. AI building is on paid plans from $20 a month.

More in Guides

We.Inc is an AI-powered website builder you can resell under your own brand. Launch a branded client dashboard, bill on Stripe Connect, and deliver AI-generated websites in minutes. White-label plans start at $99 a month for 25 client sites, with a 7-day free trial and no per-site fees.

Product

Who It's For

Features

Resources

Company

View Sitemap