VOOZH about

URL: https://deepwiki.com/WordPress/mcp-adapter/5.3-session-management

⇱ Session Management | WordPress/mcp-adapter | DeepWiki


Loading...
Menu

Session Management

This document describes the session management system used by the HTTP transport layer to maintain stateful connections between MCP clients and the WordPress MCP Adapter. Sessions ensure that clients are authenticated and authorized for the duration of their interaction with the server.

For information about transport-level permissions and authentication, see Transport Permissions. For details about the HTTP transport protocol implementation, see HTTP Transport.


Overview

The MCP Adapter implements a session-based communication model for HTTP transport, as required by the MCP 2025-06-18 Streamable HTTP specification. Sessions are:

  • Created during the initialize request when no Mcp-Session-Id header is present
  • Validated for all subsequent requests (except initialize)
  • Terminated via HTTP DELETE requests
  • Stored in WordPress user meta for persistence across requests
  • Identified by the Mcp-Session-Id HTTP header

The session management system is implemented primarily in HttpSessionValidator and integrated into the request processing pipeline via HttpRequestHandler and RequestRouter.

Sources: includes/Transport/Infrastructure/RequestRouter.php154-172 includes/Transport/Infrastructure/HttpRequestHandler.php169-203 tests/Integration/HttpTransportTest.php405-435


Architecture Overview


Session Flow Overview

StepActionComponentResult
1Client sends initialize without sessionHttpRequestHandlerDetects no Mcp-Session-Id header
2Handler routes to initialize handlerRequestRouterCalls HttpSessionValidator::create_session()
3Session created and storedHttpSessionValidatorReturns session ID string
4Session ID added to responseHttpRequestHandlerSets Mcp-Session-Id header via filter
5Client sends subsequent request with sessionHttpRequestHandlerExtracts Mcp-Session-Id from header
6Session validated before routingHttpSessionValidatorReturns true or error array
7Request processed normallyRequestRouterHandler executes business logic
8Client sends DELETE to terminateHttpRequestHandlerCalls HttpSessionValidator::terminate_session()

Sources: includes/Transport/Infrastructure/RequestRouter.php40-130 includes/Transport/Infrastructure/HttpRequestHandler.php46-67 tests/Integration/HttpTransportTest.php77-118


Session Creation

Sessions are created automatically during the first initialize request when no Mcp-Session-Id header is present. The creation process is coordinated between RequestRouter and HttpSessionValidator.

Creation Flow


Code Flow

The session creation process begins in RequestRouter::handle_initialize_with_session():

RequestRouter::handle_initialize_with_session()
 └─> context->initialize_handler->handle(request_id)
 └─> if (http_context && !result['error'] && !http_context->session_id)
 └─> HttpSessionValidator::create_session(params)
 ├─> Returns session_id (string) on success
 └─> Returns error array on failure
 └─> result['_session_id'] = session_id

The _session_id is then extracted by HttpRequestHandler::process_jsonrpc_request() and added to the response headers:

HttpRequestHandler::process_jsonrpc_request()
 └─> if (isset(result['_session_id']))
 └─> add_session_header_to_response(result['_session_id'])
 └─> unset(result['_session_id'])

Sources: includes/Transport/Infrastructure/RequestRouter.php154-172 includes/Transport/Infrastructure/HttpRequestHandler.php192-195 includes/Transport/Infrastructure/HttpRequestHandler.php256-276

Session Creation Requirements

RequirementCheckError Code
User must be authenticatedget_current_user_id() > 0McpErrorFactory::UNAUTHORIZED (-401)
No existing active sessionCheck http_context->session_idN/A (skipped if session exists)
Initialize must succeedNo error in init resultVarious (from initialize handler)

When session creation fails, the error is extracted from the JSON-RPC response and returned directly:


Sources: includes/Transport/Infrastructure/RequestRouter.php160-165 tests/Integration/HttpTransportTest.php272-321 tests/Unit/Transport/Infrastructure/RequestRouterTest.php334-366


Session Validation

All requests except initialize must include a valid Mcp-Session-Id header. Session validation occurs in HttpRequestHandler::process_jsonrpc_request() before the request is routed to handlers.

Validation Flow


Code Flow

