The Model Context Protocol (MCP) is an open-source standard published by Anthropic in November 2024 for connecting AI applications to external systems. Before MCP existed, every AI integration was a custom one-off: a different API contract, a different authentication scheme, a different data format. A developer building a coding assistant that needed access to GitHub, a local filesystem, and a Postgres database had to write three separate integrations from scratch. MCP replaces that fragmentation with a single universal protocol — one that any AI host can speak and any data source or tool can implement. The official documentation describes it as "a USB-C port for AI applications": a standardized connector that works regardless of what is on either end.
Get more guides like this in your inbox
No spam. Unsubscribe anytime.
The Problem MCP Solves
To understand why MCP matters, it helps to understand what the world looked like before it. AI assistants like Claude and GPT-4 are powerful reasoners, but they are isolated by default — they can only work with what is in their context window. Giving them access to external data required either stuffing that data into the prompt (expensive, limited by context size, and stale the moment the session ends) or building a custom function-calling integration for every tool the agent needed to use. The function-calling approach works, but it does not compose. An integration built for Claude does not work with GPT-4. An integration built for one application does not work in another. Every team building an AI product was rebuilding the same plumbing from scratch. MCP solves this by defining a standard protocol at the boundary between the AI application and the external world. A server built to the MCP spec works with any MCP-compatible client — Claude Desktop, Cursor, VS Code, Zed, or a custom agent you build yourself. Build once, integrate everywhere.
Core Architecture: Hosts, Clients, and Servers
MCP uses a client-server architecture with three distinct roles. Understanding these roles is the foundation for everything else in the protocol.
The Three Roles
An MCP Host is the AI application that the user interacts with directly — Claude Desktop, Cursor, VS Code with the Copilot extension, or a custom agent you build. The host is responsible for managing connections to one or more MCP servers and presenting the results to the user or to the LLM. An MCP Client is a component inside the host that maintains a dedicated connection to a single MCP server. The host creates one client per server. The client handles the protocol-level communication: sending requests, receiving responses, and managing the connection lifecycle. An MCP Server is a program that exposes tools, data, or prompt templates to MCP clients. A server can be a small script running locally on your machine (like the official filesystem server) or a remote service running on a cloud platform (like the official Sentry MCP server). The server does not know or care which host is using it — it only speaks the MCP protocol.
MCP Architecture
┌─────────────────────────────────────┐
│ MCP Host │
│ (Claude Desktop, Cursor, VS Code) │
│ │
│ ┌──────────┐ ┌──────────┐ │
│ │ MCP │ │ MCP │ │
│ │ Client 1 │ │ Client 2 │ │
│ └────┬─────┘ └────┬─────┘ │
└───────┼───────────────┼─────────────┘
│ │
stdio/HTTP stdio/HTTP
│ │
┌────▼─────┐ ┌────▼──────────┐
│ MCP │ │ MCP │
│ Server │ │ Server │
│ (local) │ │ (remote) │
│filesystem│ │ Sentry API │
└──────────┘ └───────────────┘Transport Types: stdio vs Streamable HTTP
MCP supports two transport mechanisms, and choosing the right one depends on whether your server runs locally or remotely. Stdio transport uses standard input and output streams for communication between the host and server. The host launches the server as a child process and communicates by writing JSON-RPC messages to its stdin and reading responses from its stdout. This is the standard transport for local servers — it has zero network overhead, requires no authentication setup, and is the simplest to implement. The critical rule for stdio servers is that you must never write anything to stdout except valid JSON-RPC messages. Any debug output, log lines, or print statements must go to stderr instead. Streamable HTTP transport uses HTTP POST for client-to-server messages with optional Server-Sent Events for streaming responses. This is the transport for remote servers — services running on a cloud platform that many clients connect to simultaneously. It supports standard HTTP authentication including bearer tokens, API keys, and OAuth. The official MCP documentation recommends OAuth for remote server authentication.
// Claude Desktop config: local stdio server
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/home/user/projects"],
"transport": "stdio"
}
}
}
// Claude Desktop config: remote HTTP server
{
"mcpServers": {
"sentry": {
"url": "https://mcp.sentry.io/mcp",
"transport": "http"
}
}
}The Three Primitives: Tools, Resources, and Prompts
MCP servers expose three types of primitives to clients. These are the building blocks of everything an MCP server can offer. Understanding the distinction between them is essential for both using and building MCP servers effectively. Tools are executable functions that the LLM can invoke to perform actions. A tool might query a database, call an external API, run a terminal command, or write a file. Tools are the most commonly used primitive — when people talk about "giving an agent tools", they are almost always talking about MCP tools. Each tool has a name, a description (which the LLM reads to decide when to use it), and a JSON Schema that defines its input parameters. Resources are data sources that provide contextual information without executing an action. A resource might be the contents of a file, the schema of a database, or the output of a read-only API call. Resources are identified by URIs and can be read by the client. They are analogous to GET endpoints in a REST API — they return data but do not change state. Prompts are reusable templates that help structure interactions with the LLM. A prompt might be a system prompt that configures the model for a specific task, or a few-shot example set that teaches the model how to use a particular tool. Prompts are less commonly discussed but are powerful for building consistent, reproducible agent behaviors.
Primitives at a Glance
The following table summarizes the three server primitives and their typical use cases.
Primitive | Initiated by | Purpose | Example
-----------|-------------|--------------------------------|---------------------------
Tools | LLM | Execute actions, change state | query_database, send_email
Resources | Client/LLM | Read data, provide context | file://readme.md, db://schema
Prompts | User/Client | Structure LLM interactions | code-review-templateThe JSON-RPC Foundation
Under the hood, all MCP communication is JSON-RPC 2.0. Every message — whether it is a tool call, a resource read, or a lifecycle event — is a JSON object with a specific structure. You do not need to write raw JSON-RPC to use MCP (the SDKs handle this), but understanding the format helps when debugging or building custom integrations. A client discovering available tools sends a tools/list request. The server responds with an array of tool definitions. When the LLM decides to use a tool, the client sends a tools/call request with the tool name and arguments. The server executes the tool and returns the result. This same pattern applies to resources (resources/list, resources/read) and prompts (prompts/list, prompts/get).
// Client requests available tools
{ "jsonrpc": "2.0", "id": 1, "method": "tools/list" }
// Server responds with tool definitions
{
"jsonrpc": "2.0", "id": 1,
"result": {
"tools": [{
"name": "read_file",
"description": "Read the contents of a file at the given path",
"inputSchema": {
"type": "object",
"properties": {
"path": { "type": "string", "description": "Absolute path to the file" }
},
"required": ["path"]
}
}]
}
}
// Client calls the tool
{
"jsonrpc": "2.0", "id": 2,
"method": "tools/call",
"params": { "name": "read_file", "arguments": { "path": "/home/user/notes.md" } }
}Lifecycle: How a Connection is Established
Every MCP connection goes through a defined lifecycle. When a host launches a server (or connects to a remote one), the first exchange is an initialization handshake. The client sends an initialize request with its protocol version and the capabilities it supports. The server responds with its own version and capabilities. The client then sends an initialized notification to confirm the handshake is complete. Only after this exchange can tools, resources, and prompts be used. This capability negotiation is how MCP handles version compatibility — a client and server can discover what each other supports before attempting to use any features.
Building Your First MCP Server (Python)
The fastest way to understand MCP is to build a minimal server. The Python SDK's FastMCP class uses decorators and type hints to generate tool definitions automatically — you write a normal Python function and decorate it with @mcp.tool(). The following example builds a server with two tools: one that reads a file and one that lists the contents of a directory. This is a simplified version of what the official filesystem server does.
# Install: uv add "mcp[cli]"
from pathlib import Path
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("local-files")
@mcp.tool()
def read_file(path: str) -> str:
"""Read the contents of a text file.
Args:
path: Absolute path to the file to read
"""
return Path(path).read_text()
@mcp.tool()
def list_directory(path: str) -> list[str]:
"""List the files and directories at a given path.
Args:
path: Absolute path to the directory
"""
return [str(p) for p in Path(path).iterdir()]
if __name__ == "__main__":
mcp.run(transport="stdio") # stdio for local useBuilding Your First MCP Server (TypeScript)
The TypeScript SDK follows the same pattern. The @modelcontextprotocol/sdk package provides a McpServer class and a StdioServerTransport for local servers. Tool definitions use Zod schemas for input validation.
// Install: npm install @modelcontextprotocol/sdk zod
import { McpServer, StdioServerTransport } from "@modelcontextprotocol/sdk/server";
import { z } from "zod";
import { readFileSync, readdirSync } from "fs";
const server = new McpServer({ name: "local-files", version: "1.0.0" });
server.tool(
"read_file",
"Read the contents of a text file",
{ path: z.string().describe("Absolute path to the file") },
async ({ path }) => ({
content: [{ type: "text", text: readFileSync(path, "utf-8") }]
})
);
server.tool(
"list_directory",
"List files and directories at a path",
{ path: z.string().describe("Absolute path to the directory") },
async ({ path }) => ({
content: [{ type: "text", text: readdirSync(path).join("\n") }]
})
);
const transport = new StdioServerTransport();
await server.connect(transport);Connecting to Claude Desktop
Once your server is written, connecting it to Claude Desktop requires adding a single entry to Claude's configuration file. On macOS, this file lives at ~/Library/Application Support/Claude/claude_desktop_config.json. On Windows, it is at %APPDATA%\Claude\claude_desktop_config.json. Add your server under the mcpServers key, then restart Claude Desktop. The server will appear in Claude's tool list automatically.
// ~/Library/Application Support/Claude/claude_desktop_config.json
{
"mcpServers": {
"local-files": {
"command": "python",
"args": ["/path/to/your/server.py"]
},
"memory": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-memory"]
},
"filesystem": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-filesystem",
"/Users/yourname/Documents",
"/Users/yourname/Projects"
]
}
}
}The Official Reference Servers
Anthropic maintains a set of official reference server implementations that cover the most common use cases. These are production-quality servers you can use immediately without writing any code. They are the fastest way to extend a local agent with real capabilities.
// All official servers — add to claude_desktop_config.json
{
"mcpServers": {
// Persistent memory across sessions (knowledge graph)
"memory": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-memory"]
},
// Read, search, and manipulate Git repositories
"git": {
"command": "uvx",
"args": ["mcp-server-git", "--repository", "/path/to/repo"]
},
// Fetch web pages and convert to LLM-friendly text
"fetch": {
"command": "uvx",
"args": ["mcp-server-fetch"]
},
// Time and timezone conversion
"time": {
"command": "uvx",
"args": ["mcp-server-time"]
},
// Sequential thinking for complex multi-step reasoning
"sequential-thinking": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-sequential-thinking"]
}
}
}Agent Integration: Connecting Hermes Agent to MCP Servers
MCP is not just for Claude Desktop. Any agent framework that supports MCP can use the same servers. Hermes Agent v0.9.0 added native MCP client support, meaning you can connect it to any MCP server using the standard configuration format. This is the pattern that makes MCP genuinely powerful for private AI setups: you build or install MCP servers once, and they work across every agent and host you use.
# ~/.hermes/config.yaml — connect Hermes Agent to MCP servers
mcp_servers:
- name: filesystem
command: npx
args: ["-y", "@modelcontextprotocol/server-filesystem", "/home/user/projects"]
transport: stdio
- name: memory
command: npx
args: ["-y", "@modelcontextprotocol/server-memory"]
transport: stdio
- name: git
command: uvx
args: ["mcp-server-git", "--repository", "/home/user/projects/myrepo"]
transport: stdio
- name: fetch
command: uvx
args: ["mcp-server-fetch"]
transport: stdioAgent Integration: Hermes as an MCP Server
The relationship can also be reversed. In v0.9.0, Hermes Agent can run as an MCP server itself — exposing its skills, memory, and tool-use capabilities to any MCP client. This means Claude Desktop, Cursor, or VS Code can use your local Hermes Agent (backed by Ollama) as their agent backend. All processing stays on your machine. The Hermes session becomes a tool that your editor's AI assistant can call.
# Start Hermes as an MCP server (stdio — for Claude Desktop, Cursor)
hermes mcp serve
# Start as HTTP MCP server (for VS Code, web clients)
# Note: HTTP transport flags may vary by version — check `hermes mcp serve --help`
hermes mcp serve --http --port 3100
# Add to Claude Desktop config to use Hermes as a backend agent:
# {
# "mcpServers": {
# "hermes": {
# "command": "hermes",
# "args": ["mcp", "serve"]
# }
# }
# }Advanced Pattern: Building a Private Knowledge Base Server
One of the most practical uses of MCP for private AI practitioners is building a personal knowledge base server — a server that gives your agent access to your own notes, documents, and research without sending any of that data to a cloud provider. The following example builds a server that indexes a directory of Markdown files and exposes them as both resources (for direct reading) and a search tool (for semantic lookup). This pattern is the foundation of a fully local RAG (retrieval-augmented generation) system.
# A minimal private knowledge base MCP server
# Install: uv add "mcp[cli]" pathlib
import sys
from pathlib import Path
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("knowledge-base")
NOTES_DIR = Path.home() / "notes"
@mcp.resource("notes://list")
def list_notes() -> str:
"""List all notes in the knowledge base."""
notes = list(NOTES_DIR.glob("**/*.md"))
return "\n".join(str(n.relative_to(NOTES_DIR)) for n in notes)
@mcp.resource("notes://{filename}")
def get_note(filename: str) -> str:
"""Read a specific note by filename."""
note_path = NOTES_DIR / filename
if not note_path.exists():
return f"Note not found: {filename}"
return note_path.read_text()
@mcp.tool()
def search_notes(query: str) -> str:
"""Search notes for a keyword or phrase.
Args:
query: The text to search for across all notes
"""
results = []
for note_path in NOTES_DIR.glob("**/*.md"):
content = note_path.read_text()
if query.lower() in content.lower():
# Return filename and a snippet around the match
idx = content.lower().find(query.lower())
snippet = content[max(0, idx-100):idx+200].strip()
results.append(f"## {note_path.name}\n{snippet}\n")
return "\n---\n".join(results) if results else "No notes found matching that query."
if __name__ == "__main__":
mcp.run(transport="stdio")Advanced Pattern: Chaining MCP Servers in an Agent
The real power of MCP in agentic systems comes from chaining multiple servers together. An agent connected to the filesystem, memory, fetch, and git servers simultaneously can perform complex multi-step tasks that would be impossible with a single tool. The agent orchestrates the servers — it might fetch a web page, extract the relevant information, save it to the knowledge base, and commit the update to a git repository, all in a single session. The following example shows how to configure a multi-server agent setup in Hermes Agent and what a typical multi-step task looks like.
# Full private agent stack — Hermes Agent setup wizard
# Run: hermes setup
# Provider: Custom endpoint → http://127.0.0.1:11434/v1
# Model: qwen3.5:9b
# MCP servers are configured in ~/.hermes/mcp.json after setup:
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem",
"/home/user/projects", "/home/user/notes"]
},
"memory": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-memory"]
},
"fetch": {
"command": "uvx",
"args": ["mcp-server-fetch"]
},
"git": {
"command": "uvx",
"args": ["mcp-server-git", "--repository", "/home/user/projects/research"]
}
}
}Where to Find MCP Servers
The MCP server ecosystem has grown rapidly since the protocol launched in November 2024. There are now four primary places to discover servers, each with different curation standards and trust levels. The official GitHub repository at github.com/modelcontextprotocol/servers is the authoritative source. It contains the reference implementations maintained by the MCP steering group — filesystem, git, fetch, memory, sequential-thinking, time, and a handful of others. These are the servers with the highest trust level: they are MIT-licensed, actively maintained, and reviewed by the core team. The official MCP Registry at registry.mcp.run is the formal registry launched in early 2026. Servers listed here have passed a basic review process. This is the recommended starting point for discovering servers beyond the reference implementations. Smithery.ai is a community-curated directory with install counts and user reviews. It is useful for finding servers with real-world adoption data. It lists thousands of servers with real-world install counts. mcp.so is a broader community marketplace with over 19,000 listed servers. The lower barrier to listing means quality varies significantly — treat servers from this source as requiring more careful review before installation. The official documentation also maintains a list of verified third-party servers including integrations for Postgres, GitHub, Slack, Google Drive, Notion, Sentry, and others. These are listed in the README of the official repository under 'Third-party servers'.
Discovery Source | Trust Level | Count (Mar 2026) | Notes
-------------------------|-------------|-----------------|----------------------------------
github.com/mcp/servers | Highest | ~20 reference | Steering group maintained
registry.mcp.run | High | Growing | Formal review process
Smithery.ai | Medium | Thousands | Community, has install counts
mcp.so | Variable | Large | Open marketplace, review carefullyHow to Add MCP Servers to Your Setup
Adding an MCP server to your local agent setup is a three-step process: install the server, configure your host to connect to it, and verify the connection. The exact configuration file location depends on which host you are using. For Claude Desktop, the configuration file is claude_desktop_config.json — located at ~/Library/Application Support/Claude/ on macOS and %APPDATA%\Claude\ on Windows. For Hermes Agent, configuration lives in ~/.hermes/config.yaml. For Cursor and VS Code, MCP configuration is in the workspace or user settings JSON. The pattern is the same across all hosts: you provide a server name, the command to launch it (for stdio servers), or a URL (for remote HTTP servers), and any arguments the server needs.
// Claude Desktop: claude_desktop_config.json
// macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
// Windows: %APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/home/user/projects"]
},
"memory": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-memory"]
},
"postgres": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-postgres", "postgresql://localhost/mydb"]
}
}
}Adding MCP Servers to Hermes Agent
Hermes Agent v0.9.0 introduced first-class MCP client support. Servers are declared in the mcp_servers block of ~/.hermes/config.yaml. Each server entry requires a name (used to reference the server in tool calls), the command to launch it, and any arguments. You can add as many servers as you need — Hermes will launch each one as a child process when it starts and maintain the connection for the session. After editing the config file, restart Hermes for the changes to take effect. You can verify the connection by running hermes tools which will show all tools available across all connected MCP servers.
# ~/.hermes/config.yaml
providers:
- type: ollama
model: qwen3.5:9b
base_url: http://127.0.0.1:11434/v1
mcp_servers:
filesystem:
command: "npx"
args: ["-y", "@modelcontextprotocol/server-filesystem", "/home/user/projects"]
memory:
command: "npx"
args: ["-y", "@modelcontextprotocol/server-memory"]
git:
command: "uvx"
args: ["mcp-server-git", "--repository", "/home/user/myrepo"]
fetch:
command: "uvx"
args: ["mcp-server-fetch"]MCP Security: Attack Vectors You Need to Know
The official MCP Security Best Practices document (published at modelcontextprotocol.io) identifies six attack categories that apply to MCP deployments. Understanding these is essential before connecting any third-party MCP server to your agent. Confused Deputy Attack: MCP proxy servers that connect to third-party APIs using a static OAuth client ID can be exploited. An attacker sends a crafted authorization link to a user who has previously authenticated — the third-party server's consent cookie causes it to skip the consent screen, and the authorization code is redirected to the attacker. This affects any MCP server that acts as an OAuth proxy. Mitigation: only use MCP proxy servers that implement per-client consent storage. Token Passthrough: Servers that blindly forward tokens from MCP clients to downstream APIs without validating audience or scope allow attackers to escalate privileges. Mitigation: review server source code for token handling before connecting. Server-Side Request Forgery (SSRF): MCP servers that fetch URLs based on tool input can be used to probe internal networks, access cloud metadata endpoints, or reach services behind firewalls. The fetch server, for example, should never be given access to internal network ranges. Mitigation: use servers that implement URL allowlisting and block RFC 1918 address ranges. Session Hijacking via Prompt Injection: If your agent reads external content (web pages, emails, documents) and that content contains instructions designed to manipulate the agent, those instructions can cause the agent to misuse its tools or exfiltrate session tokens. This is the most common real-world attack vector. Mitigation: treat all tool output as untrusted, never include session tokens in tool responses. Local Server Compromise: A local MCP server runs with your user's permissions. A malicious or compromised server has full access to everything you can access. The supply chain attack on the litellm package (which led Hermes Agent to remove it in v0.5.0) is an example of this risk. Mitigation: only install servers from trusted sources, pin dependency versions, and monitor servers for security updates. Scope Minimization Violations: Servers that request broader permissions than needed create unnecessary attack surface. A filesystem server given access to your entire home directory is a larger risk than one scoped to a single project folder.
A Security Checklist for Every MCP Server You Install
Before connecting any MCP server to your agent, work through this checklist. It applies equally to official servers, community servers, and servers you build yourself.
Before installing any MCP server:
[ ] Is the source repository public and actively maintained?
[ ] When was the last commit? (Abandoned repos = unpatched vulnerabilities)
[ ] Does the server have a published security policy or CVE history?
[ ] What permissions does it request? (filesystem paths, network access, env vars)
[ ] Does it use any dependencies with known supply chain issues?
[ ] Is it scoped to the minimum access it needs to function?
After installing:
[ ] Watch the server's GitHub repository for security advisories
[ ] Pin the version in your config (use exact version, not "latest")
[ ] Review the changelog before upgrading
[ ] Check NVD (nvd.nist.gov) for CVEs against the package name periodically
For remote HTTP servers:
[ ] Does it require authentication? (Reject any that don't)
[ ] Is the connection over HTTPS?
[ ] Is the server operated by a party you trust with your data?The MCP Ecosystem Today
As of March 2026, MCP has broad adoption across the AI tooling ecosystem. The official MCP registry lists hundreds of servers across categories including databases (Postgres, SQLite, MongoDB), developer tools (GitHub, GitLab, Jira, Linear), productivity (Google Drive, Notion, Obsidian), and infrastructure (Docker, Kubernetes, AWS). On the client side, Claude Desktop, Cursor, VS Code, Zed, Windsurf, and Cline all support MCP natively. Hermes Agent v0.9.0 added both MCP client and MCP server modes. The protocol is now governed under the Linux Foundation Projects umbrella, which ensures it remains open and vendor-neutral. The specification, SDKs, and reference servers are all MIT-licensed and available on GitHub at github.com/modelcontextprotocol.
What to Build Next
If you are new to MCP, the fastest path to a useful local setup is to install three official servers that provide the most immediate value: the filesystem server (so your agent can read and write your files), the memory server (so your agent remembers things across sessions), and the fetch server (so your agent can read web pages without a cloud API). From there, the most impactful custom server to build for a private AI practitioner is a knowledge base server over your own notes and documents — the pattern shown in the advanced section above. Once you have that running locally against Ollama, you have a fully private, fully capable agent that can reason over your own knowledge base without any data leaving your machine. For a curated list of the most useful MCP servers with verified install instructions and security notes for each, see the companion guide: Top 30 MCP Servers for Private AI Practitioners.