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\MetaObject;
15:
16: use Nexus\Assert\Assert;
17: use Nexus\Mcp\Core\Schema\Implementation;
18: use Nexus\Mcp\Core\Schema\MetaObject;
19:
20: /**
21: * Extends `MetaObject` with additional result-specific fields.
22: * All key naming rules from `MetaObject` apply.
23: *
24: * @extends MetaObject<array<string, mixed>>
25: *
26: * @see https://modelcontextprotocol.io/specification/2026-07-28/schema#resultmetaobject
27: */
28: abstract readonly class ResultMetaObject extends MetaObject
29: {
30: public const string SERVER_INFO_KEY = 'io.modelcontextprotocol/serverInfo';
31:
32: /**
33: * @param array<string, mixed> $extras
34: */
35: public function __construct(public ?Implementation $serverInfo = null, array $extras = [])
36: {
37: parent::__construct(extras: $extras);
38: }
39:
40: /**
41: * Whether a server identity is present, in the typed slot or among the extras
42: * a directly constructed instance may still carry it in.
43: *
44: * @internal
45: */
46: public function declaresServerInfo(): bool
47: {
48: return null !== $this->serverInfo || \array_key_exists(self::SERVER_INFO_KEY, $this->extras);
49: }
50:
51: #[\Override]
52: public function toArray(): array
53: {
54: $out = [];
55:
56: if (null !== $this->serverInfo) {
57: $out[self::SERVER_INFO_KEY] = $this->serverInfo->toArray();
58: }
59:
60: $out += $this->extras;
61:
62: return $out;
63: }
64:
65: /**
66: * Splits the typed server identity out of a raw `_meta` map, leaving the rest as extras.
67: *
68: * @param array<string, mixed> $data
69: *
70: * @return array{null|Implementation, array<string, mixed>}
71: */
72: protected static function splitServerInfo(array $data): array
73: {
74: $serverInfo = null;
75:
76: if (\array_key_exists(self::SERVER_INFO_KEY, $data)) {
77: Assert::that($data[self::SERVER_INFO_KEY])
78: ->isArray(\sprintf('"_meta.%s" must be an object, {type} given.', self::SERVER_INFO_KEY))
79: ->isMap(\sprintf('"_meta.%s" must be a string-keyed object.', self::SERVER_INFO_KEY))
80: ;
81: $serverInfo = Implementation::fromArray($data[self::SERVER_INFO_KEY]);
82: unset($data[self::SERVER_INFO_KEY]);
83: }
84:
85: return [$serverInfo, $data];
86: }
87: }
88: