diff --git a/clients/dotnet/src/AgentHostProtocol.Abstractions/Generated/Commands.generated.cs b/clients/dotnet/src/AgentHostProtocol.Abstractions/Generated/Commands.generated.cs index 2fdea2d8..2b82c602 100644 --- a/clients/dotnet/src/AgentHostProtocol.Abstractions/Generated/Commands.generated.cs +++ b/clients/dotnet/src/AgentHostProtocol.Abstractions/Generated/Commands.generated.cs @@ -174,6 +174,16 @@ public sealed record InitializeResult [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public Implementation? ServerInfo { get; init; } + /// Optional implementation-specific extension metadata advertised by the host. + /// + /// Hosts and clients MAY agree on namespaced keys for capabilities that are not + /// part of the standardized protocol. Clients MUST ignore keys they do not + /// understand. Capabilities needed for interoperable behavior SHOULD use typed + /// fields on {@link InitializeResult} instead. + [JsonPropertyName("_meta")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public Dictionary? Meta { get; init; } + /// Snapshots for each `initialSubscriptions` URI public required List Snapshots { get; init; } diff --git a/clients/go/ahptypes/commands.generated.go b/clients/go/ahptypes/commands.generated.go index a8d3dcea..2fc55b11 100644 --- a/clients/go/ahptypes/commands.generated.go +++ b/clients/go/ahptypes/commands.generated.go @@ -149,6 +149,13 @@ type InitializeResult struct { // identifies the negotiated protocol, `serverInfo` identifies the host // software behind it. ServerInfo *Implementation `json:"serverInfo,omitempty"` + // Optional implementation-specific extension metadata advertised by the host. + // + // Hosts and clients MAY agree on namespaced keys for capabilities that are not + // part of the standardized protocol. Clients MUST ignore keys they do not + // understand. Capabilities needed for interoperable behavior SHOULD use typed + // fields on {@link InitializeResult} instead. + Meta map[string]json.RawMessage `json:"_meta,omitempty"` // Snapshots for each `initialSubscriptions` URI Snapshots []Snapshot `json:"snapshots"` // Suggested default directory for remote filesystem browsing diff --git a/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/generated/Commands.generated.kt b/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/generated/Commands.generated.kt index 521e2c4a..14c8ff48 100644 --- a/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/generated/Commands.generated.kt +++ b/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/generated/Commands.generated.kt @@ -345,6 +345,16 @@ data class InitializeResult( * software behind it. */ val serverInfo: Implementation? = null, + /** + * Optional implementation-specific extension metadata advertised by the host. + * + * Hosts and clients MAY agree on namespaced keys for capabilities that are not + * part of the standardized protocol. Clients MUST ignore keys they do not + * understand. Capabilities needed for interoperable behavior SHOULD use typed + * fields on {@link InitializeResult} instead. + */ + @SerialName("_meta") + val meta: Map? = null, /** * Snapshots for each `initialSubscriptions` URI */ diff --git a/clients/rust/crates/ahp-types/src/commands.rs b/clients/rust/crates/ahp-types/src/commands.rs index fcae9de8..dc8f02b9 100644 --- a/clients/rust/crates/ahp-types/src/commands.rs +++ b/clients/rust/crates/ahp-types/src/commands.rs @@ -255,6 +255,14 @@ pub struct InitializeResult { /// software behind it. #[serde(default, skip_serializing_if = "Option::is_none")] pub server_info: Option, + /// Optional implementation-specific extension metadata advertised by the host. + /// + /// Hosts and clients MAY agree on namespaced keys for capabilities that are not + /// part of the standardized protocol. Clients MUST ignore keys they do not + /// understand. Capabilities needed for interoperable behavior SHOULD use typed + /// fields on {@link InitializeResult} instead. + #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")] + pub meta: Option, /// Snapshots for each `initialSubscriptions` URI pub snapshots: Vec, /// Suggested default directory for remote filesystem browsing diff --git a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/Commands.generated.swift b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/Commands.generated.swift index dbb88a16..81b97560 100644 --- a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/Commands.generated.swift +++ b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/Commands.generated.swift @@ -310,6 +310,13 @@ public struct InitializeResult: Codable, Sendable { /// identifies the negotiated protocol, `serverInfo` identifies the host /// software behind it. public var serverInfo: Implementation? + /// Optional implementation-specific extension metadata advertised by the host. + /// + /// Hosts and clients MAY agree on namespaced keys for capabilities that are not + /// part of the standardized protocol. Clients MUST ignore keys they do not + /// understand. Capabilities needed for interoperable behavior SHOULD use typed + /// fields on {@link InitializeResult} instead. + public var meta: [String: AnyCodable]? /// Snapshots for each `initialSubscriptions` URI public var snapshots: [Snapshot] /// Suggested default directory for remote filesystem browsing @@ -335,10 +342,24 @@ public struct InitializeResult: Codable, Sendable { /// host does not expose an automation catalogue or automation commands. public var automations: AutomationCapabilities? + enum CodingKeys: String, CodingKey { + case protocolVersion + case serverSeq + case serverInfo + case meta = "_meta" + case snapshots + case defaultDirectory + case completionTriggerCharacters + case terminalCommandPrefix + case telemetry + case automations + } + public init( protocolVersion: String, serverSeq: Int, serverInfo: Implementation? = nil, + meta: [String: AnyCodable]? = nil, snapshots: [Snapshot], defaultDirectory: String? = nil, completionTriggerCharacters: [String]? = nil, @@ -349,6 +370,7 @@ public struct InitializeResult: Codable, Sendable { self.protocolVersion = protocolVersion self.serverSeq = serverSeq self.serverInfo = serverInfo + self.meta = meta self.snapshots = snapshots self.defaultDirectory = defaultDirectory self.completionTriggerCharacters = completionTriggerCharacters diff --git a/docs/.changes/20260826-initialize-result-meta.json b/docs/.changes/20260826-initialize-result-meta.json new file mode 100644 index 00000000..2a8969b1 --- /dev/null +++ b/docs/.changes/20260826-initialize-result-meta.json @@ -0,0 +1,4 @@ +{ + "type": "added", + "message": "`InitializeResult._meta` for hosts to advertise implementation-specific extension capabilities in initialize responses." +} diff --git a/docs/specification/lifecycle.md b/docs/specification/lifecycle.md index aee0434f..a2dd20cc 100644 --- a/docs/specification/lifecycle.md +++ b/docs/specification/lifecycle.md @@ -8,7 +8,7 @@ The client initiates the connection with an `initialize` **request**. The client ``` 1. Client → Server: initialize(protocolVersions[], clientId, clientInfo?, initialSubscriptions?, locale?) -2. Server → Client: { protocolVersion, serverSeq, serverInfo?, snapshots[], defaultDirectory? } +2. Server → Client: { protocolVersion, serverSeq, serverInfo?, _meta?, snapshots[], defaultDirectory? } ``` ### Initialize (Client → Server) @@ -49,6 +49,9 @@ The client initiates the connection with an `initialize` **request**. The client "protocolVersion": "0.3.0", "serverSeq": 42, "serverInfo": { "name": "acme-agent-host", "version": "1.4.2" }, + "_meta": { + "com.example.chatTargetStateFile": true + }, "defaultDirectory": "file:///home/testuser", "snapshots": [ { @@ -63,6 +66,8 @@ The client initiates the connection with an `initialize` **request**. The client `protocolVersion` is the version the server selected from the client's `protocolVersions` list. Both peers MUST use this version for the rest of the connection. +`_meta` is an optional, opaque map for implementation-specific extension capabilities advertised by the host. Hosts and clients MAY agree on namespaced keys; clients MUST ignore keys they do not understand. Capabilities needed for interoperable behavior should be added as typed `InitializeResult` fields instead. + If present, `defaultDirectory` provides a server-local starting location for remote filesystem browsing. If the server cannot accept the connection for any other reason, it MUST return a JSON-RPC error. See [Error Codes](/reference/error-codes) for defined codes. diff --git a/schema/commands.schema.json b/schema/commands.schema.json index 429ba8a2..dbda097a 100644 --- a/schema/commands.schema.json +++ b/schema/commands.schema.json @@ -147,6 +147,11 @@ "$ref": "#/$defs/Implementation", "description": "Optional identity of the server implementation (name and version).\nInformational only — see {@link Implementation} for how it may and may not\nbe used. Whereas {@link InitializeResult.protocolVersion | `protocolVersion`}\nidentifies the negotiated protocol, `serverInfo` identifies the host\nsoftware behind it." }, + "_meta": { + "type": "object", + "additionalProperties": {}, + "description": "Optional implementation-specific extension metadata advertised by the host.\n\nHosts and clients MAY agree on namespaced keys for capabilities that are not\npart of the standardized protocol. Clients MUST ignore keys they do not\nunderstand. Capabilities needed for interoperable behavior SHOULD use typed\nfields on {@link InitializeResult} instead." + }, "snapshots": { "type": "array", "items": { diff --git a/schema/errors.schema.json b/schema/errors.schema.json index 7fc9e5eb..0e2457bc 100644 --- a/schema/errors.schema.json +++ b/schema/errors.schema.json @@ -5799,6 +5799,11 @@ "$ref": "#/$defs/Implementation", "description": "Optional identity of the server implementation (name and version).\nInformational only — see {@link Implementation} for how it may and may not\nbe used. Whereas {@link InitializeResult.protocolVersion | `protocolVersion`}\nidentifies the negotiated protocol, `serverInfo` identifies the host\nsoftware behind it." }, + "_meta": { + "type": "object", + "additionalProperties": {}, + "description": "Optional implementation-specific extension metadata advertised by the host.\n\nHosts and clients MAY agree on namespaced keys for capabilities that are not\npart of the standardized protocol. Clients MUST ignore keys they do not\nunderstand. Capabilities needed for interoperable behavior SHOULD use typed\nfields on {@link InitializeResult} instead." + }, "snapshots": { "type": "array", "items": { diff --git a/types/common/commands.ts b/types/common/commands.ts index 47bf7016..ec93fc82 100644 --- a/types/common/commands.ts +++ b/types/common/commands.ts @@ -248,6 +248,15 @@ export interface InitializeResult { * software behind it. */ serverInfo?: Implementation; + /** + * Optional implementation-specific extension metadata advertised by the host. + * + * Hosts and clients MAY agree on namespaced keys for capabilities that are not + * part of the standardized protocol. Clients MUST ignore keys they do not + * understand. Capabilities needed for interoperable behavior SHOULD use typed + * fields on {@link InitializeResult} instead. + */ + _meta?: Record; /** Snapshots for each `initialSubscriptions` URI */ snapshots: Snapshot[]; /** Suggested default directory for remote filesystem browsing */ diff --git a/types/test-cases/round-trips/044-initialize-result-meta.json b/types/test-cases/round-trips/044-initialize-result-meta.json new file mode 100644 index 00000000..c200b7a4 --- /dev/null +++ b/types/test-cases/round-trips/044-initialize-result-meta.json @@ -0,0 +1,54 @@ +{ + "name": "initialize-result-meta", + "group": "A", + "description": "InitializeResult preserves opaque, implementation-specific extension capabilities in its optional _meta map.", + "type": "InitializeResult", + "input": { + "protocolVersion": "0.5.2", + "serverSeq": 7, + "_meta": { + "com.example.chatTargetStateFile": { + "supported": true, + "formats": [ + "json", + "jsonc" + ] + }, + "com.example.experimentalMode": null + }, + "snapshots": [ + { + "resource": "ahp-root://", + "state": { + "agents": [] + }, + "fromSeq": 7 + } + ] + }, + "acceptableOutputs": [ + { + "protocolVersion": "0.5.2", + "serverSeq": 7, + "_meta": { + "com.example.chatTargetStateFile": { + "supported": true, + "formats": [ + "json", + "jsonc" + ] + }, + "com.example.experimentalMode": null + }, + "snapshots": [ + { + "resource": "ahp-root://", + "state": { + "agents": [] + }, + "fromSeq": 7 + } + ] + } + ] +}