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\JsonRpc\ResourceContentsDispatcher;
18: use Nexus\Mcp\Core\Schema\MetaObject;
19: use Nexus\Mcp\Core\Schema\Resource\BlobResourceContents;
20: use Nexus\Mcp\Core\Schema\Resource\ResourceContents;
21: use Nexus\Mcp\Core\Schema\Resource\TextResourceContents;
22: use Nexus\Mcp\Core\Schema\Result;
23:
24: /**
25: * The server's response to a resources/read request from the client.
26: *
27: * @see https://modelcontextprotocol.io/specification/2025-11-25/schema#readresourceresult
28: */
29: final readonly class ReadResourceResult extends Result implements ServerResult
30: {
31: /**
32: * @var list<BlobResourceContents|TextResourceContents>
33: */
34: public array $contents;
35:
36: /**
37: * @param list<BlobResourceContents|TextResourceContents> $contents
38: */
39: public function __construct(array $contents, MetaObject $meta = new MetaObject())
40: {
41: Assert::that($contents)
42: ->isList('"result.contents" must be a list, non-list array given.')
43: ->values()->isInstanceOf(ResourceContents::class)
44: ;
45:
46: $this->contents = $contents;
47:
48: parent::__construct($meta);
49: }
50:
51: /**
52: * @param array<string, mixed> $data
53: */
54: #[\Override]
55: public static function fromArray(array $data): static
56: {
57: Assert::that($data)->hasOffset('contents', '"result" missing the required "contents" key.');
58: Assert::that($data['contents'])
59: ->isList('"result.contents" must be a list, {type} given.')
60: ->values()
61: ->isArray('each "result.contents" must be an object, {type} given.')
62: ->isMap('each "result.contents" must be a string-keyed object.')
63: ;
64: $contents = array_map(
65: static fn(array $entry): BlobResourceContents|TextResourceContents => ResourceContentsDispatcher::fromArray($entry, 'ReadResourceResult contents'),
66: $data['contents'],
67: );
68:
69: $meta = new MetaObject();
70:
71: if (\array_key_exists('_meta', $data)) {
72: Assert::that($data['_meta'])
73: ->isArray('"result._meta" must be an object, {type} given.')
74: ->isMap('"result._meta" must be a string-keyed object.')
75: ;
76: $meta = MetaObject::fromArray($data['_meta']);
77: }
78:
79: return new self($contents, $meta);
80: }
81:
82: #[\Override]
83: public function toArray(): array
84: {
85: return [
86: ...parent::toArray(),
87: 'contents' => array_map(static fn(ResourceContents $entry): array => $entry->toArray(), $this->contents),
88: ];
89: }
90:
91: #[\Override]
92: public function jsonSerialize(): array
93: {
94: return $this->toArray();
95: }
96: }
97: