Cristhian Villegas
Architecture12 min read2 views

What is MCP? Complete Guide to the Model Context Protocol

What is MCP? Complete Guide to the Model Context Protocol

The Problem MCP Solves: Why AI Needs a Universal Protocol

Imagine you have an incredibly intelligent assistant — it can write code, analyze data, draft emails, and answer complex questions. But it is locked in a room with no phone, no internet, and no access to your files. That is essentially the situation with most Large Language Models (LLMs) today: powerful reasoning engines isolated from the real world.

Every time you want an AI model to interact with an external tool — a database, a file system, a GitHub repository, a Slack channel — someone has to build a custom integration. If you have N AI applications and M tools, you end up with N x M integrations, each with its own protocol, authentication, and error handling. This is the fragmentation problem that was crippling the AI ecosystem.

Enter the Model Context Protocol (MCP), created by Anthropic and released as an open standard in November 2024. MCP is a universal, open protocol that standardizes how AI models connect to external data sources and tools. Think of it as the USB-C of AI — one connector to rule them all.

The USB-C Analogy: Before USB-C, every device had its own charger and cable. MCP does for AI what USB-C did for hardware: it replaces a mess of proprietary integrations with a single, universal standard. Any MCP-compatible AI client can connect to any MCP server, instantly gaining access to its tools and data.

Diagram showing MCP client-server architecture connecting AI models to external tools

Source: Model Context Protocol — Official Documentation

MCP Architecture: Hosts, Clients, and Servers

MCP follows a client-server architecture with three distinct roles. Understanding these roles is essential to grasping how the protocol works.

MCP Host: The host is the AI application that the user interacts with. Examples include Claude Desktop, Claude Code, Cursor, Windsurf, or any custom application built with the MCP SDK. The host is responsible for managing the lifecycle of MCP clients and for presenting tool results to the user.

MCP Client: Each host creates one MCP client per server connection. The client handles the communication protocol — establishing connections, sending requests, receiving responses, and managing the lifecycle of the session. Clients maintain a 1:1 relationship with servers.

MCP Server: The server is a lightweight program that exposes specific capabilities through the MCP protocol. A server might provide access to a PostgreSQL database, a GitHub repository, the local file system, a Slack workspace, or any other data source or tool. Servers are where the real integration logic lives.

text
1┌─────────────────────────────────────────────┐
2│                  MCP HOST                    │
3│            (Claude Desktop, Cursor)          │
4│                                              │
5│  ┌──────────┐  ┌──────────┐  ┌──────────┐   │
6│  │ Client A │  │ Client B │  │ Client C │   │
7│  └────┬─────┘  └────┬─────┘  └────┬─────┘   │
8└───────┼──────────────┼──────────────┼────────┘
9        │              │              │
10        ▼              ▼              ▼
11   ┌─────────┐   ┌─────────┐   ┌─────────┐
12   │ Server  │   │ Server  │   │ Server  │
13   │ GitHub  │   │ Postgres│   │  Slack  │
14   └─────────┘   └─────────┘   └─────────┘

Communication between clients and servers uses JSON-RPC 2.0 over two transport mechanisms:

  • stdio (standard input/output): The server runs as a local subprocess. The client communicates via stdin/stdout. This is the most common transport for local MCP servers and is what Claude Desktop uses.
  • SSE (Server-Sent Events) over HTTP: For remote servers that need to be accessible over the network. The client sends requests via HTTP POST and receives responses via an SSE stream.

The Three Primitives: Tools, Resources, and Prompts

MCP servers expose their capabilities through three core primitives. Each serves a different purpose and gives the AI model different types of access.

Tools are the most powerful primitive. They are executable functions that the AI model can invoke to perform actions. A tool might query a database, create a GitHub issue, send a Slack message, or run a shell command. Tools are model-controlled — the AI decides when and how to use them based on the conversation context.

Resources provide read-only access to data. They are similar to GET endpoints in a REST API. A resource might expose the contents of a file, the results of a database query, or a live feed of metrics. Resources are application-controlled — the host application decides when to fetch and present them.

