P015 min

Development Environment

Set up your toolchain: Node.js, TypeScript, the MCP SDK, and the Inspector for debugging.

On This Page

Key Concepts

  • Node.js 18+ and TypeScript 5+ required
  • @modelcontextprotocol/sdk package
  • MCP Inspector for debugging
  • Claude Desktop config file
  • stdio transport for local development
  • tsconfig strict mode for MCP

Time to get your hands dirty. In this module, you will set up everything you need to build and test MCP servers locally. By the end, you will have a working project directory, the MCP SDK installed, the Inspector running, and Claude Desktop configured to connect to custom servers.

Prerequisites Checklist

Before you start, make sure you have these installed. Open a terminal and run each command. If any fails, install it before proceeding.

# Check Node.js (need 18 or higher)
node --version
# Expected: v18.x.x or higher (v20+ recommended)

# Check npm
npm --version
# Expected: 9.x.x or higher

# Check TypeScript (install globally if missing)
npx tsc --version
# Expected: Version 5.x.x

# Check git (useful for version control)
git --version
# Expected: git version 2.x.x

If Node.js is missing or outdated, install it from nodejs.org or use a version manager like nvm:

# Install nvm (if you don't have it)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash

# Install and use Node 20
nvm install 20
nvm use 20

Project Setup

Create a fresh project directory. We will use this throughout the course, adding files as we build increasingly complex servers.

# Create the project directory
mkdir mcp-learning && cd mcp-learning

# Initialize a new npm project
npm init -y

# Install TypeScript as a dev dependency
npm install -D typescript

# Install the Node.js types
npm install -D @types/node

Your package.json should now list typescript and @types/node in devDependencies.

TypeScript Configuration

MCP servers use modern TypeScript features. Create a tsconfig.json in your project root with these settings:

{
  "compilerOptions": {
    // Target Node.js 18+ runtime
    "target": "ES2022",
    "module": "Node16",
    "moduleResolution": "Node16",

    // Output directory for compiled JavaScript
    "outDir": "./dist",
    "rootDir": "./src",

    // Strict mode catches bugs before runtime
    "strict": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,

    // Enable source maps for debugging
    "sourceMap": true,
    "declaration": true,

    // Allow JSON imports (useful for config files)
    "resolveJsonModule": true,
    "esModuleInterop": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}

Let us break down the critical settings:

  • target: "ES2022" — Enables modern features like top-level await, which MCP servers commonly use.
  • module: "Node16" — Uses Node.js's native ESM module system. The MCP SDK is distributed as ESM, so this is required.
  • strict: true — Catches null reference errors, implicit any types, and other common bugs at compile time. Never turn this off.

You also need to tell Node.js your project uses ESM. Open package.json and add the type field:

{
  "name": "mcp-learning",
  "version": "1.0.0",
  "type": "module",     // <-- Add this line
  "scripts": {
    "build": "tsc",
    "start": "node dist/index.js"
  },
  // ... rest of package.json
}

Key Takeaway: The "type": "module" field in package.json is mandatory. Without it, Node.js treats your files as CommonJS and the MCP SDK imports will fail with confusing errors.

Installing the MCP SDK

The official MCP TypeScript SDK provides everything you need: server and client classes, transport implementations, type definitions, and utility functions.

# Install the MCP SDK
npm install @modelcontextprotocol/sdk

That is it. One package. It includes:

  • McpServer — The class you will use to create servers. Handles initialization, capability registration, and message routing.
  • StdioServerTransport — Connects your server to stdin/stdout for local development.
  • SSEServerTransport and StreamableHTTPServerTransport — For HTTP-based deployments (later in the course).
  • Full TypeScript types for every MCP message, capability, and primitive.

Create a src directory and a minimal file to verify the import works:

# Create the source directory
mkdir src

# Create a test file: src/index.ts
// src/index.ts — Verify the SDK imports correctly
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";

// If this compiles without errors, your setup is correct
console.log("MCP SDK imported successfully");
console.log("McpServer:", typeof McpServer);
console.log("StdioServerTransport:", typeof StdioServerTransport);

Build and run it:

# Compile TypeScript to JavaScript
npm run build

# Run the compiled output
npm start

# Expected output:
# MCP SDK imported successfully
# McpServer: function
# StdioServerTransport: function

If you see those three lines, your project is correctly configured. If you get errors, check the Troubleshooting section below.

The MCP Inspector

The MCP Inspector is a developer tool that connects to your server and lets you interact with it visually. Think of it as Postman for MCP — you can list tools, call them, read resources, and see the raw JSON-RPC messages going back and forth.

# Run the inspector (no install needed, npx downloads it)
npx @modelcontextprotocol/inspector

This launches a web UI (usually at http://localhost:6274) where you can:

  1. Point it at your server — enter the command to launch your server (e.g., node dist/index.js).
  2. See the initialization handshake — watch the capability negotiation happen in real time.
  3. List and call tools — see every tool the server exposes, fill in parameters, and execute calls.
  4. Read resources — browse available resources and view their contents.
  5. View raw messages — see the exact JSON-RPC messages flowing between client and server.

You will use the Inspector constantly throughout this course. Bookmark the command.

Try It Yourself: Run npx @modelcontextprotocol/inspector now. You will not have a server to connect yet (we build that in the next module), but familiarize yourself with the UI. Click around, look at the different tabs. When we build our first server, you will already know the tool.

Claude Desktop Configuration

Claude Desktop is an MCP host. You can configure it to connect to your custom MCP servers. The configuration lives in a JSON file:

# macOS
~/Library/Application Support/Claude/claude_desktop_config.json

# Windows
%APPDATA%\Claude\claude_desktop_config.json

# Linux
~/.config/Claude/claude_desktop_config.json

Open (or create) this file. The structure looks like this:

{
  "mcpServers": {
    "my-first-server": {
      "command": "node",
      "args": ["/absolute/path/to/mcp-learning/dist/index.js"],
      "env": {
        "SOME_API_KEY": "optional-environment-variables"
      }
    }
  }
}

Let us break down each field:

  • "my-first-server" — A name you choose. It appears in Claude Desktop's server list.
  • command — The executable to run. For TypeScript servers compiled to JavaScript, this is node.
  • args — Arguments passed to the command. Use the absolute path to your compiled JavaScript file. Relative paths will break.
  • env — Optional. Environment variables passed to the server process. Useful for API keys and configuration.

Do not add this config yet — we do not have a working server. In the next module, you will build one and come back here to wire it up. For now, just know where the file lives and what the format looks like.

Key Takeaway: Claude Desktop uses stdio transport. It spawns your server as a child process and communicates over stdin/stdout. That is why the config specifies a command and args, not a URL. The server runs locally on your machine.

Verify Everything Works

Run through this checklist to confirm your environment is ready. Each step should succeed before you move on.

# 1. TypeScript compiles without errors
cd /path/to/mcp-learning
npm run build
# Expected: No errors. dist/ directory created with index.js

# 2. The compiled server runs
npm start
# Expected: "MCP SDK imported successfully"

# 3. MCP Inspector launches
npx @modelcontextprotocol/inspector
# Expected: Web UI opens at http://localhost:6274

# 4. You know where Claude Desktop config lives
# macOS: ls ~/Library/Application\ Support/Claude/
# Linux: ls ~/.config/Claude/
# Windows: dir %APPDATA%\Claude\

If all four pass, you are ready to build your first MCP server in the next module.

Troubleshooting

ERR_MODULE_NOT_FOUND or Cannot find module

This usually means one of two things:

  • Missing "type": "module" in package.json. Without this, Node.js treats .js files as CommonJS and ESM imports fail.
  • Wrong import path. The MCP SDK requires full subpath imports. You must write @modelcontextprotocol/sdk/server/mcp.js, not just @modelcontextprotocol/sdk. The .js extension is required even though the source is TypeScript.

TypeScript errors about module resolution

If you see errors like “Cannot find module” in TypeScript but not at runtime, check that moduleResolution is set to "Node16" in tsconfig.json. The older "node" setting does not understand package.json exports maps, which the MCP SDK uses.

Inspector will not connect to server

  • Make sure your server is not writing anything to stdout except MCP messages. Any console.log in a running MCP server will corrupt the stdio transport. Use console.error for debug logging (writes to stderr, which does not interfere).
  • Make sure you are pointing the Inspector at the compiled .js file, not the .ts source.

Claude Desktop does not show the server

  • Restart Claude Desktop after editing the config file. It only reads the config at startup.
  • Use absolute paths in the args array. Relative paths resolve from Claude Desktop's working directory, which is not your project folder.
  • Check Claude Desktop's logs for error messages. On macOS: ~/Library/Logs/Claude/.

Common Mistakes

  • Using console.log in MCP servers. This is the number one beginner mistake. MCP servers communicate over stdout. A console.log injects random text into the JSON-RPC stream and breaks everything. Always use console.error for debug output — it goes to stderr, which is separate.
  • Forgetting the .js extension in imports. When using ESM with TypeScript, you write import ... from "./myfile.js" even though the source file is myfile.ts. TypeScript will find the .ts file during compilation, and Node.js will find the .js file at runtime.
  • Using CommonJS (require) instead of ESM (import). The MCP SDK is ESM-only. If you see require is not defined, you are accidentally in CommonJS mode. Check for "type": "module" in package.json.
  • Relative paths in Claude Desktop config. Always use absolute paths. ./dist/index.js will not work because the working directory is not what you expect.

Your development environment is ready. You have Node.js, TypeScript, the MCP SDK, the Inspector, and you know where Claude Desktop's config lives. In the next module, you will write your first MCP server from scratch — a real, working server that registers a tool and handles requests.