Skip to main content

How to Build an MCP Server in TypeScript & Python: Production Guide (2026)

Step-by-step tutorial on building a production Model Context Protocol (MCP) server in TypeScript and Python. Learn resources, tools, prompts, and Cursor integration.

How to Build an MCP Server in TypeScript & Python: Production Guide (2026)

How to Build an MCP Server in TypeScript & Python: Production Guide (2026)

The Model Context Protocol (MCP) has emerged as the universal standard for connecting Large Language Models (LLMs) to real-world software tools, databases, and enterprise data sources.

Instead of writing bespoke, proprietary tool-calling schemas for OpenAI, Anthropic, or Google Gemini, developers now write an MCP Server once. That server can be discovered, queried, and executed by any compliant AI client—including Cursor, Claude Desktop, VS Code, and autonomous backend agents.

In this practical, code-heavy 2026 tutorial, we walk step-by-step through building a production-ready MCP server in both TypeScript and Python.

You will learn how to:

  1. Initialize the official @modelcontextprotocol/sdk.
  2. Expose read-only Resources (system configs and metrics).
  3. Implement executable Tools with strict JSON Schema validation.
  4. Define pre-built Prompts for complex workflows.
  5. Connect your local server to Cursor and Claude Desktop via standard input/output (stdio).

In This Guide


Core MCP Primitives Quick Recap

Before writing code, recall the three foundational building blocks defined by the Model Context Protocol specification:

Knowledge Graph
┌────────────────────────────────────────────────────────┐
│                   The 3 MCP Primitives                 │
├────────────────────┬───────────────────┬───────────────┤
│ 1. Resources       │ 2. Tools          │ 3. Prompts    │
├────────────────────┼───────────────────┼───────────────┤
│ Read-only data     │ Executable actions│ Pre-engineered│
│ (Like HTTP GET)    │ (Like HTTP POST)  │ templates with│
│ Exposes files, DB  │ Queries DBs, runs │ parameter     │
│ schemas, and logs  │ tests, updates PRs│ inputs        │
└────────────────────┴───────────────────┴───────────────┘

For a thorough architectural breakdown of the protocol, read our guide on what is an MCP server complete guide and MCP server fundamentals.


Building an MCP Server in TypeScript (Step-by-Step)

The official TypeScript SDK is the most widely adopted framework for building desktop and local IDE adapters.

1. Initialize the Project

BASH
mkdir my-mcp-server-ts
cd my-mcp-server-ts
npm init -y
npm install @modelcontextprotocol/sdk zod
npm install -D typescript @types/node tsx
npx tsc --init

2. Implement the Server (src/index.ts)

Create src/index.ts and write the complete server definition:

TYPESCRIPT
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
  ListResourcesRequestSchema,
  ReadResourceRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import { z } from "zod";

// Initialize server metadata
const server = new Server(
  {
    name: "company-architecture-server",
    version: "1.0.0",
  },
  {
    capabilities: {
      resources: {},
      tools: {},
    },
  }
);

// 1. Define a Resource (Read-only service directory)
server.setRequestHandler(ListResourcesRequestSchema, async () => {
  return {
    resources: [
      {
        uri: "architecture://services/directory",
        name: "Microservices Directory",
        mimeType: "application/json",
        description: "List of active production microservices and their owners",
      },
    ],
  };
});

server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
  if (request.params.uri === "architecture://services/directory") {
    const services = [
      { name: "Auth-Service", port: 8080, owner: "Security Team" },
      { name: "Payment-Worker", port: 9020, owner: "Billing Team" },
    ];
    return {
      contents: [
        {
          uri: request.params.uri,
          mimeType: "application/json",
          text: JSON.stringify(services, null, 2),
        },
      ],
    };
  }
  throw new Error("Resource not found");
});

// 2. Define a Tool (Executable architecture search)
server.setRequestHandler(ListToolsRequestSchema, async () => {
  return {
    tools: [
      {
        name: "query_service_history",
        description: "Retrieve past architectural trade-offs and decisions for a given microservice",
        inputSchema: {
          type: "object",
          properties: {
            serviceName: {
              type: "string",
              description: "The name of the service (e.g., Auth-Service, Payment-Worker)",
            },
          },
          required: ["serviceName"],
        },
      },
    ],
  };
});

server.setRequestHandler(CallToolRequestSchema, async (request) => {
  if (request.params.name === "query_service_history") {
    const serviceName = String(request.params.arguments?.serviceName);

    // Mock response simulating an organizational memory lookup
    const history = {
      service: serviceName,
      lastDecision: "Migrated from REST to gRPC in May 2026",
      owner: "Alex Torres",
      linkedPR: "github.com/company/repo/pull/412",
    };

    return {
      content: [
        {
          type: "text",
          text: JSON.stringify(history, null, 2),
        },
      ],
    };
  }
  throw new Error("Tool not found");
});

// 3. Connect via Standard Input/Output (stdio)
async function run() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
  console.error("Architecture MCP Server running on stdio");
}

run().catch((error) => {
  console.error("Fatal error:", error);
  process.exit(1);
});

Building an MCP Server in Python (Step-by-Step)

For AI engineers, data scientists, and backend Python developers, the official Python SDK utilizes FastMCP for clean, decorator-driven development.

1. Initialize the Python Environment

BASH
mkdir my-mcp-server-py
cd my-mcp-server-py
python -m venv .venv
source .venv/bin/activate  # Or on Windows: .venv\Scripts\activate
pip install mcp

2. Implement the Server with FastMCP (server.py)

PYTHON
from mcp.server.fastmcp import FastMCP

# Initialize FastMCP Server
mcp = FastMCP("Enterprise-Memory-Server")

# 1. Define a Resource
@mcp.resource("config://production/limits")
def get_limits() -> str:
    """Returns production rate limits and timeout thresholds."""
    return """
    {
      "global_rate_limit_rps": 5000,
      "database_timeout_ms": 250,
      "max_payload_size_mb": 10
    }
    """

# 2. Define a Tool
@mcp.tool()
def search_code_decisions(service: str, query: str) -> str:
    """
    Search historical architectural decisions for a service.
    
    Args:
        service: Microservice identifier
        query: Specific technical question or topic
    """
    # In production, query Memora's Knowledge Graph here
    return f"Service '{service}' records indicate '{query}' was resolved in ADR-48 with AES-256 encryption."

# 3. Define a Prompt Template
@mcp.prompt()
def review_architecture(service: str) -> str:
    """Pre-loads service context into the conversation."""
    return f"Please review the following proposed architectural change for {service}, taking into account all historical ADRs."

if __name__ == "__main__":
    mcp.run()

Testing & Connecting to Cursor and Claude Desktop

Once your server is implemented, connect it to your daily AI developer tools:

Configuring Cursor IDE

  1. Open Cursor Settings (Ctrl+Shift+J / Cmd+Shift+J).
  2. Navigate to FeaturesMCP Servers.
  3. Click Add New MCP Server.
  4. Set Command: node and Args: C:/path/to/my-mcp-server-ts/dist/index.js.

Configuring Claude Desktop

Edit your claude_desktop_config.json:

JSON
{
  "mcpServers": {
    "my-python-server": {
      "command": "python",
      "args": ["C:/path/to/my-mcp-server-py/server.py"]
    }
  }
}

Once saved, restart Claude or Cursor. The AI client will negotiate capabilities and display your new tools under its tool catalog.

For more integration details, read our complete guide on how to use an MCP server.


Production Best Practices: Error Handling, Sandboxing & Security

When transitioning your MCP server from local prototype to enterprise production:

  1. Standardize on stderr for Logging: Never write debug statements to stdout when running over stdio transport. stdout is reserved strictly for JSON-RPC 2.0 protocol packets; extraneous print statements will corrupt the protocol stream.
  2. Strict Schema Validation: Always validate arguments with Zod (TypeScript) or Pydantic (Python) before executing business logic.
  3. Subprocess Isolation: Enforce least-privilege user permissions to prevent unauthorized filesystem traversals.
  4. Connect to Shared Memory: Rather than maintaining hardcoded mock dictionaries, connect your MCP server to a centralized enterprise memory engine like Memora to ensure all team members share synchronized ground-truth context.

Learn more about token efficiency in our benchmark report on AI memory codebase context without token waste.


Frequently Asked Questions (FAQ)

What is the Model Context Protocol (MCP) SDK? The Model Context Protocol SDK is an open-source library provided by Anthropic and the open-source community that allows developers to build MCP servers and clients in TypeScript and Python using standardized JSON-RPC 2.0 interfaces.

Can I run an MCP server locally without exposing external ports? Yes. By using the standard input/output (stdio) transport, the MCP server runs as a local child process spawned by your IDE (like Cursor or Claude Desktop), opening zero public network ports and providing maximum enterprise security.

What is the difference between an MCP Resource and an MCP Tool? An MCP Resource is passive, read-only data that an AI model can inspect without modifying system state (analogous to an HTTP GET request). An MCP Tool is an executable function that can perform calculations or execute external API changes (analogous to an HTTP POST request).

How do I debug an MCP server when it fails to connect? You can debug an MCP server by inspecting host application logs (Cursor or Claude Desktop console) and ensuring all diagnostic logging inside your server code writes strictly to stderr rather than stdout.

Essential Organizational Memory Architecture

Explore Memora's foundational guides on Graph RAG, persistent AI memory, and automated knowledge discovery:

Quick Knowledge Check

Why do standard vector search systems fail on complex technical context?

Was this article helpful?