Prompts are reusable templates that help users interact with the AI more effectively. A server can expose a set of prompts that guide users through complex workflows. For example, a database MCP server might provide a "debug slow query" prompt that asks the user for the query and then structures the analysis.

When to use each: Use Tools when the AI needs to take action (write, create, modify). Use Resources when the AI needs to read data. Use Prompts when you want to provide guided workflows for complex tasks.

Building an MCP Server in Python

Let us build a practical MCP server that provides access to a SQLite database. This example demonstrates how to create tools and resources that an AI model can use to query and analyze data.

First, install the MCP Python SDK:

bash
1pip install mcp[cli]
2# or with uv (recommended)
3uv add "mcp[cli]"

Now, create the server:

python
1"""MCP Server: SQLite Database Explorer"""
2import sqlite3
3from mcp.server.fastmcp import FastMCP
4
5# Initialize the MCP server
6mcp = FastMCP("sqlite-explorer")
7
8DB_PATH = "my_database.db"
9
10@mcp.tool()
11def query_database(sql: str) -> str:
12    """Execute a read-only SQL query against the database.
13
14    Args:
15        sql: The SQL SELECT query to execute
16    """
17    if not sql.strip().upper().startswith("SELECT"):
18        return "Error: Only SELECT queries are allowed for safety."
19
20    conn = sqlite3.connect(DB_PATH)
21    try:
22        cursor = conn.execute(sql)
23        columns = [desc[0] for desc in cursor.description]
24        rows = cursor.fetchall()
25
26        # Format as a readable table
27        result = " | ".join(columns) + "\n"
28        result += "-" * len(result) + "\n"
29        for row in rows:
30            result += " | ".join(str(val) for val in row) + "\n"
31        return result if rows else "Query returned no results."
32    except Exception as e:
33        return f"SQL Error: {e}"
34    finally:
35        conn.close()
36
37@mcp.tool()
38def list_tables() -> str:
39    """List all tables in the database with their column definitions."""
40    conn = sqlite3.connect(DB_PATH)
41    try:
42        tables = conn.execute(
43            "SELECT name FROM sqlite_master WHERE type='table'"
44        ).fetchall()
45
46        result = []
47        for (table_name,) in tables:
48            cols = conn.execute(f"PRAGMA table_info({table_name})").fetchall()
49            col_defs = ", ".join(f"{c[1]} ({c[2]})" for c in cols)
50            result.append(f"{table_name}: {col_defs}")
51        return "\n".join(result) if result else "No tables found."
52    finally:
53        conn.close()
54
55@mcp.resource("schema://database")
56def get_database_schema() -> str:
57    """Provide the complete database schema as a resource."""
58    conn = sqlite3.connect(DB_PATH)
59    try:
60        schema = conn.execute(
61            "SELECT sql FROM sqlite_master WHERE type='table'"
62        ).fetchall()
63        return "\n\n".join(s[0] for s in schema if s[0])
64    finally:
65        conn.close()
66
67if __name__ == "__main__":
68    mcp.run()

Building an MCP Server in TypeScript

The TypeScript SDK follows a similar pattern. Here is an equivalent MCP server that provides GitHub repository tools:

bash
1npm install @modelcontextprotocol/sdk
typescript
1import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3import { z } from "zod";
4
5const server = new McpServer({
6  name: "github-explorer",
7  version: "1.0.0",
8});
9
10// Tool: Search GitHub repositories
11server.tool(
12  "search_repos",
13  "Search GitHub repositories by keyword",
14  { query: z.string(), language: z.string().optional() },
15  async ({ query, language }) => {
16    const params = new URLSearchParams({ q: query });
17    if (language) params.append("q", `language:${language}`);
18
19    const response = await fetch(
20      `https://api.github.com/search/repositories?${params}`,
21      { headers: { Accept: "application/vnd.github.v3+json" } }
22    );
23    const data = await response.json();
24
25    const results = data.items.slice(0, 5).map((repo: any) =>
26      `${repo.full_name} (★${repo.stargazers_count}) - ${repo.description}`
27    );
28
29    return { content: [{ type: "text", text: results.join("\n") }] };
30  }
31);
32
33// Tool: Get repository details
34server.tool(
35  "get_repo_info",
36  "Get detailed information about a GitHub repository",
37  { owner: z.string(), repo: z.string() },
38  async ({ owner, repo }) => {
39    const response = await fetch(
40      `https://api.github.com/repos/${owner}/${repo}`,
41      { headers: { Accept: "application/vnd.github.v3+json" } }
42    );
43    const data = await response.json();
44
45    const info = [
46      `Name: ${data.full_name}`,
47      `Description: ${data.description}`,
48      `Stars: ${data.stargazers_count}`,
49      `Forks: ${data.forks_count}`,
50      `Language: ${data.language}`,
51      `Open Issues: ${data.open_issues_count}`,
52      `Created: ${data.created_at}`,
53      `Last Push: ${data.pushed_at}`,
54    ];
55
56    return { content: [{ type: "text", text: info.join("\n") }] };
57  }
58);
59
60// Start the server
61const transport = new StdioServerTransport();
62await server.connect(transport);

Using MCP with Claude Desktop, Claude Code, and Cursor

Once you have built an MCP server, connecting it to your AI tools is straightforward. Each tool has its own configuration method.

Claude Desktop uses a JSON configuration file. On macOS, it is located at ~/Library/Application Support/Claude/claude_desktop_config.json. On Windows, it is at %APPDATA%\Claude\claude_desktop_config.json.

json
1{
2  "mcpServers": {
3    "sqlite-explorer": {
4      "command": "python",
5      "args": ["path/to/sqlite_server.py"],
6      "env": {
7        "DB_PATH": "/path/to/database.db"
8      }
9    },
10    "github-explorer": {
11      "command": "node",
12      "args": ["path/to/github_server.js"],
13      "env": {
14        "GITHUB_TOKEN": "ghp_your_token_here"
15      }
16    }
17  }
18}

Claude Code manages MCP servers through its CLI. You can add servers directly from the command line:

bash
1# Add a local MCP server
2claude mcp add sqlite-explorer -- python path/to/sqlite_server.py
3
4# Add with environment variables
5claude mcp add github-explorer -e GITHUB_TOKEN=ghp_xxx -- node path/to/github_server.js
6
7# List configured servers
8claude mcp list
9
10# Remove a server
11claude mcp remove sqlite-explorer

Cursor supports MCP servers through its settings. Navigate to Settings > Features > MCP Servers and add your server configuration. Cursor also supports the .cursor/mcp.json file in your project root for project-specific servers.

Security note: MCP servers run with the permissions of the user who starts them. Be careful with tools that can execute arbitrary code or access sensitive data. Always review what permissions an MCP server requires before connecting it. Never expose MCP servers with write access to untrusted users.

Real-World Use Cases and the MCP Ecosystem

The MCP ecosystem has grown rapidly since its launch. Here are some of the most impactful use cases and available servers:

Database Access: MCP servers for PostgreSQL, MySQL, SQLite, and MongoDB allow AI models to query databases, explore schemas, and even generate optimized queries. This is a game-changer for data analysts and developers who spend hours writing SQL.

Development Workflows: The official GitHub MCP server lets AI models create issues, review pull requests, search code, and manage repositories. Combined with a filesystem MCP server, you get an AI that can truly understand and modify codebases.

Communication: Slack and email MCP servers enable AI assistants to read messages, search conversations, and send responses. This turns your AI into a true productivity assistant that is aware of your team's communication.

Cloud Infrastructure: AWS has released an official MCP server that provides access to CloudWatch logs, S3 buckets, and other services. This is invaluable for DevOps engineers who need to diagnose issues quickly.

Knowledge Management: MCP servers for Notion, Confluence, and Google Drive allow AI models to search and retrieve organizational knowledge. Instead of the AI only knowing what is in its training data, it can access your company's specific documentation.

Major companies that have adopted MCP:

  • OpenAI: Added MCP support to the Agents SDK in March 2025, validating MCP as an industry standard
  • Google: Integrated MCP into the Gemini ecosystem and Agent Development Kit (ADK)
  • Microsoft: Copilot Studio and the Semantic Kernel SDK now support MCP
  • AWS: Released official MCP servers for their cloud services
  • Block (Square): An early adopter, integrating MCP across their development platform
  • Zed, Sourcegraph, Codeium: Development tools that have embraced MCP for enhanced AI coding assistance

