Claude Desktop MCP: Setup Guide for MCP Servers and Custom Connectors
TL;DR — Claude Desktop MCP setup: edit claude_desktop_config.json, add mcpServers, restart. DEV Community: "Settings > Developer > Edit Config. macOS: ~/Library/Application Support/Claude/. Windows: %APPDATA%\Claude\. Restart fully — Cmd+Q, not just close window. Validate JSON with jsonlint.com. Check logs at ~/Library/Logs/Claude/." Hatchloop: "Top-level key must be exactly mcpServers (camelCase, plural). Nest env inside server. Use absolute paths. Full path to executable — Claude Desktop uses minimal PATH." HeyClaude: "Local MCP servers run on your computer, expose tools Claude can call with approval. Enable by editing single JSON file. Hammer icon verifies tools loaded." MCPPlayground: "Desktop Extensions (.dxt) — one-click, no JSON. Custom Connectors for remote OAuth servers. Old @modelcontextprotocol/server-github archived; use github/github-mcp-server." MyMCPTools: "Filesystem, GitHub, Postgres, Brave Search — all configurable in mcpServers JSON." Learn more with MCP guide, build MCP server, build MCP client, and MCP transports.
DEV Community provides the 2026 guide: "Go to Settings > Developer and click Edit Config. This opens claude_desktop_config.json in your default editor and creates the file if it does not exist. This JSON file is where you define every local MCP server Claude should connect to."
HeyClaude explains the concept: "Claude Desktop can connect to local MCP servers, which are programs that run on your computer and expose tools Claude can call with your approval — reading files, querying a database, searching the web, and more. You enable these servers by editing a single JSON file, claude_desktop_config.json."
Claude Desktop MCP Architecture
> Edit Config"] Config["claude_desktop_config.json
mcpServers JSON structure"] Hammer["Hammer Icon
bottom-right of input
verifies tools loaded"] Tools["Available Tools
Claude calls with
user approval"] end subgraph LocalServers["Local MCP Servers (stdio)"] FS["Filesystem Server
npx @modelcontextprotocol
/server-filesystem
read/write files"] GitHub["GitHub Server
docker ghcr.io/github
/github-mcp-server
repos, issues, PRs"] Postgres["Postgres Server
npx @modelcontextprotocol
/server-postgres
SQL queries"] Brave["Brave Search
npx @modelcontextprotocol
/server-brave-search
web search"] end subgraph RemoteServers["Remote MCP Servers (HTTP)"] Connectors["Custom Connectors
Settings > Connectors
> Add custom connector"] OAuth["OAuth Authentication
Streamable HTTP transport
Pro, Max, Team, Enterprise"] Sentry["Sentry Server
remote, HTTPS"] Slack["Slack Server
remote, HTTPS"] end subgraph DesktopExt["Desktop Extensions"] DXT[".dxt Files
one-click install
drag into Settings > Extensions
no JSON, no Node.js"] end Settings --> Config Config --> FS Config --> GitHub Config --> Postgres Config --> Brave FS --> Hammer GitHub --> Hammer Postgres --> Hammer Brave --> Hammer Hammer --> Tools Connectors --> OAuth OAuth --> Sentry OAuth --> Slack Sentry --> Tools Slack --> Tools DXT --> Tools
Config File Locations
| OS | Path |
|---|---|
| macOS | ~/Library/Application Support/Claude/claude_desktop_config.json |
| Windows | %APPDATA%\Claude\claude_desktop_config.json |
| Linux | ~/.config/Claude/claude_desktop_config.json |
Server Configuration Examples
| Server | Command | Package | Env Vars | Use Case |
|---|---|---|---|---|
| Filesystem | npx |
@modelcontextprotocol/server-filesystem |
None | Read/write files |
| GitHub | docker |
ghcr.io/github/github-mcp-server |
GITHUB_PERSONAL_ACCESS_TOKEN |
Repos, issues, PRs |
| Postgres | npx |
@modelcontextprotocol/server-postgres |
None (conn string in args) | SQL queries |
| Brave Search | npx |
@modelcontextprotocol/server-brave-search |
BRAVE_API_KEY |
Web search |
| Custom | python |
Your server.py |
Any | Custom tools |
Implementation
from dataclasses import dataclass
from typing import Optional
from enum import Enum
class ServerType(Enum):
FILESYSTEM = "filesystem"
GITHUB = "github"
POSTGRES = "postgres"
BRAVE_SEARCH = "brave_search"
CUSTOM = "custom"
REMOTE = "remote"
@dataclass
class ClaudeDesktopMCPSetup:
"""Claude Desktop MCP setup guide and configuration."""
def get_config_paths(self) -> dict:
"""Config file locations by OS."""
return {
"macOS": (
"~/Library/Application Support/Claude/"
"claude_desktop_config.json"
),
"Windows": (
"%APPDATA%\\Claude\\"
"claude_desktop_config.json"
),
"Linux": (
"~/.config/Claude/"
"claude_desktop_config.json"
),
"how_to_open": (
"Settings > Developer > Edit Config "
"creates file if it does not exist "
"and opens in default editor"
),
}
def get_filesystem_config(self) -> str:
"""Filesystem MCP server config."""
return (
'{\n'
' "mcpServers": {\n'
' "filesystem": {\n'
' "command": "npx",\n'
' "args": [\n'
' "-y",\n'
' "@modelcontextprotocol/'
'server-filesystem",\n'
' "/Users/username/Documents",\n'
' "/Users/username/Projects"\n'
' ]\n'
' }\n'
' }\n'
'}\n'
'\n'
'# Paths after package name are\n'
'# directories Claude can access.\n'
'# Use absolute paths, not relative.\n'
'# Windows: use escaped backslashes\n'
'# or forward slashes in paths.'
)
def get_github_config(self) -> str:
"""GitHub MCP server config (official Docker)."""
return (
'{\n'
' "mcpServers": {\n'
' "github": {\n'
' "command": "docker",\n'
' "args": [\n'
' "run", "-i", "--rm",\n'
' "-e",\n'
' "GITHUB_PERSONAL_ACCESS_TOKEN",\n'
' "ghcr.io/github/'
'github-mcp-server"\n'
' ],\n'
' "env": {\n'
' "GITHUB_PERSONAL_ACCESS_TOKEN":\n'
' "ghp_your_token_here"\n'
' }\n'
' }\n'
' }\n'
'}\n'
'\n'
'# Create PAT at:\n'
'# github.com/settings/'
'# personal-access-tokens/new\n'
'# Scopes: repo, read:org\n'
'# Old npm package\n'
'# @modelcontextprotocol/server-github\n'
'# was archived in 2025.\n'
'# Use official Go-based server:\n'
'# github/github-mcp-server v1.0.0'
)
def get_postgres_config(self) -> str:
"""Postgres MCP server config."""
return (
'{\n'
' "mcpServers": {\n'
' "postgres": {\n'
' "command": "npx",\n'
' "args": [\n'
' "-y",\n'
' "@modelcontextprotocol/'
'server-postgres",\n'
' "postgresql://localhost:'
'5432/mydb"\n'
' ]\n'
' }\n'
' }\n'
'}\n'
'\n'
'# Connection string is passed\n'
'# as last arg to the server.\n'
'# Claude can query your database\n'
'# with read-only access by default.'
)
def get_multi_server_config(self) -> str:
"""Multiple MCP servers in one config."""
return (
'{\n'
' "mcpServers": {\n'
' "filesystem": {\n'
' "command": "npx",\n'
' "args": [\n'
' "-y",\n'
' "@modelcontextprotocol/'
'server-filesystem",\n'
' "/Users/username/Projects"\n'
' ]\n'
' },\n'
' "github": {\n'
' "command": "docker",\n'
' "args": [\n'
' "run", "-i", "--rm",\n'
' "-e",\n'
' "GITHUB_PERSONAL_ACCESS_TOKEN",\n'
' "ghcr.io/github/'
'github-mcp-server"\n'
' ],\n'
' "env": {\n'
' "GITHUB_PERSONAL_ACCESS_TOKEN":\n'
' "ghp_your_token"\n'
' }\n'
' },\n'
' "postgres": {\n'
' "command": "npx",\n'
' "args": [\n'
' "-y",\n'
' "@modelcontextprotocol/'
'server-postgres",\n'
' "postgresql://localhost:'
'5432/mydb"\n'
' ]\n'
' },\n'
' "brave-search": {\n'
' "command": "npx",\n'
' "args": [\n'
' "-y",\n'
' "@modelcontextprotocol/'
'server-brave-search"\n'
' ],\n'
' "env": {\n'
' "BRAVE_API_KEY":\n'
' "BSA_your_key"\n'
' }\n'
' }\n'
' }\n'
'}'
)
def get_custom_server_config(self) -> str:
"""Custom Python MCP server config."""
return (
'{\n'
' "mcpServers": {\n'
' "my-server": {\n'
' "command":\n'
' "/path/to/.venv/bin/python",\n'
' "args": [\n'
' "/path/to/server.py"\n'
' ],\n'
' "env": {\n'
' "API_KEY": "your-key"\n'
' }\n'
' }\n'
' }\n'
'}\n'
'\n'
'# Use absolute path to Python\n'
'# and to your server script.\n'
'# Claude Desktop uses minimal PATH.\n'
'# On Windows use:\n'
'# "command": "cmd",\n'
'# "args": ["/c", "python",\n'
'# "C:\\path\\to\\server.py"]'
)
def get_remote_connectors(self) -> dict:
"""Remote MCP servers via Custom Connectors."""
return {
"what": (
"Custom Connectors for remote MCP "
"servers hosted on the web with OAuth"
),
"how": [
"Settings > Connectors > "
"Add custom connector",
"Paste remote MCP server URL",
"Must use Streamable HTTP transport",
"Authenticate with OAuth",
"Tools appear in Claude Desktop",
],
"availability": (
"Pro, Max, Team, and Enterprise plans"
),
"vs_local": (
"Local STDIO servers use "
"claude_desktop_config.json. "
"Remote servers use Custom Connectors. "
"Remote servers require no local setup "
"but depend on provider uptime."
),
}
def get_desktop_extensions(self) -> dict:
"""Desktop Extensions (.dxt) one-click install."""
return {
"what": (
"Desktop Extensions (.dxt) — "
"one-click MCP server installation"
),
"how": [
"Download .dxt file",
"Drag into Settings > Extensions",
"Done — no JSON editing, "
"no Node.js, no PATH issues",
],
"best_for": "End users who want simplicity",
"vs_manual": (
"Manual JSON config is more flexible, "
"required for custom servers, env vars, "
"or anything not published as .dxt"
),
}
def get_troubleshooting(self) -> dict:
"""Troubleshooting guide."""
return {
"server_not_appearing": {
"causes": [
"Malformed JSON in config file",
"Wrong top-level key "
"(must be mcpServers, camelCase)",
"Did not restart fully "
"(Cmd+Q on macOS, Alt+F4 on Windows)",
"npx or docker not in PATH",
"Relative paths instead of absolute",
"Missing or wrong env vars",
],
"fixes": [
"Validate JSON at jsonlint.com",
"Check top-level key is mcpServers",
"Quit completely and relaunch",
"Use full path to executable",
"Use absolute paths for all files",
"Check API keys and env vars",
],
},
"tools_not_working": {
"causes": [
"API key typo causes silent failure",
"Docker not running for Docker servers",
"Filesystem paths do not exist",
"GitHub token lacks required scopes",
],
"fixes": [
"Regenerate and re-paste API keys",
"Start Docker Desktop before Claude",
"Verify filesystem paths exist",
"Check token scopes: repo, read:org",
],
},
"check_logs": {
"macOS": "~/Library/Logs/Claude/",
"Windows": "%APPDATA%\\Claude\\logs\\",
"use": (
"Read error output from MCP servers "
"to diagnose issues"
),
},
"common_json_mistakes": [
"Wrong top-level key: mcp_servers "
"instead of mcpServers",
"env at top level instead of "
"inside server object",
"Trailing commas in JSON",
"Using short names (npx) instead of "
"full paths",
"Relative paths instead of absolute",
],
"windows_specific": [
"Use cmd /c prefix for npx commands",
"Use escaped backslashes or "
"forward slashes in paths",
"Check %LOCALAPPDATA%\\Packages\\"
"Claude_*\\LocalCache\\Roaming\\Claude\\ "
"for config on some Windows installs",
"${APPDATA} ENOENT error: add "
"expanded %APPDATA% to env block",
],
}
def get_verification(self) -> dict:
"""How to verify MCP servers are working."""
return {
"steps": [
"Restart Claude Desktop completely "
"(quit from dock/tray, not just window)",
"Look for hammer icon in bottom-right "
"of conversation input box",
"Click icon to see tools the server exposes",
"Try using a tool in conversation",
"Claude will ask for approval before "
"executing tool calls",
],
"indicator": (
"Hammer icon (🔨) in bottom-right "
"of input box indicates tools are loaded"
),
"no_indicator": (
"If indicator does not appear: "
"check JSON validity, restart fully, "
"read logs, verify PATH"
),
}
Claude Desktop MCP Checklist
- [ ] Open Settings > Developer > Edit Config to create/edit claude_desktop_config.json
- [ ] macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
- [ ] Windows: %APPDATA%\Claude\claude_desktop_config.json
- [ ] Linux: ~/.config/Claude/claude_desktop_config.json
- [ ] Top-level key must be exactly mcpServers (camelCase, plural)
- [ ] Common misspellings: mcp_servers, mcpServer, MCPServers, servers — all valid JSON but load zero servers
- [ ] Each server has: command, args, optional env
- [ ] Nest env inside each server object, not at top level
- [ ] Use string values for all env vars
- [ ] Use absolute paths, not relative
- [ ] Use full path to executable — Claude Desktop uses minimal PATH
- [ ] Short names like npx or docker may fail even when they work in terminal
- [ ] Filesystem server: npx -y @modelcontextprotocol/server-filesystem /path/to/dir
- [ ] Paths after package name are directories Claude can access
- [ ] GitHub server: docker run -i --rm -e GITHUB_PERSONAL_ACCESS_TOKEN ghcr.io/github/github-mcp-server
- [ ] Create GitHub PAT at github.com/settings/personal-access-tokens/new with repo and read:org scopes
- [ ] Old npm package @modelcontextprotocol/server-github was archived in 2025
- [ ] Use official Go-based server: github/github-mcp-server v1.0.0 (April 2026)
- [ ] Postgres server: npx -y @modelcontextprotocol/server-postgres postgresql://localhost:5432/mydb
- [ ] Brave Search: npx -y @modelcontextprotocol/server-brave-search with BRAVE_API_KEY env
- [ ] Custom Python server: command=/path/to/python, args=[/path/to/server.py]
- [ ] On Windows: use cmd /c prefix for npx commands
- [ ] On Windows: use escaped backslashes or forward slashes in paths
- [ ] Validate JSON at jsonlint.com before restarting
- [ ] A single missing comma or trailing comma breaks the entire config
- [ ] Restart Claude Desktop completely — Cmd+Q on macOS, Alt+F4 on Windows
- [ ] Closing the window is NOT enough — app continues in system tray
- [ ] Verify: hammer icon (🔨) appears in bottom-right of input box
- [ ] Click hammer icon to see tools the server exposes
- [ ] Claude asks for user approval before executing tool calls
- [ ] Local servers run as child processes of Claude Desktop via stdio
- [ ] Local servers work offline but need Node.js or Docker installed
- [ ] Remote servers: use Custom Connectors (Settings > Connectors > Add custom connector)
- [ ] Remote servers use Streamable HTTP transport with OAuth
- [ ] Custom Connectors available on Pro, Max, Team, and Enterprise plans
- [ ] Remote servers require no local setup but depend on provider uptime
- [ ] Desktop Extensions (.dxt): one-click install, drag into Settings > Extensions
- [ ] .dxt: no JSON editing, no Node.js, no PATH issues — best for end users
- [ ] Manual JSON config more flexible — required for custom servers and env vars
- [ ] Check logs: macOS ~/Library/Logs/Claude/, Windows %APPDATA%\Claude\logs\
- [ ] Docker must be running for Docker-based servers before launching Claude
- [ ] Confirm npx is in PATH: which npx (macOS/Linux) or where npx (Windows)
- [ ] API key typos cause silent failures — regenerate and re-paste
- [ ] For filesystem server, verify paths actually exist
- [ ] For GitHub, verify token has necessary scopes (repo, read:org)
- [ ] Windows ${APPDATA} ENOENT: add expanded %APPDATA% to env block
- [ ] Windows config may be in %LOCALAPPDATA%\Packages\Claude_*\LocalCache\Roaming\Claude\
- [ ] Claude Code uses claude add; Claude Desktop uses claude_desktop_config.json
- [ ] Can test remote MCP servers in browser with MCP Playground before wiring
- [ ] Read MCP developer guide for protocol
- [ ] Read build MCP server for server creation
- [ ] Read build MCP client for client implementation
- [ ] Read MCP transports for transport details
- [ ] Read MCP tools for tool development
- [ ] Test: filesystem server reads files from specified directories
- [ ] Test: GitHub server lists repos and issues with valid token
- [ ] Test: hammer icon appears after restart with valid config
- [ ] Test: Claude asks for approval before tool execution
- [ ] Test: multiple servers work simultaneously in one config
- [ ] Document server configs, env vars, paths, and troubleshooting steps
FAQ
How do you set up MCP servers in Claude Desktop?
Edit claude_desktop_config.json in Settings > Developer > Edit Config, add mcpServers JSON, restart Claude Desktop completely. DEV Community: "Go to Settings > Developer and click Edit Config. This opens claude_desktop_config.json in your default editor and creates the file if it does not exist. macOS: ~/Library/Application Support/Claude/claude_desktop_config.json. Windows: %APPDATA%\Claude\claude_desktop_config.json. Linux: ~/.config/Claude/claude_desktop_config.json." HeyClaude: "Claude Desktop can connect to local MCP servers — programs that run on your computer and expose tools Claude can call with your approval. You enable these by editing a single JSON file." MCPPlayground: "Open Claude Desktop, Settings, Developer, Edit Config. Add MCP servers to claude_desktop_config.json. Restart Claude Desktop completely. Look for hammer icon to verify tools are loaded." Steps: (1) Settings > Developer > Edit Config. (2) Add mcpServers JSON with command, args, env. (3) Quit and relaunch Claude Desktop (Cmd+Q on macOS). (4) Verify hammer icon appears in input box.
What is the correct claude_desktop_config.json format?
Use mcpServers as the top-level key (camelCase, plural), with each server having command, args, and optional env. Hatchloop: "The top-level key must be exactly mcpServers (camelCase, plural). Common misspellings — mcp_servers, mcpServer, MCPServers, servers — are valid JSON, so nothing errors. Claude Desktop just looks for mcpServers, does not find it, and loads zero servers. Nest env inside the server, use string values, match names exactly." Format: {"mcpServers": {"server-name": {"command": "npx", "args": ["-y", "@modelcontextprotocol/server-name"], "env": {"API_KEY": "value"}}}}. Common mistakes: (1) Wrong top-level key (mcpServers not mcp_servers). (2) env at top level instead of inside server. (3) Trailing commas. (4) Relative paths instead of absolute. (5) Short command names instead of full paths.
How do you add filesystem, GitHub, and Postgres MCP servers to Claude Desktop?
Add multiple servers to the mcpServers object with their respective commands, args, and env vars. MyMCPTools: "Filesystem server gives Claude direct access to read and write files. GitHub server requires GITHUB_PERSONAL_ACCESS_TOKEN. Postgres server takes connection string as arg." DEV Community: "GitHub MCP: use Docker with ghcr.io/github/github-mcp-server. Create PAT at github.com/settings/personal-access-tokens/new with repo and read:org scopes." MCPPlayground: "Old npm package @modelcontextprotocol/server-github was archived in 2025. GitHub official Go-based server at github/github-mcp-server (v1.0.0, April 2026) is recommended." Filesystem: npx -y @modelcontextprotocol/server-filesystem /path/to/dir. GitHub: docker run -i --rm -e GITHUB_PERSONAL_ACCESS_TOKEN ghcr.io/github/github-mcp-server. Postgres: npx -y @modelcontextprotocol/server-postgres postgresql://localhost:5432/mydb.
How do you connect Claude Desktop to remote MCP servers?
Use Custom Connectors in Settings > Connectors > Add custom connector with the remote server URL using Streamable HTTP transport and OAuth. MCPPlayground: "For remote MCP servers hosted on the web with OAuth, you do not use claude_desktop_config.json — you use Custom Connectors. Paste the remote MCP server URL (must use Streamable HTTP transport). Custom Connectors are available on Pro, Max, Team, and Enterprise plans. For local STDIO servers, keep using claude_desktop_config.json." DEV Community: "Local MCP servers run on your machine as child processes. Remote MCP servers run on external infrastructure and connect over HTTPS with OAuth. Remote servers require no local setup but depend on provider uptime. Local servers work offline but need Node.js or Docker installed." Steps: (1) Settings > Connectors > Add custom connector. (2) Paste remote MCP server URL. (3) Authenticate with OAuth. (4) Tools appear in Claude Desktop.
How do you troubleshoot MCP server issues in Claude Desktop?
Check JSON validity, restart fully, verify PATH, check logs, use absolute paths, and confirm API keys. DEV Community: "Restart fully — quit Claude Desktop (Cmd+Q on macOS, Alt+F4 on Windows) and relaunch. Closing the window is not enough; the app continues running in the system tray. Validate your JSON — a missing comma or extra trailing comma will break the entire config. Paste into jsonlint.com. Confirm npx is in your PATH. Check API keys. Docker must be running for Docker-based servers. Check logs: macOS ~/Library/Logs/Claude/, Windows %APPDATA%\Claude\logs." Hatchloop: "Use full path to executable. Claude Desktop launches config with a minimal PATH, so short names like npx or docker often fail even when they work in your terminal." HeyClaude: "Server/tools icon not showing: restart completely, check JSON validity, use absolute paths, read logs. Tool calls failing silently: check logs, verify server runs independently, restart." MCPPlayground: "Desktop Extensions (.dxt) — one-click way. Download .dxt file, drag into Settings > Extensions. No JSON editing, no Node.js, no PATH issues."
Want a self-hosted AI company brain that does all of this out of the box?
Book a demo →