Model Context Protocol (MCP) is an open standard developed by Anthropic that gives AI models a consistent, secure way to connect to external tools, data sources, and services. Think of it as a universal adapter: instead of every AI app building custom integrations with every data source, MCP provides one protocol that any client (Claude, Cursor, Continue.dev) can speak to any server (filesystem, GitHub, databases).
What Problem Does MCP Solve?
Before MCP, connecting an LLM to external tools meant writing one-off function-calling integrations for every combination of model and service. These integrations couldn’t be reused across clients, had no standard security model, and required duplicated effort.
MCP defines a client–server architecture where:
- MCP Servers expose tools, resources, and prompts from a specific service
- MCP Clients (AI apps like Claude Desktop, Cursor) connect to one or more servers
- Communication happens over JSON-RPC 2.0 via stdio or HTTP with SSE
The protocol handles capability negotiation, tool discovery, and secure context passing — so the AI app doesn’t need to know the internals of each service.
Core Concepts
Tools
Tools are callable functions exposed by an MCP server. When Claude connects to a filesystem MCP server, it can call tools like read_file, write_file, list_directory, and search_files. Tools have typed input schemas defined in JSON Schema.
Resources
Resources are data sources the AI can read — think files, database rows, web pages. Unlike tools (which perform actions), resources are read-only context providers.
Prompts
Servers can expose reusable prompt templates. A GitHub MCP server might expose a summarize_pr prompt that takes a PR number and returns a formatted summary request.
Available MCP Servers
Anthropic maintains a repository of reference servers at github.com/modelcontextprotocol/servers. Notable ones:
| Server | What it exposes |
|---|---|
filesystem | Read/write local files and directories |
github | Repos, issues, PRs, file contents via GitHub API |
postgres | Query PostgreSQL databases |
sqlite | Query local SQLite databases |
slack | Read channels, post messages |
puppeteer | Browser automation and web scraping |
brave-search | Web search via Brave Search API |
memory | Persistent knowledge graph across conversations |
Community servers extend this list to hundreds of integrations including Jira, Notion, AWS, Docker, and more.
Connecting MCP Servers to Claude Desktop
Claude Desktop on macOS and Windows supports MCP via a config file.
1. Install a server. For the filesystem server (requires Node.js):
npm install -g @modelcontextprotocol/server-filesystem
2. Edit the Claude Desktop config.
On macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
On Windows: %APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-filesystem",
"/Users/yourname/Documents"
]
},
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_yourtoken"
}
}
}
}
3. Restart Claude Desktop. You’ll see a hammer icon in the chat interface indicating tools are available.
Building a Simple MCP Server in Python
The Python mcp SDK makes it straightforward to expose custom tools.
Install the SDK:
pip install mcp
Create a simple server (weather_server.py):
from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp import types
import httpx
server = Server("weather")
@server.list_tools()
async def list_tools() -> list[types.Tool]:
return [
types.Tool(
name="get_weather",
description="Get current weather for a city",
inputSchema={
"type": "object",
"properties": {
"city": {"type": "string", "description": "City name"}
},
"required": ["city"]
}
)
]
@server.call_tool()
async def call_tool(name: str, arguments: dict) -> list[types.TextContent]:
if name == "get_weather":
city = arguments["city"]
async with httpx.AsyncClient() as client:
resp = await client.get(
f"https://wttr.in/{city}?format=3"
)
return [types.TextContent(type="text", text=resp.text)]
raise ValueError(f"Unknown tool: {name}")
async def main():
async with stdio_server() as (read_stream, write_stream):
await server.run(read_stream, write_stream,
server.create_initialization_options())
if __name__ == "__main__":
import asyncio
asyncio.run(main())
Register in claude_desktop_config.json:
{
"mcpServers": {
"weather": {
"command": "python3",
"args": ["/path/to/weather_server.py"]
}
}
}
Claude can now call your weather tool in conversation.
MCP vs Function Calling
| Feature | MCP | Function Calling |
|---|---|---|
| Reusability | Any MCP client | Specific to one model/app |
| Discovery | Server advertises tools | Developer defines per-request |
| Transport | stdio or HTTP/SSE | API payload |
| Resources | Yes (read data) | No |
| Prompts | Yes | No |
| Auth | Server-side | Developer manages |
MCP is a superset of function calling — it adds server-managed discovery, resources, and prompts on top of the callable tool concept.
Security Considerations
MCP servers run as local processes or remote services with real access to your data. Key considerations:
- Principle of least privilege: Only grant the filesystem server access to directories Claude needs
- Review server source code before installing community servers — they can read and write files
- Token scoping: When configuring GitHub or Slack servers, use fine-grained tokens with minimum permissions
- Remote MCP servers: HTTP-based servers expose attack surface; use authentication and run over HTTPS only
MCP represents a significant architectural shift for AI tooling — from bespoke integrations to a composable ecosystem where any client can work with any server. As more tools adopt the protocol, the gap between AI assistants and fully capable agents continues to close.