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\Result;
15:
16: use Nexus\Assert\Assert;
17: use Nexus\Mcp\Core\Schema\MetaObject;
18: use Nexus\Mcp\Core\Schema\Result;
19:
20: /**
21: * The server's response to a completion/complete request.
22: *
23: * @see https://modelcontextprotocol.io/specification/2025-11-25/schema#completeresult
24: */
25: final readonly class CompleteResult extends Result implements ServerResult
26: {
27: /**
28: * @var array{values: list<string>, total?: int, hasMore?: bool}
29: */
30: public array $completion;
31:
32: /**
33: * @param array{values: list<string>, total?: int, hasMore?: bool} $completion
34: */
35: public function __construct(array $completion, MetaObject $meta = new MetaObject())
36: {
37: Assert::that($completion['values'])
38: ->isList('"result.completion.values" must be a list, non-list array given.')
39: ->values()->isString('each "result.completion.values" must be a string, {type} given.')
40: ;
41:
42: $normalized = ['values' => $completion['values']];
43:
44: if (\array_key_exists('total', $completion)) {
45: Assert::that($completion['total'])->isInt('"result.completion.total" must be an int, {type} given.');
46: $normalized['total'] = $completion['total'];
47: }
48:
49: if (\array_key_exists('hasMore', $completion)) {
50: Assert::that($completion['hasMore'])->isBool('"result.completion.hasMore" must be a bool, {type} given.');
51: $normalized['hasMore'] = $completion['hasMore'];
52: }
53:
54: $this->completion = $normalized;
55:
56: parent::__construct($meta);
57: }
58:
59: /**
60: * @param array<string, mixed> $data
61: */
62: #[\Override]
63: public static function fromArray(array $data): static
64: {
65: Assert::that($data)->hasOffset('completion', '"result" missing the required "completion" key.');
66: Assert::that($data['completion'])
67: ->isArray('"result.completion" must be an object, {type} given.')
68: ->isMap('"result.completion" must be a string-keyed object.')
69: ;
70:
71: Assert::that($data['completion'])->hasOffset('values', '"result" missing the required "completion.values" key.');
72: Assert::that($data['completion']['values'])
73: ->isList('"result.completion.values" must be a list, {type} given.')
74: ->values()->isString('each "result.completion.values" must be a string, {type} given.')
75: ;
76:
77: $completion = ['values' => $data['completion']['values']];
78:
79: if (\array_key_exists('total', $data['completion'])) {
80: Assert::that($data['completion']['total'])->isInt('"result.completion.total" must be an int, {type} given.');
81: $completion['total'] = $data['completion']['total'];
82: }
83:
84: if (\array_key_exists('hasMore', $data['completion'])) {
85: Assert::that($data['completion']['hasMore'])->isBool('"result.completion.hasMore" must be a bool, {type} given.');
86: $completion['hasMore'] = $data['completion']['hasMore'];
87: }
88:
89: $meta = new MetaObject();
90:
91: if (\array_key_exists('_meta', $data)) {
92: Assert::that($data['_meta'])
93: ->isArray('"result._meta" must be an object, {type} given.')
94: ->isMap('"result._meta" must be a string-keyed object.')
95: ;
96: $meta = MetaObject::fromArray($data['_meta']);
97: }
98:
99: return new self($completion, $meta);
100: }
101:
102: #[\Override]
103: public function toArray(): array
104: {
105: return [
106: ...parent::toArray(),
107: 'completion' => $this->completion,
108: ];
109: }
110:
111: #[\Override]
112: public function jsonSerialize(): array
113: {
114: return $this->toArray();
115: }
116: }
117: