Skip to main content

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

TransportUse Case
stdioLocal tools, CLI integrations (most common)
SSE (Server-Sent Events)Remote servers, web deployments
Streamable HTTPProduction 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

ServerWhat It Does
@modelcontextprotocol/server-filesystemRead/write local files
@modelcontextprotocol/server-postgresQuery PostgreSQL databases
@modelcontextprotocol/server-githubGitHub issues, PRs, repos
@modelcontextprotocol/server-slackRead/send Slack messages
@modelcontextprotocol/server-brave-searchWeb search via Brave
mcp-server-sqliteSQLite 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 subprocess or eval
  • 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.)