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\RequestParams;
15:
16: use Nexus\Assert\Assert;
17: use Nexus\Mcp\Core\Schema\Arrayable;
18: use Nexus\Mcp\Core\Schema\Elicitation\ElicitResult;
19: use Nexus\Mcp\Core\Schema\RequestMetaObject;
20: use Nexus\Mcp\Core\Schema\Result\InputResponse;
21:
22: /**
23: * Parameters for a `resources/read` request.
24: *
25: * @extends ResourceRequestParams<array{
26: * _meta: template-type<RequestMetaObject, Arrayable, 'T'>,
27: * uri: string,
28: * inputResponses?: array<string, array<string, mixed>>,
29: * requestState?: string,
30: * }>
31: *
32: * @see https://modelcontextprotocol.io/specification/draft/schema#readresourcerequestparams
33: */
34: final readonly class ReadResourceRequestParams extends ResourceRequestParams
35: {
36: /**
37: * @var null|array<string, InputResponse>
38: */
39: public ?array $inputResponses;
40:
41: /**
42: * @param null|array<string, InputResponse> $inputResponses
43: */
44: public function __construct(
45: string $uri,
46: RequestMetaObject $meta,
47: ?array $inputResponses = null,
48: public ?string $requestState = null,
49: ) {
50: $inputResponses = [] === $inputResponses ? null : $inputResponses;
51:
52: if (null !== $inputResponses) {
53: Assert::that($inputResponses)
54: ->isMap('"params.inputResponses" must be a string-keyed object.')
55: ->values()
56: ->isInstanceOf(InputResponse::class, 'each "params.inputResponses" entry must be an InputResponse, {type} given.')
57: ;
58: }
59:
60: $this->inputResponses = $inputResponses;
61:
62: parent::__construct(uri: $uri, meta: $meta);
63: }
64:
65: #[\Override]
66: public static function fromArray(array $data): static
67: {
68: Assert::that($data)->hasOffset('uri', '"params" is missing the required "uri" key.');
69: $uri = $data['uri'];
70: Assert::that($uri)->isString('"params.uri" must be a string, {type} given.');
71:
72: $inputResponses = null;
73:
74: if (\array_key_exists('inputResponses', $data)) {
75: Assert::that($data['inputResponses'])
76: ->isArray('"params.inputResponses" must be an object, {type} given.')
77: ->isMap('"params.inputResponses" must be a string-keyed object.')
78: ->values()
79: ->isArray('each "params.inputResponses" entry must be an object, {type} given.')
80: ->isMap('each "params.inputResponses" entry must be a string-keyed object.')
81: ;
82: $inputResponses = array_map(ElicitResult::fromArray(...), $data['inputResponses']);
83: }
84:
85: $requestState = null;
86:
87: if (\array_key_exists('requestState', $data)) {
88: Assert::that($data['requestState'])->isString('"params.requestState" must be a string, {type} given.');
89: $requestState = $data['requestState'];
90: }
91:
92: Assert::that($data)->hasOffset('_meta', '"params" is missing the required "_meta" key.');
93: Assert::that($data['_meta'])
94: ->isArray('"params._meta" must be an object, {type} given.')
95: ->isMap('"params._meta" must be a string-keyed object.')
96: ;
97: $meta = RequestMetaObject::fromArray($data['_meta']);
98:
99: return new self(uri: $uri, meta: $meta, inputResponses: $inputResponses, requestState: $requestState);
100: }
101:
102: #[\Override]
103: public function toArray(): array
104: {
105: $data = [
106: '_meta' => $this->meta->toArray(),
107: 'uri' => $this->uri,
108: ];
109:
110: if (null !== $this->inputResponses) {
111: $data['inputResponses'] = array_map(
112: static fn(InputResponse $response): array => $response->toArray(),
113: $this->inputResponses,
114: );
115: }
116:
117: if (null !== $this->requestState) {
118: $data['requestState'] = $this->requestState;
119: }
120:
121: return $data;
122: }
123: }
124: