Skip to content

Commit 05e4742

Browse files
committed
feat(http): enhance HTTP transport with new protocol support, session management, and improved error handling
1 parent 728f5a7 commit 05e4742

File tree

12 files changed

+1039
-432
lines changed

12 files changed

+1039
-432
lines changed

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@
2323
"squizlabs/php_codesniffer": "^3.6",
2424
"friendsofphp/php-cs-fixer": "^3.0",
2525
"mockery/mockery": "^1.0",
26-
"phpstan/phpstan": "^1.0"
26+
"phpstan/phpstan": "^1.0",
27+
"phpstan/phpstan-deprecation-rules": "*"
2728
},
2829
"suggest": {
2930
"hyperf/config": "^2.2 || ^3.0",

examples/http-server-test.php

Lines changed: 99 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,28 @@
2828
use Psr\Log\AbstractLogger;
2929
use 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
3254
date_default_timezone_set('Asia/Shanghai');
3355

@@ -46,20 +68,78 @@
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+
49101
if ($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());
@@ -69,18 +149,24 @@
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);
78158
http_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
79164
foreach ($response->getHeaders() as $name => $values) {
80165
foreach ($values as $value) {
81166
header("{$name}: {$value}");
82167
}
83168
}
169+
84170
echo $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

Comments
 (0)