Setting up your first MCP server in Claude Code (the part nobody explains)
MCP (Model Context Protocol) lets Claude Code talk to external tools and services. The documentation covers the protocol. This covers what actually breaks when you first set it up.
The thing that trips everyone up: stdio vs SSE
Claude Code supports two transport types for MCP servers:
-
stdio: Claude spawns the server as a subprocess and communicates via stdin/stdout -
sse: Server runs independently, Claude connects over HTTP
For local tools (file system operations, shell commands, database queries), use stdio. It's simpler — no port to manage, no server to keep running.
For remote tools or services that multiple clients share, use sse.
Most first-time MCP users start with stdio and don't realize they need to specify this explicitly.
Minimal stdio server (Node.js)
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
const server = new Server(
{ name: 'my-tool', version: '1.0.0' },
{ capabilities: { tools: {} } }
);
server.setRequestHandler('tools/list', async () => ({
tools: [{
name: 'get_timestamp',
description: 'Returns current UTC timestamp',
inputSchema: { type: 'object', properties: {} }
}]
}));
server.setRequestHandler('tools/call', async (req) => {
if (req.params.name === 'get_timestamp') {
return { content: [{ type: 'text', text: new Date().toISOString() }] };
}
throw new Error('Unknown tool: ' + req.params.name);
});
const transport = new StdioServerTransport();
await server.connect(transport);
The settings.json entry
{
"mcpServers": {
"my-tool": {
"command": "node",
"args": ["/absolute/path/to/server.js"],
"env": {}
}
}
}
Three things that catch people:
- The path must be absolute — relative paths don't work
- The command runs from Claude's working directory, not the server file's directory
- Environment variables in
envare merged with the inherited shell environment
Debugging when it doesn't work
Claude Code logs MCP errors to ~/.claude/logs/. Check there first.
The most common errors:
-
ENOENT: file not found — check the absolute path -
EACCES: permission denied —chmod +xthe file - Server exits immediately — check the script for syntax errors, it's crashing on startup
- Tool not showing up — the
tools/listhandler isn't returning the right format
What you actually get
Once it's working, you can ask Claude to use your tool directly:
Use the get_timestamp tool to log the current time.
Claude discovers the tool, calls it, and uses the result in its response. No prompt engineering required — the tool description does the work.
I maintain 5 configured MCP servers in the MCP Server Starter Kit — TypeScript template + working examples for filesystem, shell, HTTP, database, and notification servers. $49, instant download.
Top comments (0)