The validation check is straightforward and mandatory:

HttpRequestHandler::process_jsonrpc_request()
 └─> if (method !== 'initialize')
 └─> session_validation = HttpSessionValidator::validate_session(context)
 └─> if (session_validation !== true)
 └─> return JsonRpcResponseBuilder::create_error_response(request_id, error)

Sources: includes/Transport/Infrastructure/HttpRequestHandler.php174-180 tests/Integration/HttpTransportTest.php251-270 tests/Unit/Transport/Infrastructure/HttpRequestHandlerTest.php123-144

Validation Error Scenarios

ScenarioError MessageError CodeHTTP Status
Missing Mcp-Session-Id header"Missing Mcp-Session-Id header"McpErrorFactory::INVALID_REQUEST (-32600)400
Invalid/expired session ID"Invalid or expired session"McpErrorFactory::INVALID_PARAMS (-32602)200*
User not authenticated"Authentication required"McpErrorFactory::UNAUTHORIZED (-401)401

*Note: Invalid session errors return HTTP 200 with JSON-RPC error in body, while missing headers return HTTP 400.

Sources: tests/Integration/HttpTransportTest.php269 tests/Integration/HttpTransportTest.php503 tests/Integration/HttpTransportTest.php328


Session Termination

Sessions can be explicitly terminated by sending a DELETE request to the MCP endpoint with the Mcp-Session-Id header. This removes the session from storage and prevents further use of that session ID.

Termination Flow


Code Integration

Session termination is handled as a special HTTP method case:

HttpRequestHandler::handle_request()
 └─> if (method === 'DELETE')
 └─> handle_session_termination(context)
 └─> result = HttpSessionValidator::terminate_session(context)
 └─> if (result !== true)
 └─> return WP_REST_Response(result, http_status)
 └─> return WP_REST_Response(null, 200)

Sources: includes/Transport/Infrastructure/HttpRequestHandler.php58-60 includes/Transport/Infrastructure/HttpRequestHandler.php225-234 tests/Integration/HttpTransportTest.php340-385

Termination Behavior

AspectBehavior
Success ResponseHTTP 200 with null body
Missing HeaderHTTP 400 with error object in body
Invalid SessionSession is silently ignored (returns success)
Side EffectSession ID immediately becomes invalid for validation

After termination, any attempts to use the terminated session ID will result in "Invalid or expired session" errors.

Sources: tests/Integration/HttpTransportTest.php340-385 tests/Unit/Transport/Infrastructure/HttpRequestHandlerTest.php277-309


Session Storage and Data Structure

Sessions are stored in WordPress user meta under the key mcp_adapter_sessions. This allows sessions to persist across HTTP requests while remaining scoped to individual users.

Storage Schema


Storage Operations

OperationWordPress FunctionPurpose
Readget_user_meta( $user_id, 'mcp_adapter_sessions', true )Retrieve all sessions for user
Writeupdate_user_meta( $user_id, 'mcp_adapter_sessions', $sessions )Store updated session array
Deletedelete_user_meta( $user_id, 'mcp_adapter_sessions' )Remove all sessions (cleanup)

Session Data Format

Each session entry in the array contains metadata from the initialize request:


Sources: includes/Transport/Infrastructure/RequestRouter.php160 tests/Unit/Transport/Infrastructure/RequestRouterTest.php67

User Association

Sessions are always associated with the currently authenticated WordPress user:

ContextUser Retrieval
Session Creationget_current_user_id() must return valid user ID > 0
Session ValidationSessions read from current user's meta
Session TerminationSession removed from current user's meta
Unauthenticated RequestReturns UNAUTHORIZED error before session operations

This ensures sessions are automatically isolated per-user, and users cannot access or manipulate other users' sessions.

Sources: tests/Integration/HttpTransportTest.php272-321 tests/Unit/Transport/Infrastructure/RequestRouterTest.php293-332


Error Handling

Session management integrates with the standard MCP error handling system, using McpErrorFactory to generate consistent JSON-RPC error responses.

Error Code Mapping


Error Response Format

All session errors follow the JSON-RPC 2.0 error format:


HTTP Status Code Mapping

The McpErrorFactory::get_http_status_for_error() method maps error codes to HTTP status codes:

