Session files store complete MCP request/response sequences as JSON, providing a portable record of interactions for replay, debugging, and evidence.
A session file contains a ProxySession object with metadata and an ordered list of ProxyMessage entries:
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"started_at": "2026-03-04T10:00:00+00:00",
"ended_at": "2026-03-04T10:05:30+00:00",
"transport": "stdio",
"server_command": "python -m my_server",
"server_url": null,
"messages": [
{
"proxy_id": "msg-001",
"sequence": 0,
"timestamp": "2026-03-04T10:00:01+00:00",
"direction": "client_to_server",
"transport": "stdio",
"jsonrpc_id": 1,
"method": "initialize",
"correlated_id": null,
"modified": false,
"payload": {
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {},
"clientInfo": {
"name": "qai-agent",
"version": "0.5.1"
}
}
}
},
{
"proxy_id": "msg-002",
"sequence": 1,
"timestamp": "2026-03-04T10:00:02+00:00",
"direction": "server_to_client",
"transport": "stdio",
"jsonrpc_id": 1,
"method": null,
"correlated_id": "msg-001",
"modified": false,
"payload": {
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2024-11-05",
"capabilities": {},
"serverInfo": {
"name": "example-server",
"version": "1.0.0"
}
}
}
}
],
"metadata": {
"target": "example-server",
"notes": "Captured during security audit"
}
}
Session Fields
| Field | Type | Description |
|---|
id | string | Unique session UUID |
started_at | ISO 8601 timestamp | When the proxy started |
ended_at | ISO 8601 timestamp or null | When the proxy ended (null if still active) |
transport | string | Transport type: stdio, sse, or streamable-http |
server_command | string or null | Server startup command (stdio only) |
server_url | string or null | Server endpoint URL (SSE/HTTP only) |
messages | array | Ordered list of ProxyMessage objects |
metadata | object | Custom metadata (target name, audit notes, etc.) |
Message Fields
| Field | Type | Description |
|---|
proxy_id | string | Unique proxy-assigned UUID for this message |
sequence | integer | Monotonic sequence number (0-based) within the session |
timestamp | ISO 8601 timestamp | When the proxy received this message |
direction | string | client_to_server or server_to_client |
transport | string | Transport type (stdio, sse, or streamable-http) |
jsonrpc_id | integer, string, or null | JSON-RPC id field (null for notifications) |
method | string or null | JSON-RPC method name (null for responses) |
correlated_id | string or null | Proxy ID of the request this response correlates to |
modified | boolean | true if the user modified this message before forwarding |
payload | object | The complete JSON-RPC message content |
original_payload | object or null | Pre-modification snapshot (present only when modified is true) |
Saving Sessions
Auto-save on Startup
Use --session-file to automatically save when the proxy exits:
qai proxy start \
--transport stdio \
--target-command "python my_server.py" \
--session-file session.json
Save During Session
Press s in the TUI at any time to save the current session to disk.
Export Command
Export a saved session to a new file:
qai proxy export \
--session-file session.json \
--output report.json \
--output-format json
Inspecting Sessions
Quick Review
Print session contents to stdout:
qai proxy inspect --session-file session.json
Output:
Session: 550e8400-e29b-41d4-a716-446655440000
Transport: stdio
Server command: python my_server.py
Messages: 12
#000 > initialize id=1
#001 < (response) id=1 corr=msg-001
#002 > notifications/initialized
#003 > tools/call id=2
#004 < (response) id=2 corr=msg-003
#005 > tools/call id=3
#006 < (response) id=3 corr=msg-005
Verbose Output
Include full JSON payloads:
qai proxy inspect --session-file session.json -v
Message Modification Recording
When you modify a message in intercept mode, the proxy records both versions:
{
"proxy_id": "msg-005",
"sequence": 4,
"direction": "client_to_server",
"modified": true,
"payload": {
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "search",
"arguments": {
"query": "MODIFIED QUERY"
}
}
},
"original_payload": {
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "search",
"arguments": {
"query": "original query"
}
}
}
}
The original_payload field is only present when modified is true, preserving evidence of user modifications.
Use Cases
Finding Reproduction
Attach the session file when reporting a vulnerability to provide complete evidence:
qai proxy export \
--session-file vulnerable_interaction.json \
--output vulnerability_evidence.json
Regression Testing
Store sessions from successful interactions and replay them against new versions:
# Save baseline
qai proxy start \
--transport stdio \
--target-command "python server_v1.py" \
--session-file baseline_v1.json
# Replay against v2
qai proxy replay \
--session-file baseline_v1.json \
--target-command "python server_v2.py" \
--output v2_results.json
Audit Trails
Export sessions with metadata for compliance documentation:
# Session with audit notes
qai proxy export \
--session-file security_test.json \
--output audit_evidence.json
Raw session captures may contain sensitive data — prompts, tokens, tool arguments, and server responses. Do not commit session files to public repositories or share them via unsecured channels. Redact or encrypt sensitive fields before sharing, and store exports only in private, access-controlled locations. Use inspect --verbose only on sanitized data when reviewing full payloads.
File Size Considerations
Session files scale linearly with message count and payload size. A typical agent interaction with 50 messages averages 10-50 KB. High-volume capture sessions can be 1-10 MB for thousands of messages.
For long-running proxies, periodically save sessions with --session-file to manage file size.