Configure your development environment for building MCP servers with TypeScript and the official SDK
Before we start building MCP servers, let's ensure you have everything you need. Don't worry - the setup is straightforward!
You'll need:
Why Node.js 18+? MCP SDK uses modern JavaScript features and the native fetch API, which requires Node.js 18 or higher.
This module assumes you:
If you're new to TypeScript, don't worry! We'll explain TypeScript-specific concepts as we go.
Let's set up your development environment step by step.
First, check if you have Node.js installed:
<CodeExample title="Checking Node.js Version" language="bash" code={`# Check Node.js version (should be 18.x or higher) node --version
npm --version
/>
If you need to install or update Node.js:
While not required, these tools will improve your development experience:
<CodeExample title="Optional Global Tools" language="bash" code={`# TypeScript compiler (optional - we'll use tsx for development) npm install -g typescript
npm install -g @modelcontextprotocol/inspector`} />
Pro Tip: Using tsx
instead of tsc
during development allows you to run TypeScript files directly without compilation!
Verify your Node.js installation
Now let's create your first MCP server project from scratch.
<CodeExample title="Initialize Project" language="bash" code={`# Create project directory mkdir my-first-mcp-server cd my-first-mcp-server
npm init -y
npm install --save-dev typescript @types/node tsx npm install @modelcontextprotocol/sdk`} />
Create a tsconfig.json
file to configure TypeScript for MCP development:
<CodeExample
title="TypeScript Configuration"
language="json"
fileName="tsconfig.json"
code={{ "compilerOptions": { "target": "ES2022", "module": "Node16", "moduleResolution": "Node16", "lib": ["ES2022"], "outDir": "./dist", "rootDir": "./src", "strict": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "resolveJsonModule": true, "declaration": true, "declarationMap": true, "sourceMap": true }, "include": ["src/**/*"], "exclude": ["node_modules", "dist"] }
}
highlightLines={[3, 4, 5, 9]}
/>
Important: The module
and moduleResolution
settings must be "Node16" to work properly with the MCP SDK's ES modules.
Add important configuration to your package.json
:
<CodeExample
title="Package Configuration"
language="json"
fileName="package.json"
code={{ "name": "my-first-mcp-server", "version": "1.0.0", "type": "module", "main": "dist/index.js", "scripts": { "dev": "tsx watch src/index.ts", "build": "tsc", "start": "node dist/index.js" }, // ... dependencies }
}
highlightLines={[4, 6, 7, 8, 9]}
/>
Key Points:
"type": "module"
enables ES modulestsx watch
provides hot reloading during developmentnpm run dev
for development, npm run build
for productionSet up a clean project structure:
Your project should now look like this:
my-first-mcp-server/
├── node_modules/
├── src/
│ └── index.ts
├── package.json
├── package-lock.json
└── tsconfig.json
Create and configure a new MCP server project
Configure TypeScript for MCP development
Module content not available.
Once you've built your server, let's test it!
Add these helpful scripts to your package.json
:
<CodeExample
title="Package.json Scripts"
language="json"
fileName="package.json"
code={{ "name": "my-first-mcp-server", "version": "1.0.0", "type": "module", "scripts": { "dev": "tsx watch src/index.ts", "build": "tsc", "start": "node dist/index.js", "test": "npx @modelcontextprotocol/inspector" }, // ... other fields }
}
highlightLines={[5, 6, 7, 8, 9]}
/>
The MCP Inspector is a powerful tool for testing your server:
Start your server in one terminal:
Run the inspector in another terminal:
Connect to your server in the inspector:
npm run dev
Success! If everything is set up correctly, you should see your server's resources in the inspector.
Issue: "Cannot find module" errors
Solution: Ensure all imports end with .js
extension (even for TypeScript files)
Issue: "Module not found" for MCP SDK
Solution: Check that you're using Node.js 18+ and have "type": "module"
in package.json
Issue: Server doesn't respond in inspector Solution: Make sure you're using stdio transport and the server is running
Add convenient scripts for development
As your MCP server grows, a good structure becomes essential. Here's a recommended approach:
<CodeExample
title="Recommended Project Structure"
language="text"
code={my-mcp-server/ ├── src/ │ ├── index.ts # Main server entry point │ ├── handlers/ # Request handlers │ │ ├── resources.ts # Resource handlers │ │ └── tools.ts # Tool handlers │ ├── providers/ # Business logic │ │ ├── database.ts # Database connections │ │ └── files.ts # File system operations │ └── types/ # TypeScript type definitions ├── dist/ # Compiled output ├── tests/ # Test files ├── .gitignore ├── package.json ├── tsconfig.json └── README.md
}
/>
<CodeExample title="Example Handler Organization" language="typescript" fileName="src/handlers/resources.ts" code={`import { Server } from '@modelcontextprotocol/sdk/server/index.js';
export function registerResourceHandlers(server: Server) { // Register all resource-related handlers server.setRequestHandler('resources/list', async () => { return { resources: [ ...await fileProvider.listResources(), ...await databaseProvider.listResources() ] }; });
server.setRequestHandler('resources/read', async (request) => { // Delegate to appropriate provider based on URI scheme const uri = request.params.uri;
if (uri.startsWith('file://')) {
return fileProvider.readResource(uri);
} else if (uri.startsWith('db://')) {
return databaseProvider.readResource(uri);
}
throw new Error('Unknown resource type');
}); }`} />
Organize your MCP server for maintainability