Skip to content

Commit 1fc5e9c

Browse files
committed
Add support for pagination
1 parent 7641a8c commit 1fc5e9c

14 files changed

+245
-84
lines changed

src/mcp-sdk/src/Capability/Prompt/CollectionInterface.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,16 @@
1313

1414
namespace Symfony\AI\McpSdk\Capability\Prompt;
1515

16+
use Symfony\AI\McpSdk\Exception\InvalidCursorException;
17+
1618
interface CollectionInterface
1719
{
1820
/**
19-
* @return MetadataInterface[]
21+
* @param int $count the number of metadata items to return
22+
*
23+
* @return iterable<MetadataInterface>
24+
*
25+
* @throws InvalidCursorException if no item with $lastIdentifier was found
2026
*/
21-
public function getMetadata(): array;
27+
public function getMetadata(int $count, ?string $lastIdentifier = null): iterable;
2228
}

src/mcp-sdk/src/Capability/PromptChain.php

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use Symfony\AI\McpSdk\Capability\Prompt\PromptGet;
2020
use Symfony\AI\McpSdk\Capability\Prompt\PromptGetResult;
2121
use Symfony\AI\McpSdk\Capability\Prompt\PromptGetterInterface;
22+
use Symfony\AI\McpSdk\Exception\InvalidCursorException;
2223
use Symfony\AI\McpSdk\Exception\PromptGetException;
2324
use Symfony\AI\McpSdk\Exception\PromptNotFoundException;
2425

@@ -35,9 +36,28 @@ public function __construct(
3536
) {
3637
}
3738

38-
public function getMetadata(): array
39+
public function getMetadata(int $count, ?string $lastIdentifier = null): iterable
3940
{
40-
return array_filter($this->items, fn ($item) => $item instanceof MetadataInterface);
41+
$found = null === $lastIdentifier;
42+
foreach ($this->items as $item) {
43+
if (!$item instanceof MetadataInterface) {
44+
continue;
45+
}
46+
47+
if (false === $found) {
48+
$found = $item->getName() === $lastIdentifier;
49+
continue;
50+
}
51+
52+
yield $item;
53+
if (--$count <= 0) {
54+
break;
55+
}
56+
}
57+
58+
if (!$found) {
59+
throw new InvalidCursorException($lastIdentifier);
60+
}
4161
}
4262

4363
public function get(PromptGet $input): PromptGetResult

src/mcp-sdk/src/Capability/Resource/CollectionInterface.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,16 @@
1313

1414
namespace Symfony\AI\McpSdk\Capability\Resource;
1515

16+
use Symfony\AI\McpSdk\Exception\InvalidCursorException;
17+
1618
interface CollectionInterface
1719
{
1820
/**
19-
* @return MetadataInterface[]
21+
* @param int $count the number of metadata items to return
22+
*
23+
* @return iterable<MetadataInterface>
24+
*
25+
* @throws InvalidCursorException if no item with $lastIdentifier was found
2026
*/
21-
public function getMetadata(): array;
27+
public function getMetadata(int $count, ?string $lastIdentifier = null): iterable;
2228
}

src/mcp-sdk/src/Capability/ResourceChain.php

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use Symfony\AI\McpSdk\Capability\Resource\ResourceRead;
2020
use Symfony\AI\McpSdk\Capability\Resource\ResourceReaderInterface;
2121
use Symfony\AI\McpSdk\Capability\Resource\ResourceReadResult;
22+
use Symfony\AI\McpSdk\Exception\InvalidCursorException;
2223
use Symfony\AI\McpSdk\Exception\ResourceNotFoundException;
2324
use Symfony\AI\McpSdk\Exception\ResourceReadException;
2425

@@ -35,9 +36,28 @@ public function __construct(
3536
) {
3637
}
3738

38-
public function getMetadata(): array
39+
public function getMetadata(int $count, ?string $lastIdentifier = null): iterable
3940
{
40-
return array_filter($this->items, fn ($item) => $item instanceof MetadataInterface);
41+
$found = null === $lastIdentifier;
42+
foreach ($this->items as $item) {
43+
if (!$item instanceof MetadataInterface) {
44+
continue;
45+
}
46+
47+
if (false === $found) {
48+
$found = $item->getUri() === $lastIdentifier;
49+
continue;
50+
}
51+
52+
yield $item;
53+
if (--$count <= 0) {
54+
break;
55+
}
56+
}
57+
58+
if (!$found) {
59+
throw new InvalidCursorException($lastIdentifier);
60+
}
4161
}
4262

