MCP is written with LLM apps as the clients, not human end-users. It provides a set of conventions on how to agnostically provide context to LLM apps.
Concepts of MCP
There are 3 key participants in the MCP architecture:
- MCP Host: The AI application that manages one or more MCP clients.
- MCP Client: A component that maintains a connection to an MCP server and obtains context from an MCP server for the MCP host to use.
- MCP Server: A program that provides context to MCP clients.
MCP consists of two layers:
- Transport layer: The outer layer that defines communication mechanisms and
channels that enable client-server data exchange, e.g., message framing,
authorization, etc. MCP supports two transport mechanisms:
- Stdio for local processes on the same machine.
- Streamable HTTP for remote server communication with bearer tokens, API keys, and custom headers.
- Data layer: The inner layer that defines the JSON-RPC based protocol for client-server communication, e.g., lifecycle management and core primitives.
MCP primitives define what clients and servers can offer each other. Servers can expose:
- Tools: Executable functions that the MCP host can invoke to perform actions.
- Resources: Data sources that provide contextual information.
- Prompts: Reusable templates to help structure LLM inference.
… where each primitive has associated methods for discovery (*/list),
retrieval (*/get). Additionally, there’s tools/call for execution.
Clients can expose these MCP primitives:
- Sampling: Allows servers to request LLM inference from the client’s AI application, enabling the MCP server to stay model-independent.
- Elicitation: Allows servers to request additional information from users.
- Logging: Enables servers to send log messages to clients for debugging and monitoring purposes.
- Tasks (Experimental): Durable execution wrappers that enable deferred result retrieval and status tracking for MCP requests.
MCP also supports notifications to enable dynamic updates between servers and clients.
Sample Flow w/ Tool Calls
The client sends an initialize request, e.g.,
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-06-18",
"capabilities": { "elicitation": {} },
"clientInfo": { "name": "example-client", "version": "1.0.0" }
}
}
… and the server responds:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2025-06-18",
"capabilities": {
"tools": { "listChanged": true },
"resources": {}
},
"serverInfo": { "name": "example-server", "version": "1.0.0" }
}
}
… and the MCP host stores these capabilities for later use.
If a mutually compatible protocolVersion cannot be found, the connection
should be terminated. Otherwise, the client notifies the server that it’s ready:
{ "jsonrpc": "2.0", "method": "notifications/initialized" }
To discover available tools, the client sends {"jsonrpc": "2.0", "id": 2, "method": "tools/list"} and the server responds, e.g.,
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"tools": [
{
"name": "weather_current", // Unique within the server's namespace
"title": "Weather Information", // Human readable name of the tool
"description": "Get current weather information for any location worldwide",
"inputSchema": { // Enables type validation and documentation on required params
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "City name, address, or coordinates (latitude, longitude)"
},
"units": {
"type": "string",
"enum": ["metric", "imperial", "kelvin"],
"description": "Temperature units to use in response",
"default": "metric"
}
},
"required": ["location"]
}
}
]
}
}
… and the MCP host combines all the tools from the MCP servers into a unified tool registry that the LLM can access.
When the LLM decides to use a given tool, the MCP host routes it to the
appropriate MCP client which sends a tools/call request to the MCP server,
e.g.,
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "weather_current", // Must match the name from tools/list
"arguments": { "location": "San Francisco", "units": "imperial" }
}
}
… and the MCP server responds:
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"content": [
{
"type": "text",
"text": "Current weather in San Francisco: 68°F, partly cloudy with light winds from the west at 8 mph. Humidity: 65%"
}
]
}
}
One of the common criticisms for MCP is that cases like weather_current can
already be solved with existing tech, i.e., expose the API docs and a utility
for making network calls.
For real-time updates, MCP supports notifications. For example, an MCP server
that specified "tools": { "listChanged": true } can send a notification like:
{ "jsonrpc": "2.0", "method": "notifications/tools/list_changed" }. The client
typically reacts by requesting tools/list and refreshing its list of available
tools. That way, the client doesn’t need to poll for changes.
Notes on MCP Primitives
Resources provide structured access to information that the AI app can
retrieve and pass to the model as context, e.g., a server can expose
calendar://events/2026 to return calendar availability for the user. A server
can also expose resource templates, e.g.,
travel://activities/{city}/{category} for flexible queries, e.g.,
travel://activities/barcelona/museums.
The boundaries here seem pretty fluid. For example, filtering to contextual
data, e.g., travel://activities/barcelona/museums and
file://documents/travel/passport.pdf, may require an inference to map the user
query against the list of available resources. Furthermore, resource templates
seem like they should be behind a tool call, e.g., getAttractions(city: str | None, category: str | None).
Prompts provide reusable templates for common scenarios, e.g., a
plan-vacation prompt that accepts a destination, duration, budget, and
interests.
I don’t fully understand the utility here. If the vacation MCP server provides
a plan-vacation prompt, then the customizations are more like a way to ensure
that the user provides all of the required data upfront. Contrast this to a case
where the user has vague vacation plans and the host needs to elicit more
specific information from the user before calling a tool in the vacation MCP
server.
If the plan-vacation prompt contains procedural guidance on how to call the
tools in the vacation MCP server, then why not have those instructions in some
internal system prompt? Ah, we’re assuming that vacation has an LLM, which is
not true in general.
References
- Architecture overview - Model Context Protocol. modelcontextprotocol.io . Accessed May 9, 2026.
- Understanding MCP servers - Model Context Protocol. modelcontextprotocol.io . Accessed May 9, 2026.
There seems to be additional bookkeeping needed on the MCP host. While
weather_currentis unique inexample-server’s namespace, that might not hold in the MCP hosts’s tool registry. Maybe the host’s LLM sees a tool name likeexample-server.weather_current, and the host strips the prefix at the host/client boundary.