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: use Nexus\Mcp\Core\Schema\Arrayable;
18:
19: /**
20: * Use TitledSingleSelectEnumSchema instead.
21: * This interface will be removed in a future version.
22: *
23: * @implements Arrayable<array{
24: * type: 'string',
25: * enum: list<non-empty-string>,
26: * title?: non-empty-string,
27: * description?: non-empty-string,
28: * enumNames?: list<non-empty-string>,
29: * default?: string,
30: * }>
31: *
32: * @see https://modelcontextprotocol.io/specification/2025-11-25/schema#legacytitledenumschema
33: */
34: final readonly class LegacyTitledEnumSchema implements Arrayable, EnumSchema
35: {
36: public const string TYPE = 'string';
37:
38: /**
39: * @var list<non-empty-string>
40: */
41: public array $enum;
42:
43: /**
44: * @var null|non-empty-string
45: */
46: public ?string $title;
47:
48: /**
49: * @var null|non-empty-string
50: */
51: public ?string $description;
52:
53: /**
54: * @var null|list<non-empty-string>
55: */
56: public ?array $enumNames;
57:
58: /**
59: * @param list<string> $enum
60: * @param null|list<string> $enumNames
61: */
62: public function __construct(
63: array $enum,
64: ?string $title = null,
65: ?string $description = null,
66: ?array $enumNames = null,
67: public ?string $default = null,
68: ) {
69: Assert::that($enum)
70: ->isList('legacy titled enum schema "enum" must be a list, non-list array given.')
71: ->values()->isNonEmptyString('each legacy titled enum schema "enum" must be a non-empty string.')
72: ;
73: Assert::that($title)->nullOr()->isNonEmptyString('legacy titled enum schema "title" must be a non-empty string or null.');
74: Assert::that($description)->nullOr()->isNonEmptyString('legacy titled enum schema "description" must be a non-empty string or null.');
75:
76: if (null !== $enumNames) {
77: Assert::that($enumNames)
78: ->isList('legacy titled enum schema "enumNames" must be a list, non-list array given.')
79: ->values()->isNonEmptyString('each legacy titled enum schema "enumNames" must be a non-empty string.')
80: ;
81: }
82:
83: $this->enum = $enum;
84: $this->title = $title;
85: $this->description = $description;
86: $this->enumNames = $enumNames;
87: }
88:
89: /**
90: * @param array<string, mixed> $data
91: */
92: #[\Override]
93: public static function fromArray(array $data): static
94: {
95: Assert::that($data)->hasOffset('type', 'legacy titled enum schema missing the required "type" key.');
96: $type = $data['type'];
97: Assert::that($type)->isIdentical(self::TYPE, 'legacy titled enum schema "type" must be {other}, {value} given.');
98:
99: Assert::that($data)->hasOffset('enum', 'legacy titled enum schema missing the required "enum" key.');
100: Assert::that($data['enum'])
101: ->isList('legacy titled enum schema "enum" must be a list, non-list array given.')
102: ->values()->isString('each legacy titled enum schema "enum" must be a string, {type} given.')
103: ;
104: $enum = $data['enum'];
105:
106: $title = $data['title'] ?? null;
107: Assert::that($title)->nullOr()->isString('legacy titled enum schema "title" must be a string or null, {type} given.');
108:
109: $description = $data['description'] ?? null;
110: Assert::that($description)->nullOr()->isString('legacy titled enum schema "description" must be a string or null, {type} given.');
111:
112: $enumNames = null;
113:
114: if (isset($data['enumNames'])) {
115: Assert::that($data['enumNames'])
116: ->isList('legacy titled enum schema "enumNames" must be a list, non-list array given.')
117: ->values()->isString('each legacy titled enum schema "enumNames" must be a string, {type} given.')
118: ;
119: $enumNames = $data['enumNames'];
120: }
121:
122: $default = $data['default'] ?? null;
123: Assert::that($default)->nullOr()->isString('legacy titled enum schema "default" must be a string or null, {type} given.');
124:
125: return new self($enum, $title, $description, $enumNames, $default);
126: }
127:
128: #[\Override]
129: public function toArray(): array
130: {
131: $data = [
132: 'type' => self::TYPE,
133: 'enum' => $this->enum,
134: ];
135:
136: if (null !== $this->title) {
137: $data['title'] = $this->title;
138: }
139:
140: if (null !== $this->description) {
141: $data['description'] = $this->description;
142: }
143:
144: if (null !== $this->enumNames) {
145: $data['enumNames'] = $this->enumNames;
146: }
147:
148: if (null !== $this->default) {
149: $data['default'] = $this->default;
150: }
151:
152: return $data;
153: }
154:
155: #[\Override]
156: public function jsonSerialize(): array
157: {
158: return $this->toArray();
159: }
160: }
161: