Build Your First MCP Server in 20 Minutes (TypeScript)

Published: (March 8, 2026 at 12:28 AM EST)
3 min read
Source: Dev.to

Source: Dev.to

Overview

MCP (Model Context Protocol) lets AI assistants call external tools directly. This guide shows how to build a simple MCP server in TypeScript that extracts structured data from text.

Prerequisites

  • Node.js 18+
  • TypeScript
  • An MCP‑compatible client (e.g., Claude Desktop, Cursor)

Project Setup

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

tsconfig.json

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

Note: The MCP SDK requires module: "Node16" and moduleResolution: "Node16".

Server Implementation (src/index.ts)

#!/usr/bin/env node

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

// -------------------------------------------------------------------
// Tool definition
// -------------------------------------------------------------------
server.tool(
  "my_tool_name",
  "Description of what this tool does",
  {
    // Parameters defined with Zod
    input_text: z.string().describe("The text to process"),
    format: z.enum(["json", "csv"]).optional().describe("Output format"),
  },
  async ({ input_text, format }) => {
    // Your logic here
    const result = await processText(input_text, format);

    return {
      content: [
        {
          type: "text" as const,
          text: JSON.stringify(result, null, 2),
        },
      ],
    };
  }
);

// -------------------------------------------------------------------
// Server startup
// -------------------------------------------------------------------
async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
}

main().catch(console.error);

Tool Definition Breakdown

PartPurpose
NameIdentifier the AI uses to call the tool
DescriptionHelps the AI decide when to use it
SchemaZod schema describing parameters
HandlerAsync function that performs the work

Build and Run

npx tsc
node dist/index.js

The server now listens for MCP messages on stdin.

Testing with MCP Inspector

npx @modelcontextprotocol/inspector node dist/index.js

Registering the Server with Claude Desktop

Add the following entry to ~/Library/Application Support/Claude/claude_desktop_config.json:

{
  "mcpServers": {
    "my-tool": {
      "command": "node",
      "args": ["/absolute/path/to/dist/index.js"]
    }
  }
}

Restart Claude Desktop; the tool will appear in the tools menu.

Wrapping a REST API as an MCP Tool

server.tool(
  "extract_data",
  "Extract structured JSON from unstructured text",
  {
    text: z.string().describe("Text to extract from"),
    schema: z.enum(["receipt", "invoice", "email", "resume"]),
  },
  async ({ text, schema }) => {
    const response = await fetch("https://your-api.com/extract", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ text, schema }),
    });

    const result = await response.json();

    return {
      content: [
        {
          type: "text" as const,
          text: JSON.stringify(result.data, null, 2),
        },
      ],
    };
  }
);

Best Practices

  • Be specific in tool descriptions; the AI uses them to choose the right tool.
  • Use zod .describe() on every parameter to guide the AI.
  • Return results with type: "text"; the AI can parse JSON from plain text.
  • Handle errors gracefully: return an error message as text instead of throwing.

Skip the Tutorial – Use a Ready‑Made Server

git clone https://github.com/avatrix1/structureai-mcp.git
cd structureai-mcp && npm install && npm run build

This pre‑built server extracts structured data from receipts, invoices, emails, and more. It includes 10 free requests and requires no API key.

Built by Avatrix LLC. Full source:

0 views
Back to Blog

Related posts

Read more »