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