Overview
MCP messages define the communication format between clients and servers. This reference documents all message types, their structure, and usage patterns.
MCP follows a request-response pattern similar to JSON-RPC 2.0 with extensions for streaming and bidirectional communication.
Protocol Transport Architecture
The MCP protocol supports multiple transport layers for communication between clients and servers. The diagram below illustrates how messages flow through the system:
Transport Options
Process-based communication using stdin/stdout. Best for local CLI integrations. # Server reads from stdin, writes to stdout
echo '{"jsonrpc":"2.0","id":1,"method":"initialize"}' | mcp-server
HTTP-based one-way streaming from server to client. Ideal for web applications. const eventSource = new EventSource ( '/mcp/stream' );
eventSource . onmessage = ( event ) => {
const message = JSON . parse ( event . data );
// Handle message
};
Full-duplex bidirectional communication. Best for real-time interactive applications. import websockets
async with websockets.connect( 'ws://localhost:8000/mcp/ws' ) as ws:
await ws.send(json.dumps(request))
response = await ws.recv()
Message Structure
All MCP messages follow this base structure:
{
"jsonrpc" : "2.0" ,
"id" : "request-123" ,
"method" : "tools/call" ,
"params" : {
"name" : "chat" ,
"arguments" : { "query" : "Hello" }
}
}
Protocol version, always "2.0"
Unique request identifier for matching responses
The method to invoke (e.g., "tools/call", "resources/read")
Method-specific parameters
Response Messages
Success Response
{
"jsonrpc" : "2.0" ,
"id" : "request-123" ,
"result" : {
"content" : [
{
"type" : "text" ,
"text" : "Hello! How can I help you?"
}
]
}
}
Error Response
{
"jsonrpc" : "2.0" ,
"id" : "request-123" ,
"error" : {
"code" : -32602 ,
"message" : "Invalid params" ,
"data" : {
"field" : "query" ,
"reason" : "Required field missing"
}
}
}
Error Codes
Code Message Description -32700 Parse error Invalid JSON -32600 Invalid Request Invalid request object -32601 Method not found Method does not exist -32602 Invalid params Invalid method parameters -32603 Internal error Internal server error -32000 Server error Generic server error
Message Types
Initialize
Request :
{
"jsonrpc" : "2.0" ,
"id" : 1 ,
"method" : "initialize" ,
"params" : {
"protocolVersion" : "2024-11-05" ,
"capabilities" : {
"roots" : {
"listChanged" : true
},
"sampling" : {}
},
"clientInfo" : {
"name" : "example-client" ,
"version" : "1.0.0"
}
}
}
Response :
{
"jsonrpc" : "2.0" ,
"id" : 1 ,
"result" : {
"protocolVersion" : "2024-11-05" ,
"capabilities" : {
"logging" : {},
"prompts" : {
"listChanged" : true
},
"resources" : {
"subscribe" : true ,
"listChanged" : true
},
"tools" : {
"listChanged" : true
}
},
"serverInfo" : {
"name" : "mcp-server-langgraph" ,
"version" : "2.8.0"
}
}
}
Request :
{
"jsonrpc" : "2.0" ,
"id" : 2 ,
"method" : "tools/list" ,
"params" : {}
}
Response :
{
"jsonrpc" : "2.0" ,
"id" : 2 ,
"result" : {
"tools" : [
{
"name" : "chat" ,
"description" : "Chat with the AI agent" ,
"inputSchema" : {
"type" : "object" ,
"properties" : {
"query" : {
"type" : "string" ,
"description" : "User query"
}
},
"required" : [ "query" ]
}
}
]
}
}
Request :
{
"jsonrpc" : "2.0" ,
"id" : 3 ,
"method" : "tools/call" ,
"params" : {
"name" : "chat" ,
"arguments" : {
"query" : "What is the weather?" ,
"conversation_id" : "conv_123"
}
}
}
Response :
{
"jsonrpc" : "2.0" ,
"id" : 3 ,
"result" : {
"content" : [
{
"type" : "text" ,
"text" : "I don't have access to real-time weather data. Please check a weather service."
}
],
"isError" : false
}
}
Resources/List
Request :
{
"jsonrpc" : "2.0" ,
"id" : 4 ,
"method" : "resources/list" ,
"params" : {}
}
Response :
{
"jsonrpc" : "2.0" ,
"id" : 4 ,
"result" : {
"resources" : [
{
"uri" : "conversation://conv_123" ,
"name" : "Conversation History" ,
"description" : "Chat conversation context" ,
"mimeType" : "application/json"
}
]
}
}
Resources/Read
Request :
{
"jsonrpc" : "2.0" ,
"id" : 5 ,
"method" : "resources/read" ,
"params" : {
"uri" : "conversation://conv_123"
}
}
Response :
{
"jsonrpc" : "2.0" ,
"id" : 5 ,
"result" : {
"contents" : [
{
"uri" : "conversation://conv_123" ,
"mimeType" : "application/json" ,
"text" : "{ \" messages \" : [...]}"
}
]
}
}
Prompts/List
Request :
{
"jsonrpc" : "2.0" ,
"id" : 6 ,
"method" : "prompts/list" ,
"params" : {}
}
Response :
{
"jsonrpc" : "2.0" ,
"id" : 6 ,
"result" : {
"prompts" : [
{
"name" : "code_review" ,
"description" : "Review code for quality and best practices" ,
"arguments" : [
{
"name" : "code" ,
"description" : "Code to review" ,
"required" : true
}
]
}
]
}
}
Prompts/Get
Request :
{
"jsonrpc" : "2.0" ,
"id" : 7 ,
"method" : "prompts/get" ,
"params" : {
"name" : "code_review" ,
"arguments" : {
"code" : "def add(a, b): return a + b"
}
}
}
Response :
{
"jsonrpc" : "2.0" ,
"id" : 7 ,
"result" : {
"description" : "Review code for quality and best practices" ,
"messages" : [
{
"role" : "user" ,
"content" : {
"type" : "text" ,
"text" : "Please review this code: \n\n def add(a, b): return a + b"
}
}
]
}
}
Content Types
Text Content
{
"type" : "text" ,
"text" : "This is plain text content"
}
Image Content
{
"type" : "image" ,
"data" : "base64-encoded-image-data" ,
"mimeType" : "image/png"
}
Resource Content
{
"type" : "resource" ,
"resource" : {
"uri" : "file:///path/to/file.txt" ,
"mimeType" : "text/plain" ,
"text" : "File contents"
}
}
Notifications
Notifications are messages sent without expecting a response (no id field):
{
"jsonrpc" : "2.0" ,
"method" : "notifications/tools/list_changed"
}
Resources/ListChanged
{
"jsonrpc" : "2.0" ,
"method" : "notifications/resources/list_changed"
}
Resources/Updated
{
"jsonrpc" : "2.0" ,
"method" : "notifications/resources/updated" ,
"params" : {
"uri" : "conversation://conv_123"
}
}
Streaming Messages
For streaming responses, the server sends multiple messages:
Content Start
{
"jsonrpc" : "2.0" ,
"id" : 8 ,
"result" : {
"type" : "content_start"
}
}
Content Delta
{
"jsonrpc" : "2.0" ,
"id" : 8 ,
"result" : {
"type" : "content_delta" ,
"delta" : "Quantum computing"
}
}
Content End
{
"jsonrpc" : "2.0" ,
"id" : 8 ,
"result" : {
"type" : "content_end" ,
"conversation_id" : "conv_123" ,
"usage" : {
"prompt_tokens" : 20 ,
"completion_tokens" : 150 ,
"total_tokens" : 170
}
}
}
Progress Updates
For long-running operations:
{
"jsonrpc" : "2.0" ,
"method" : "notifications/progress" ,
"params" : {
"progressToken" : "token-123" ,
"progress" : 50 ,
"total" : 100
}
}
Example Flows
Complete Chat Interaction
import asyncio
import json
import httpx
async def chat_example ():
async with httpx.AsyncClient() as client:
# 1. Initialize
init_response = await client.post(
"http://localhost:8000/mcp" ,
json = {
"jsonrpc" : "2.0" ,
"id" : 1 ,
"method" : "initialize" ,
"params" : {
"protocolVersion" : "2024-11-05" ,
"clientInfo" : { "name" : "example" , "version" : "1.0" }
}
},
headers = { "Authorization" : f "Bearer { token } " }
)
print ( "Initialized:" , init_response.json())
# 2. List tools
tools_response = await client.post(
"http://localhost:8000/mcp" ,
json = {
"jsonrpc" : "2.0" ,
"id" : 2 ,
"method" : "tools/list"
},
headers = { "Authorization" : f "Bearer { token } " }
)
print ( "Available tools:" , tools_response.json())
# 3. Call chat tool
chat_response = await client.post(
"http://localhost:8000/mcp" ,
json = {
"jsonrpc" : "2.0" ,
"id" : 3 ,
"method" : "tools/call" ,
"params" : {
"name" : "chat" ,
"arguments" : { "query" : "Hello!" }
}
},
headers = { "Authorization" : f "Bearer { token } " }
)
result = chat_response.json()
print ( "Response:" , result[ "result" ][ "content" ][ 0 ][ "text" ])
asyncio.run(chat_example())
Batch Requests
Send multiple requests in a single HTTP call:
[
{
"jsonrpc" : "2.0" ,
"id" : 1 ,
"method" : "tools/list"
},
{
"jsonrpc" : "2.0" ,
"id" : 2 ,
"method" : "resources/list"
},
{
"jsonrpc" : "2.0" ,
"id" : 3 ,
"method" : "prompts/list"
}
]
Response :
[
{
"jsonrpc" : "2.0" ,
"id" : 1 ,
"result" : { "tools" : [ ... ]}
},
{
"jsonrpc" : "2.0" ,
"id" : 2 ,
"result" : { "resources" : [ ... ]}
},
{
"jsonrpc" : "2.0" ,
"id" : 3 ,
"result" : { "prompts" : [ ... ]}
}
]
Validation
Request Validation
All requests must:
Include jsonrpc: "2.0"
Have a unique id (except notifications)
Specify a valid method
Provide required params for the method
Response Validation
Clients should validate:
Response id matches request id
Either result or error is present (not both)
Content types match expected formats
Best Practices
Always use unique IDs for requests to prevent confusion: import uuid
request_id = str (uuid.uuid4())
request = {
"jsonrpc" : "2.0" ,
"id" : request_id,
"method" : "tools/call" ,
"params" : { ... }
}
Always check for error responses: response = await client.post(url, json = request)
data = response.json()
if "error" in data:
code = data[ "error" ][ "code" ]
message = data[ "error" ][ "message" ]
raise Exception ( f "MCP Error { code } : { message } " )
return data[ "result" ]
Set reasonable timeouts for requests: async with httpx.AsyncClient( timeout = 30.0 ) as client:
response = await client.post(url, json = request)
Combine multiple requests to reduce latency: batch = [
{ "jsonrpc" : "2.0" , "id" : 1 , "method" : "tools/list" },
{ "jsonrpc" : "2.0" , "id" : 2 , "method" : "resources/list" }
]
responses = await client.post(url, json = batch)
Next Steps
MCP Messages : Standardized communication protocol for AI applications!