Skip to content

08 - MCP (Model Context Protocol) ​


1. What is MCP? ​

What: MCP (Model Context Protocol) is an open protocol created by Anthropic that standardizes how AI applications connect to external data sources and tools. Think of it as "USB-C for AI" β€” one standard interface instead of custom integrations for every tool.

Before MCP:                        With MCP:
β”Œβ”€β”€β”€β”€β”€β”  custom API  β”Œβ”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”            β”Œβ”€β”€β”€β”€β”€β”€β”
β”‚ App │──────────────→│Slack β”‚     β”‚ App │──MCP──────→│Slack β”‚
β”‚     β”‚  custom API  β”Œβ”€β”€β”€β”€β”€β”€β”     β”‚     β”‚  (same     β”Œβ”€β”€β”€β”€β”€β”€β”
β”‚     │──────────────→│GitHubβ”‚     β”‚     β”‚  protocol) β”‚GitHubβ”‚
β”‚     β”‚  custom API  β”Œβ”€β”€β”€β”€β”€β”€β”     β”‚     │──MCP──────→│      β”‚
β”‚     │──────────────→│ DB   β”‚     β”‚     β”‚            β”Œβ”€β”€β”€β”€β”€β”€β”
β””β”€β”€β”€β”€β”€β”˜              β””β”€β”€β”€β”€β”€β”€β”˜     β”‚     │──MCP──────→│ DB   β”‚
                                  β””β”€β”€β”€β”€β”€β”˜            β””β”€β”€β”€β”€β”€β”€β”˜
N apps Γ— M tools = NΓ—M integrations    vs.    N+M integrations

2. Architecture: Host, Client, Server ​

Three-layer architecture:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              HOST APPLICATION             β”‚
β”‚  (Claude Desktop, VS Code, custom app)   β”‚
β”‚                                           β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”             β”‚
β”‚  β”‚ MCP      β”‚  β”‚ MCP      β”‚  ...        β”‚
β”‚  β”‚ Client 1 β”‚  β”‚ Client 2 β”‚             β”‚
β”‚  β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
        β”‚              β”‚
   β”Œβ”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”
   β”‚ MCP      β”‚  β”‚ MCP      β”‚
   β”‚ Server A β”‚  β”‚ Server B β”‚
   β”‚ (GitHub) β”‚  β”‚ (DB)     β”‚
   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
ComponentRoleExample
HostThe AI application that users interact withClaude Desktop, IDE extension
ClientMaintains 1:1 connection with a serverCreated by host, one per server
ServerExposes tools, resources, and promptsGitHub MCP server, database server

Key design principle: The host controls which servers to connect to and what permissions to grant. Servers are sandboxed β€” they can only expose capabilities, not directly access the model.


3. Transport: stdio and SSE ​

How clients and servers communicate:

stdio (Standard I/O):

Client spawns server as a child process.
Communication via stdin/stdout using JSON-RPC 2.0.

Client β†’ stdin  β†’ Server
Client ← stdout ← Server
         stderr β†’ Logging
json
// Client sends request
{"jsonrpc": "2.0", "id": 1, "method": "tools/list", "params": {}}

// Server responds
{"jsonrpc": "2.0", "id": 1, "result": {"tools": [...]}}

Best for: Local servers, CLI tools, same-machine communication.

SSE (Server-Sent Events) / Streamable HTTP:

Client connects via HTTP.
Server β†’ Client: SSE stream for server-initiated messages.
Client β†’ Server: HTTP POST for requests.

Best for: Remote servers, web deployments, cloud-hosted tools.


4. Primitives: Tools, Resources, Prompts ​

MCP servers expose three types of capabilities:

Tools (model-controlled) ​

Functions the model can call. Like function calling, but standardized.

typescript
// Server defines a tool
server.tool(
  "search_codebase",
  "Search for code patterns in the repository",
  {
    query: z.string().describe("Search query"),
    file_pattern: z.string().optional().describe("Glob pattern like '*.ts'")
  },
  async ({ query, file_pattern }) => {
    const results = await grep(query, file_pattern);
    return { content: [{ type: "text", text: JSON.stringify(results) }] };
  }
);

Resources (application-controlled) ​

Data the application can read, like files or database records. Identified by URIs.

typescript
// Server exposes a resource
server.resource(
  "config",
  "file:///app/config.json",
  async () => ({
    contents: [{ uri: "file:///app/config.json", text: configData }]
  })
);

Prompts (user-controlled) ​

Pre-built prompt templates that users can select.

typescript
// Server defines a prompt template
server.prompt(
  "code_review",
  "Review code for best practices",
  [{ name: "code", description: "Code to review", required: true }],
  async ({ code }) => ({
    messages: [{
      role: "user",
      content: { type: "text", text: `Review this code:\n\n${code}` }
    }]
  })
);
PrimitiveControlled ByPurpose
ToolsAI model (decides when to call)Actions and computations
ResourcesApplication (attaches to context)Data and file access
PromptsUser (selects from menu)Template workflows

5. Building an MCP Server ​

Using the TypeScript SDK:

typescript
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";

const server = new McpServer({
  name: "my-tool-server",
  version: "1.0.0"
});

// Define a tool
server.tool(
  "get_weather",
  "Get current weather for a city",
  { city: z.string() },
  async ({ city }) => {
    const weather = await fetchWeather(city);
    return {
      content: [{ type: "text", text: `Weather in ${city}: ${weather}` }]
    };
  }
);

// Start server with stdio transport
const transport = new StdioServerTransport();
await server.connect(transport);

Using the Python SDK:

python
from mcp.server import Server
from mcp.server.stdio import stdio_server
import mcp.types as types

server = Server("my-tool-server")

@server.list_tools()
async def list_tools():
    return [types.Tool(
        name="get_weather",
        description="Get current weather for a city",
        inputSchema={
            "type": "object",
            "properties": {"city": {"type": "string"}},
            "required": ["city"]
        }
    )]

@server.call_tool()
async def call_tool(name: str, arguments: dict):
    if name == "get_weather":
        weather = await fetch_weather(arguments["city"])
        return [types.TextContent(type="text", text=f"Weather: {weather}")]

async def main():
    async with stdio_server() as (read, write):
        await server.run(read, write, server.create_initialization_options())

6. Configuring MCP in Claude Desktop ​

json
// ~/Library/Application Support/Claude/claude_desktop_config.json
{
  "mcpServers": {
    "my-server": {
      "command": "node",
      "args": ["/path/to/server/index.js"],
      "env": {
        "API_KEY": "your-key"
      }
    },
    "python-server": {
      "command": "python",
      "args": ["-m", "my_mcp_server"]
    }
  }
}

7. Security Considerations ​

Key security principles for MCP:

ConcernMitigation
Tool permissionsHost should require user approval before tool execution
Data exposureServers should only expose data the user has access to
Prompt injection via toolsTool results can contain adversarial content β€” host must sanitize
Server authenticationUse API keys/tokens for remote servers
Least privilegeServers should request minimum needed permissions
Input validationValidate all tool arguments with schemas (Zod, JSON Schema)

Trust boundaries:

User ← trusts β†’ Host application
Host ← manages β†’ MCP clients
Client ← validates β†’ MCP server responses
Server ← sandboxed β†’ External systems

The user trusts the host.
The host does NOT blindly trust servers.
Tool calls require user confirmation (or explicit pre-approval).

Prompt injection risk: An MCP server returning malicious content in tool results could influence the model. Hosts should treat tool results as untrusted user input.

Frontend interview preparation reference.