Building MCP Servers with TypeScript: A Comprehensive Guide

Learn how to build robust MCP servers using TypeScript. This guide covers setup, architecture, and best practices for AI agent integration on agentmarket.co.

Introduction: Why TypeScript for MCP Servers?

Hey there, fellow developers! Ever found yourself wrestling with JavaScript's quirks when building mission-critical applications? If so, you're not alone. That's where TypeScript comes to the rescue, especially when we're talking about building MCP (Modular Command Processing) servers—a cornerstone for AI agent interactions. At agentmarket.co, we're all about efficiency and reliability, and TypeScript helps us achieve just that.

TypeScript is a superset of JavaScript that adds static typing. This means you can catch errors during development rather than at runtime. For MCP servers, which handle complex logic and data flow, this can be a lifesaver. Imagine debugging a critical AI agent integration only to find a simple type mismatch causing havoc. TypeScript helps you avoid these headaches.

Setting Up Your TypeScript Environment

First things first, let's get your environment ready. You'll need Node.js and npm (or yarn) installed. If you don't have them, head over to nodejs.org and download the latest version.

Once you have Node.js and npm installed, create a new project directory and navigate into it:

mkdir my-mcp-server
cd my-mcp-server

Next, initialize your project with npm:

npm init -y

Now, let's install TypeScript and its necessary dependencies:

npm install typescript ts-node @types/node --save-dev
  • typescript: The TypeScript compiler.
  • ts-node: Allows you to run TypeScript files directly.
  • @types/node: TypeScript definitions for Node.js.

Create a tsconfig.json file to configure the TypeScript compiler:

npx tsc --init

Open tsconfig.json and configure it to your needs. A good starting point is:

{
  "compilerOptions": {
    "target": "es2020",
    "module": "commonjs",
    "outDir": "./dist",
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "skipLibCheck": true
  }
}

Building a Basic MCP Server

Let's create a simple MCP server that listens for commands and responds accordingly. Create a file named src/index.ts:

// src/index.ts

import * as http from 'http';

const server = http.createServer((req, res) => {
  if (req.method === 'POST' && req.url === '/command') {
    let body = '';
    req.on('data', (chunk) => {
      body += chunk;
    });
    req.on('end', () => {
      try {
        const command = JSON.parse(body);
        // Process the command here
        const response = {
          status: 'success',
          message: `Command received: ${command.action}`,
        };
        res.writeHead(200, { 'Content-Type': 'application/json' });
        res.end(JSON.stringify(response));
      } catch (error) {
        res.writeHead(400, { 'Content-Type': 'application/json' });
        res.end(JSON.stringify({ status: 'error', message: 'Invalid JSON' }));
      }
    });
  } else {
    res.writeHead(404, { 'Content-Type': 'text/plain' });
    res.end('Not Found');
  }
});

const port = process.env.PORT || 3000;
server.listen(port, () => {
  console.log(`Server listening on port ${port}`);
});

This code sets up a basic HTTP server that listens for POST requests on the /command endpoint. It parses the JSON payload, extracts the action, and sends back a response.

To run your server, add a script to your package.json:

"scripts": {
  "start": "ts-node src/index.ts",
  "build": "tsc",
  "serve": "node dist/index.js"
}

Now you can run:

npm run start

Your server should now be running on port 3000 (or the port specified in your environment).

Enhancing Your MCP Server with TypeScript Features

Let's leverage TypeScript's features to make our server more robust. We'll add interfaces and classes to define the structure of our commands and responses.

Create a file named src/types.ts:

// src/types.ts

export interface Command {
  action: string;
  payload: any;
}

export interface Response {
  status: 'success' | 'error';
  message: string;
  data?: any;
}

Now, update src/index.ts to use these types:

// src/index.ts

import * as http from 'http';
import { Command, Response } from './types';

const server = http.createServer((req, res) => {
  if (req.method === 'POST' && req.url === '/command') {
    let body = '';
    req.on('data', (chunk) => {
      body += chunk;
    });
    req.on('end', () => {
      try {
        const command: Command = JSON.parse(body);
        // Process the command here
        const response: Response = {
          status: 'success',
          message: `Command received: ${command.action}`,
        };
        res.writeHead(200, { 'Content-Type': 'application/json' });
        res.end(JSON.stringify(response));
      } catch (error) {
        const response: Response = {
          status: 'error',
          message: 'Invalid JSON',
        };
        res.writeHead(400, { 'Content-Type': 'application/json' });
        res.end(JSON.stringify(response));
      }
    });
  } else {
    res.writeHead(404, { 'Content-Type': 'text/plain' });
    res.end('Not Found');
  }
});

const port = process.env.PORT || 3000;
server.listen(port, () => {
  console.log(`Server listening on port ${port}`);
});

By adding types, we've made our code more readable and less prone to errors. TypeScript will now check if the data we're working with conforms to the Command and Response interfaces.

Integrating with AI Agents

The real power of MCP servers comes into play when integrating with AI agents. Let's imagine you have an AI agent that performs sentiment analysis. Your MCP server can receive text from clients, pass it to the AI agent, and return the sentiment score.

Here's a simplified example:

// src/index.ts

import * as http from 'http';
import { Command, Response } from './types';

// Mock AI Agent (replace with actual AI agent integration)
const analyzeSentiment = (text: string): number => {
  // In reality, this would call an AI agent API
  // For now, let's just return a random number between -1 and 1
  return Math.random() * 2 - 1;
};

const server = http.createServer((req, res) => {
  if (req.method === 'POST' && req.url === '/command') {
    let body = '';
    req.on('data', (chunk) => {
      body += chunk;
    });
    req.on('end', () => {
      try {
        const command: Command = JSON.parse(body);
        if (command.action === 'analyzeSentiment') {
          const text = command.payload.text;
          const sentimentScore = analyzeSentiment(text);
          const response: Response = {
            status: 'success',
            message: `Sentiment analysis complete. Score: ${sentimentScore}`,
            data: { sentimentScore },
          };
          res.writeHead(200, { 'Content-Type': 'application/json' });
          res.end(JSON.stringify(response));
        } else {
          const response: Response = {
            status: 'error',
            message: 'Unknown command',
          };
          res.writeHead(400, { 'Content-Type': 'application/json' });
          res.end(JSON.stringify(response));
        }
      } catch (error) {
        const response: Response = {
          status: 'error',
          message: 'Invalid JSON',
        };
        res.writeHead(400, { 'Content-Type': 'application/json' });
        res.end(JSON.stringify(response));
      }
    });
  } else {
    res.writeHead(404, { 'Content-Type': 'text/plain' });
    res.end('Not Found');
  }
});

const port = process.env.PORT || 3000;
server.listen(port, () => {
  console.log(`Server listening on port ${port}`);
});

In this example, we added a mock analyzeSentiment function that simulates calling an AI agent. In a real-world scenario, you would replace this with an actual API call to your AI agent.

Conclusion

Building MCP servers with TypeScript provides a robust and reliable foundation for integrating with AI agents. By leveraging TypeScript's static typing and object-oriented features, you can create more maintainable and scalable applications. Whether you're building simple command processors or complex AI-driven systems, TypeScript is a valuable tool in your arsenal. Check out agentmarket.co for more insights and resources on AI agent development!