Security Considerations and Best Practices

With great power comes great responsibility. MCP servers can have significant access to sensitive systems, so security must be a top priority.

Principle of Least Privilege: Each MCP server should have the minimum permissions necessary. A database MCP server that only needs to read data should not have write access. Use read-only database users and scoped API tokens.

Input Validation: MCP servers must rigorously validate all inputs from the AI model. Remember that the AI generates these inputs based on conversation context, which could include adversarial prompts. SQL injection, command injection, and path traversal attacks are all possible if inputs are not sanitized.

Authentication and Authorization: For remote MCP servers (using SSE transport), implement proper authentication. Use OAuth 2.0 or API keys, and always use HTTPS. The MCP specification supports authentication headers in the SSE transport.

Human-in-the-Loop: For sensitive operations (deleting data, sending messages, modifying infrastructure), always implement confirmation steps. Most MCP hosts (including Claude Desktop) will ask the user for confirmation before executing tools, but your server should also have safeguards.

Audit Logging: Log all tool invocations, including the inputs and outputs. This is critical for debugging, compliance, and detecting misuse. Include timestamps, the user identity, and the full request/response payload.

python
1# Example: Adding audit logging to an MCP tool
2import logging
3from datetime import datetime
4
5logger = logging.getLogger("mcp-audit")
6
7@mcp.tool()
8def delete_record(table: str, record_id: int) -> str:
9    """Delete a record from the database (requires confirmation)."""
10    logger.info(
11        f"[{datetime.utcnow().isoformat()}] DELETE requested: "
12        f"table={table}, id={record_id}"
13    )
14
15    # Validate table name (prevent SQL injection)
16    allowed_tables = {"users", "orders", "products"}
17    if table not in allowed_tables:
18        return f"Error: Table '{table}' is not in the allowed list."
19
20    # Execute with parameterized query
21    conn = sqlite3.connect(DB_PATH)
22    try:
23        conn.execute(f"DELETE FROM {table} WHERE id = ?", (record_id,))
24        conn.commit()
25        logger.info(f"DELETE successful: {table}/{record_id}")
26        return f"Record {record_id} deleted from {table}."
27    except Exception as e:
28        logger.error(f"DELETE failed: {e}")
29        return f"Error: {e}"
30    finally:
31        conn.close()
Official registry: You can find a growing list of community and official MCP servers at github.com/modelcontextprotocol/servers. Always review the source code of third-party servers before connecting them to your AI tools.

The Future of MCP: Where the Protocol Is Headed

MCP is still young, but its trajectory is remarkable. In just over a year since its release, it has become the de facto standard for AI-tool integration, with adoption from every major AI company.

What to expect in 2026 and beyond:

  • Streamable HTTP transport: A new transport mechanism that combines the simplicity of HTTP with the real-time capabilities of SSE, making it easier to build and deploy remote MCP servers
  • Enhanced authentication: Native OAuth 2.1 support with PKCE, making it seamless to connect MCP servers to enterprise identity providers
  • Multi-agent MCP: As AI agents become more sophisticated, MCP will evolve to support agent-to-agent communication, where one AI agent's MCP server becomes another agent's tool
  • Enterprise MCP gateways: Centralized servers that manage authentication, rate limiting, and audit logging for all MCP connections in an organization
  • MCP marketplaces: App-store-like ecosystems where developers can publish and discover MCP servers, similar to what happened with browser extensions and IDE plugins

MCP is not just a protocol — it is the foundation for a future where AI is not isolated but deeply connected to the tools and data that power our digital lives. If you are building AI applications, learning MCP today is one of the highest-leverage investments you can make.

To get started, visit the official documentation at modelcontextprotocol.io and explore the GitHub organization for SDKs, examples, and community servers.

Share:
CV

Cristhian Villegas

Software Engineer specializing in Java, Spring Boot, Angular & AWS. Building scalable distributed systems with clean architecture.

Comments

Sign in to leave a comment

No comments yet. Be the first!

Related Articles