Back to Blog

    Building Your Own MCP Server - Getting Started

    January 12, 2026
    TechnologyArtificial IntelligenceModel Context ProtocolTypescript

    TL;DR: Learn to build Model Context Protocol (MCP) servers that enable seamless AI integration with external systems. This comprehensive tutorial covers everything from setup to deployment, with working code examples and practical tools you can use immediately. Perfect for developers looking to extend AI capabilities with custom integrations.

    What is MCP?

    The Model Context Protocol (MCP) is an open standard that enables seamless integration between Large Language Model (LLM) applications and external data sources and tools. Think of it as a universal adapter that allows AI assistants to securely interact with your local files, databases, APIs, and business tools.

    Key Benefits

    • Standardized Integration: One protocol for connecting to any system
    • Security: Controlled access with granular permissions
    • Bi-directional Communication: Real-time interaction between AI and external systems
    • Extensible: Support for tools, resources, and prompt templates

    Architecture Overview

    MCP follows a client-server architecture inspired by the Language Server Protocol (LSP):

    Core Components

    1. MCP Host: The AI application (e.g., Claude Desktop, Cursor, Zed)
    2. MCP Client: Manages connections and protocol communication
    3. MCP Server: Your custom server exposing tools and resources
    4. Transport Layer: Communication mechanism (stdio, Streamable HTTP)

    Setting Up Your Development Environment

    Prerequisites

    # Node.js 18+ and npm
    node --version  # Should be 18+
    npm --version
    
    # TypeScript (recommended)
    npm install -g typescript
    
    # MCP Inspector for testing
    npm install -g @modelcontextprotocol/inspector
    

    Project Initialization

    # Create new project
    mkdir my-mcp-server
    cd my-mcp-server
    
    # Initialize package.json
    npm init -y
    
    # Install core dependencies
    npm install @modelcontextprotocol/sdk
    
    # Install development dependencies
    npm install -D typescript @types/node ts-node
    

    TypeScript Configuration

    Create tsconfig.json:

    {
      "compilerOptions": {
        "target": "ES2020",
        "module": "ESNext",
        "moduleResolution": "node",
        "rootDir": "./src",
        "outDir": "./dist",
        "strict": true,
        "esModuleInterop": true,
        "allowSyntheticDefaultImports": true,
        "skipLibCheck": true,
        "forceConsistentCasingInFileNames": true,
        "resolveJsonModule": true,
        "types": ["node"]
      },
      "include": ["src/**/*"]
    }
    

    Package.json Scripts

    Update your package.json:

    {
      "name": "my-mcp-server",
      "version": "1.0.0",
      "type": "module",
      "main": "dist/server.js",
      "scripts": {
        "build": "tsc",
        "start": "node dist/server.js",
        "dev": "ts-node --esm src/server.ts",
        "inspect": "npx @modelcontextprotocol/inspector node dist/server.js"
      }
    }
    

    Building Your First MCP Server

    Basic Server Structure

    Create src/server.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";
    
    // Create the MCP server
    const server = new McpServer({
      name: "My First MCP Server",
      version: "1.0.0",
    });
    
    // Add your first tool (using modern register API)
    server.registerTool(
      "hello_world",
      {
        description: "Say hello with a custom message",
        inputSchema: {
          message: z.string().describe("Message to display")
        }
      },
      async ({ message }: { message: string }) => {
        return {
          content: [
            {
              type: "text",
              text: `Hello, ${message}! This is your first MCP tool.`,
            },
          ],
        };
      }
    );
    
    // Add a simple file reader tool
    server.registerTool(
      "read_file",
      {
        description: "Read content from a file",
        inputSchema: {
          path: z.string().describe("File path to read")
        }
      },
      async ({ path }: { path: string }) => {
        try {
          const fs = await import('fs/promises');
          const content = await fs.readFile(path, 'utf-8');
    
          return {
            content: [
              {
                type: "text",
                text: content,
              },
            ],
          };
        } catch (error) {
          return {
            content: [
              {
                type: "text",
                text: `Error reading file: ${error instanceof Error ? error.message : 'Unknown error'}`,
              },
            ],
          };
        }
      }
    );
    
    // Start the server
    async function main() {
      const transport = new StdioServerTransport();
      await server.connect(transport);
      console.error("🚀 MCP Server started successfully!");
    }
    
    // Error handling
    process.on('uncaughtException', (error) => {
      console.error('❌ Uncaught exception:', error);
      process.exit(1);
    });
    
    process.on('unhandledRejection', (reason, promise) => {
      console.error('❌ Unhandled rejection:', reason);
      process.exit(1);
    });
    
    main().catch((error) => {
      console.error('❌ Failed to start server:', error);
      process.exit(1);
    });
    

    Testing Your Server

    # Build and test
    npm run build
    npm run inspect
    
    # This opens the MCP Inspector web interface
    # where you can test your tools interactively
    

    Connecting to Claude Desktop

    To use your server with Claude Desktop, add it to your configuration:

    // Claude Desktop config
    // macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
    // Windows: %APPDATA%\Claude\claude_desktop_config.json
    {
      "mcpServers": {
        "my-first-server": {
          "command": "node",
          "args": ["/absolute/path/to/your/dist/server.js"],
          "env": {}
        }
      }
    }
    

    After adding this configuration:

    1. Restart Claude Desktop
    2. You should see your tools available in the interface
    3. Try asking Claude to use your hello_world tool!

    Key Concepts Learned

    • MCP Server Structure: Basic setup with McpServer and transport
    • Modern APIs: Using registerTool with JSON Schema validation
    • Error Handling: Proper async error handling and process management
    • Testing: Using MCP Inspector for development and debugging
    • Integration: Connecting your server to Claude Desktop

    © 2026 Harmanpreet Singh. All rights reserved.