The Problem MCP Solves
Without MCP, Claude only knows what's in the conversation. If you want Claude to query your database, you have to copy the query results into the chat. If you want Claude to check a GitHub issue, you have to paste the issue text. Claude is smart but blind to anything outside the conversation window.
The Model Context Protocol (MCP) solves this by giving Claude a standardized way to call external systems. MCP turns Claude from a conversationalist into an agent that can actively retrieve information and take actions on your behalf.
The Protocol: JSON-RPC over stdio
MCP is built on JSON-RPC 2.0, a simple remote procedure call protocol that uses JSON for encoding. Messages are sent over stdio (standard input/output) — the MCP server runs as a subprocess and Claude communicates with it via stdin/stdout.
There's also an HTTP+SSE transport for servers that need to run remotely or handle multiple clients, but the stdio model is more common for local tools.
In the MCP model:
- Claude is the client — it sends requests to the MCP server
- Your server is the host — it receives requests and returns results
- The protocol handles discovery — Claude asks the server what tools it has, then uses them
Three Primitives: Tools, Resources, Prompts
MCP exposes three types of capabilities to Claude:
Functions Claude can call. A tool has a name, description, and JSON Schema for its inputs. Claude decides when to call a tool based on the description. Examples: read_file, query_database, send_email, search_web.
Static or dynamic data Claude can read — like documents, schemas, or configuration files. Resources have a URI scheme (e.g., file://, db://) and can be text or binary. Claude can browse and read resources without explicit tool calls.
Pre-built prompt templates that users can select. Less commonly used — most integrations focus on Tools.
How a Tool Call Works
When Claude decides to use a tool, here is the exact sequence:
1. User sends a message: "What tables are in my database?"
2. Claude recognizes it needs the list_tables tool
3. Claude sends a tools/call request to the MCP server:
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "list_tables",
"arguments": {}
}
}
4. MCP server executes the query, returns:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{ "type": "text", "text": "users, posts, comments, sessions" }
]
}
}
5. Claude reads the result and responds to the user:
"Your database has 4 tables: users, posts, comments, and sessions."Installing MCP Servers
MCP servers are configured in a JSON file that Claude Desktop reads on startup. The file location:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/Users/me/projects"],
"env": {}
},
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_your_token_here"
}
},
"postgres": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-postgres"],
"env": {
"POSTGRES_CONNECTION_STRING": "postgresql://localhost/mydb"
}
}
}
}Each server entry specifies a command to run (usually npx), arguments for that command, and any environment variables the server needs. Claude Desktop starts each server as a subprocess when it launches.
Building Your First MCP Server
The @modelcontextprotocol/sdk package makes building an MCP server straightforward. Here's a minimal server that exposes a tool to read files:
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import { z } from "zod";
import * as fs from "fs";
const server = new Server(
{ name: "my-file-server", version: "1.0.0" },
{ capabilities: { tools: {} } }
);
// Tell Claude what tools are available
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
{
name: "read_file",
description: "Read the contents of a text file",
inputSchema: {
type: "object",
properties: {
path: {
type: "string",
description: "The absolute path to the file to read",
},
},
required: ["path"],
},
},
],
}));
// Execute tool calls from Claude
server.setRequestHandler(CallToolRequestSchema, async (request) => {
if (request.params.name === "read_file") {
const { path } = z.object({ path: z.string() }).parse(request.params.arguments);
const content = fs.readFileSync(path, "utf-8");
return {
content: [{ type: "text", text: content }],
};
}
throw new Error(`Unknown tool: ${request.params.name}`);
});
// Start the server
const transport = new StdioServerTransport();
await server.connect(transport);# Install the SDK
npm install @modelcontextprotocol/sdk zod
# Build and run
npx tsc && node dist/index.js
# Add to claude_desktop_config.json
{
"mcpServers": {
"my-file-server": {
"command": "node",
"args": ["/path/to/your/server/dist/index.js"],
"env": {}
}
}
}Security Model
MCP servers run locally on your machine as subprocesses launched by Claude Desktop. They run with the same OS permissions as the user who started Claude Desktop — not as a privileged process.
This means:
- A filesystem server can only access files your user account can access
- Claude always asks for permission before calling a tool (in most configurations)
- MCP servers cannot access the network unless they explicitly make network calls
- You control exactly what paths, databases, and APIs each server can access via configuration
Popular MCP Servers
@modelcontextprotocol/server-filesystemRead and write local files and directories
@modelcontextprotocol/server-githubBrowse repos, issues, and PRs via GitHub API
@modelcontextprotocol/server-postgresQuery PostgreSQL databases with natural language
@modelcontextprotocol/server-sqliteRead and query SQLite database files
@modelcontextprotocol/server-brave-searchSearch the web using Brave Search API
@modelcontextprotocol/server-puppeteerControl a headless browser — scrape or test web apps
@modelcontextprotocol/server-slackRead channels, threads, and send messages to Slack
Browse the full directory at clauderules.net/mcp — it includes installation instructions, configuration examples, and community reviews for each server.
Debugging MCP Issues
Common issues and how to diagnose them:
- Server doesn't appear in Claude Desktop: Restart Claude Desktop after editing the config file. Check the JSON is valid (use a linter).
- Tools aren't listed: Run the server command manually in your terminal to see startup errors. Check for missing environment variables.
- Tool calls fail silently: Add console.error logging to your server — Claude Desktop captures stderr from MCP server processes.
- npx not found: Use the absolute path to npx in the command field:
/usr/local/bin/npx. - Permission denied: Verify the paths in your config are readable/writable by your user account.
node --inspect dist/index.js to attach the Node.js debugger and step through tool execution.