1: <?php
2:
3: declare(strict_types=1);
4:
5: /**
6: * This file is part of the Nexus MCP SDK package.
7: *
8: * (c) 2026 John Paul E. Balandan, CPA <paulbalandan@gmail.com>
9: *
10: * For the full copyright and license information, please view
11: * the LICENSE file that was distributed with this source code.
12: */
13:
14: namespace Nexus\Mcp\Core\Schema\Result;
15:
16: use Nexus\Assert\Assert;
17: use Nexus\Mcp\Core\Schema\Arrayable;
18: use Nexus\Mcp\Core\Schema\Cursor;
19: use Nexus\Mcp\Core\Schema\Enum\CacheScope;
20: use Nexus\Mcp\Core\Schema\Enum\ResultType;
21: use Nexus\Mcp\Core\Schema\MetaObject;
22: use Nexus\Mcp\Core\Schema\Prompt\Prompt;
23: use Nexus\Mcp\Core\Validation\EnumValueValidator;
24:
25: /**
26: * The result returned by the server for a `prompts/list` request.
27: *
28: * @extends PaginatedResult<array{
29: * _meta?: template-type<MetaObject, Arrayable, 'T'>,
30: * resultType: non-empty-string,
31: * prompts: list<template-type<Prompt, Arrayable, 'T'>>,
32: * nextCursor?: non-empty-string,
33: * ttlMs: int,
34: * cacheScope: value-of<CacheScope>,
35: * }>
36: *
37: * @see https://modelcontextprotocol.io/specification/draft/schema#listpromptsresult
38: */
39: final readonly class ListPromptsResult extends PaginatedResult implements ServerResult
40: {
41: /**
42: * @var list<Prompt>
43: */
44: public array $prompts;
45:
46: /**
47: * @param list<Prompt> $prompts
48: */
49: public function __construct(
50: array $prompts,
51: int $ttlMs,
52: CacheScope $cacheScope,
53: ?Cursor $nextCursor = null,
54: MetaObject $meta = new MetaObject(),
55: ) {
56: Assert::that($prompts)
57: ->isList('"result.prompts" must be a list, non-list array given.')
58: ->values()->isInstanceOf(Prompt::class)
59: ;
60:
61: $this->prompts = $prompts;
62:
63: parent::__construct(ttlMs: $ttlMs, cacheScope: $cacheScope, nextCursor: $nextCursor, meta: $meta);
64: }
65:
66: #[\Override]
67: public static function fromArray(array $data): static
68: {
69: Assert::that($data)->hasOffset('prompts', '"result" is missing the required "prompts" key.');
70: Assert::that($data['prompts'])
71: ->isList('"result.prompts" must be a list, {type} given.')
72: ->values()
73: ->isArray('each "result.prompt" must be an object, {type} given.')
74: ->isMap('each "result.prompt" must be a string-keyed object.')
75: ;
76: $prompts = array_map(Prompt::fromArray(...), $data['prompts']);
77:
78: Assert::that($data)->hasOffset('ttlMs', '"result" is missing the required "ttlMs" key.');
79: $ttlMs = $data['ttlMs'];
80: Assert::that($ttlMs)->isInt('"result.ttlMs" must be an integer, {type} given.');
81:
82: Assert::that($data)->hasOffset('cacheScope', '"result" is missing the required "cacheScope" key.');
83: $cacheScope = EnumValueValidator::parse(CacheScope::class, $data['cacheScope'], '"result.cacheScope"');
84:
85: $nextCursor = null;
86:
87: if (\array_key_exists('nextCursor', $data)) {
88: $raw = $data['nextCursor'];
89: Assert::that($raw)->isString('"result.nextCursor" must be a string, {type} given.');
90: $nextCursor = new Cursor(cursor: $raw);
91: }
92:
93: $meta = new MetaObject();
94:
95: if (\array_key_exists('_meta', $data)) {
96: Assert::that($data['_meta'])
97: ->isArray('"result._meta" must be an object, {type} given.')
98: ->isMap('"result._meta" must be a string-keyed object.')
99: ;
100: $meta = MetaObject::fromArray($data['_meta']);
101: }
102:
103: return new self(
104: prompts: $prompts,
105: ttlMs: $ttlMs,
106: cacheScope: $cacheScope,
107: nextCursor: $nextCursor,
108: meta: $meta,
109: );
110: }
111:
112: #[\Override]
113: public function toArray(): array
114: {
115: $data = [];
116: $meta = $this->meta->toArray();
117:
118: if ([] !== $meta) {
119: $data['_meta'] = $meta;
120: }
121:
122: $data['resultType'] = self::getResultType();
123: $data['prompts'] = array_map(static fn(Prompt $prompt): array => $prompt->toArray(), $this->prompts);
124:
125: if (null !== $this->nextCursor) {
126: $data['nextCursor'] = $this->nextCursor->cursor;
127: }
128:
129: $data['ttlMs'] = $this->ttlMs;
130: $data['cacheScope'] = $this->cacheScope->value;
131:
132: return $data;
133: }
134:
135: #[\Override]
136: protected function getResultType(): string
137: {
138: return ResultType::Complete->value;
139: }
140: }
141: