🔧Tool Design & MCPLesson 2.3

MCP Architecture & Primitives

Understanding MCP hosts, clients, servers, and the three primitives.

25 min

Learning Objectives

  • Explain the MCP client-server architecture
  • Distinguish between Tools, Resources, and Prompts
  • Understand JSON-RPC 2.0 transport

MCP Architecture and Primitives

The Model Context Protocol (MCP) is an open standard created by Anthropic that defines how AI applications connect to external data sources and tools. Think of MCP as the “USB-C for AI” -- a universal protocol that lets any AI application communicate with any data source through a standardized interface. Understanding MCP's architecture is essential for the CCA-F exam and for building scalable, maintainable agentic systems.

Why MCP Exists

Before MCP, every AI application had to build custom integrations for each external system it needed to access. If you had 5 AI apps and 10 data sources, you needed 50 custom connectors. MCP reduces this to an M + N problem: each AI app implements one MCP client, and each data source implements one MCP server. The protocol handles the rest.

  • Without MCP: M applications x N data sources = M*N custom integrations
  • With MCP: M applications + N data sources = M + N implementations

This standardization means that a tool built as an MCP server works with Claude Desktop, Claude Code, IDE extensions, and any other MCP-compatible host -- without any changes to the server itself.

The Three Roles in MCP

MCP defines three distinct roles that participate in every interaction. Understanding these roles and their responsibilities is critical for the exam.

MCP Host

The host is the AI application that the end user interacts with. Examples include Claude Desktop, an IDE with AI features, or a custom chatbot application. The host is responsible for:

  • Providing the user interface
  • Managing one or more MCP client instances
  • Controlling which servers the clients can connect to
  • Enforcing security policies and user consent
  • Deciding how to surface MCP capabilities (tools, resources, prompts) to the AI model

MCP Client

The client is a protocol-level component embedded within the host. Each client maintains a 1:1 connection with a single MCP server. The client handles:

  • Establishing and maintaining the connection to an MCP server
  • Protocol negotiation and capability exchange
  • Routing requests and responses between the host and server
  • Message serialization using JSON-RPC 2.0

MCP Server

The server exposes specific capabilities (tools, resources, prompts) to clients. Each server is typically focused on a specific domain -- a database, a file system, a web API, etc. The server handles:

  • Exposing available tools, resources, and prompts via capability discovery
  • Executing tool calls and returning results
  • Providing resource data when requested
  • Managing its own authentication with backend systems
Exam Tip: The exam tests the distinction between hosts, clients, and servers extensively. Remember: hosts face the user, clients maintain 1:1 connections with servers, and servers expose capabilities. A single host can manage multiple clients, each connected to a different server. Clients and servers have a 1:1 relationship.

The Three MCP Primitives

MCP defines three core primitives that servers can expose. Each primitive serves a different purpose and is controlled differently. This control model is one of the most important concepts for the exam.

1. Tools (Model-Controlled)

Tools are functions that the AI model can invoke to perform actions or retrieve computed information. They are the MCP equivalent of the tool use API. Tools are model-controlled -- the LLM decides when and how to call them based on context. Tools enable the model to take actions and interact with external systems.

# Example: MCP tool exposed by a database server
# Tool definition (what the server advertises)
{
    "name": "query_users",
    "description": "Query the user database with filters. Returns matching user records.",
    "inputSchema": {
        "type": "object",
        "properties": {
            "status": {
                "type": "string",
                "enum": ["active", "inactive", "suspended"],
                "description": "Filter by account status"
            },
            "created_after": {
                "type": "string",
                "description": "ISO 8601 date to filter users created after this date"
            }
        }
    }
}

Key characteristics of tools:

  • Invoked by the AI model based on conversation context
  • Can have side effects (create, update, delete operations)
  • Accept structured input parameters defined by JSON Schema
  • Return results that the model incorporates into its response

2. Resources (Application-Controlled)

Resources are data that can be read by the AI application. Unlike tools, resources are application-controlled -- the host application decides when to fetch and include resource data, not the model. Resources are identified by URIs and can represent files, database records, API responses, or any structured data.

