2828use Psr \Log \AbstractLogger ;
2929use Psr \Log \LoggerInterface ;
3030
31+ /**
32+ * Simple session ID generator for testing.
33+ */
34+ function generateSessionId (): string
35+ {
36+ return 'mcp_session_ ' . uniqid () . '_ ' . bin2hex (random_bytes (8 ));
37+ }
38+
39+ /**
40+ * Extract session ID from request headers.
41+ */
42+ function getSessionIdFromHeaders (array $ headers ): ?string
43+ {
44+ // Check for Mcp-Session-Id header (case-insensitive)
45+ foreach ($ headers as $ name => $ value ) {
46+ if (strtolower ($ name ) === 'mcp-session-id ' ) {
47+ return is_array ($ value ) ? $ value [0 ] : $ value ;
48+ }
49+ }
50+ return null ;
51+ }
52+
3153// Set timezone to Shanghai
3254date_default_timezone_set ('Asia/Shanghai ' );
3355
4668 exit ;
4769}
4870
71+ // Handle DELETE requests for session termination
72+ if ($ method === 'DELETE ' ) {
73+ $ sessionId = getSessionIdFromHeaders ($ headers );
74+ if (! $ sessionId ) {
75+ http_response_code (400 );
76+ header ('Content-Type: application/json ' );
77+ echo json_encode ([
78+ 'error ' => [
79+ 'code ' => -32002 ,
80+ 'message ' => 'Missing Mcp-Session-Id header for session termination. ' ,
81+ ],
82+ ]);
83+ exit ;
84+ }
85+
86+ // Log session termination
87+ error_log ("Session terminated: {$ sessionId }" );
88+
89+ // Return success response for session termination
90+ http_response_code (200 );
91+ header ('Content-Type: application/json ' );
92+ header ("Mcp-Session-Id: {$ sessionId }" );
93+ echo json_encode ([
94+ 'success ' => true ,
95+ 'message ' => 'Session terminated successfully ' ,
96+ 'session_id ' => $ sessionId ,
97+ ]);
98+ exit ;
99+ }
100+
49101if ($ method !== 'POST ' ) {
50102 http_response_code (405 );
51103 header ('Content-Type: application/json ' );
104+ header ('Allow: POST, DELETE ' );
52105 echo json_encode ([
53106 'jsonrpc ' => '2.0 ' ,
54107 'error ' => [
55108 'code ' => -32601 ,
56- 'message ' => 'Method not allowed - use POST for JSON-RPC ' ,
109+ 'message ' => 'Method not allowed - use POST for JSON-RPC or DELETE for session termination ' ,
57110 ],
58111 'id ' => null ,
59112 ]);
60113 exit ;
61114}
62115
116+ // Parse request body to determine if this is an initialize request
117+ $ requestData = json_decode ($ body , true );
118+ $ isInitialize = isset ($ requestData ['method ' ]) && $ requestData ['method ' ] === 'initialize ' ;
119+
120+ // Simple session handling for testing
121+ $ sessionId = null ;
122+ if ($ isInitialize ) {
123+ // For initialize request, generate new session ID
124+ $ sessionId = generateSessionId ();
125+ } else {
126+ // For other requests, just check if session header exists
127+ $ sessionId = getSessionIdFromHeaders ($ headers );
128+ if (! $ sessionId ) {
129+ http_response_code (401 );
130+ header ('Content-Type: application/json ' );
131+ echo json_encode ([
132+ 'jsonrpc ' => '2.0 ' ,
133+ 'error ' => [
134+ 'code ' => -32002 ,
135+ 'message ' => 'Missing Mcp-Session-Id header. Please include session ID. ' ,
136+ ],
137+ 'id ' => $ requestData ['id ' ] ?? null ,
138+ ]);
139+ exit ;
140+ }
141+ }
142+
63143// Create MCP server instance for processing
64144$ container = createContainer ();
65145$ app = new Application ($ container , getConfig ());
69149$ mcpServer
70150 ->registerTool (createEchoTool ())
71151 ->registerTool (createCalculatorTool ())
72- ->registerTool (createStreamableInfoTool ())
152+ ->registerTool (createStreamableInfoTool ($ sessionId ))
73153 ->registerPrompt (createGreetingPrompt ())
74154 ->registerResource (createSystemInfoResource ())
75155 ->registerTemplate (createStreamableLogTemplate ());
76156
77157$ response = $ mcpServer ->http ($ request );
78158http_response_code ($ response ->getStatusCode ());
159+
160+ // Add Mcp-Session-Id header to response
161+ header ("Mcp-Session-Id: {$ sessionId }" );
162+
163+ // Add other headers from response
79164foreach ($ response ->getHeaders () as $ name => $ values ) {
80165 foreach ($ values as $ value ) {
81166 header ("{$ name }: {$ value }" );
82167 }
83168}
169+
84170echo $ response ->getBody ()->getContents ();
85171
86172/**
@@ -207,7 +293,7 @@ function createCalculatorTool(): RegisteredTool
207293 });
208294}
209295
210- function createStreamableInfoTool (): RegisteredTool
296+ function createStreamableInfoTool (string $ sessionId ): RegisteredTool
211297{
212298 $ tool = new Tool (
213299 'streamable_info ' ,
@@ -219,7 +305,7 @@ function createStreamableInfoTool(): RegisteredTool
219305 'Get Streamable HTTP server information and capabilities '
220306 );
221307
222- return new RegisteredTool ($ tool , function (array $ args ): array {
308+ return new RegisteredTool ($ tool , function (array $ args ) use ( $ sessionId ) : array {
223309 return [
224310 'transport ' => 'streamable-http ' ,
225311 'protocol_version ' => '2025-03-26 ' ,
@@ -228,16 +314,22 @@ function createStreamableInfoTool(): RegisteredTool
228314 'version ' => '1.0.0 ' ,
229315 'php_version ' => PHP_VERSION ,
230316 ],
317+ 'session_info ' => [
318+ 'current_session_id ' => $ sessionId ,
319+ 'session_created_at ' => date ('c ' ),
320+ 'note ' => 'This is a test server with simplified session handling ' ,
321+ ],
231322 'capabilities ' => [
232323 'direct_request_response ' => true ,
233324 'sse_notifications ' => true ,
234- 'session_optional ' => true ,
235- 'stateless_mode ' => true ,
325+ 'session_header_validation ' => true ,
326+ 'simplified_testing ' => true ,
236327 ],
237328 'features ' => [
238329 'no_complex_broadcasting ' => true ,
239- 'simplified_session_management ' => true ,
330+ 'header_based_session_check ' => true ,
240331 'direct_message_routing ' => true ,
332+ 'test_mode_enabled ' => true ,
241333 ],
242334 'runtime_info ' => [
243335 'start_time ' => date ('c ' ),
0 commit comments