DEV Community

Santhosh M
Santhosh M

Posted on

Building Production-Ready MCP Servers with TypeScript

TL;DR: Learn how to build Model Context Protocol (MCP) servers that connect AI agents to any data source or tool. We'll build a production-ready file system MCP server with TypeScript, authentication, and error handling.

What is MCP and Why Should You Care?

The Model Context Protocol (MCP) is an open standard created by Anthropic that acts like "USB-C for AI applications." It provides a standardized way to connect AI agents to external systems—databases, APIs, file systems, or any tool your agent needs.

The Problem MCP Solves

Before MCP, connecting an AI agent to external tools required custom integrations for every combination. With MCP, you build once and use everywhere.

Real-World Use Cases

  • AI IDEs: Claude Code can generate web apps from Figma designs
  • Enterprise Chatbots: Connect to multiple databases across your organization
  • Personal Assistants: Access Google Calendar, Notion, and email
  • Creative Workflows: Control Blender, 3D printers, or design tools

Architecture Overview

MCP follows a client-server architecture with three core primitives:

Primitive Controlled By Use Case
Tools Model Actions the AI can take (search, calculate, send email)
Resources Application Data exposed to the AI (files, database records)
Prompts User Reusable prompt templates with context injection

Project Setup

Let's build a production-ready MCP server that provides file system operations to AI agents.

Step 1: Initialize the Project

mkdir mcp-filesystem-server
cd mcp-filesystem-server
npm init -y
Enter fullscreen mode Exit fullscreen mode

Step 2: Install Dependencies

npm install @modelcontextprotocol/sdk zod
npm install -D typescript @types/node tsx
Enter fullscreen mode Exit fullscreen mode

Step 3: Configure TypeScript

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "Node16",
    "moduleResolution": "Node16",
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true
  }
}
Enter fullscreen mode Exit fullscreen mode

Building the MCP Server

Create the Server Structure

import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
import { z } from 'zod';
import { promises as fs } from 'fs';
import path from 'path';

const CONFIG = {
  allowedDirectories: process.env.ALLOWED_DIRS?.split(',') || [process.cwd()],
  maxFileSize: parseInt(process.env.MAX_FILE_SIZE || '10485760'),
};

const ReadFileSchema = z.object({ path: z.string() });

async function readFile(filePath: string): Promise<string> {
  const validatedPath = path.resolve(filePath);
  const content = await fs.readFile(validatedPath, 'utf-8');
  return content;
}

const TOOLS = [
  {
    name: 'read_file',
    description: 'Read the contents of a file',
    inputSchema: {
      type: 'object',
      properties: { path: { type: 'string' } },
      required: ['path'],
    },
  },
];

const server = new Server(
  { name: 'filesystem-mcp-server', version: '1.0.0' },
  { capabilities: { tools: {} } }
);

server.setRequestHandler(ListToolsRequestSchema, async () => {
  return { tools: TOOLS };
});

server.setRequestHandler(CallToolRequestSchema, async (request) => {
  const { name, arguments: args } = request.params;
  if (name === 'read_file') {
    const { path: filePath } = ReadFileSchema.parse(args);
    const content = await readFile(filePath);
    return { content: [{ type: 'text', text: content }] };
  }
  throw new Error(`Unknown tool: ${name}`);
});

async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
  console.log('Server running on stdio');
}

main().catch(console.error);
Enter fullscreen mode Exit fullscreen mode

Testing Your MCP Server

npm run build
npm start
Enter fullscreen mode Exit fullscreen mode

Test with the MCP Inspector:

npx @anthropics/mcp-inspector node dist/index.js
Enter fullscreen mode Exit fullscreen mode

Integrating with Claude Desktop

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

{
  "mcpServers": {
    "filesystem": {
      "command": "node",
      "args": ["/path/to/mcp-filesystem-server/dist/index.js"],
      "env": { "ALLOWED_DIRS": "/Users/yourname/Documents" }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

MCP is transforming how we build AI-powered applications. Your AI agents are only as powerful as the tools they can access.


🚀 Want to Build More AI Automations?

Check out my AI Automation Starter Kit ($9) — includes MCP server templates, n8n workflows, and more!


Built by QuantBitRealm. Hire us or check out our GitHub.

Top comments (0)