Skip to content

Commit 757b959

Browse files
[Server] Feat: Add comprehensive HTTP inspector tests with improved framework (#125)
* feat: add comprehensive HTTP inspector tests and improve test framework * chore: remove debug flag from server configuration
1 parent ca18caf commit 757b959

File tree

100 files changed

+1877
-189
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

100 files changed

+1877
-189
lines changed
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the official PHP MCP SDK.
5+
*
6+
* A collaboration between Symfony and the PHP Foundation.
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Mcp\Tests\Inspector\Http;
13+
14+
final class HttpClientCommunicationTest extends HttpInspectorSnapshotTestCase
15+
{
16+
protected function setUp(): void
17+
{
18+
$this->markTestSkipped('Test skipped: SDK cannot handle logging/setLevel requests required by logging capability, and built-in PHP server does not support sampling.');
19+
}
20+
21+
public static function provideMethods(): array
22+
{
23+
return [
24+
...parent::provideMethods(),
25+
'Prepare Project Briefing (Simple)' => [
26+
'method' => 'tools/call',
27+
'options' => [
28+
'toolName' => 'prepare_project_briefing',
29+
'toolArgs' => [
30+
'projectName' => 'Website Redesign',
31+
'milestones' => ['Discovery', 'Design', 'Development', 'Testing'],
32+
],
33+
],
34+
'testName' => 'prepare_project_briefing_simple',
35+
],
36+
'Prepare Project Briefing (Complex)' => [
37+
'method' => 'tools/call',
38+
'options' => [
39+
'toolName' => 'prepare_project_briefing',
40+
'toolArgs' => [
41+
'projectName' => 'Mobile App Launch',
42+
'milestones' => ['Market Research', 'UI/UX Design', 'MVP Development', 'Beta Testing', 'Marketing Campaign', 'Public Launch'],
43+
],
44+
],
45+
'testName' => 'prepare_project_briefing_complex',
46+
],
47+
'Run Service Maintenance' => [
48+
'method' => 'tools/call',
49+
'options' => [
50+
'toolName' => 'run_service_maintenance',
51+
'toolArgs' => [
52+
'serviceName' => 'Payment Gateway API',
53+
],
54+
],
55+
'testName' => 'run_service_maintenance',
56+
],
57+
];
58+
}
59+
60+
protected function getServerScript(): string
61+
{
62+
return \dirname(__DIR__, 3).'/examples/http-client-communication/server.php';
63+
}
64+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the official PHP MCP SDK.
5+
*
6+
* A collaboration between Symfony and the PHP Foundation.
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Mcp\Tests\Inspector\Http;
13+
14+
final class HttpCombinedRegistrationTest extends HttpInspectorSnapshotTestCase
15+
{
16+
public static function provideMethods(): array
17+
{
18+
return [
19+
...parent::provideMethods(),
20+
'Manual Greeter Tool' => [
21+
'method' => 'tools/call',
22+
'options' => [
23+
'toolName' => 'manualGreeter',
24+
'toolArgs' => ['user' => 'HTTP Test User'],
25+
],
26+
'testName' => 'manual_greeter',
27+
],
28+
'Discovered Status Check Tool' => [
29+
'method' => 'tools/call',
30+
'options' => [
31+
'toolName' => 'discovered_status_check',
32+
'toolArgs' => [],
33+
],
34+
'testName' => 'discovered_status_check',
35+
],
36+
'Read Priority Config (Manual Override)' => [
37+
'method' => 'resources/read',
38+
'options' => [
39+
'uri' => 'config://priority',
40+
],
41+
'testName' => 'config_priority',
42+
],
43+
];
44+
}
45+
46+
protected function getServerScript(): string
47+
{
48+
return \dirname(__DIR__, 3).'/examples/http-combined-registration/server.php';
49+
}
50+
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the official PHP MCP SDK.
5+
*
6+
* A collaboration between Symfony and the PHP Foundation.
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Mcp\Tests\Inspector\Http;
13+
14+
final class HttpComplexToolSchemaTest extends HttpInspectorSnapshotTestCase
15+
{
16+
public static function provideMethods(): array
17+
{
18+
return [
19+
...parent::provideMethods(),
20+
'Schedule Event (Meeting with Time)' => [
21+
'method' => 'tools/call',
22+
'options' => [
23+
'toolName' => 'schedule_event',
24+
'toolArgs' => [
25+
'title' => 'Team Standup',
26+
'date' => '2024-12-01',
27+
'type' => 'meeting',
28+
'time' => '09:00',
29+
'priority' => 'normal',
30+
'attendees' => ['alice@example.com', 'bob@example.com'],
31+
'sendInvites' => true,
32+
],
33+
],
34+
'testName' => 'schedule_event_meeting_with_time',
35+
],
36+
'Schedule Event (All Day Reminder)' => [
37+
'method' => 'tools/call',
38+
'options' => [
39+
'toolName' => 'schedule_event',
40+
'toolArgs' => [
41+
'title' => 'Project Deadline',
42+
'date' => '2024-12-15',
43+
'type' => 'reminder',
44+
'priority' => 'high',
45+
],
46+
],
47+
'testName' => 'schedule_event_all_day_reminder',
48+
],
49+
'Schedule Event (Call with High Priority)' => [
50+
'method' => 'tools/call',
51+
'options' => [
52+
'toolName' => 'schedule_event',
53+
'toolArgs' => [
54+
'title' => 'Client Call',
55+
'date' => '2024-12-02',
56+
'type' => 'call',
57+
'time' => '14:30',
58+
'priority' => 'high',
59+
'attendees' => ['client@example.com'],
60+
'sendInvites' => false,
61+
],
62+
],
63+
'testName' => 'schedule_event_high_priority',
64+
],
65+
'Schedule Event (Other Event with Low Priority)' => [
66+
'method' => 'tools/call',
67+
'options' => [
68+
'toolName' => 'schedule_event',
69+
'toolArgs' => [
70+
'title' => 'Office Party',
71+
'date' => '2024-12-20',
72+
'type' => 'other',
73+
'time' => '18:00',
74+
'priority' => 'low',
75+
'attendees' => ['team@company.com'],
76+
],
77+
],
78+
'testName' => 'schedule_event_low_priority',
79+
],
80+
];
81+
}
82+
83+
protected function getServerScript(): string
84+
{
85+
return \dirname(__DIR__, 3).'/examples/http-complex-tool-schema/server.php';
86+
}
87+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the official PHP MCP SDK.
5+
*
6+
* A collaboration between Symfony and the PHP Foundation.
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Mcp\Tests\Inspector\Http;
13+
14+
final class HttpDiscoveryUserProfileTest extends HttpInspectorSnapshotTestCase
15+
{
16+
public static function provideMethods(): array
17+
{
18+
return [
19+
...parent::provideMethods(),
20+
'Send Welcome Tool' => [
21+
'method' => 'tools/call',
22+
'options' => [
23+
'toolName' => 'send_welcome',
24+
'toolArgs' => ['userId' => '101', 'customMessage' => 'Welcome to our platform!'],
25+
],
26+
'testName' => 'send_welcome',
27+
],
28+
'Test Tool Without Params' => [
29+
'method' => 'tools/call',
30+
'options' => [
31+
'toolName' => 'test_tool_without_params',
32+
'toolArgs' => [],
33+
],
34+
'testName' => 'test_tool_without_params',
35+
],
36+
'Read User Profile 101' => [
37+
'method' => 'resources/read',
38+
'options' => [
39+
'uri' => 'user://101/profile',
40+
],
41+
'testName' => 'read_user_profile_101',
42+
],
43+
'Read User Profile 102' => [
44+
'method' => 'resources/read',
45+
'options' => [
46+
'uri' => 'user://102/profile',
47+
],
48+
'testName' => 'read_user_profile_102',
49+
],
50+
'Read User ID List' => [
51+
'method' => 'resources/read',
52+
'options' => [
53+
'uri' => 'user://list/ids',
54+
],
55+
'testName' => 'read_user_id_list',
56+
],
57+
'Generate Bio Prompt (Formal)' => [
58+
'method' => 'prompts/get',
59+
'options' => [
60+
'promptName' => 'generate_bio_prompt',
61+
'promptArgs' => ['userId' => '101', 'tone' => 'formal'],
62+
],
63+
'testName' => 'generate_bio_prompt',
64+
],
65+
];
66+
}
67+
68+
protected function getServerScript(): string
69+
{
70+
return \dirname(__DIR__, 3).'/examples/http-discovery-userprofile/server.php';
71+
}
72+
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the official PHP MCP SDK.
5+
*
6+
* A collaboration between Symfony and the PHP Foundation.
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Mcp\Tests\Inspector\Http;
13+
14+
use Mcp\Tests\Inspector\InspectorSnapshotTestCase;
15+
use Symfony\Component\Process\Process;
16+
17+
abstract class HttpInspectorSnapshotTestCase extends InspectorSnapshotTestCase
18+
{
19+
private Process $serverProcess;
20+
private int $serverPort;
21+
22+
protected function setUp(): void
23+
{
24+
parent::setUp();
25+
$this->startServer();
26+
}
27+
28+
protected function tearDown(): void
29+
{
30+
$this->stopServer();
31+
parent::tearDown();
32+
}
33+
34+
abstract protected function getServerScript(): string;
35+
36+
protected function getServerConnectionArgs(): array
37+
{
38+
return [\sprintf('http://127.0.0.1:%d', $this->serverPort)];
39+
}
40+
41+
protected function getTransport(): string
42+
{
43+
return 'http';
44+
}
45+
46+
private function startServer(): void
47+
{
48+
$this->serverPort = 8000 + (getmypid() % 1000);
49+
50+
$this->serverProcess = new Process([
51+
'php',
52+
'-S',
53+
\sprintf('127.0.0.1:%d', $this->serverPort),
54+
$this->getServerScript(),
55+
]);
56+
57+
$this->serverProcess->start();
58+
59+
$timeout = 5; // seconds
60+
$startTime = time();
61+
62+
while (time() - $startTime < $timeout) {
63+
if ($this->serverProcess->isRunning() && $this->isServerReady()) {
64+
return;
65+
}
66+
usleep(100000); // 100ms
67+
}
68+
69+
$this->fail(\sprintf('Server failed to start on port %d within %d seconds', $this->serverPort, $timeout));
70+
}
71+
72+
private function stopServer(): void
73+
{
74+
if (isset($this->serverProcess)) {
75+
$this->serverProcess->stop(1, \SIGTERM);
76+
}
77+
}
78+
79+
private function isServerReady(): bool
80+
{
81+
$context = stream_context_create([
82+
'http' => [
83+
'timeout' => 1,
84+
'method' => 'GET',
85+
],
86+
]);
87+
88+
// Try a simple health check - this will likely fail with MCP but should respond
89+
$response = @file_get_contents(\sprintf('http://127.0.0.1:%d', $this->serverPort), false, $context);
90+
91+
// We don't care about the response content, just that the server is accepting connections
92+
return false !== $response || false === str_contains(error_get_last()['message'] ?? '', 'Connection refused');
93+
}
94+
95+
protected function getSnapshotFilePath(string $method, ?string $testName = null): string
96+
{
97+
$className = substr(static::class, strrpos(static::class, '\\') + 1);
98+
$suffix = $testName ? '-'.preg_replace('/[^a-zA-Z0-9_]/', '_', $testName) : '';
99+
100+
return __DIR__.'/snapshots/'.$className.'-'.str_replace('/', '_', $method).$suffix.'.json';
101+
}
102+
}

0 commit comments

Comments
 (0)