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 (see the Python MCP SDK page for the Python equivalent). 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

See the GitHub MCP server, mindsdb (Postgres + multi-DB), and browser-automation MCPs for installation instructions and live config examples.

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.

Frequently asked questions

What is MCP (Model Context Protocol)?+

MCP is an open standard that lets you connect Claude to external tools and data sources. Without MCP, Claude only knows what's in the conversation — if you want it to query your database or read a GitHub issue you have to copy-paste the data in. MCP turns Claude from a conversationalist into an agent that can actively retrieve information and take actions on your behalf, by giving it a standardized way to call external systems like file servers, databases, and web APIs.

What protocol does MCP use under the hood?+

MCP is built on JSON-RPC 2.0, a lightweight remote procedure call protocol that uses JSON for encoding. Messages are most commonly sent over stdio — the MCP server runs as a subprocess and Claude communicates with it via stdin and stdout. There's also an HTTP+SSE transport for servers that need to run remotely or handle multiple clients, but stdio is the dominant model for local tools. In MCP, Claude is the client that sends requests and your server is the host that returns results; the protocol itself handles tool discovery.

What are tools, resources, and prompts in MCP?+

MCP exposes three types of capabilities to Claude. Tools are functions Claude can call, each with a name, description, and JSON Schema for inputs — examples include read_file, query_database, and search_web. Resources are static or dynamic data Claude can read, addressed by URI schemes like file:// or db://, useful for documents, schemas, and config. Prompts are pre-built prompt templates users can select. Most integrations focus on tools; resources and prompts are less commonly used.

How do I install an MCP server in Claude Desktop?+

MCP servers are configured in claude_desktop_config.json, which Claude Desktop reads on startup. On macOS the file lives at ~/Library/Application Support/Claude/claude_desktop_config.json; on Windows it's at %APPDATA%\Claude\claude_desktop_config.json. Each server entry specifies a command to run (usually npx), the arguments for that command, and any environment variables the server needs. Claude Desktop launches each server as a subprocess when it starts. After editing the config, restart Claude Desktop and look for the MCP indicator in the UI to confirm it loaded.

Are MCP servers safe to run on my computer?+

MCP servers run locally as subprocesses with the same OS permissions as the user who started Claude Desktop — not as a privileged process. A filesystem server can only access files your user account can access, MCP servers cannot reach the network unless they explicitly make network calls, and Claude typically asks for permission before invoking a tool. That said, you should review the source code of any community MCP server before running it — a malicious server could exfiltrate files or make unauthorized network requests. Stick to official servers or well-audited community projects.

Can I write my own MCP server?+

Yes. The @modelcontextprotocol/sdk package makes it straightforward. A minimal server registers handlers for ListToolsRequestSchema (telling Claude which tools exist and their input schemas) and CallToolRequestSchema (executing the tool when Claude calls it), then connects via StdioServerTransport. After installing the SDK with npm, building with TypeScript, and pointing claude_desktop_config.json at your compiled output, the server appears alongside other MCP integrations. The article walks through a complete read_file server in about 30 lines of TypeScript.

Get the Claude Code Starter Pack

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