Message Flow & Lifecycle
See how a complete MCP session works from start to finish.
The MCP Connection Lifecycle
Every MCP session follows a specific lifecycle. Understanding this flow is essential before we start building servers.
┌─────────────────────────────────────────────────────────────┐
│ MCP LIFECYCLE │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. INITIALIZATION │
│ Client ──► initialize request │
│ Server ◄── initialize response (capabilities) │
│ Client ──► notifications/initialized │
│ │
├─────────────────────────────────────────────────────────────┤
│ │
│ 2. OPERATION (normal usage) │
│ Client ──► tools/list │
│ Server ◄── list of tools │
│ Client ──► tools/call │
│ Server ◄── tool result │
│ ... (repeat as needed) │
│ │
├─────────────────────────────────────────────────────────────┤
│ │
│ 3. SHUTDOWN │
│ Client ──► close connection │
│ (Server exits or connection drops) │
│ │
└─────────────────────────────────────────────────────────────┘
Phase 1: Initialization
Before any tools can be called or resources read, the client and server must complete a handshake. This establishes protocol version and capabilities.
Step 1: Client sends initialize request
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-11-25",
"capabilities": {
"sampling": {}
},
"clientInfo": {
"name": "claude-desktop",
"version": "1.0.0"
}
}
}
Step 2: Server responds with capabilities
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2025-11-25",
"capabilities": {
"tools": {},
"resources": {}
},
"serverInfo": {
"name": "my-mcp-server",
"version": "1.0.0"
}
}
}
Step 3: Client confirms initialization
{
"jsonrpc": "2.0",
"method": "notifications/initialized"
}
The notifications/initialized message has no id field.
This makes it a notification, which doesn't expect a response.
Phase 2: Normal Operation
After initialization, the client can start using the server's capabilities. Here's a typical tool interaction:
List available tools
// Request
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/list"
}
// Response
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"tools": [
{
"name": "get_weather",
"description": "Get weather for a city",
"inputSchema": {
"type": "object",
"properties": {
"city": {"type": "string"}
},
"required": ["city"]
}
}
]
}
}
Call a tool
// Request
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "get_weather",
"arguments": {
"city": "San Francisco"
}
}
}
// Response
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"content": [
{
"type": "text",
"text": "San Francisco: 68°F, Sunny"
}
]
}
}
Key MCP Methods
Here are the main methods you'll implement:
| Method | Purpose |
|---|---|
initialize |
Exchange capabilities and version |
tools/list |
Get available tools |
tools/call |
Execute a tool |
resources/list |
Get available resources |
resources/read |
Read a resource's content |
prompts/list |
Get available prompts |
prompts/get |
Get a prompt's content |
What's Next?
Congratulations! You now understand the fundamentals of MCP:
- What MCP is and why it exists
- The client-server architecture
- Tools, Resources, and Prompts
- STDIO vs HTTP/SSE transports
- The message flow and lifecycle
In the next lesson, we'll build a simple HTTP server using Python's standard library. This will give you the foundation to build MCP servers with the HTTP/SSE transport.
Starting in Lesson 2, we'll write actual Python code. Make sure you have Python 3.8+ installed and a code editor ready. Let's build!