How to Set Up and Configure MCP Servers for Claude Code
How to Set Up and Configure MCP Servers for Claude Code
I wanted to extend Claude Code with MCP servers. I found the official docs but got confused by one question: Do I need to install Python packages locally on my dev machine, or is there some sort of hosted gateway I can run on a VM or in the cloud?
Turns out the answer is: it depends on the MCP server. Let me walk you through what I learned.
What Are MCP Servers Anyway?
MCP (Model Context Protocol) servers are plugins that extend Claude Code’s capabilities. They give Claude access to external systems like databases, APIs, file systems, and more.
Think of them like npm packages for your AI assistant. Each server provides specific tools and resources that Claude can use.
┌─────────────┐ ┌─────────────┐ ┌─────────────┐│ Claude Code │ ──stdio─→│ MCP Server │ ───────→│ External ││ (Client) │ or │ (Plugin) │ │ System ││ │ HTTP │ │ │ │└─────────────┘ └─────────────┘ └─────────────┘There are two main types:
- stdio servers - Run as local child processes on your machine
- HTTP servers - Remote servers accessed over the network
This distinction matters a lot for setup.
Local vs Hosted: The Core Confusion
When I first looked at MCP servers, the documentation was scattered. Some repos said “npm install”, others said “pip install”, and a few mentioned HTTP URLs.
Here’s what I figured out:
Local Installation (stdio servers)
Most MCP servers run locally on your development machine. They spawn as child processes that Claude Code communicates with via standard input/output.
Examples: Filesystem MCP, PostgreSQL MCP, Docker MCP
Best for: Personal development, sensitive data, low latency
Hosted Installation (HTTP servers)
Some MCP servers can run remotely on VMs or cloud instances. You connect to them via HTTP.
Examples: Context7 MCP, GitHub MCP (enterprise deployments)
Best for: Team sharing, centralized management, enterprise deployments
Decision Matrix
| Scenario | Recommended Approach |
|---|---|
| Personal development | Local stdio |
| Team collaboration | Hosted HTTP |
| Sensitive data | Local stdio |
| Enterprise deployment | Hosted with policies |
| Quick testing | Local stdio |
For most developers starting out, local stdio servers are the way to go. That’s what I use for daily development.
Prerequisites
Before setting up MCP servers, I made sure I had the basics:
# Check Claude Codeclaude --version
# Check Node.js (for Node.js-based MCPs)node --version # Need 18+
# Check Python (for Python-based MCPs)python --version # Need 3.8+For Node.js MCPs, npx comes bundled with Node.js. For Python MCPs, I needed pip installed.
Setting Up Node.js MCP Servers
Let me start with the Filesystem MCP - probably the most commonly used one.
The npx Approach
The cool thing about Node.js MCPs is that npx handles everything. No manual installation needed.
I tried adding this to my configuration:
{ "mcpServers": { "filesystem": { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/Users/cowrie/projects"], "env": { "LOG_LEVEL": "debug" } } }}The -y flag tells npx to automatically download and run the package without prompting. I specify the allowed directory for security - Claude can only access files in that path.
What I Got Wrong at First
I initially forgot to specify the allowed directory and got an error:
Error: Filesystem server requires at least one allowed directory pathThen I tried using a path that didn’t exist:
Error: Directory /nonexistent/path does not existMCP servers validate their configuration at startup. This caught me off guard but makes sense for security.
Setting Up Python MCP Servers
Python MCPs typically require a bit more setup. Let me walk through the PostgreSQL MCP as an example.
Cloning and Installing
First, I cloned the repository:
git clone https://github.com/crystaldba/postgres-mcp.gitcd postgres-mcppip install -e .The -e flag installs in development mode, which is useful for debugging.
Configuration
Then I added it to my configuration:
{ "mcpServers": { "postgres": { "command": "python", "args": ["-m", "postgres_mcp"], "env": { "DATABASE_URL": "postgresql://user:pass@localhost:5432/mydb" } } }}The Environment Variable Trap
I hardcoded the database URL at first. Bad idea. When I committed my config to dotfiles, I almost exposed my credentials.
Now I use environment variables:
{ "mcpServers": { "postgres": { "command": "python", "args": ["-m", "postgres_mcp"], "env": { "DATABASE_URL": "${DATABASE_URL}" } } }}Then I set the actual value in my shell:
export DATABASE_URL="postgresql://user:pass@localhost:5432/mydb"Using the Claude Code CLI
Claude Code has a CLI for managing MCP servers. I found this easier than editing JSON files manually.
Adding a Server
# Basic syntaxclaude mcp add-json <name> '<json-config>'
# Example: Add a local stdio serverclaude mcp add-json my-filesystem '{ "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/home/user/projects"]}'
# Example: Add an HTTP serverclaude mcp add-json remote-api '{ "url": "https://mcp.example.com/mcp", "headers": { "Authorization": "Bearer your-token" }}'Listing Servers
claude mcp listThis shows all configured servers and their status.
Configuration File Locations
I got confused about where to put configuration files. Turns out there are multiple options:
Global Configuration
Location: ~/.claude.json or ~/.claude/mcp.json
This applies to all your projects. I use this for servers I always want available, like the filesystem MCP.
Project-Level Configuration
Location: .mcp.json in project root
This is project-specific and can be committed to git for team sharing. I use this for project-specific database connections.
{ "database-tools": { "command": "python", "args": ["-m", "project_db_mcp"], "env": { "DB_URL": "${PROJECT_DB_URL}" } }}Configuration Hierarchy
┌─────────────────────────────────────────┐│ ~/.claude.json (Global) ││ - Always available servers ││ - Personal tools │└─────────────────────────────────────────┘ │ ▼┌─────────────────────────────────────────┐│ .mcp.json (Project Level) ││ - Project-specific servers ││ - Team shared configuration │└─────────────────────────────────────────┘ │ ▼┌─────────────────────────────────────────┐│ Merged Configuration ││ - Both global and project servers ││ - Project can override global │└─────────────────────────────────────────┘Popular MCP Server Examples
Here are the MCP servers I actually use day-to-day.
GitHub CLI MCP
For interacting with GitHub repositories, issues, and PRs:
# macOSbrew install gh
# Ubuntusudo apt install gh
# Authenticategh auth login{ "mcpServers": { "github": { "command": "gh", "args": ["mcp"] } }}Context7 MCP
For fetching up-to-date documentation for any library:
{ "mcpServers": { "context7": { "command": "npx", "args": ["-y", "@upstash/context7-mcp"] } }}This is super useful when I need current docs for a library that changed recently.
Docker MCP
For managing Docker containers and images:
{ "mcpServers": { "docker": { "command": "docker", "args": ["mcp", "serve"] } }}Requires Docker to be installed and running.
Troubleshooting Common Issues
Server Not Starting
Symptoms: MCP server doesn’t appear in Claude Code, “command not found” errors.
What I check:
# Verify command existswhich npxwhich python
# Test server manuallynpx -y @modelcontextprotocol/server-filesystem /tmp
# Check logsclaude mcp listMost of the time, the issue is a missing dependency or wrong path.
Permission Denied
Symptoms: “Permission denied” errors, cannot access files.
What I check:
# Make script executablechmod +x /path/to/server
# Check file permissionsls -la /path/to/serverEnvironment Variables Not Loading
Symptoms: API keys not recognized, configuration values missing.
What I check:
# Verify environment variable is setecho $GITHUB_TOKEN
# Set in shell profile if missingecho 'export GITHUB_TOKEN="your-token"' >> ~/.bashrcsource ~/.bashrcConnection Refused (HTTP Servers)
Symptoms: “Connection refused” or timeout errors for HTTP servers.
What I check:
# Verify server is runningcurl http://localhost:8080/health
# Check firewallsudo ufw status
# Verify URL in configurationEnterprise Deployment
For teams, there are enterprise features worth knowing about.
Allowlists and Denylists
Control which MCP servers users can configure:
{ "allowedMcpServers": [ { "serverName": "github" }, { "serverName": "sentry" }, { "serverCommand": ["npx", "-y", "@modelcontextprotocol/server-filesystem"] }, { "serverUrl": "https://mcp.company.com/*" } ], "deniedMcpServers": [ { "serverName": "dangerous-server" }, { "serverUrl": "https://*.untrusted.com/*" } ]}Managed Configuration
For complete control, use a managed configuration file that users cannot modify:
{ "mcpServers": { "github": { "url": "https://api.githubcopilot.com/mcp/" }, "sentry": { "url": "https://mcp.sentry.dev/mcp" } }}Best Practices I Follow
Security:
- Never hardcode secrets in configuration files
- Use environment variables:
"API_KEY": "${API_KEY}" - Restrict file system access to specific directories
Organization:
- Use descriptive server names
- Use project-level
.mcp.jsonfor team sharing - Document each server’s purpose in comments
Maintenance:
- Keep MCP servers updated
- Review and rotate API keys regularly
- Audit server access logs in enterprise settings
Summary
In this post, I walked through how to set up and configure MCP servers for Claude Code. The key points:
- Most MCPs run locally via stdio - use npx for Node.js, pip for Python
- Configuration uses simple JSON in
~/.claude.jsonor.mcp.json - Environment variables keep secrets secure - never hardcode credentials
- HTTP servers exist for teams - use them for centralized management
Start with the Filesystem MCP to get comfortable, then explore other servers based on your needs. The MCP ecosystem is growing fast, and the setup process becomes second nature after a few tries.
Final Words + More Resources
My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!
Comments