Model Context Protocol (MCP) Servers
MCP is an open standard that lets LLMs connect to external tools, data sources, and services through a unified interface. Think of it as a USB-C port for AI — one protocol, many integrations.
How It Works
Host (Claude, Cursor, etc.)
│
│ MCP Protocol (JSON-RPC over stdio/SSE)
▼
MCP Server
│
▼
External System (DB, API, filesystem, etc.)
An MCP server exposes three primitives:
- Tools — functions the LLM can call (e.g. run a query, send a message)
- Resources — data the LLM can read (e.g. files, database records)
- Prompts — reusable prompt templates
Building a Simple MCP Server (Python)
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("my-server")
@mcp.tool()
def get_weather(city: str) -> str:
"""Get current weather for a city."""
# Call your weather API here
return f"Weather in {city}: 22°C, sunny"
@mcp.resource("notes://{note_id}")
def get_note(note_id: str) -> str:
"""Read a note by ID."""
return notes_db.get(note_id)
if __name__ == "__main__":
mcp.run()
Install the SDK:
pip install mcp
Transport Options
| Transport | Use Case |
|---|---|
stdio | Local tools, CLI integrations (most common) |
SSE (Server-Sent Events) | Remote servers, web deployments |
Streamable HTTP | Production APIs (newer standard) |
Connecting to Claude Desktop
Add to ~/Library/Application Support/Claude/claude_desktop_config.json (macOS):
{
"mcpServers": {
"my-server": {
"command": "python",
"args": ["/path/to/server.py"]
}
}
}
For a Node.js server:
{
"mcpServers": {
"my-server": {
"command": "node",
"args": ["/path/to/server.js"]
}
}
}
Connecting to Claude Code
Add to your project's .claude/settings.json or run:
claude mcp add my-server python /path/to/server.py
Useful Community MCP Servers
| Server | What It Does |
|---|---|
@modelcontextprotocol/server-filesystem | Read/write local files |
@modelcontextprotocol/server-postgres | Query PostgreSQL databases |
@modelcontextprotocol/server-github | GitHub issues, PRs, repos |
@modelcontextprotocol/server-slack | Read/send Slack messages |
@modelcontextprotocol/server-brave-search | Web search via Brave |
mcp-server-sqlite | SQLite database access |
Building a Database MCP Server (Example)
from mcp.server.fastmcp import FastMCP
import sqlite3
mcp = FastMCP("sqlite-server")
DB_PATH = "data.db"
@mcp.tool()
def query(sql: str) -> list[dict]:
"""Run a read-only SQL query."""
conn = sqlite3.connect(DB_PATH)
conn.row_factory = sqlite3.Row
cur = conn.execute(sql)
return [dict(row) for row in cur.fetchall()]
@mcp.tool()
def list_tables() -> list[str]:
"""List all tables in the database."""
conn = sqlite3.connect(DB_PATH)
cur = conn.execute("SELECT name FROM sqlite_master WHERE type='table'")
return [row[0] for row in cur.fetchall()]
Security Considerations
- Validate all inputs — treat LLM-supplied arguments as untrusted user input
- Scope permissions — expose only what the LLM needs (read-only DB access where possible)
- Avoid shell execution — never pass LLM input directly to
subprocessoreval - Use allowlists — for filesystem servers, restrict to specific directories
- Log tool calls — audit what the LLM is doing via your server
When to Build a Custom MCP Server
Build one when you want an LLM to:
- Query your internal databases or APIs
- Interact with proprietary tools
- Access real-time data not in the LLM's training set
- Perform actions in your own systems (create tickets, update records, etc.)