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\RequestParams;
15:
16: use Nexus\Assert\Assert;
17: use Nexus\Mcp\Core\Schema\Elicitation\ElicitRequestedSchema;
18: use Nexus\Mcp\Core\Schema\RequestMetaObject;
19: use Nexus\Mcp\Core\Schema\Task\TaskMetadata;
20:
21: /**
22: * The parameters for a request to elicit non-sensitive information from the user via a form in the client.
23: *
24: * @see https://modelcontextprotocol.io/specification/2025-11-25/schema#elicitrequestformparams
25: */
26: final readonly class ElicitRequestFormParams extends TaskAugmentedRequestParams implements ElicitRequestParams
27: {
28: public const string MODE = 'form';
29:
30: /**
31: * @var non-empty-string
32: */
33: public string $message;
34:
35: /**
36: * @var 'form'
37: */
38: public string $mode;
39:
40: public function __construct(
41: string $message,
42: public ElicitRequestedSchema $requestedSchema,
43: string $mode = self::MODE,
44: ?TaskMetadata $task = null,
45: RequestMetaObject $meta = new RequestMetaObject(),
46: ) {
47: Assert::that($message)->isNonEmptyString('"params.message" must be a non-empty string.');
48: Assert::that($mode)->isIdentical(self::MODE, '"params.mode" must be {other}, {value} given.');
49:
50: $this->message = $message;
51: $this->mode = $mode;
52:
53: parent::__construct($task, $meta);
54: }
55:
56: /**
57: * @param array<string, mixed> $data
58: */
59: #[\Override]
60: public static function fromArray(array $data): static
61: {
62: $mode = $data['mode'] ?? self::MODE;
63: Assert::that($mode)->isString('"params.mode" must be a string, {type} given.');
64:
65: Assert::that($data)->hasOffset('message', 'missing the required "message" key.');
66: $message = $data['message'];
67: Assert::that($message)->isString('"params.message" must be a string, {type} given.');
68:
69: Assert::that($data)->hasOffset('requestedSchema', 'missing the required "requestedSchema" key.');
70: Assert::that($data['requestedSchema'])
71: ->isArray('"params.requestedSchema" must be an object, {type} given.')
72: ->isMap('"params.requestedSchema" must be a string-keyed object.')
73: ;
74: $requestedSchema = ElicitRequestedSchema::fromArray($data['requestedSchema']);
75:
76: $task = null;
77:
78: if (\array_key_exists('task', $data)) {
79: Assert::that($data['task'])
80: ->isArray('"params.task" must be an object, {type} given.')
81: ->isMap('"params.task" must be a string-keyed object.')
82: ;
83: $task = TaskMetadata::fromArray($data['task']);
84: }
85:
86: $meta = new RequestMetaObject();
87:
88: if (\array_key_exists('_meta', $data)) {
89: Assert::that($data['_meta'])
90: ->isArray('"params._meta" must be an object, {type} given.')
91: ->isMap('"params._meta" must be a string-keyed object.')
92: ;
93: $meta = RequestMetaObject::fromArray($data['_meta']);
94: }
95:
96: return new self($message, $requestedSchema, $mode, $task, $meta);
97: }
98:
99: #[\Override]
100: public function toArray(): array
101: {
102: return [
103: ...parent::toArray(),
104: 'mode' => $this->mode,
105: 'message' => $this->message,
106: 'requestedSchema' => $this->requestedSchema->toArray(),
107: ];
108: }
109:
110: #[\Override]
111: public function jsonSerialize(): array
112: {
113: return $this->toArray();
114: }
115: }
116: