Problem: Claude Code Can't See Your Tools by Default
Claude Code is powerful out of the box — but it has no access to your GitHub PRs, your Postgres database, your Slack messages, or your internal APIs. Every time you need context from an external system, you're copying and pasting manually.
MCP (Model Context Protocol) fixes this. It lets Claude Code call external tools directly during a session — no copy-paste, no context switching.
You'll learn:
- How to add MCP servers to Claude Code via the CLI and config file
- How to connect GitHub, a local Postgres database, and a filesystem server
- How to verify MCP tools are active and debug when they're not
Time: 20 min | Difficulty: Intermediate
Why MCP Exists
Claude Code runs as a CLI agent. By default it can read files, run shell commands, and call the Anthropic API — nothing else. MCP is an open standard that defines how AI assistants connect to external tools via a JSON-RPC-style protocol over stdio or HTTP.
Each MCP server exposes a set of tools (callable functions) and optionally resources (readable data). Claude Code discovers these at startup and can invoke them mid-conversation.
Claude Code ──stdio──▶ MCP Server Process
│
Tool: get_pull_requests()
Tool: run_sql_query()
Tool: read_file()
The servers run as separate processes — they're isolated, and you can write your own in any language that speaks JSON over stdio.
Solution
Step 1: Confirm Claude Code Version
MCP support requires Claude Code 1.x or later.
claude --version
Expected output:
claude-code/1.x.x
If you're on an older version, update:
npm update -g @anthropic-ai/claude-code
Step 2: Add Your First MCP Server (GitHub)
The official GitHub MCP server lets Claude read PRs, issues, file contents, and repo metadata directly.
First, install the server:
npm install -g @modelcontextprotocol/server-github
Then register it with Claude Code:
claude mcp add github \
--command "npx" \
--args "-y @modelcontextprotocol/server-github" \
--env GITHUB_PERSONAL_ACCESS_TOKEN=ghp_yourtoken
What this does: Registers a server named github that launches via npx and injects your PAT as an environment variable. The token needs repo and read:org scopes for full functionality.
Verify it registered:
claude mcp list
Expected output:
github npx -y @modelcontextprotocol/server-github [running]
Step 3: Add a Postgres MCP Server
The official Postgres server exposes query and list_tables tools. Claude can run read-only SQL against your database mid-session.
npm install -g @modelcontextprotocol/server-postgres
Register it, scoping it to your local dev database:
claude mcp add postgres \
--command "npx" \
--args "-y @modelcontextprotocol/server-postgres" \
--env DATABASE_URL=postgresql://localhost:5432/myapp_dev
Security note: Use a read-only database user for this. Claude Code runs in your terminal session — if you paste a production URL with write access, Claude can modify data if you instruct it to.
Step 4: Add a Filesystem Server for Project Docs
The filesystem server lets Claude read directories outside your current working directory — useful for monorepos or shared internal documentation.
claude mcp add docs \
--command "npx" \
--args "-y @modelcontextprotocol/server-filesystem /home/user/company-docs"
The path at the end is the root directory the server is allowed to read. Claude cannot access anything above it.
Step 5: Verify with a Config File (Optional but Recommended)
claude mcp add writes to ~/.claude.json. You can also edit this file directly to manage multiple servers in one place:
{
"mcpServers": {
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_yourtoken"
}
},
"postgres": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-postgres"],
"env": {
"DATABASE_URL": "postgresql://readonly:pass@localhost:5432/myapp_dev"
}
},
"docs": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/home/user/company-docs"]
}
}
}
This config is loaded every time Claude Code starts. Commit a version without secrets to your dotfiles repo for reproducibility.
Step 6: Use MCP Tools in a Session
Start a Claude Code session:
claude
Claude automatically connects to all registered MCP servers on startup. You'll see:
✓ MCP server "github" connected (8 tools)
✓ MCP server "postgres" connected (2 tools)
✓ MCP server "docs" connected (3 tools)
Now you can ask Claude things like:
> List open PRs on my repo that touch the auth module
> Show me the schema for the users table
> Find any doc that mentions our rate-limiting policy
Claude calls the MCP tools automatically — no syntax required on your end.
Verification
Run this in a session to confirm tools are visible:
claude -p "List all available MCP tools"
You should see: A formatted list of tool names grouped by server — github.get_pull_request, postgres.query, filesystem.read_file, etc.
If a server shows [failed] in claude mcp list:
spawn npx ENOENT→ Node.js not on PATH; runwhich npxto confirmAuthentication failed→ Check your env var name matches exactly what the server expects- Server starts then exits → Run the server manually (
npx -y @modelcontextprotocol/server-github) to see its startup error
Scoping MCP to a Project
Global config in ~/.claude.json applies to every session. For project-specific servers, create .claude.json in your project root:
{
"mcpServers": {
"project-db": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-postgres"],
"env": {
"DATABASE_URL": "postgresql://localhost:5432/this_project_only"
}
}
}
}
Claude Code merges project-level config with global config. Project servers take precedence on name conflicts.
Building a Custom MCP Server
If no public server fits your tool, write your own. The SDK handles protocol boilerplate:
npm install @modelcontextprotocol/sdk
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
const server = new Server(
{ name: "my-internal-api", version: "1.0.0" },
{ capabilities: { tools: {} } }
);
// Register a tool
server.setRequestHandler("tools/list", async () => ({
tools: [{
name: "get_feature_flags",
description: "Returns active feature flags for an environment",
inputSchema: {
type: "object",
properties: {
environment: { type: "string", enum: ["staging", "production"] }
},
required: ["environment"]
}
}]
}));
// Handle tool calls
server.setRequestHandler("tools/call", async (req) => {
if (req.params.name === "get_feature_flags") {
const env = req.params.arguments.environment;
// Call your internal API here
const flags = await fetchFlagsFromAPI(env);
return { content: [{ type: "text", text: JSON.stringify(flags) }] };
}
});
const transport = new StdioServerTransport();
await server.connect(transport);
Register it the same way:
claude mcp add feature-flags \
--command "node" \
--args "/path/to/my-server/index.js"
What You Learned
- MCP servers connect to Claude Code via stdio — they're isolated processes, not plugins
~/.claude.jsonstores global server config; project-level.claude.jsonoverrides per repo- Use read-only credentials for database servers — Claude will use whatever permissions you give it
- The official MCP server registry has 20+ pre-built servers for GitHub, Slack, Postgres, filesystem, and more
When not to use MCP: For one-off lookups, piping output directly into the session is faster than setting up a server. MCP pays off when you need the same external context repeatedly across sessions.
Tested on Claude Code 1.x, Node.js 22, macOS 15 and Ubuntu 24.04