Claude Code ships with powerful built-in tools — reading files, running Bash commands, searching codebases. But the moment you need to pull a GitHub PR diff, query your Postgres database, or post a Slack message, you've hit the edge of what's built in. That's where MCP servers come in.
Model Context Protocol (MCP) is an open standard Anthropic developed for connecting AI models to external tools and data sources. Think of it like USB-C for AI integrations: one standardized connector, infinite peripherals. Any service that implements the MCP spec can plug into Claude Code, and Claude can call it just like its native tools.
What MCP actually is
MCP defines three primitives that a server can expose:
- Tools — functions Claude can call with arguments and get a result back. The GitHub MCP server's
create_issuetool is a good example: Claude passes a title and body, the server calls the GitHub API, and returns the new issue URL. - Resources — data Claude can read on demand. Think of these like virtual files: a database MCP server might expose each table as a resource Claude can read without writing a SQL query.
- Prompts — reusable prompt templates the server exposes. Less commonly used in practice, but useful for standardizing how your team asks Claude to interact with a particular service.
In day-to-day Claude Code use, tools are what you'll mostly care about. Resources are useful for read-heavy workflows (like reading docs or database schemas). You can mostly ignore prompt primitives until you're building your own servers.
Why MCP matters for Claude Code specifically
Claude Code already has Bash, which means you could theoretically just write shell scripts to call any API. The difference with MCP is that Claude gets typed, documented tool schemas — it understands what arguments a tool expects, what it returns, and when to use it. That leads to much more reliable behavior than hoping Claude constructs a correct curl command from scratch.
With the right MCP servers configured, Claude Code can:
- Read PR diffs and post review comments on GitHub
- Run queries against your dev database and interpret the results
- Search Slack message history to find context for a bug
- Control a headless browser for end-to-end testing
- Query your project management tool to understand open issues
None of this requires writing glue code. You configure the server, and Claude uses it naturally within your existing conversations.
Configuring MCP servers
MCP servers are configured in Claude Code's settings files under the mcpServers key. Each server entry needs a command to launch it and optional args and env.
Here's the GitHub MCP server configured at the user level (~/.claude/settings.json):
{
"mcpServers": {
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_xxxxxxxxxxxxxxxxxxxx"
}
}
}
}
Claude Code launches this server process when it starts and keeps it running for the session. When Claude decides it needs to call a GitHub tool, it sends a JSON-RPC request to the server process over stdio.
For project-scoped servers, put the same config in .claude/settings.json at your repo root. Project-level servers only activate when Claude Code is run inside that directory (or a subdirectory). This is useful for database connections that are project-specific — you don't want your personal ~/.claude/settings.json hardcoding database credentials for every project.
The claude mcp add shortcut
Instead of editing JSON by hand, you can use the CLI:
# Add a server globally
claude mcp add github --global \
-e GITHUB_PERSONAL_ACCESS_TOKEN=ghp_xxx \
-- npx -y @modelcontextprotocol/server-github
# Add a server for just this project
claude mcp add postgres \
-e DATABASE_URL=postgres://localhost:5432/mydb \
-- npx -y @modelcontextprotocol/server-postgres
The --global flag writes to ~/.claude/settings.json. Without it, the server is added to .claude/settings.json in the current directory.
To see what's currently connected:
claude mcp list
Popular ready-to-use MCP servers
The official Anthropic GitHub org maintains reference servers for common integrations. All of these run via npx with no installation step — npx downloads them on first use.
@modelcontextprotocol/server-github
GitHub repos, PRs, issues, and code search. The most useful server for development workflows. Needs a Personal Access Token with appropriate permissions. See GitHub Integration for a full walkthrough.
@modelcontextprotocol/server-filesystem
Enhanced file operations beyond what Claude Code's built-in Read and Write tools provide. Useful for projects where you want Claude to have a more structured view of the file system, or to restrict access to a specific directory tree.
@modelcontextprotocol/server-puppeteer
Browser automation via Puppeteer. Claude can navigate to URLs, fill in forms, take screenshots, and extract content from pages that require JavaScript rendering. Great for testing frontend flows or scraping content that's not available via API.
@modelcontextprotocol/server-postgres
Connect to a PostgreSQL database and run queries. Claude can explore the schema, run SELECTs to understand data shapes, and (if you allow it) run INSERTs and UPDATEs. Keep this read-only in production environments.
@modelcontextprotocol/server-slack
Read and write Slack messages. Claude can search message history to find context, post updates to a channel, or read threads. Useful for "what were we discussing about this bug last week?" queries.
Community servers
The MCP ecosystem has grown fast. There are community-built servers for Notion, Linear, Jira, Figma, Stripe, and Obsidian, among others. Evaluate community servers carefully before giving them credentials — check the source code and understand what they can access. The MCP blog post covers the protocol's design philosophy and ecosystem in more depth.
MCP vs built-in tools: when to use which
Built-in tools (Read, Write, Bash, Glob, Grep) are optimized for local file and code work. They're fast, don't need network calls, and have no setup. Use them for everything involving your codebase.
Reach for MCP when:
- You need data that lives outside your local filesystem (GitHub, databases, APIs)
- You need to write back to an external service (post a comment, create an issue)
- The external API is complex enough that you don't want Claude constructing raw curl commands
- You want the interaction to be reliable across sessions without prompt-engineering the API format every time
Don't over-MCP your setup. If you're only occasionally querying a database, a Bash tool call with psql works fine. MCP pays off when you're doing it repeatedly and want Claude to have real semantic understanding of the tool's capabilities.
Building a minimal MCP server
If you have an internal API or data source without a public MCP server, you can build one. The mcp Python SDK makes this about 30 lines for a simple tool.
Here's a minimal server that exposes one tool: looking up a user by ID from a hypothetical internal API:
import asyncio
import json
import os
import httpx
from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp.types import Tool, TextContent
app = Server("internal-api")
@app.list_tools()
async def list_tools():
return [
Tool(
name="get_user",
description="Look up a user by their ID in the internal user database",
inputSchema={
"type": "object",
"properties": {
"user_id": {
"type": "string",
"description": "The user's UUID"
}
},
"required": ["user_id"]
}
)
]
@app.call_tool()
async def call_tool(name: str, arguments: dict):
if name == "get_user":
user_id = arguments["user_id"]
async with httpx.AsyncClient() as client:
response = await client.get(
f"https://api.internal.company.com/users/{user_id}",
headers={"Authorization": f"Bearer {os.environ['INTERNAL_API_KEY']}"}
)
return [TextContent(type="text", text=json.dumps(response.json()))]
if __name__ == "__main__":
asyncio.run(stdio_server(app))
Install with pip install mcp httpx, then add to your settings:
{
"mcpServers": {
"internal-api": {
"command": "python",
"args": ["/path/to/server.py"],
"env": {
"INTERNAL_API_KEY": "your-key-here"
}
}
}
}
Three things to get right when building MCP tools: write a clear description (Claude uses this to decide when to call the tool), define a proper JSON Schema for inputSchema (Claude uses this to construct valid arguments), and return useful error messages rather than raw stack traces.
Troubleshooting MCP connections
MCP problems fall into three categories:
Server doesn't start
Run claude mcp list to check which servers Claude Code thinks are configured. If a server shows an error state, the process failed to launch. Common causes: missing npx in PATH, wrong path in args, or a missing environment variable.
Test the server command manually in your terminal first:
GITHUB_PERSONAL_ACCESS_TOKEN=ghp_xxx npx -y @modelcontextprotocol/server-github
If it errors there, it'll error inside Claude Code too. Fix it in the terminal, then you know the config is right.
Server starts but tools don't appear
After adding an MCP server, restart Claude Code — it doesn't hot-reload server configs. Once restarted, ask Claude "what MCP tools do you have available?" and it should list them. If it doesn't, check that the server process is exporting tools correctly.
Tool calls fail at runtime
Check that your environment variables are set and valid. API tokens expire. Database URLs need the right hostname and credentials. Add a simple test prompt before doing anything complex: "Use the postgres MCP server to show me the list of tables."
For GitHub, make sure your Personal Access Token has the right scopes. Fine-grained tokens are better than classic tokens — grant only the specific permissions the server needs. If you're getting 403s on specific operations (like creating issues), your token probably doesn't have write permissions for that resource.
Most MCP problems are configuration issues, not bugs. When in doubt, test the underlying command outside of Claude Code first, then bring it back in.