# MCP Servers and Claude Code: A Practical Guide to Connecting and Building

> How to expand Claude Code's capabilities with Model Context Protocol: connecting the filesystem, GitHub, PostgreSQL, Brave Search, and developing a custom server in TypeScript.

Out of the box, Claude Code can already inspect local files, run terminal commands, and edit project code. However, in real-world development workflows, that is rarely enough: you frequently need to query a PostgreSQL database, check open Pull Requests on GitHub, fetch the latest cloud documentation, or trigger internal corporate APIs.

To solve this problem, Anthropic introduced the **Model Context Protocol (MCP)** — an open standard that turns Claude Code from a local repository assistant into a full-fledged orchestration hub for external systems and services.

In this practical guide, we'll examine MCP architecture, configure official ready-made servers, build a custom TypeScript server from scratch, and verify our setup with hands-on practice tasks.

---

## 1. What is an MCP Server

**Model Context Protocol (MCP)** is an open communication protocol designed by Anthropic that standardizes how Large Language Models (LLMs) interact with external tools and structured data sources.

Instead of writing custom, proprietary integrations for every service, MCP introduces a unified client-server architecture:

```text
┌─────────────────────────────────────────────────────────────┐
│                     Claude Code (Client)                    │
└──────────────────────────────┬──────────────────────────────┘
                               │ JSON-RPC 2.0 (stdio / SSE)
                               ▼
┌─────────────────────────────────────────────────────────────┐
│                     MCP Server (Adapter)                    │
└──────┬───────────────────────┼───────────────────────┬──────┘
       │                       │                       │
       ▼                       ▼                       ▼
┌─────────────┐         ┌─────────────┐         ┌─────────────┐
│ Local Files │         │ GitHub API  │         │ PostgreSQL  │
│ and Notes   │         │ and Issues  │         │ Database    │
└─────────────┘         └─────────────┘         └─────────────┘
```

Every MCP Server exposes three fundamental primitives to the model:

- **Tools** — Executable functions with typed JSON Schema parameters that Claude Code can invoke autonomously during problem solving (e.g., `create_issue`, `execute_query`).
- **Resources** — Passive data or schemas that the assistant can read as input context (files, database schemas, application logs).
- **Prompts** — Pre-configured prompt templates that simplify repetitive operational tasks.

### Capability Comparison

| Scenario | Without MCP (Default Claude Code) | With Connected MCP Servers |
| :--- | :--- | :--- |
| **File Access** | Restricted strictly to the current project directory | Access to any permitted external folders and notes |
| **Repository Data** | Local files only via `git diff` / `git log` | Read issues, pull requests, reviews, and GitHub APIs |
| **Databases** | Only if a local CLI client is manually run | Direct schema inspection, table queries, and SQL execution |
| **Information Search** | Local grep / ripgrep in project files | Live web search via Brave Search / Tavily |
| **Internal Services** | Unavailable without custom shell scripts | Direct function calls to microservices via typed SDKs |

---

## 2. Architecture and Request Lifecycle

MCP communication is built on the standard **JSON-RPC 2.0** protocol. For local tools, communication takes place over standard input/output streams (`stdio`), while remote servers utilize Server-Sent Events (`SSE`) or HTTP.

### Step-by-Step Request Lifecycle

1. **Initialization & Handshake:** When a Claude Code session starts, it reads the configuration, spawns configured server processes, and requests their available tools (`tools/list`).
2. **Capability Publishing:** Each MCP Server returns its supported methods, complete with JSON schemas for arguments and descriptions of what each tool does.
3. **Intent Detection:** When you enter a natural language prompt, Claude compares your request against the registered tools.
4. **Tool Execution Request:** If external data or actions are required, Claude sends a structured `tools/call` JSON-RPC request to the server with valid arguments.
5. **Server Execution:** The server communicates with the external database, API, or disk, and returns the result to the client.
6. **Context Synthesis:** Claude interprets the raw payload and crafts a coherent, formatted answer for you.

> [!NOTE]
> The entire workflow is transparent to the developer: you don't need to memorize function signatures or CLI flags. Claude automatically selects the right tool based on the context of your task.

---

## 3. Connecting an MCP Server to Claude Code

MCP servers are registered using JSON under the `mcpServers` key. Claude Code supports two configuration tiers:

1. **Project-level (`.claude/settings.json`)** — Scoped exclusively to the current project directory and safely commit-ready for your team.
2. **Global-level (`~/.claude/settings.json`)** — Available across all projects for your local operating system user.

:::tabs
=== Project (.claude/settings.json)
```json
{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": [
        "-y",
        "@anthropic-ai/mcp-filesystem",
        "./docs"
      ]
    }
  }
}
```
=== Global (~/.claude/settings.json)
```json
{
  "mcpServers": {
    "github": {
      "command": "npx",
      "args": [
        "-y",
        "@anthropic-ai/mcp-github"
      ],
      "env": {
        "GITHUB_TOKEN": "ghp_your_token_here"
      }
    }
  }
}
```
:::

### Configuration Schema Parameters

Each server definition in `mcpServers` consists of three core properties:

| Parameter | Type | Required | Description and Purpose | Example Values |
| :--- | :--- | :--- | :--- | :--- |
| `command` | `string` | Yes | Executable binary used to start the server process | `"npx"`, `"node"`, `"uvx"`, `"docker"` |
| `args` | `string[]` | Yes | Array of startup arguments (package names, paths, flags) | `["-y", "@anthropic-ai/mcp-filesystem", "/path"]` |
| `env` | `object` | No | Environment variables for authentication tokens and API keys | `{"GITHUB_TOKEN": "ghp_...", "DEBUG": "1"}` |

> [!TIP]
> For Python-based MCP servers, you can run `uvx` instead of `npx`, for example: `"command": "uvx", "args": ["mcp-server-git"]`.

---

## 4. Catalog of Ready-Made MCP Servers

Anthropic and the open-source community provide production-ready servers for common developer tools. You don't need to write code from scratch — simply install and run the appropriate npm or python package.

| Server | Official Package | Authentication / Access | Core Capabilities |
| :--- | :--- | :--- | :--- |
| **Filesystem** | `@anthropic-ai/mcp-filesystem` | Permitted directory paths | Read, write, and search files outside project roots |
| **GitHub** | `@anthropic-ai/mcp-github` | Personal Access Token (`GITHUB_TOKEN`) | Search repositories, read issues, review & open PRs |
| **PostgreSQL** | `@anthropic-ai/mcp-postgres` | Connection string URI | Inspect schemas, read tables, execute SQL queries |
| **Brave Search** | `@anthropic-ai/mcp-brave-search` | Search API Key (`BRAVE_API_KEY`) | Live internet search without hallucinations |

### 1. Filesystem Server

Gives Claude Code access to directories outside the repository (e.g., a shared notes directory or Obsidian vault):

```json
{
  "mcpServers": {
    "docs": {
      "command": "npx",
      "args": [
        "-y",
        "@anthropic-ai/mcp-filesystem",
        "/Users/username/Developer/knowledge-base"
      ]
    }
  }
}
```

### 2. GitHub Server

Enables the assistant to interact directly with GitHub issues, PR reviews, and commit history:

```json
{
  "mcpServers": {
    "github": {
      "command": "npx",
      "args": [
        "-y",
        "@anthropic-ai/mcp-github"
      ],
      "env": {
        "GITHUB_TOKEN": "ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
      }
    }
  }
}
```

### 3. PostgreSQL Server

Allows Claude Code to run analytical or diagnostic SQL queries against your local or remote database:

```json
{
  "mcpServers": {
    "postgres": {
      "command": "npx",
      "args": [
        "-y",
        "@anthropic-ai/mcp-postgres",
        "postgresql://postgres:password@localhost:5432/my_app_db"
      ]
    }
  }
}
```

### 4. Brave Search Server

Integrates a real-time web search engine so Claude can check recent library release notes, patch advisories, and documentation:

