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\ContentBlock;
15:
16: use Nexus\Assert\Assert;
17: use Nexus\Mcp\Core\Schema\Annotations;
18: use Nexus\Mcp\Core\Schema\Arrayable;
19: use Nexus\Mcp\Core\Schema\ContentBlock;
20: use Nexus\Mcp\Core\Schema\MetaObject;
21: use Nexus\Mcp\Core\Schema\MetaObject\PayloadMetaObject;
22:
23: /**
24: * Text provided to or from an LLM.
25: *
26: * @implements Arrayable<array{
27: * text: string,
28: * type: 'text',
29: * annotations?: template-type<Annotations, Arrayable, 'T'>,
30: * _meta?: template-type<PayloadMetaObject, MetaObject, 'T'>,
31: * }>
32: *
33: * @see https://modelcontextprotocol.io/specification/2026-07-28/schema#textcontent
34: */
35: final readonly class TextContent implements Arrayable, ContentBlock
36: {
37: public const string TYPE = 'text';
38:
39: public function __construct(
40: public string $text,
41: public Annotations $annotations = new Annotations(),
42: public PayloadMetaObject $meta = new PayloadMetaObject(),
43: ) {
44: }
45:
46: #[\Override]
47: public static function fromArray(array $data): static
48: {
49: Assert::that($data)->hasOffset('type', 'text content is missing the required "type" key.');
50: $type = $data['type'];
51: Assert::that($type)->isIdentical(self::TYPE, 'text content "type" must be {other}, {value} given.');
52:
53: Assert::that($data)->hasOffset('text', 'text content is missing the required "text" key.');
54: $text = $data['text'];
55: Assert::that($text)->isString('text content "text" must be a string, {type} given.');
56:
57: $annotations = new Annotations();
58:
59: if (\array_key_exists('annotations', $data)) {
60: Assert::that($data['annotations'])
61: ->isArray('text content "annotations" must be an object, {type} given.')
62: ->isMap('text content "annotations" must be a string-keyed object.')
63: ;
64: $annotations = Annotations::fromArray($data['annotations']);
65: }
66:
67: $meta = new PayloadMetaObject();
68:
69: if (\array_key_exists('_meta', $data)) {
70: Assert::that($data['_meta'])
71: ->isArray('text content "_meta" must be an object, {type} given.')
72: ->isMap('text content "_meta" must be a string-keyed object.')
73: ;
74: $meta = PayloadMetaObject::fromArray($data['_meta']);
75: }
76:
77: return new self(text: $text, annotations: $annotations, meta: $meta);
78: }
79:
80: #[\Override]
81: public function toArray(): array
82: {
83: $data = [
84: 'text' => $this->text,
85: 'type' => self::TYPE,
86: ];
87:
88: $annotations = $this->annotations->toArray();
89:
90: if ([] !== $annotations) {
91: $data['annotations'] = $annotations;
92: }
93:
94: $meta = $this->meta->toArray();
95:
96: if ([] !== $meta) {
97: $data['_meta'] = $meta;
98: }
99:
100: return $data;
101: }
102:
103: #[\Override]
104: public function jsonSerialize(): array
105: {
106: return $this->toArray();
107: }
108: }
109: