Let's build a real MCP server from scratch. Forget abstractions — by the end of this module, you'll have a working server that any MCP client can connect to.
mkdir my-mcp-server && cd my-mcp-server npm init -y npm install @modelcontextprotocol/sdk zod npm install -D typescript @types/node tsx
// tsconfig.json
{
"compilerOptions": {
"target": "ES2022",
"module": "Node16",
"moduleResolution": "Node16",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"declaration": true
},
"include": ["src/**/*"]
}
{
"type": "module",
"bin": { "my-mcp-server": "./dist/index.js" },
"scripts": {
"build": "tsc",
"dev": "tsx src/index.ts",
"inspect": "npx @modelcontextprotocol/inspector tsx src/index.ts"
}
}
| File | Purpose |
|---|---|
src/index.ts | Server entry point — creates McpServer, attaches transport |
src/tools.ts | Tool definitions and handler functions |
src/resources.ts | Resource definitions and data providers |
src/prompts.ts | Prompt templates for UI-driven workflows |
tsconfig.json | TypeScript compiler configuration |
"type": "module" in package.json. The MCP SDK uses ES modules exclusively — CommonJS imports will fail with cryptic errors.