```json
{
  "mcpServers": {
    "brave-search": {
      "command": "npx",
      "args": [
        "-y",
        "@anthropic-ai/mcp-brave-search"
      ],
      "env": {
        "BRAVE_API_KEY": "BSAu_your_brave_search_api_key"
      }
    }
  }
}
```

---

## 5. How Claude Code Uses Tools in Conversation

Once a server is registered, you do not need special commands or flags. Claude Code inspects your natural language prompt and autonomously decides when to trigger a tool.

### Workflow Example: Interacting with GitHub

**User Prompt:**
> "Check the open issues assigned to me in the acme/platform repository and summarize the most urgent ones."

**Internal Claude Code Lifecycle:**
1. Claude identifies that local repository files lack this remote metadata.
2. It generates a `mcp__github__search_issues` call with filters `repo:acme/platform state:open assignee:@me`.
3. The GitHub server returns structured JSON records.
4. Claude synthesizes the data into clean, readable output:

```markdown
Found 3 open issues assigned to you:

1. **#42 — Fix login redirect loop** (Priority: High, Created: 2 days ago)
2. **#38 — Add rate limiting to auth API** (Priority: Medium, Created: 5 days ago)
3. **#35 — Update user profile settings page** (Priority: Low, Created: 1 week ago)

Would you like to examine the codebase to patch the redirect loop in #42?
```

---

## 6. Building a Custom MCP Server in TypeScript

When ready-made servers don't cover your proprietary internal APIs or domain-specific workflows, you can build a custom MCP Server in minutes using `@modelcontextprotocol/sdk`.

### Step 1. Project Initialization and Dependencies

Create a dedicated directory and install the necessary libraries:

```bash
mkdir my-mcp-server && cd my-mcp-server
npm init -y
npm install @modelcontextprotocol/sdk zod
npm install -D typescript @types/node tsx
```

### Step 2. Server Implementation (`server.ts`)

Create `server.ts` defining the server and a custom tool:

```typescript
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";

// 1. Initialize server with descriptive metadata
const server = new McpServer({
  name: "internal-crm-server",
  version: "1.0.0",
});

// 2. Register a tool with typed Zod input validation
server.tool(
  "lookup-user",
  "Look up a customer profile by their email address",
  {
    email: z.string().email().describe("Registered user email address"),
  },
  async ({ email }) => {
    // Replace with real database or microservice query
    const mockUser = {
      id: "usr_99812",
      email,
      name: "Alex Kowalski",
      plan: "Enterprise",
      status: "active",
      createdAt: "2024-03-15T10:00:00Z",
    };

    return {
      content: [
        {
          type: "text",
          text: JSON.stringify(mockUser, null, 2),
        },
      ],
    };
  }
);

// 3. Connect the server via stdio transport
async function run() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
  console.error("Internal CRM MCP server started on stdio");
}

run().catch((error) => {
  console.error("Server startup error:", error);
  process.exit(1);
});
```

### Step 3. Registering the Server in Settings

Register your script in `.claude/settings.json`:

```json
{
  "mcpServers": {
    "crm": {
      "command": "npx",
      "args": [
        "tsx",
        "/Users/username/Developer/my-mcp-server/server.ts"
      ]
    }
  }
}
```

> [!TIP]
> Running TypeScript with `tsx` avoids having to pre-compile your files with `tsc` during development.

---

## 7. Security and Sandbox Isolation

MCP gives Claude Code significant autonomy, but also allows code execution and data access on your machine. Follow these security rules:

### 1. Servers Inherit Your Permissions
MCP servers run under your operating system user account. A buggy or malicious server has the same file and network permissions as your shell.

### 2. Secret and Token Isolation
Never commit secrets to git. Store sensitive credentials in `~/.claude/settings.json` or source them via `.env` files added to `.gitignore`.

### 3. Audit Third-Party Packages Before Launch
Before connecting community servers:
- Verify that the source code is public and active.
- Inspect network requests initiated during startup.
- Review what directories the server accesses.

### 4. Configuration Level Separation