# Example: MCP resources exposed by a file system server
# Resources are identified by URIs

# Static resource - a specific known file
{
    "uri": "file:///config/app-settings.json",
    "name": "Application Settings",
    "description": "Current application configuration",
    "mimeType": "application/json"
}

# Resource template - dynamic resources with parameters
{
    "uriTemplate": "db://users/{user_id}/profile",
    "name": "User Profile",
    "description": "Profile data for a specific user",
    "mimeType": "application/json"
}

Key characteristics of resources:

  • Controlled by the host application, not the model
  • Identified by URIs (static) or URI templates (dynamic with parameters)
  • Read-only -- they provide data but do not perform actions
  • Can be used to provide context to the model without a tool call
  • Support subscriptions for change notifications

3. Prompts (User-Controlled)

Prompts are pre-built prompt templates that servers can expose to users. They are user-controlled -- the end user typically selects which prompt to use (e.g., from a slash command menu). Prompts can include arguments that get filled in at invocation time.

# Example: MCP prompt exposed by a code review server
{
    "name": "review_code",
    "description": "Generate a thorough code review for the given code",
    "arguments": [
        {
            "name": "language",
            "description": "Programming language of the code",
            "required": True
        },
        {
            "name": "code",
            "description": "The code to review",
            "required": True
        },
        {
            "name": "focus_areas",
            "description": "Specific areas to focus the review on (e.g., security, performance)",
            "required": False
        }
    ]
}

Key characteristics of prompts:

  • Selected by the user, not the model or application
  • Accept arguments that get filled in before being sent to the model
  • Standardize common interaction patterns across applications
  • Surfaced through UI elements like slash command menus
Exam Tip: The control model for each primitive is a high-frequency exam topic. Remember the mnemonic: Tools = Model-controlled, Resources = Application-controlled, Prompts = User-controlled. The exam will present scenarios and ask which primitive is appropriate. For example: “An application wants to automatically include the user's recent Git history in every conversation” -- this is a Resource (application-controlled). “A user wants to trigger a code review workflow” -- this is a Prompt (user-controlled).

JSON-RPC 2.0 Protocol

All MCP communication uses JSON-RPC 2.0 as its wire format. JSON-RPC is a lightweight remote procedure call protocol that uses JSON for encoding. MCP uses three types of JSON-RPC messages:

  • Requests: Messages with an id, method, and optional params. The sender expects a response.
  • Responses: Messages with an id matching a request, plus either a result or an error field.
  • Notifications: Messages with a method but no id. These are fire-and-forget; no response is expected.
# JSON-RPC 2.0 message examples

# Request (expects a response)
{"jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": {"name": "get_weather", "arguments": {"city": "Tokyo"}}}

# Successful response
{"jsonrpc": "2.0", "id": 1, "result": {"content": [{"type": "text", "text": "Weather in Tokyo: 22C, Clear"}]}}

# Error response
{"jsonrpc": "2.0", "id": 1, "error": {"code": -32602, "message": "Invalid params: city is required"}}

# Notification (no id, no response expected)
{"jsonrpc": "2.0", "method": "notifications/tools/list_changed"}

Protocol Transport Layer

MCP supports multiple transport mechanisms for communication between clients and servers. The transport layer is independent of the protocol messages -- the same JSON-RPC messages flow over any transport.

stdio (Standard Input/Output)

The server runs as a subprocess of the client. Communication happens over stdin/stdout pipes. This is the simplest transport, ideal for local tools and development.

  • Server runs as a child process
  • Messages are newline-delimited JSON on stdin/stdout
  • No network configuration needed
  • Best for: local tools, CLI integrations, development/testing

HTTP with SSE (Server-Sent Events)

The server runs as an HTTP endpoint. The client connects via HTTP, and the server can push updates using Server-Sent Events. This is appropriate for remote/networked servers.

  • Server exposes HTTP endpoints
  • Client sends requests via HTTP POST
  • Server pushes notifications via SSE stream
  • Best for: remote servers, shared services, cloud deployments

