Protocol Deep Dive
Relevant source files
The following files were used as context for generating this wiki page:
The Model Context Protocol (MCP) is a JSON-RPC based protocol designed for communication between a client and a server, enabling the client to interact with server-provided capabilities like tools, resources, and prompts. This document provides a technical deep dive into the protocol's structure, communication transports, message flow, and core features as implemented in this Python SDK.
The protocol is designed to be transport-agnostic, but this SDK provides two primary transport implementations: Server-Sent Events (SSE) and a custom StreamableHTTP transport. Both facilitate the asynchronous, bidirectional communication required for features like progress notifications and server-initiated requests.
Communication Transports
MCP communication is session-based and can be established over two main transports.
Server-Sent Events (SSE)
The SSE transport uses a standard /sse endpoint. The client establishes a persistent connection, and all communication, both client-to-server and server-to-client, occurs over this single channel.
Sources: tests/server/fastmcp/test_integration.py:126-127, tests/server/fastmcp/test_server.py:79-82
StreamableHTTP
The StreamableHTTP transport is a custom implementation that uses standard HTTP methods over a /mcp endpoint to simulate a bidirectional stream. It is designed for environments where true persistent connections might be challenging.
POST /mcp: The client sends requests to the server. The server can stream back responses (notifications, results) astext/event-stream.GET /mcp: The client can open a long-lived GET request to receive server-initiated notifications. Only one GET stream is allowed per session.DELETE /mcp: Terminates the session.
This transport relies on mcp-session-id and mcp-protocol-version headers to manage the session state across multiple HTTP requests.
The following diagram illustrates the StreamableHTTP flow.
Resumability
The StreamableHTTP transport supports session resumption. The server can use an EventStore to save messages. If a client disconnects, it can reconnect and provide the Last-Event-ID header to receive any missed events.
Sources: tests/shared/test_streamable_http.py:53-83
Session Lifecycle
A typical MCP session follows a clear lifecycle from initialization to termination.
This diagram shows the sequence of a basic client-server interaction.
Initialization
The session begins when the client sends an initialize request. This request includes client information and its capabilities. The server responds with its own information and capabilities.
initialize Parameter | Type | Description |
|---|---|---|
clientInfo | ClientInfo | Name and version of the client. |
protocolVersion | str | The protocol version the client wishes to use. |
capabilities | ClientCapabilities | The capabilities supported by the client. |
Sources: mcp/types.py, tests/shared/test_streamable_http.py:43-52
Core Capabilities
The protocol defines three main capabilities a server can expose: Tools, Resources, and Prompts.
Tools
Tools are functions that the client can execute on the server. The server advertises available tools, and the client can invoke them using a tools/call request.
Tool Definition
A tool is defined by its name, description, input schema, and optionally an output schema and title.
The get_display_name utility determines the user-facing name for a tool with the following precedence: title > annotations.title > name.
Sources: tests/server/fastmcp/test_title.py:165-179
Tool Invocation and Content Types
When a tool is called, it can return various types of content. The FastMCP server automatically converts Python return types into the appropriate ContentBlock objects.
| Python Return Type | MCP Content Type | Notes |
|---|---|---|
str, int, dict, etc. | TextContent | Primitives are serialized to a JSON string. |
Image (helper class) | ImageContent | Image data is Base64 encoded. |
Audio (helper class) | AudioContent | Audio data is Base64 encoded. |
list[ContentBlock] | list[ContentBlock] | A list of mixed content blocks. |
pydantic.BaseModel | TextContent + structuredContent | The result is available as both a JSON string and a structured dictionary. |
Sources: tests/server/fastmcp/test_server.py:313-323, 326-340, 381-404, 502-523
Resources
Resources represent data that the client can read from the server, such as files or configuration settings. They are identified by a URI.
- Static Resources: Have a fixed URI (e.g.,
config://settings). - Resource Templates: Have a URI with parameters (e.g.,
github://repos/{owner}/{repo}). The client provides values for the parameters to access a specific resource.
Sources: tests/server/fastmcp/test_server.py:732-745, 804-814, tests/server/fastmcp/test_integration.py:301-315
Prompts
Prompts are templates for generating messages, often used to construct inputs for language models. Like tools, they can have parameters. The client uses prompts/get to retrieve the rendered messages.
Sources: tests/server/fastmcp/test_server.py:1011-1021, tests/server/fastmcp/test_integration.py:330-348
Asynchronous Notifications
A key feature of MCP is the ability for the server to send asynchronous notifications to the client, independent of a specific request-response cycle. This is used for logging, progress updates, and state change notifications.
Notification Flow
The following diagram shows a tool call that reports progress and sends log messages.
Notification Types
The protocol defines several standard notification types:
| Notification | Purpose |
|---|---|
progress | Reports the progress of a long-running operation. |
log | Sends a log message from the server to the client. |
resourceListChanged | Informs the client that the list of available resources has changed. |
toolListChanged | Informs the client that the list of available tools has changed. |
Sources: tests/server/fastmcp/test_integration.py:61-75
Authentication and Authorization
The protocol integrates OAuth 2.0 for secure authentication and authorization, following RFC specifications for discovery and token handling.
OAuth 2.0 Flow
The authentication process involves the client, a Resource Server (the MCP server), and an Authorization Server.
This diagram shows the complete OAuth 2.0 authorization code flow with PKCE as used by the MCP server.
Sources: tests/server/fastmcp/auth/test_auth_integration.py:623-703, examples/servers/simple-auth/README.md
Bearer Token Authentication
Once the client obtains an access token, it includes it in the Authorization header of subsequent requests to the MCP server. The BearerAuthBackend middleware on the server is responsible for validating this token.
- It checks for a header in the format
Authorization: Bearer <token>. - It verifies that the token is valid and not expired.
- If valid, it populates the request scope with an
AuthenticatedUserandAuthCredentials, which include the client ID and granted scopes. - If the token is invalid, missing, or expired, it denies access.
Sources: tests/server/auth/middleware/test_bearer_auth.py:115-144, 182-200
Conclusion
The Model Context Protocol provides a robust and flexible framework for client-server communication, particularly in AI and agent-based applications. Its support for multiple transports (SSE and StreamableHTTP), a clear session lifecycle, and asynchronous notifications enables complex interactions. The integration of standard OAuth 2.0 ensures that these interactions can be performed securely. The FastMCP server implementation in this SDK offers a high-level, developer-friendly way to build powerful MCP servers in Python.