```text
┌─────────────────────────────────────────────────────────────┐
│                    ~/.claude/settings.json                  │
│    Global Tools: GitHub, Web Search, Browser Automation     │
└──────────────────────────────┬──────────────────────────────┘
                               │
                               ▼
┌─────────────────────────────────────────────────────────────┐
│                    .claude/settings.json                    │
│    Project Tools: Local Dev DB, custom repository scripts   │
└─────────────────────────────────────────────────────────────┘
```

> [!WARNING]
> Do not connect MCP servers with write access to production databases during interactive development sessions. Use read-only database replicas or isolated Docker containers instead.

---

## 8. Hands-On Practice: Step-by-Step Setup

Follow these two exercises to connect and test MCP servers in your environment.

### Task 1. Connecting the GitHub MCP Server

1. Generate a GitHub Personal Access Token (`repo` and `read:org` scopes).
2. Add the server to `~/.claude/settings.json`:

```json
{
  "mcpServers": {
    "github": {
      "command": "npx",
      "args": [
        "-y",
        "@anthropic-ai/mcp-github"
      ],
      "env": {
        "GITHUB_TOKEN": "ghp_your_token_here"
      }
    }
  }
}
```

3. Launch a new Claude Code session and run a test prompt:

```bash
claude
```

> **Test Prompt:**  
> "Show my 5 most recently updated repositories on GitHub and their current status."

- [ ] Claude Code calls the GitHub tool without authentication errors.
- [ ] Returns your repository list accurately.

---

### Task 2. Connecting the Filesystem Server for External Notes

1. Configure the `filesystem` server in `.claude/settings.json`:

```json
{
  "mcpServers": {
    "external-docs": {
      "command": "npx",
      "args": [
        "-y",
        "@anthropic-ai/mcp-filesystem",
        "/path/to/your/notes/folder"
      ]
    }
  }
}
```

2. Test with the following prompt:

> **Test Prompt:**  
> "Find all markdown files in external-docs discussing API architecture and give me a high-level summary."

- [ ] Claude accesses files outside the current project root.
- [ ] Successfully synthesizes information from external files.

---

## 9. Quick Knowledge Check

Test your understanding of Model Context Protocol architecture.

### Question 1. What is the primary purpose of an MCP Server?

- **A.** A cloud VM for hosting Claude foundation models
- **B.** An adapter process giving LLMs standardized access to external tools and data
- **C.** A library for compressing vector embeddings
- **D.** A web server for hosting compiled frontend code

> [!TIP]
> **Correct Answer: B.**  
> An MCP Server acts as an adapter bridging models and external tools, exposing standard Tools, Resources, and Prompts.

---

### Question 2. Where is repository-specific MCP configuration stored?

- **A.** `~/.claude/settings.json`
- **B.** `package.json`
- **C.** `.claude/settings.json` in the project root
- **D.** `CLAUDE.md`

> [!TIP]
> **Correct Answer: C.**  
> Project-specific configuration lives in `.claude/settings.json`, whereas `~/.claude/settings.json` houses machine-wide developer tools.

---

### Question 3. How does Claude Code decide which tool to trigger?

- **A.** The user must supply a `--tool=name` CLI flag with every query
- **B.** You must first run `/mcp select`
- **C.** The model evaluates the prompt against registered JSON schemas and chooses autonomously
- **D.** All tools run simultaneously and redundant results are discarded

> [!TIP]
> **Correct Answer: C.**  
> Claude compares the user's intent with registered tool descriptions and schemas, dispatching requests with valid parameters when needed.

---

## 10. Architecture Summary and Checklist

Model Context Protocol elevates Claude Code into an extensible AI development environment. Instead of manually pasting file contents or schema dumps into chats, you establish persistent, secure communication channels once.

### Environment Readiness Checklist

- [x] **Configuration Tiers:** Global tools live in `~/.claude/settings.json`; project-specific servers live in `.claude/settings.json`.
- [x] **Security Guardrails:** Tokens are excluded from version control; databases use read-only privileges.
- [x] **Verification:** Server tools are verified with targeted prompts upon session startup.
- [x] **Extensibility:** Custom servers can be scaffolded rapidly in TypeScript using `@modelcontextprotocol/sdk`.