Streamable HTTP

The newest transport option, Streamable HTTP provides a more flexible approach where the server can operate statelessly or maintain state using session IDs. It uses standard HTTP POST for requests and optional SSE for streaming responses.

  • Supports both stateless and stateful operation
  • Uses HTTP POST with optional SSE streaming
  • Better suited for serverless and horizontally scaled deployments
  • Best for: production deployments, serverless architectures
Exam Tip: Know the transport options and when to use each. The exam may describe a deployment scenario and ask which transport is appropriate. Key rule: stdio for local processes, SSE for remote persistent servers, Streamable HTTP for scalable production deployments. All transports carry the same JSON-RPC 2.0 messages.

Capability Negotiation

When a client connects to a server, they exchange capability information during an initialization handshake. This tells each side what features the other supports.

# Initialization handshake (simplified)

# Client sends: initialize request
{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "initialize",
    "params": {
        "protocolVersion": "2024-11-05",
        "capabilities": {
            "roots": {"listChanged": True}
        },
        "clientInfo": {
            "name": "MyAIApp",
            "version": "1.0.0"
        }
    }
}

# Server responds with its capabilities
{
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
        "protocolVersion": "2024-11-05",
        "capabilities": {
            "tools": {"listChanged": True},
            "resources": {"subscribe": True, "listChanged": True},
            "prompts": {"listChanged": True}
        },
        "serverInfo": {
            "name": "DatabaseServer",
            "version": "2.0.0"
        }
    }
}

# Client acknowledges initialization is complete
{"jsonrpc": "2.0", "method": "notifications/initialized"}

MCP Message Flow

Understanding how messages flow through the MCP architecture is essential. Here is the complete flow for a tool invocation:

  • Step 1: Host receives a user query that requires external data.
  • Step 2: Host includes available MCP tools in the API call to Claude.
  • Step 3: Claude returns a tool_use response requesting a specific tool.
  • Step 4: Host routes the tool call through the appropriate MCP client.
  • Step 5: Client sends a tools/call JSON-RPC request to the server.
  • Step 6: Server executes the tool and returns the result.
  • Step 7: Client passes the result back to the host.
  • Step 8: Host includes the result as a tool_result in the next API call.
  • Step 9: Claude incorporates the result and responds to the user.

Discovery Methods

Clients discover what a server offers through specific listing methods:

# Discovery methods for each primitive

# List available tools
{"jsonrpc": "2.0", "id": 2, "method": "tools/list"}

# List available resources
{"jsonrpc": "2.0", "id": 3, "method": "resources/list"}

# List available prompts
{"jsonrpc": "2.0", "id": 4, "method": "prompts/list"}

# Read a specific resource
{"jsonrpc": "2.0", "id": 5, "method": "resources/read", "params": {"uri": "file:///config/app.json"}}

# Call a specific tool
{"jsonrpc": "2.0", "id": 6, "method": "tools/call", "params": {"name": "query_users", "arguments": {"status": "active"}}}

# Get a specific prompt
{"jsonrpc": "2.0", "id": 7, "method": "prompts/get", "params": {"name": "review_code", "arguments": {"language": "python", "code": "def hello(): pass"}}}

Dynamic Capability Updates

MCP supports dynamic updates to server capabilities. When a server adds, removes, or modifies its tools, resources, or prompts, it can notify connected clients using change notifications:

  • notifications/tools/list_changed -- Tools have been added, removed, or modified
  • notifications/resources/list_changed -- Resources have changed
  • notifications/prompts/list_changed -- Prompts have changed

Upon receiving these notifications, clients should re-fetch the relevant list to update their local view of the server's capabilities.

Key Takeaway: MCP's architecture consists of three roles (Host, Client, Server) and three primitives (Tools, Resources, Prompts). The key differentiator between primitives is their control model: tools are model-controlled, resources are application-controlled, and prompts are user-controlled. Communication uses JSON-RPC 2.0 over stdio, SSE, or Streamable HTTP transports. The protocol begins with a capability negotiation handshake. Servers can dynamically update their capabilities and notify clients of changes.