Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,16 @@ public sealed record InitializeResult
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public Implementation? ServerInfo { get; init; }

/// <summary>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.</summary>
[JsonPropertyName("_meta")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public Dictionary<string, JsonElement>? Meta { get; init; }

/// <summary>Snapshots for each `initialSubscriptions` URI</summary>
public required List<Snapshot> Snapshots { get; init; }

Expand Down
7 changes: 7 additions & 0 deletions clients/go/ahptypes/commands.generated.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<String, JsonElement>? = null,
/**
* Snapshots for each `initialSubscriptions` URI
*/
Expand Down
8 changes: 8 additions & 0 deletions clients/rust/crates/ahp-types/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,14 @@ pub struct InitializeResult {
/// software behind it.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub server_info: Option<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.
#[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
pub meta: Option<JsonObject>,
/// Snapshots for each `initialSubscriptions` URI
pub snapshots: Vec<Snapshot>,
/// Suggested default directory for remote filesystem browsing
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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,
Expand All @@ -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
Expand Down
4 changes: 4 additions & 0 deletions docs/.changes/20260826-initialize-result-meta.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"type": "added",
"message": "`InitializeResult._meta` for hosts to advertise implementation-specific extension capabilities in initialize responses."
}
7 changes: 6 additions & 1 deletion docs/specification/lifecycle.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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": [
{
Expand All @@ -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.
Expand Down
5 changes: 5 additions & 0 deletions schema/commands.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand Down
5 changes: 5 additions & 0 deletions schema/errors.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand Down
9 changes: 9 additions & 0 deletions types/common/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, unknown>;
/** Snapshots for each `initialSubscriptions` URI */
snapshots: Snapshot[];
/** Suggested default directory for remote filesystem browsing */
Expand Down
54 changes: 54 additions & 0 deletions types/test-cases/round-trips/044-initialize-result-meta.json
Original file line number Diff line number Diff line change
@@ -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
}
]
}
]
}