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\Elicitation;
15:
16: use Nexus\Assert\Assert;
17:
18: /**
19: * Schema for single-selection enumeration without display titles for options.
20: *
21: * @implements SingleSelectEnumSchema<array{
22: * type: 'string',
23: * enum: list<non-empty-string>,
24: * title?: non-empty-string,
25: * description?: non-empty-string,
26: * default?: string,
27: * }>
28: *
29: * @see https://modelcontextprotocol.io/specification/2026-07-28/schema#untitledsingleselectenumschema
30: */
31: final readonly class UntitledSingleSelectEnumSchema implements SingleSelectEnumSchema
32: {
33: public const string TYPE = 'string';
34:
35: /**
36: * @param list<non-empty-string> $enum
37: * @param null|non-empty-string $title
38: * @param null|non-empty-string $description
39: */
40: public function __construct(
41: public array $enum,
42: public ?string $title = null,
43: public ?string $description = null,
44: public ?string $default = null,
45: ) {
46: Assert::that($enum)
47: ->isList('untitled single select enum schema "enum" must be a list, non-list array given.')
48: ->values()->isNonEmptyString('each untitled single select enum schema "enum" must be a non-empty string.')
49: ;
50: Assert::that($title)
51: ->nullOr()
52: ->isNonEmptyString('untitled single select enum schema "title" must be a non-empty string or null.')
53: ;
54: Assert::that($description)
55: ->nullOr()
56: ->isNonEmptyString('untitled single select enum schema "description" must be a non-empty string or null.')
57: ;
58: }
59:
60: #[\Override]
61: public static function fromArray(array $data): static
62: {
63: Assert::that($data)->hasOffset('type', 'untitled single select enum schema is missing the required "type" key.');
64: $type = $data['type'];
65: Assert::that($type)->isIdentical(self::TYPE, 'untitled single select enum schema "type" must be {other}, {value} given.');
66:
67: Assert::that($data)->hasOffset('enum', 'untitled single select enum schema is missing the required "enum" key.');
68: Assert::that($data['enum'])
69: ->isList('untitled single select enum schema "enum" must be a list, non-list array given.')
70: ->values()->isNonEmptyString('each untitled single select enum schema "enum" must be a non-empty string, {type} given.')
71: ;
72: $enum = $data['enum'];
73:
74: $title = $data['title'] ?? null;
75: Assert::that($title)->nullOr()->isNonEmptyString('untitled single select enum schema "title" must be a non-empty string or null, {type} given.');
76:
77: $description = $data['description'] ?? null;
78: Assert::that($description)->nullOr()->isNonEmptyString('untitled single select enum schema "description" must be a non-empty string or null, {type} given.');
79:
80: $default = $data['default'] ?? null;
81: Assert::that($default)->nullOr()->isString('untitled single select enum schema "default" must be a string or null, {type} given.');
82:
83: return new self(enum: $enum, title: $title, description: $description, default: $default);
84: }
85:
86: #[\Override]
87: public function toArray(): array
88: {
89: $data = [
90: 'type' => self::TYPE,
91: 'enum' => $this->enum,
92: ];
93:
94: if (null !== $this->title) {
95: $data['title'] = $this->title;
96: }
97:
98: if (null !== $this->description) {
99: $data['description'] = $this->description;
100: }
101:
102: if (null !== $this->default) {
103: $data['default'] = $this->default;
104: }
105:
106: return $data;
107: }
108:
109: #[\Override]
110: public function jsonSerialize(): array
111: {
112: return $this->toArray();
113: }
114: }
115: