Here's what you built and how the pieces connect:
src/index.ts
└── McpServer with 4 tools
├── say_hello
├── read_file
├── fetch_url
└── list_directory
↓ compiled to
build/index.js
↓ registered in
claude_desktop_config.json ←→ ~/.cursor/mcp.json ←→ .vscode/mcp.json
↓ started by
Claude Desktop / Cursor / VS Code
↓ tools available to
Claude (decides when to call them based on tool descriptions)
The three things that make MCP servers work well
Tool descriptions are everything. Claude decides when to call your tool based entirely on the description you write. "Reads a file" is fine. "Reads the full text contents of any file on the local filesystem given a path — useful when the user asks to read, review, or summarize a local document" is better. Claude will use the second one in more situations where it's actually appropriate.
Always handle errors. Don't let unhandled exceptions crash your server. Wrap every handler in try/catch and return isError: true with a message. Claude can handle error responses gracefully — unexpected crashes are much harder to debug.
Never use console.log() in a stdio server. Ever. console.error() only.
MCP in one sentence
It's a standard way for Claude (and any other AI) to call functions you define, so you don't have to copy-paste context manually or build custom integrations for every AI app you use.
Updated February 2026 · MCP spec version 2025-03-26 · TypeScript SDK v1.x