Skip to content

Commit 095ea2a

Browse files
authored
Address issue with pagination limit builder class class (#83)
1 parent 3ec4cf6 commit 095ea2a

File tree

5 files changed

+58
-45
lines changed

5 files changed

+58
-45
lines changed

phpstan-baseline.neon

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -78,30 +78,12 @@ parameters:
7878
count: 1
7979
path: src/Server/ServerBuilder.php
8080

81-
-
82-
message: '#^Property Mcp\\Server\\ServerBuilder\:\:\$discoveryExcludeDirs type has no value type specified in iterable type array\.$#'
83-
identifier: missingType.iterableValue
84-
count: 1
85-
path: src/Server/ServerBuilder.php
86-
8781
-
8882
message: '#^Property Mcp\\Server\\ServerBuilder\:\:\$instructions is never read, only written\.$#'
8983
identifier: property.onlyWritten
9084
count: 1
9185
path: src/Server/ServerBuilder.php
9286

93-
-
94-
message: '#^Property Mcp\\Server\\ServerBuilder\:\:\$paginationLimit \(int\|null\) is never assigned null so it can be removed from the property type\.$#'
95-
identifier: property.unusedType
96-
count: 1
97-
path: src/Server/ServerBuilder.php
98-
99-
-
100-
message: '#^Property Mcp\\Server\\ServerBuilder\:\:\$paginationLimit is never read, only written\.$#'
101-
identifier: property.onlyWritten
102-
count: 1
103-
path: src/Server/ServerBuilder.php
104-
10587
-
10688
message: '#^Property Mcp\\Server\\ServerBuilder\:\:\$prompts type has no value type specified in iterable type array\.$#'
10789
identifier: missingType.iterableValue

src/JsonRpc/Handler.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ public static function make(
7373
SessionStoreInterface $sessionStore,
7474
SessionFactoryInterface $sessionFactory,
7575
LoggerInterface $logger = new NullLogger(),
76+
int $paginationLimit = 50,
7677
): self {
7778
return new self(
7879
messageFactory: MessageFactory::make(),
@@ -82,12 +83,12 @@ public static function make(
8283
new NotificationHandler\InitializedHandler(),
8384
new RequestHandler\InitializeHandler($registry->getCapabilities(), $implementation),
8485
new RequestHandler\PingHandler(),
85-
new RequestHandler\ListPromptsHandler($referenceProvider),
86+
new RequestHandler\ListPromptsHandler($referenceProvider, $paginationLimit),
8687
new RequestHandler\GetPromptHandler($promptGetter),
87-
new RequestHandler\ListResourcesHandler($referenceProvider),
88+
new RequestHandler\ListResourcesHandler($referenceProvider, $paginationLimit),
8889
new RequestHandler\ReadResourceHandler($resourceReader),
8990
new RequestHandler\CallToolHandler($toolCaller, $logger),
90-
new RequestHandler\ListToolsHandler($referenceProvider),
91+
new RequestHandler\ListToolsHandler($referenceProvider, $paginationLimit),
9192
],
9293
logger: $logger,
9394
);

src/Server/RequestHandler/Reference/Page.php

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@
1212
namespace Mcp\Server\RequestHandler\Reference;
1313

1414
/**
15-
* @implements \ArrayAccess<int|string, mixed>
15+
* @extends \ArrayObject<int|string, mixed>
1616
*/
17-
final class Page implements \Countable, \ArrayAccess
17+
final class Page extends \ArrayObject
1818
{
1919
/**
2020
* @param array<int|string, mixed> $references Items can be Tool, Prompt, ResourceTemplate, or Resource
@@ -23,30 +23,11 @@ public function __construct(
2323
public readonly array $references,
2424
public readonly ?string $nextCursor,
2525
) {
26+
parent::__construct($references, \ArrayObject::ARRAY_AS_PROPS);
2627
}
2728

2829
public function count(): int
2930
{
3031
return \count($this->references);
3132
}
32-
33-
public function offsetExists(mixed $offset): bool
34-
{
35-
return isset($this->references[$offset]);
36-
}
37-
38-
public function offsetGet(mixed $offset): mixed
39-
{
40-
return $this->references[$offset] ?? null;
41-
}
42-
43-
public function offsetSet(mixed $offset, mixed $value): void
44-
{
45-
return;
46-
}
47-
48-
public function offsetUnset(mixed $offset): void
49-
{
50-
return;
51-
}
5233
}

src/Server/ServerBuilder.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ final class ServerBuilder
7676

7777
private int $sessionTtl = 3600;
7878

79-
private ?int $paginationLimit = 50;
79+
private int $paginationLimit = 50;
8080

8181
private ?string $instructions = null;
8282

@@ -119,6 +119,9 @@ final class ServerBuilder
119119
* @var array|string[]
120120
*/
121121
private array $discoveryScanDirs = [];
122+
/**
123+
* @var array|string[]
124+
*/
122125
private array $discoveryExcludeDirs = [];
123126

124127
/**
@@ -337,6 +340,7 @@ public function build(): Server
337340
sessionStore: $sessionStore,
338341
sessionFactory: $sessionFactory,
339342
logger: $logger,
343+
paginationLimit: $this->paginationLimit,
340344
),
341345
logger: $logger,
342346
);

tests/Unit/Server/RequestHandler/ListToolsHandlerTest.php

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ public function testReturnsLastPageWithNullCursor(): void
137137
public function testReturnsAllToolsWhenCountIsLessThanPageSize(): void
138138
{
139139
// Arrange
140-
$this->addToolsToRegistry(2); // Less than page size (3)
140+
$this->addToolsToRegistry(2); // Less than page size 3
141141
$request = $this->createListToolsRequest();
142142

143143
// Act
@@ -239,6 +239,51 @@ public function testMaintainsStableCursorsAcrossCalls(): void
239239
$this->assertEquals($result1->tools, $result2->tools);
240240
}
241241

242+
#[TestDox('Uses custom page size when provided')]
243+
public function testUsesCustomPageSizeWhenProvided(): void
244+
{
245+
// Arrange
246+
$customPageSize = 5;
247+
$customHandler = new ListToolsHandler($this->registry, pageSize: $customPageSize);
248+
$this->addToolsToRegistry(10);
249+
$request = $this->createListToolsRequest();
250+
251+
// Act
252+
$response = $customHandler->handle($request, $this->session);
253+
254+
// Assert
255+
/** @var ListToolsResult $result */
256+
$result = $response->result;
257+
$this->assertInstanceOf(ListToolsResult::class, $result);
258+
$this->assertCount($customPageSize, $result->tools);
259+
$this->assertNotNull($result->nextCursor);
260+
}
261+
262+
#[TestDox('Different page sizes produce different pagination results')]
263+
public function testDifferentPageSizesProduceDifferentPaginationResults(): void
264+
{
265+
// Arrange
266+
$this->addToolsToRegistry(10);
267+
$smallPageHandler = new ListToolsHandler($this->registry, pageSize: 2);
268+
$largePageHandler = new ListToolsHandler($this->registry, pageSize: 7);
269+
$request = $this->createListToolsRequest();
270+
271+
// Act
272+
$smallPageResponse = $smallPageHandler->handle($request, $this->session);
273+
$largePageResponse = $largePageHandler->handle($request, $this->session);
274+
275+
// Assert
276+
/** @var ListToolsResult $smallResult */
277+
$smallResult = $smallPageResponse->result;
278+
/** @var ListToolsResult $largeResult */
279+
$largeResult = $largePageResponse->result;
280+
281+
$this->assertCount(2, $smallResult->tools);
282+
$this->assertCount(7, $largeResult->tools);
283+
$this->assertNotNull($smallResult->nextCursor);
284+
$this->assertNotNull($largeResult->nextCursor);
285+
}
286+
242287
private function addToolsToRegistry(int $count): void
243288
{
244289
for ($i = 0; $i < $count; ++$i) {

0 commit comments

Comments
 (0)