4363
public function read(ResourceRead $input): ResourceReadResult

src/mcp-sdk/src/Capability/Tool/CollectionInterface.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,16 @@
1313

1414
namespace Symfony\AI\McpSdk\Capability\Tool;
1515

16+
use Symfony\AI\McpSdk\Exception\InvalidCursorException;
17+
1618
interface CollectionInterface
1719
{
1820
/**
19-
* @return MetadataInterface[]
21+
* @param int $count the number of metadata items to return
22+
*
23+
* @return iterable<MetadataInterface>
24+
*
25+
* @throws InvalidCursorException if no item with $lastIdentifier was found
2026
*/
21-
public function getMetadata(): array;
27+
public function getMetadata(int $count, ?string $lastIdentifier = null): iterable;
2228
}

src/mcp-sdk/src/Capability/ToolChain.php

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use Symfony\AI\McpSdk\Capability\Tool\ToolCall;
2020
use Symfony\AI\McpSdk\Capability\Tool\ToolCallResult;
2121
use Symfony\AI\McpSdk\Capability\Tool\ToolExecutorInterface;
22+
use Symfony\AI\McpSdk\Exception\InvalidCursorException;
2223
use Symfony\AI\McpSdk\Exception\ToolExecutionException;
2324
use Symfony\AI\McpSdk\Exception\ToolNotFoundException;
2425

@@ -35,9 +36,28 @@ public function __construct(
3536
) {
3637
}
3738

38-
public function getMetadata(): array
39+
public function getMetadata(int $count, ?string $lastIdentifier = null): iterable
3940
{
40-
return array_filter($this->items, fn ($item) => $item instanceof MetadataInterface);
41+
$found = null === $lastIdentifier;
42+
foreach ($this->items as $item) {
43+
if (!$item instanceof MetadataInterface) {
44+
continue;
45+
}
46+
47+
if (false === $found) {
48+
$found = $item->getName() === $lastIdentifier;
49+
continue;
50+
}
51+
52+
yield $item;
53+
if (--$count <= 0) {
54+
break;
55+
}
56+
}
57+
58+
if (!$found) {
59+
throw new InvalidCursorException($lastIdentifier);
60+
}
4161
}
4262

4363
public function call(ToolCall $input): ToolCallResult

src/mcp-sdk/src/Exception/ExceptionInterface.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,6 @@
1313

1414
namespace Symfony\AI\McpSdk\Exception;
1515

16-
interface ExceptionInterface
16+
interface ExceptionInterface extends \Throwable
1717
{
1818
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of the Symfony package.
7+
*
8+
* (c) Fabien Potencier <[email protected]>
9+
*
10+
* For the full copyright and license information, please view the LICENSE
11+
* file that was distributed with this source code.
12+
*/
13+
14+
namespace Symfony\AI\McpSdk\Exception;
15+
16+
class HandlerNotFoundException extends \InvalidArgumentException implements NotFoundExceptionInterface
17+
{
18+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of the Symfony package.
7+
*
8+
* (c) Fabien Potencier <[email protected]>
9+
*
10+
* For the full copyright and license information, please view the LICENSE
11+
* file that was distributed with this source code.
12+
*/
13+
14+
namespace Symfony\AI\McpSdk\Exception;
15+
16+
final class InvalidCursorException extends \InvalidArgumentException implements ExceptionInterface
17+
{
18+
public function __construct(
19+
public readonly string $cursor,
20+
) {
21+
parent::__construct(\sprintf('Invalid value for pagination parameter "cursor": "%s"', $cursor));
22+
}
23+
}

src/mcp-sdk/src/Exception/PromptNotFoundException.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,6 @@ final class PromptNotFoundException extends \RuntimeException implements NotFoun
2020
public function __construct(
2121
public readonly PromptGet $promptGet,
2222
) {
23-
parent::__construct(\sprintf('Resource not found for uri: "%s"', $promptGet->name));
23+
parent::__construct(\sprintf('Prompt not found for name: "%s"', $promptGet->name));
2424
}
2525
}

0 commit comments

Comments
 (0)