<?php
* This file is part of the official PHP MCP SDK.
*
* A collaboration between Symfony and the PHP Foundation.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Mcp\Tests\Integration;
use Mcp\Client\Handler\Notification\LoggingNotificationHandler;
use Mcp\Schema\Content\TextContent;
use Mcp\Schema\Enum\LoggingLevel;
use Mcp\Schema\Enum\ProtocolVersion;
use Mcp\Schema\Notification\LoggingMessageNotification;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\TestDox;
* Notifications a server emits while a tool is still running.
*
* These share the pipe with the response but carry no id, so what they exercise
* is delivery ordering rather than correlation.
*
* @see Fixture/notification.php for the server under test
*/
final class NotificationTest extends IntegrationTestCase
{
#[TestDox('progress notifications reach the callback passed to callTool()')]
#[DataProvider('provideEras')]
public function testProgressReachesTheCaller(ProtocolVersion $era): void
{
$client = $this->connect('notification', $this->clientBuilder()->setProtocolVersion($era));
$this->assertSame($era, $client->getProtocolVersion());
$updates = [];
$result = $client->callTool('work', [], static function (float $progress, ?float $total, ?string $message) use (&$updates): void {
$updates[] = [$progress, $total, $message];
});
$this->assertSame([[0.5, 1.0, 'halfway'], [1.0, 1.0, 'done']], $updates);
$this->assertInstanceOf(TextContent::class, $result->content[0]);
$this->assertSame('finished', $result->content[0]->text);
}
#[TestDox('progress is skipped when the caller asked for none')]
#[DataProvider('provideEras')]
public function testProgressIsSkippedWithoutAToken(ProtocolVersion $era): void
{
$client = $this->connect('notification', $this->clientBuilder()->setProtocolVersion($era));
$result = $client->callTool('work');
$this->assertInstanceOf(TextContent::class, $result->content[0]);
$this->assertSame('finished', $result->content[0]->text);
}
#[TestDox('log notifications reach a registered logging handler')]
#[DataProvider('provideEras')]
public function testLoggingReachesTheClient(ProtocolVersion $era): void
{
$logged = [];
$client = $this->connect(
'notification',
$this->clientBuilder()->setProtocolVersion($era)->addNotificationHandler(new LoggingNotificationHandler(
static function (LoggingMessageNotification $notification) use (&$logged): void {
$logged[] = [$notification->level, $notification->data];
},
)),
);
$this->assertSame($era, $client->getProtocolVersion());
$client->setLoggingLevel(LoggingLevel::Info);
$client->callTool('work');
$this->assertSame([[LoggingLevel::Info, 'starting work']], $logged);
}
}