Error CodeError TypeHTTP StatusWhen Used
-401UNAUTHORIZED401User not authenticated during session creation
-32600INVALID_REQUEST400Missing required Mcp-Session-Id header
-32602INVALID_PARAMS200Invalid or expired session ID

The distinction between HTTP 400 and 200 for different validation failures is intentional:

  • Missing header (structural issue) → HTTP 400
  • Invalid session ID (semantic issue) → HTTP 200 with JSON-RPC error

Sources: includes/Transport/Infrastructure/HttpRequestHandler.php125-128 includes/Transport/Infrastructure/HttpRequestHandler.php229 tests/Integration/HttpTransportTest.php224-229 tests/Unit/Transport/Infrastructure/RequestRouterTest.php360-362


Security Considerations

Authentication Requirements

All session operations require the user to be authenticated:


This check happens before session operations are attempted. Unauthenticated requests fail at the transport permission level (see Transport Permissions).

Sources: tests/Integration/HttpTransportTest.php272-321 tests/Integration/HttpTransportTest.php660-662

Session Isolation

Sessions are automatically isolated per WordPress user through user meta storage:

Security PropertyImplementation
User IsolationSessions stored in user_meta with $user_id key
No Cross-User Accessget_user_meta() only returns current user's sessions
Automatic CleanupSession data deleted when user is deleted

Session ID Generation

Session IDs should be:

  • Cryptographically random (e.g., using wp_generate_password() or random_bytes())
  • Sufficient entropy (at least 128 bits / 32 hex characters)
  • Unique per user (collision detection should be implemented)

The exact implementation is in HttpSessionValidator::create_session(), which is not shown in the provided files.

Best Practices

PracticeRationale
Validate session on every requestPrevents use of expired or revoked sessions
Store minimal session dataReduces attack surface and storage overhead
Implement session expirationAutomatic cleanup of stale sessions (TTL-based)
Log session eventsAudit trail for security monitoring

Session Lifecycle Management

To prevent session leaks and ensure proper cleanup:


Production implementations should include:

  • Automatic expiration based on created_at timestamp
  • Maximum session limits per user
  • Regular cleanup of expired sessions (e.g., via cron job)

Sources: tests/Unit/Transport/Infrastructure/RequestRouterTest.php64-72 tests/Integration/HttpTransportTest.php47-74


Integration with Request Pipeline

Session management is tightly integrated with the request processing pipeline to ensure consistent behavior across all HTTP requests.

Pipeline Integration Points


Request Processing Order

  1. Transport Layer (HttpTransport)

    • Receives WP_REST_Request
    • Creates HttpRequestContext (extracts Mcp-Session-Id header)
    • Delegates to HttpRequestHandler
  2. Handler Layer (HttpRequestHandler)

    • Routes by HTTP method (POST/GET/DELETE)
    • For POST: validates session before routing (except initialize)
    • For DELETE: calls terminate_session()
  3. Router Layer (RequestRouter)

    • Routes by MCP method (tools/call, resources/read, etc.)
    • For initialize: creates session after successful initialization
    • Adds _session_id to result for header injection
  4. Response Building (HttpRequestHandler)

    • Extracts _session_id from result
    • Adds Mcp-Session-Id header via WordPress filter
    • Returns formatted JSON-RPC response

Sources: includes/Transport/Infrastructure/HttpRequestHandler.php46-67 includes/Transport/Infrastructure/RequestRouter.php51-130 tests/Integration/HttpTransportTest.php77-118

Observability Integration

Session events are tracked through the observability system via RequestRouter:

RequestRouter::route_request()
 └─> start_time = microtime(true)
 └─> common_tags = ['session_id' => $http_context->session_id]
 └─> // ... execute request ...
 └─> metadata['new_session_id'] = result['_session_id'] (if present)
 └─> observability_handler->record_event('mcp.request', tags, duration)

Session-related tags in events:

  • session_id - Current session ID (or null)
  • new_session_id - Newly created session ID (for initialize)
  • method - MCP method name (e.g., initialize, tools/call)
  • status - Request status (success or error)

Sources: includes/Transport/Infrastructure/RequestRouter.php55-110 tests/Unit/Transport/Infrastructure/RequestRouterTest.php260-291