Skip to main content

What is an MCP Server?

An MCP server is a program that exposes capabilities (tools, resources, and prompts) to AI applications through the Model Context Protocol. Servers run as separate processes and communicate with clients via the MCP protocol.

Creating an MCP Server

TypeScript Server

The MCP SDK for TypeScript provides the McpServer class for creating servers.
1

Install Dependencies

npm install @modelcontextprotocol/sdk zod
2

Import Required Modules

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
3

Create Server Instance

const server = new McpServer({
  name: "My MCP Server",
  version: "1.0.0",
  capabilities: {
    resources: {},
    tools: {},
    prompts: {}
  }
});
4

Connect Transport and Start

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

main().catch(error => {
  console.error(`Server error: ${error.message}`);
  process.exit(1);
});

Python Server

The FastMCP library provides a simpler API for creating Python servers.
1

Install FastMCP

pip install mcp
2

Create Server Instance

from mcp.server.fastmcp import FastMCP

mcp = FastMCP("Calculator MCP Server")
3

Run Server

if __name__ == "__main__":
    mcp.run(transport='stdio')

Real-World Server Examples

Game of Thrones Quotes Server

This server demonstrates all three capability types (tools, resources, and prompts). Location: source/servers/basic/src/server.ts
const server = new McpServer({
  name: "Game of Thrones Quotes",
  version: "1.0.0",
  capabilities: {
    resources: { listChanged: true },
    tools: {},
    prompts: {}
  }
});
Features:
  • Fetches quotes from external API
  • Provides tools for getting random quotes and calculating LCM
  • Exposes static and dynamic resources
  • Offers analysis prompts

Calculator Server (Python)

A simple calculator demonstrating Python server implementation. Location: source/servers/calculator-py/server.py:1-34
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("Calculator MCP Server")

def add(a: float, b: float) -> float:
    return float(a + b)

def subtract(a: float, b: float) -> float:
    return float(a - b)

@mcp.tool()
def calculate(a: float, b: float, operation: str) -> float:
    if operation == "add":
        return add(a, b)
    elif operation == "subtract":
        return subtract(a, b)
    elif operation == "multiply":
        return multiply(a, b)
    elif operation == "divide":
        return divide(a, b)
    else:
        raise ValueError("Operación no válida")

TODO List Server

A CRUD server for managing TODO items. Location: source/servers/todo-ts/src/index.ts:1-13
const server = new McpServer({
    name: "TODO List MCP Server",
    version: "1.0.0",
    capabilities: {
      tools: {},
    },
});
Features:
  • Create, read, update, delete TODO items
  • Complete and clear completed TODOs
  • Demonstrates stateful server pattern

Server Lifecycle

1. Initialization

When a client connects, the server goes through an initialization handshake:
1

Client Connects

Client spawns server process and connects to stdio streams
2

Capability Exchange

Client and server exchange capability information
3

Ready State

Server enters ready state and can handle requests

2. Request Handling

Once initialized, the server processes incoming requests:
  • List requests: Return available capabilities
  • Call requests: Execute tools, read resources, get prompts
  • Notification requests: Handle updates and changes

3. Shutdown

When the client disconnects, the server cleans up and exits:
main().catch(error => {
  console.error(`Server error: ${error.message}`);
  process.exit(1);
});

Server Configuration

Declaring Capabilities

Servers must declare which capabilities they support:
capabilities: {
  resources: { 
    listChanged: true  // Server can notify when resource list changes
  },
  tools: {},           // Server supports tools
  prompts: {}          // Server supports prompts
}
Only declare capabilities you actually implement. Clients may fail if they request unsupported features.

Server Metadata

const server = new McpServer({
  name: "My Server",        // Human-readable server name
  version: "1.0.0",         // Semantic version
  capabilities: { ... }
});

Error Handling

TypeScript Error Handling

From source/servers/basic/src/server.ts:92-96:
catch (error) {
  return {
    content: [{ type: "text", text: `Error: ${(error as Error).message}` }],
    isError: true
  };
}

Python Error Handling

From source/servers/calculator-py/server.py:14-16:
def divide(a: float, b: float) -> float:
    if b == 0:
        raise ValueError("No se puede dividir por cero")
    return float(a / b)
Always include proper error handling in your tools and resources. Return descriptive error messages to help clients debug issues.

Transport Options

Stdio Transport (Most Common)

import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";

const transport = new StdioServerTransport();
await server.connect(transport);
Advantages:
  • Simple to implement
  • No network configuration
  • Process isolation
  • Works across languages

Other Transports

MCP also supports:
  • SSE (Server-Sent Events): For web-based servers
  • HTTP: For REST-like interactions

Best Practices

Give your server and capabilities clear, descriptive names:
const server = new McpServer({
  name: "Weather Data Provider",  // Clear purpose
  version: "1.0.0"
});
Always validate input parameters using schemas (Zod for TypeScript):
server.tool(
  "get_quotes",
  { count: z.number().min(1).max(10) },
  async ({ count }) => { ... }
);
Use the isError flag and provide helpful error messages:
return {
  content: [{ type: "text", text: "Count must be between 1 and 10" }],
  isError: true
};
Use stderr for logging, not stdout (which is used for MCP messages):
console.error("[INFO] Server started");

Testing Your Server

You can test your server using the MCP Inspector or by creating a simple client:
# Build your server
npm run build

# Test with MCP Inspector
npx @modelcontextprotocol/inspector node dist/server.js

Next Steps

Tools

Learn how to add tools to your server

Resources

Discover how to expose data through resources

Prompts

Create reusable prompt templates

Clients

Build clients to connect to your server

Build docs developers (and LLMs) love