Back to Learn
MCP
14 min read

How Claude MCP Servers Work: A Technical Deep Dive

clauderules.net

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:

ToolsMost Common

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.

ResourcesData Access

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.

PromptsTemplates

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:

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
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:

typescript
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);
bash
# 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
Review the source code of any community MCP server before running it. A malicious MCP server could exfiltrate files or make unauthorized network requests. Stick to official servers from the MCP organization or well-audited community servers.

Popular MCP Servers

@modelcontextprotocol/server-filesystem

Read and write local files and directories

@modelcontextprotocol/server-github

Browse repos, issues, and PRs via GitHub API

@modelcontextprotocol/server-postgres

Query PostgreSQL databases with natural language

@modelcontextprotocol/server-sqlite

Read and query SQLite database files

@modelcontextprotocol/server-brave-search

Search the web using Brave Search API

@modelcontextprotocol/server-puppeteer

Control a headless browser — scrape or test web apps

@modelcontextprotocol/server-slack

Read 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.
Run your MCP server with node --inspect dist/index.js to attach the Node.js debugger and step through tool execution.

Get the Claude Code Starter Pack

Top CLAUDE.md rules for Next.js, TypeScript, Python, Go, and React — delivered free to your inbox.