1
>
/*---------------------------------------------------------------------------------------------
commands.ts
2
>
* Copyright (c) Microsoft Corporation. All rights reserved.
3
>
* Licensed under the MIT License. See License.txt in the project root for license information.
4
>
*--------------------------------------------------------------------------------------------*/
5
>
6
>
// allow-any-unicode-comment-file
7
>
// DO NOT EDIT -- auto-generated by scripts/sync-agent-host-protocol.ts
8
>
9
>
import type { URI, Snapshot } from './state.js';
10
>
import type { ActionEnvelope, StateAction } from './actions.js';
11
>
import type { TelemetryCapabilities } from '../channels-otlp/state.js';
12
>
13
>
// ─── BaseParams ──────────────────────────────────────────────────────────────
14
>
15
>
/**
16
>
* Base shape every command's params extends.
17
>
*
18
>
* `channel` identifies the channel the command targets, mirroring the
19
>
* `channel` field on every protocol notification. For commands that operate
20
>
* on a specific channel (a session, terminal, or changeset), `channel` is
21
>
* that channel's URI. For commands that are connection-level rather than
22
>
* channel-scoped (e.g. {@link InitializeParams | `initialize`},
23
>
* {@link PingParams | `ping`}, {@link ListSessionsParams | `listSessions`},
24
>
* the `resource*` filesystem commands, and {@link AuthenticateParams |
25
>
* `authenticate`}), the params type narrows `channel` to the literal
26
>
* root URI `'ahp-root://'`.
27
>
*
28
>
* This invariant lets implementations route every incoming message —
29
>
* request, response, or notification — by inspecting `params.channel`
30
>
* without needing to know the per-method param shape.
31
>
*
32
>
* @category Commands
33
>
*/
34
>
export interface BaseParams {
35
>
/** Channel URI this command targets. */
36
>
channel: URI;
37
>
}
38
>
39
>
// ─── Pagination ──────────────────────────────────────────────────────────────
40
>
41
>
/**
42
>
* Cursor-based pagination inputs, mixed into the params of any list command
43
>
* that can page a large result set (e.g. {@link ListSessionsParams |
44
>
* `listSessions`}). The paired output is {@link PaginatedResult}.
45
>
*
46
>
* Pagination is **opaque and cursor-based**, mirroring the shape `fetchTurns`
47
>
* already uses for chat history: the server owns the ordering and keyset, and
48
>
* the client walks pages by echoing the cursor from the previous
49
>
* {@link PaginatedResult.nextCursor} back on the next request.
50
>
*
51
>
* The contract every paginated command shares:
52
>
*
53
>
* - To fetch the first page, omit `cursor`. Supply `limit` to bound the page.
54
>
* - If the result carries a {@link PaginatedResult.nextCursor}, more entries
55
>
* exist — pass it back as `cursor` to fetch the following page. A missing
56
>
* `nextCursor` signals the end of the collection.
57
>
* - Cursors are **server-defined and opaque**: clients MUST NOT parse, modify,
58
>
* or persist them across connections. An unrecognised cursor SHOULD be
59
>
* rejected with an `InvalidParams` error.
60
>
* - Pagination is **fully additive**: a client that omits `limit`/`cursor` and
61
>
* ignores `nextCursor` sees the pre-pagination behaviour (subject to any
62
>
* server-imposed cap), and a server that does not paginate ignores the inputs
63
>
* and returns everything in a single page.
64
>
*
65
>
* @category Commands
66
>
*/
67
>
export interface PaginatedParams {
68
>
/**
69
>
* Maximum number of entries to return in this page. The server SHOULD respect
70
>
* this bound but MAY return fewer entries and MAY impose its own upper cap.
71
>
* Omit to let the server choose the page size.
72
>
*/
73
>
limit?: number;
74
>
/**
75
>
* Opaque pagination cursor from a previous {@link PaginatedResult.nextCursor}.
76
>
* Omit to fetch the first page. Cursors are server-defined and MUST be treated
77
>
* as opaque — do not parse, modify, or persist them across connections. An
78
>
* unrecognised cursor SHOULD be rejected with an `InvalidParams` error.
79
>
*/
80
>
cursor?: string;
81
>
}
82
>
83
>
/**
84
>
* Cursor-based pagination output, extended by the result of any list command
85
>
* that can page a large result set (e.g. {@link ListSessionsResult |
86
>
* `listSessions`}). See {@link PaginatedParams} for the full pagination
87
>
* contract shared by every paginated command.
88
>
*
89
>
* @category Commands
90
>
*/
91
>
export interface PaginatedResult {
92
>
/**
93
>
* Opaque cursor for the next page. Present when more entries exist beyond the
94
>
* returned page; absent signals the end of the collection. Pass it back as
95
>
* {@link PaginatedParams.cursor} to fetch the following page.
96
>
*/
97
>
nextCursor?: string;
98
>
}
99
>
100
>
// ─── initialize ──────────────────────────────────────────────────────────────
101
>
102
>
/**
103
>
* Identifies a protocol implementation — the software (and build) on one end
104
>
* of the connection, as distinct from the {@link AgentInfo | agent persona} it
105
>
* hosts. Carried as {@link InitializeParams.clientInfo | `clientInfo`} on the
106
>
* client side and {@link InitializeResult.serverInfo | `serverInfo`} on the
107
>
* server side, mirroring LSP's `clientInfo`/`serverInfo` and MCP's
108
>
* `Implementation`.
109
>
*
110
>
* This is **informational only**: it exists for logging, telemetry, an
111
>
* about/status affordance, and — as a last resort — a known-issue workaround
112
>
* for a specific buggy build. It is **not** a feature-detection mechanism.
113
>
* Feature availability stays with the capability model
114
>
* ({@link ClientCapabilities} and the various `*.capabilities` declarations);
115
>
* implementations SHOULD NOT gate protocol behaviour on parsing
116
>
* {@link Implementation.version | `version`}.
117
>
*
118
>
* @category Commands
119
>
*/
120
>
export interface Implementation {
121
>
/** Implementation name, e.g. a product or package identifier. */
122
>
name: string;
123
>
/**
124
>
* Implementation version. A [SemVer](https://semver.org) string is
125
>
* recommended but not required.
126
>
*/
127
>
version?: string;
128
>
/** Optional human-readable display name. */
129
>
title?: string;
130
>
}
131
>
132
>
/**
133
>
* Establishes a new connection and negotiates the protocol version.
134
>
* This MUST be the first message sent by the client.
135
>
*
136
>
* @category Commands
137
>
* @method initialize
138
>
* @direction Client → Server
139
>
* @messageType Request
140
>
* @version 1
141
>
* @see {@link /specification/lifecycle | Lifecycle} for the full handshake flow.
142
>
*/
143
>
export interface InitializeParams extends BaseParams {
144
>
channel: 'ahp-root://';
145
>
/**
146
>
* Protocol versions the client is willing to speak, ordered from most
147
>
* preferred to least preferred. Each entry is a [SemVer](https://semver.org)
148
>
* `MAJOR.MINOR.PATCH` string (e.g. `"0.1.0"`).
149
>
*
150
>
* The server selects one entry and returns it as `InitializeResult.protocolVersion`.
151
>
* If the server cannot speak any of the offered versions, it MUST return
152
>
* error code `-32005` (`UnsupportedProtocolVersion`).
153
>
*/
154
>
protocolVersions: string[];
155
>
/** Unique client identifier */
156
>
clientId: string;
157
>
/**
158
>
* Optional identity of the client implementation (name and version).
159
>
* Informational only — see {@link Implementation} for how it may and may not
160
>
* be used. Distinct from {@link InitializeParams.clientId | `clientId`},
161
>
* which is an opaque per-connection identifier used for reconnection, not a
162
>
* human-readable implementation name.
163
>
*/
164
>
clientInfo?: Implementation;
165
>
/** URIs to subscribe to during handshake */
166
>
initialSubscriptions?: URI[];
167
>
/**
168
>
* IETF BCP 47 language tag indicating the client's preferred locale
169
>
* (e.g. `"en-US"`, `"ja"`). The server SHOULD use this to localise
170
>
* user-facing strings such as confirmation option labels.
171
>
*/
172
>
locale?: string;
173
>
/**
174
>
* Optional client capability declarations.
175
>
*
176
>
* Servers SHOULD only advertise features whose corresponding client
177
>
* capability is set here. Absent means "not declared" — the server
178
>
* MUST assume the client does not support the feature.
179
>
*/
180
>
capabilities?: ClientCapabilities;
181
>
}
182
>
183
>
/**
184
>
* Optional capabilities a client declares during `initialize`.
185
>
*
186
>
* Each field is a presence flag: an empty object `{}` means "supported",
187
>
* absence means "not supported". Sub-fields on individual capabilities
188
>
* are reserved for future per-capability options.
189
>
*
190
>
* @category Commands
191
>
*/
192
>
export interface ClientCapabilities {
193
>
/**
194
>
* Client can render
195
>
* [MCP Apps](https://github.com/modelcontextprotocol/ext-apps) — i.e.
196
>
* it can host the View sandbox, run the `ui/*` protocol against it,
197
>
* and forward `mcp://`-channel traffic on the App's behalf.
198
>
*
199
>
* Hosts SHOULD only populate
200
>
* {@link McpServerCustomization.mcpApp | `McpServerCustomization.mcpApp`}
201
>
* (and expose the corresponding
202
>
* {@link McpServerCustomization.channel | `mcp://` channel}) when this
203
>
* capability is declared. Clients that omit it MUST treat
204
>
* App-bearing tool calls as ordinary MCP tool calls.
205
>
*/
206
>
mcpApps?: Record<string, never>;
207
>
}
208
>
209
>
/**
210
>
* Result of the `initialize` command.
211
>
*
212
>
* `protocolVersion` is the version the server has selected from the client's
213
>
* `protocolVersions` list. The client and server MUST use this version for
214
>
* the rest of the connection. If the server cannot speak any of the offered
215
>
* versions it MUST return error code `-32005` (`UnsupportedProtocolVersion`)
216
>
* instead of a result.
217
>
*/
218
>
export interface InitializeResult {
219
>
/**
220
>
* Protocol version selected by the server. MUST be one of the entries in
221
>
* `InitializeParams.protocolVersions`. Formatted as a [SemVer](https://semver.org)
222
>
* `MAJOR.MINOR.PATCH` string (e.g. `"0.1.0"`).
223
>
*/
224
>
protocolVersion: string;
225
>
/** Current server sequence number */
226
>
serverSeq: number;
227
>
/**
228
>
* Optional identity of the server implementation (name and version).
229
>
* Informational only — see {@link Implementation} for how it may and may not
230
>
* be used. Whereas {@link InitializeResult.protocolVersion | `protocolVersion`}
231
>
* identifies the negotiated protocol, `serverInfo` identifies the host
232
>
* software behind it.
233
>
*/
234
>
serverInfo?: Implementation;
235
>
/** Snapshots for each `initialSubscriptions` URI */
236
>
snapshots: Snapshot[];
237
>
/** Suggested default directory for remote filesystem browsing */
238
>
defaultDirectory?: URI;
239
>
/**
240
>
* Characters that, when typed in a {@link Message} input, SHOULD cause
241
>
* the client to issue a `completions` request with
242
>
* {@link CompletionItemKind.UserMessage}. Typically includes characters like
243
>
* `'@'` or `'/'`.
244
>
*/
245
>
completionTriggerCharacters?: string[];
246
>
/**
247
>
* Prefix that the host recognizes at the start of a user {@link Message.text}
248
>
* as a shorthand for executing the remainder as a terminal command. Currently
249
>
* the standardized convention is `"!"`; absence means the host does not
250
>
* support command prefixes.
251
>
*/
252
>
terminalCommandPrefix?: string;
253
>
/**
254
>
* OTLP telemetry channels the host emits, if any. Each populated field is
255
>
* either a literal `ahp-otlp:` channel URI or an RFC 6570 URI template a
256
>
* client expands before subscribing (currently only the `logs` channel
257
>
* defines a template variable, `{level}`, for subscriber-side severity
258
>
* filtering). Clients MAY ignore signals they cannot process.
259
>
*
260
>
* @see {@link /specification/telemetry-channel | Telemetry Channel}
261
>
*/
262
>
telemetry?: TelemetryCapabilities;
263
>
}
264
>
265
>
// ─── ping ────────────────────────────────────────────────────────────────────
266
>
267
>
/**
268
>
* Verifies that the AHP connection is still alive and keeps it from being
269
>
* closed by idle-timeout intermediaries (proxies, load balancers, etc.).
270
>
*
271
>
* The server MUST respond regardless of whether the client has completed
272
>
* `initialize` or holds any subscriptions. Ping carries no payload in either
273
>
* direction; the response itself is the signal.
274
>
*
275
>
* @category Commands
276
>
* @method ping
277
>
* @direction Client → Server
278
>
* @messageType Request
279
>
* @version 1
280
>
*/
281
>
export interface PingParams extends BaseParams {
282
>
channel: 'ahp-root://';
283
>
}
284
>
285
>
// ─── reconnect ───────────────────────────────────────────────────────────────
286
>
287
>
/**
288
>
* Discriminant for reconnect result types.
289
>
*
290
>
* @category Commands
291
>
*/
292
>
export const enum ReconnectResultType {
293
>
Replay = 'replay',
294
>
Snapshot = 'snapshot',
295
>
}
296
>
297
>
/**
298
>
* Re-establishes a dropped connection. The server replays missed actions or
299
>
* provides fresh snapshots.
300
>
*
301
>
* @category Commands
302
>
* @method reconnect
303
>
* @direction Client → Server
304
>
* @messageType Request
305
>
* @version 1
306
>
* @see {@link /specification/lifecycle | Lifecycle} for details.
307
>
*/
308
>
export interface ReconnectParams extends BaseParams {
309
>
channel: 'ahp-root://';
310
>
/** Client identifier from the original connection */
311
>
clientId: string;
312
>
/** Last `serverSeq` the client received */
313
>
lastSeenServerSeq: number;
314
>
/** URIs the client was subscribed to */
315
>
subscriptions: URI[];
316
>
}
317
>
318
>
/**
319
>
* Reconnect result when the server can replay from the requested sequence.
320
>
*
321
>
* The server MUST include all replayed data in the response.
322
>
*/
323
>
export interface ReconnectReplayResult {
324
>
/** Discriminant */
325
>
type: ReconnectResultType.Replay;
326
>
/** Missed action envelopes since `lastSeenServerSeq` */
327
>
actions: ActionEnvelope[];
328
>
/**
329
>
* URIs from `ReconnectParams.subscriptions` that the server cannot resume.
330
>
* This includes resources that no longer exist (e.g. disposed sessions or
331
>
* terminals) as well as resources the client is no longer permitted to
332
>
* observe. Clients SHOULD drop these from their local subscription set.
333
>
*/
334
>
missing: URI[];
335
>
}
336
>
337
>
/**
338
>
* Reconnect result when the gap exceeds the replay buffer.
339
>
*/
340
>
export interface ReconnectSnapshotResult {
341
>
/** Discriminant */
342
>
type: ReconnectResultType.Snapshot;
343
>
/** Fresh snapshots for each subscription */
344
>
snapshots: Snapshot[];
345
>
}
346
>
347
>
/** Result of the `reconnect` command. */
348
>
export type ReconnectResult = ReconnectReplayResult | ReconnectSnapshotResult;
349
>
350
>
// ─── subscribe ───────────────────────────────────────────────────────────────
351
>
352
>
/**
353
>
* Subscribe to a URI-identified channel.
354
>
*
355
>
* A channel MAY have state associated with it (e.g. root, sessions,
356
>
* terminals) or be stateless (pure pub/sub for streaming data). For
357
>
* state-bearing channels the result includes a snapshot; for stateless
358
>
* channels `snapshot` is omitted.
359
>
*
360
>
* @category Commands
361
>
* @method subscribe
362
>
* @direction Client → Server
363
>
* @messageType Request
364
>
* @version 1
365
>
* @see {@link /specification/subscriptions | Subscriptions}
366
>
*/
367
>
export interface SubscribeParams extends BaseParams {
368
>
/**
369
>
* Optional delivery preferences for this subscription.
370
>
*
371
>
* Servers MAY use these preferences to buffer and coalesce high-frequency
372
>
* updates while preserving the same reduced state. Omit this field for the
373
>
* server's default delivery behavior.
374
>
*/
375
>
delivery?: SubscriptionDeliveryOptions;
376
>
/**
377
>
* Optional client-requested shape for the returned snapshot.
378
>
*
379
>
* Servers that do not understand a requested view ignore it and return their
380
>
* default snapshot. Clients MUST tolerate receiving more state than requested.
381
>
*/
382
>
view?: SubscribeView;
383
>
}
384
>
385
>
/**
386
>
* Optional client-requested shape for a subscription snapshot.
387
>
*
388
>
* @category Commands
389
>
*/
390
>
export interface SubscribeView {
391
>
/**
392
>
* Advisory number of most-recent completed turns to expose in a chat
393
>
* snapshot.
394
>
*
395
>
* Servers MAY return more or fewer turns than requested. When omitted, the
396
>
* host MUST return all retained turns. When older turns remain available, the
397
>
* returned {@link ChatState} carries `turnsNextCursor`; clients pass that
398
>
* cursor to `fetchTurns` to ask the host to page more turns into the chat
399
>
* state.
400
>
*/
401
>
turns?: number;
402
>
}
403
>
404
>
/**
405
>
* Advisory delivery preferences for a single subscription.
406
>
*
407
>
* @category Commands
408
>
*/
409
>
export interface SubscriptionDeliveryOptions {
410
>
/**
411
>
* Maximum time, in milliseconds, that the server may intentionally delay
412
>
* delivery while buffering/coalescing updates for this subscription.
413
>
*
414
>
* A value of `0` requests immediate delivery with no intentional coalescing.
415
>
*/
416
>
maxLatencyMs?: number;
417
>
}
418
>
419
>
/**
420
>
* Result of the `subscribe` command.
421
>
*
422
>
* `snapshot` is present when the subscribed channel has associated state, and
423
>
* absent for stateless channels.
424
>
*/
425
>
export interface SubscribeResult {
426
>
/** Snapshot of the subscribed channel's state (omitted for stateless channels) */
427
>
snapshot?: Snapshot;
428
>
}
429
>
430
>
// ─── unsubscribe ─────────────────────────────────────────────────────────────
431
>
432
>
/**
433
>
* Stop receiving updates for a channel.
434
>
*
435
>
* @category Commands
436
>
* @method unsubscribe
437
>
* @direction Client → Server
438
>
* @messageType Notification
439
>
* @version 1
440
>
* @see {@link /specification/subscriptions | Subscriptions}
441
>
*/
442
>
export interface UnsubscribeParams {
443
>
/** Channel URI to unsubscribe from */
444
>
channel: URI;
445
>
}
446
>
447
>
// ─── dispatchAction ──────────────────────────────────────────────────────────
448
>
449
>
/**
450
>
* Fire-and-forget action dispatch (write-ahead). The client applies actions
451
>
* optimistically to local state and the server echoes them back as an
452
>
* {@link ActionEnvelope} once accepted.
453
>
*
454
>
* The client → server method is named `dispatchAction`; the server's reply
455
>
* arrives on the server → client `action` notification (params:
456
>
* {@link ActionEnvelope}).
457
>
*
458
>
* @category Commands
459
>
* @method dispatchAction
460
>
* @direction Client → Server
461
>
* @messageType Notification
462
>
* @version 1
463
>
* @see {@link /guide/actions | Actions} for the full list of client-dispatchable actions.
464
>
*/
465
>
export interface DispatchActionParams {
466
>
/** Channel URI this action targets */
467
>
channel: URI;
468
>
/** Client sequence number */
469
>
clientSeq: number;
470
>
/** The action to dispatch */
471
>
action: StateAction;
472
>
}
473
>
474
>
// ─── resourceRead ────────────────────────────────────────────────────────
475
>
476
>
/**
477
>
* Encoding of fetched content data.
478
>
*
479
>
* @category Commands
480
>
*/
481
>
export const enum ContentEncoding {
482
>
Base64 = 'base64',
483
>
Utf8 = 'utf-8',
484
>
}
485
>
486
>
/**
487
>
* Reads the content of a resource by URI.
488
>
*
489
>
* Content references keep the state tree small by storing large data (images,
490
>
* long tool outputs) by reference rather than inline.
491
>
*
492
>
* Binary content (images, etc.) MUST use `base64` encoding. Text content MAY
493
>
* use `utf-8` encoding.
494
>
*
495
>
* Like all `resource*` methods, `resourceRead` is symmetrical and MAY be
496
>
* sent in either direction. Hosts use it to fetch content from a
497
>
* client-published URI (e.g. `virtual://my-client/...` plugins); clients
498
>
* use it to read host-side files. The receiver enforces access via the
499
>
* same permission/`resourceRequest` flow regardless of which peer initiated.
500
>
*
501
>
* @category Commands
502
>
* @method resourceRead
503
>
* @direction Client ↔ Server
504
>
* @messageType Request
505
>
* @version 1
506
>
* @throws `NotFound` (`-32008`) if the URI does not exist.
507
>
* @throws `PermissionDenied` (`-32009`) if the client is not permitted to read the URI.
508
>
* @example
509
>
* ```jsonc
510
>
* // Client → Server
511
>
* { "jsonrpc": "2.0", "id": 10, "method": "resourceRead",
512
>
* "params": { "uri": "ahp-session:/<uuid>/content/img-1" } }
513
>
*
514
>
* // Server → Client
515
>
* { "jsonrpc": "2.0", "id": 10, "result": {
516
>
* "data": "iVBORw0KGgo...",
517
>
* "encoding": "base64",
518
>
* "contentType": "image/png"
519
>
* }}
520
>
* ```
521
>
*/
522
>
export interface ResourceReadParams extends BaseParams {
523
>
channel: 'ahp-root://';
524
>
/** Content URI from a `ContentRef` */
525
>
uri: string;
526
>
/** Preferred encoding for the returned data (default: server-chosen) */
527
>
encoding?: ContentEncoding;
528
>
}
529
>
530
>
/**
531
>
* Result of the `resourceRead` command.
532
>
*
533
>
* The server SHOULD honor the `encoding` requested in the params. If the
534
>
* server cannot provide the requested encoding, it MUST fall back to either
535
>
* `base64` or `utf-8`.
536
>
*/
537
>
export interface ResourceReadResult {
538
>
/** Content encoded as a string */
539
>
data: string;
540
>
/** How `data` is encoded */
541
>
encoding: ContentEncoding;
542
>
/** Content type (e.g. `"image/png"`, `"text/plain"`) */
543
>
contentType?: string;
544
>
}
545
>
546
>
// ─── resourceWrite ───────────────────────────────────────────────────────────
547
>
548
>
/**
549
>
* How {@link ResourceWriteParams.data} is placed within the target file.
550
>
*
551
>
* Each mode interprets {@link ResourceWriteParams.position} differently:
552
>
*
553
>
* - `truncate` (default): rooted at the **start** of the file. The file is
554
>
* truncated at `position` (0 by default) and `data` is written from that
555
>
* offset, so the resulting file is `existing[0..position] + data`. With
556
>
* `position` omitted this is a full overwrite.
557
>
* - `append`: rooted at the **end** of the file. `position` counts bytes
558
>
* backwards from EOF, so `position: 0` (the default) writes at EOF —
559
>
* POSIX append — and `position: 5` inserts `data` 5 bytes before the
560
>
* current EOF, shifting those trailing 5 bytes after the inserted region.
561
>
* The server MUST evaluate the effective EOF and write atomically with
562
>
* respect to other appenders so concurrent `append` writes do not
563
>
* clobber each other.
564
>
* - `insert`: rooted at the **start** of the file. `position` (0 by default)
565
>
* is the byte offset at which `data` is spliced in; bytes at or after
566
>
* `position` are shifted right by `data.length`. `insert` always grows
567
>
* the file — use `truncate` to overwrite bytes in place.
568
>
*
569
>
* @category Commands
570
>
*/
571
>
export const enum ResourceWriteMode {
572
>
Truncate = 'truncate',
573
>
Append = 'append',
574
>
Insert = 'insert',
575
>
}
576
>
577
>
/**
578
>
* Writes content to a file on the server's filesystem.
579
>
*
580
>
* Binary content (images, etc.) MUST use `base64` encoding. Text content MAY
581
>
* use `utf-8` encoding.
582
>
*
583
>
* If the file does not exist, it is created. If the file already exists, the
584
>
* effect on existing bytes depends on {@link ResourceWriteParams.mode}:
585
>
* `truncate` (default) overwrites from the chosen offset onward, `append`
586
>
* preserves all existing bytes and adds `data` at a position rooted at EOF,
587
>
* and `insert` preserves all existing bytes and splices `data` in at an
588
>
* offset rooted at the start of the file.
589
>
*
590
>
* Like all `resource*` methods, `resourceWrite` is symmetrical and MAY be
591
>
* sent in either direction.
592
>
*
593
>
* @category Commands
594
>
* @method resourceWrite
595
>
* @direction Client ↔ Server
596
>
* @messageType Request
597
>
* @version 1
598
>
* @throws `NotFound` (`-32008`) if the parent directory does not exist.
599
>
* @throws `PermissionDenied` (`-32009`) if the client is not permitted to write to the path.
600
>
* @throws `AlreadyExists` (`-32010`) if `createOnly` is set and the file already exists.
601
>
* @throws `Conflict` (`-32011`) if `ifMatch` is set and the current `etag` does not match.
602
>
* @example
603
>
* ```jsonc
604
>
* // Client → Server
605
>
* { "jsonrpc": "2.0", "id": 11, "method": "resourceWrite",
606
>
* "params": { "uri": "file:///workspace/hello.txt", "data": "SGVsbG8=",
607
>
* "encoding": "base64", "contentType": "text/plain" } }
608
>
*
609
>
* // Server → Client
610
>
* { "jsonrpc": "2.0", "id": 11, "result": {} }
611
>
* ```
612
>
*/
613
>
export interface ResourceWriteParams extends BaseParams {
614
>
channel: 'ahp-root://';
615
>
/** Target file URI on the server filesystem */
616
>
uri: URI;
617
>
/** Content encoded as a string */
618
>
data: string;
619
>
/** How `data` is encoded */
620
>
encoding: ContentEncoding;
621
>
/** Content type (e.g. `"text/plain"`, `"image/png"`) */
622
>
contentType?: string;
623
>
/**
624
>
* If `true`, the server MUST fail if the file already exists instead of
625
>
* overwriting it. Useful for safe creation of new files.
626
>
*/
627
>
createOnly?: boolean;
628
>
/**
629
>
* How `data` is placed within the target file. Defaults to `'truncate'`
630
>
* (full overwrite) when omitted. See {@link ResourceWriteMode} for the
631
>
* meaning of each mode and how it interprets {@link position}.
632
>
*/
633
>
mode?: ResourceWriteMode;
634
>
/**
635
>
* Byte offset interpreted according to {@link mode}. Defaults to `0`.
636
>
* - `truncate`: offset from the start of the file at which to truncate
637
>
* before writing.
638
>
* - `append`: bytes back from EOF at which to insert `data`.
639
>
* - `insert`: offset from the start of the file at which to splice in
640
>
* `data`.
641
>
*/
642
>
position?: number;
643
>
/**
644
>
* Optimistic-concurrency token previously returned by
645
>
* {@link ResourceResolveResult.etag}. When set, the server MUST fail with
646
>
* `Conflict` if the current `etag` does not match — preventing lost
647
>
* updates between a `resourceResolve` and a subsequent `resourceWrite`.
648
>
*/
649
>
ifMatch?: string;
650
>
}
651
>
652
>
/**
653
>
* Result of the `resourceWrite` command.
654
>
*
655
>
* An empty object on success.
656
>
*/
657
>
export interface ResourceWriteResult {
658
>
}
659
>
660
>
// ─── resourceList ────────────────────────────────────────────────────────
661
>
662
>
/**
663
>
* Lists directory entries at a file URI on the server's filesystem.
664
>
*
665
>
* This is intended for remote folder pickers and similar UI that needs to let
666
>
* users navigate the server's local filesystem.
667
>
*
668
>
* The server MUST return success only if the target exists and is a directory.
669
>
* If the target does not exist, is not a directory, or cannot be accessed, the
670
>
* server MUST return a JSON-RPC error.
671
>
*
672
>
* Like all `resource*` methods, `resourceList` is symmetrical and MAY be
673
>
* sent in either direction.
674
>
*
675
>
* @category Commands
676
>
* @method resourceList
677
>
* @direction Client ↔ Server
678
>
* @messageType Request
679
>
* @version 1
680
>
* @throws `NotFound` (`-32008`) if the directory does not exist.
681
>
* @throws `PermissionDenied` (`-32009`) if the client is not permitted to browse the directory.
682
>
*/
683
>
export interface ResourceListParams extends BaseParams {
684
>
channel: 'ahp-root://';
685
>
/** Directory URI on the server filesystem */
686
>
uri: URI;
687
>
}
688
>
689
>
/**
690
>
* Directory entry returned by `resourceList`.
691
>
*/
692
>
export interface DirectoryEntry {
693
>
/** Base name of the entry */
694
>
name: string;
695
>
/** Whether the entry is a file or directory */
696
>
type: 'file' | 'directory';
697
>
}
698
>
699
>
/**
700
>
* Result of the `resourceList` command.
701
>
*/
702
>
export interface ResourceListResult {
703
>
/** Entries directly contained in the requested directory */
704
>
entries: DirectoryEntry[];
705
>
}
706
>
707
>
// ─── resourceCopy ────────────────────────────────────────────────────────────
708
>
709
>
/**
710
>
* Copies a resource from one URI to another on the server's filesystem.
711
>
*
712
>
* If the destination already exists, it is overwritten unless `failIfExists`
713
>
* is set.
714
>
*
715
>
* Like all `resource*` methods, `resourceCopy` is symmetrical and MAY be
716
>
* sent in either direction.
717
>
*
718
>
* @category Commands
719
>
* @method resourceCopy
720
>
* @direction Client ↔ Server
721
>
* @messageType Request
722
>
* @version 1
723
>
* @throws `NotFound` (`-32008`) if the source does not exist.
724
>
* @throws `PermissionDenied` (`-32009`) if the client is not permitted to read the source or write to the destination.
725
>
* @throws `AlreadyExists` (`-32010`) if `failIfExists` is set and the destination already exists.
726
>
*/
727
>
export interface ResourceCopyParams extends BaseParams {
728
>
channel: 'ahp-root://';
729
>
/** Source URI to copy from */
730
>
source: URI;
731
>
/** Destination URI to copy to */
732
>
destination: URI;
733
>
/**
734
>
* If `true`, the server MUST fail if the destination already exists instead
735
>
* of overwriting it.
736
>
*/
737
>
failIfExists?: boolean;
738
>
}
739
>
740
>
/**
741
>
* Result of the `resourceCopy` command.
742
>
*
743
>
* An empty object on success.
744
>
*/
745
>
export interface ResourceCopyResult {
746
>
}
747
>
748
>
// ─── resourceDelete ──────────────────────────────────────────────────────────
749
>
750
>
/**
751
>
* Deletes a resource at a URI on the server's filesystem.
752
>
*
753
>
* Like all `resource*` methods, `resourceDelete` is symmetrical and MAY be
754
>
* sent in either direction.
755
>
*
756
>
* @category Commands
757
>
* @method resourceDelete
758
>
* @direction Client ↔ Server
759
>
* @messageType Request
760
>
* @version 1
761
>
* @throws `NotFound` (`-32008`) if the resource does not exist.
762
>
* @throws `PermissionDenied` (`-32009`) if the client is not permitted to delete the resource.
763
>
*/
764
>
export interface ResourceDeleteParams extends BaseParams {
765
>
channel: 'ahp-root://';
766
>
/** URI of the resource to delete */
767
>
uri: URI;
768
>
/**
769
>
* If `true` and the target is a directory, delete it and all its contents
770
>
* recursively. If `false` (default), deleting a non-empty directory MUST fail.
771
>
*/
772
>
recursive?: boolean;
773
>
}
774
>
775
>
/**
776
>
* Result of the `resourceDelete` command.
777
>
*
778
>
* An empty object on success.
779
>
*/
780
>
export interface ResourceDeleteResult {
781
>
}
782
>
783
>
// ─── resourceRequest ─────────────────────────────────────────────────────────
784
>
785
>
/**
786
>
* Requests permission to access a resource on the receiver's filesystem.
787
>
*
788
>
* `resourceRequest` is symmetrical and MAY be sent in either direction: a
789
>
* client asks the server to grant access to a server-side resource, or a
790
>
* server asks the client to grant access to a client-side resource. The
791
>
* receiver decides whether to allow, deny, or prompt the user for the
792
>
* requested access.
793
>
*
794
>
* If the receiver denies access, it MUST respond with `PermissionDenied`
795
>
* (-32009). The error data MAY include a `ResourceRequestParams` value
796
>
* describing the access the caller would need to be granted for the
797
>
* operation to succeed; see `PermissionDeniedErrorData` in
798
>
* `types/errors.ts`.
799
>
*
800
>
* After a successful `resourceRequest`, the caller MAY use the corresponding
801
>
* `resource*` commands (e.g. `resourceRead`, `resourceWrite`) to perform the
802
>
* operation. Receivers MAY rescind access at any time by returning
803
>
* `PermissionDenied` on subsequent operations.
804
>
*
805
>
* Either `read`, `write`, or both SHOULD be set to `true`. A request with
806
>
* neither flag set is treated as `read: true` by receivers.
807
>
*
808
>
* @category Commands
809
>
* @method resourceRequest
810
>
* @direction Client ↔ Server
811
>
* @messageType Request
812
>
* @version 1
813
>
* @throws `PermissionDenied` (`-32009`) if access is denied.
814
>
*/
815
>
export interface ResourceRequestParams extends BaseParams {
816
>
channel: 'ahp-root://';
817
>
/**
818
>
* Resource URI being requested. Typically a `file:` URI on the receiver's
819
>
* filesystem, but any URI scheme that the receiver mediates access to is
820
>
* allowed.
821
>
*/
822
>
uri: URI;
823
>
/** Whether the caller needs read access to the resource. */
824
>
read?: boolean;
825
>
/** Whether the caller needs write access to the resource. */
826
>
write?: boolean;
827
>
}
828
>
829
>
/**
830
>
* Result of the `resourceRequest` command.
831
>
*
832
>
* An empty object on success.
833
>
*/
834
>
export interface ResourceRequestResult {
835
>
}
836
>
837
>
// ─── resourceMove ────────────────────────────────────────────────────────────
838
>
839
>
/**
840
>
* Moves (renames) a resource from one URI to another on the server's filesystem.
841
>
*
842
>
* If the destination already exists, it is overwritten unless `failIfExists`
843
>
* is set.
844
>
*
845
>
* Like all `resource*` methods, `resourceMove` is symmetrical and MAY be
846
>
* sent in either direction.
847
>
*
848
>
* @category Commands
849
>
* @method resourceMove
850
>
* @direction Client ↔ Server
851
>
* @messageType Request
852
>
* @version 1
853
>
* @throws `NotFound` (`-32008`) if the source does not exist.
854
>
* @throws `PermissionDenied` (`-32009`) if the client is not permitted to move the resource.
855
>
* @throws `AlreadyExists` (`-32010`) if `failIfExists` is set and the destination already exists.
856
>
*/
857
>
export interface ResourceMoveParams extends BaseParams {
858
>
channel: 'ahp-root://';
859
>
/** Source URI to move from */
860
>
source: URI;
861
>
/** Destination URI to move to */
862
>
destination: URI;
863
>
/**
864
>
* If `true`, the server MUST fail if the destination already exists instead
865
>
* of overwriting it.
866
>
*/
867
>
failIfExists?: boolean;
868
>
}
869
>
870
>
/**
871
>
* Result of the `resourceMove` command.
872
>
*
873
>
* An empty object on success.
874
>
*/
875
>
export interface ResourceMoveResult {
876
>
}
877
>
878
>
// ─── resourceResolve ─────────────────────────────────────────────────────────
879
>
880
>
/**
881
>
* Discriminant for {@link ResourceResolveResult.type}.
882
>
*
883
>
* @category Commands
884
>
*/
885
>
export const enum ResourceType {
886
>
File = 'file',
887
>
Directory = 'directory',
888
>
Symlink = 'symlink',
889
>
}
890
>
891
>
/**
892
>
* Resolves a resource — the combination of POSIX `stat` and `realpath`.
893
>
*
894
>
* `resourceResolve` returns metadata about the resource together with its
895
>
* canonical URI after symlink resolution. Use this in place of any
896
>
* `resourceExists` shim: a missing resource MUST surface as a `NotFound`
897
>
* JSON-RPC error rather than a success with a sentinel value. Callers that
898
>
* truly need a boolean check should attempt `resourceResolve` and treat
899
>
* `NotFound` as "does not exist".
900
>
*
901
>
* Like all `resource*` methods, `resourceResolve` is symmetrical and MAY be
902
>
* sent in either direction.
903
>
*
904
>
* @category Commands
905
>
* @method resourceResolve
906
>
* @direction Client ↔ Server
907
>
* @messageType Request
908
>
* @version 1
909
>
* @throws `NotFound` (`-32008`) if the resource does not exist.
910
>
* @throws `PermissionDenied` (`-32009`) if the caller is not permitted to stat the URI.
911
>
* @example
912
>
* ```jsonc
913
>
* // Client → Server
914
>
* { "jsonrpc": "2.0", "id": 20, "method": "resourceResolve",
915
>
* "params": { "channel": "ahp-root://", "uri": "file:///workspace/hello.txt" } }
916
>
*
917
>
* // Server → Client
918
>
* { "jsonrpc": "2.0", "id": 20, "result": {
919
>
* "uri": "file:///workspace/hello.txt",
920
>
* "type": "file",
921
>
* "size": 5,
922
>
* "mtime": "2026-01-15T12:34:56.789Z",
923
>
* "etag": "W/\"5-abc123\""
924
>
* }}
925
>
* ```
926
>
*/
927
>
export interface ResourceResolveParams extends BaseParams {
928
>
channel: 'ahp-root://';
929
>
/** URI to resolve */
930
>
uri: URI;
931
>
/**
932
>
* When `true` (default), follow symlinks and report the metadata of the
933
>
* link target — and set `uri` in the result to the canonical (realpath)
934
>
* URI. When `false`, stat the link itself (lstat semantics) and report
935
>
* `type: 'symlink'`.
936
>
*/
937
>
followSymlinks?: boolean;
938
>
}
939
>
940
>
/**
941
>
* Result of the `resourceResolve` command.
942
>
*/
943
>
export interface ResourceResolveResult {
944
>
/**
945
>
* Canonical URI after symlink resolution. Equal to the requested URI when
946
>
* `followSymlinks` is `false` or the URI does not traverse a symlink.
947
>
*/
948
>
uri: URI;
949
>
/** Resource kind. */
950
>
type: ResourceType;
951
>
/**
952
>
* Size in bytes. Omitted for directories when the provider cannot
953
>
* cheaply compute it.
954
>
*/
955
>
size?: number;
956
>
/** Last-modified time in ISO 8601 format, when known. */
957
>
mtime?: string;
958
>
/** Creation time in ISO 8601 format, when known. */
959
>
ctime?: string;
960
>
/** Sniffed MIME type, when known (e.g. `"text/plain"`, `"image/png"`). */
961
>
contentType?: string;
962
>
/**
963
>
* Opaque per-provider version token. When present, pass it as
964
>
* {@link ResourceWriteParams.ifMatch} on a subsequent `resourceWrite` to
965
>
* detect concurrent modifications.
966
>
*/
967
>
etag?: string;
968
>
}
969
>
970
>
// ─── resourceMkdir ───────────────────────────────────────────────────────────
971
>
972
>
/**
973
>
* Creates a directory on the server's filesystem with `mkdir -p` semantics.
974
>
*
975
>
* The server MUST create any missing parent directories. Creating a
976
>
* directory that already exists is a no-op success. If `uri` already
977
>
* exists but is **not** a directory, the server MUST fail with
978
>
* `AlreadyExists`.
979
>
*
980
>
* Like all `resource*` methods, `resourceMkdir` is symmetrical and MAY be
981
>
* sent in either direction.
982
>
*
983
>
* @category Commands
984
>
* @method resourceMkdir
985
>
* @direction Client ↔ Server
986
>
* @messageType Request
987
>
* @version 1
988
>
* @throws `PermissionDenied` (`-32009`) if the caller is not permitted to create the directory.
989
>
* @throws `AlreadyExists` (`-32010`) if `uri` already exists as a non-directory.
990
>
*/
991
>
export interface ResourceMkdirParams extends BaseParams {
992
>
channel: 'ahp-root://';
993
>
/** Directory URI to create (parents created as needed). */
994
>
uri: URI;
995
>
}
996
>
997
>
/**
998
>
* Result of the `resourceMkdir` command.
999
>
*
1000
>
* An empty object on success.
1001
>
*/
1002
>
export interface ResourceMkdirResult {
1003
>
}
1004
>
1005
>
// ─── authenticate ────────────────────────────────────────────────────────────
1006
>
1007
>
/**
1008
>
* Pushes a ****** for a protected resource. The `resource` field MUST
1009
>
* match a protected-resource identifier the client has discovered from the
1010
>
* server — whether declared statically in `AgentInfo.protectedResources`,
1011
>
* or discovered dynamically from a live `McpServerAuthRequiredState.resource`
1012
>
* or `ToolCallAuthRequiredState.auth.resource` (both surfaced only once the
1013
>
* corresponding MCP server or tool call actually challenges for auth).
1014
>
* Servers MUST accept any `resource` value they have themselves advertised
1015
>
* through one of these three mechanisms.
1016
>
*
1017
>
* Tokens are delivered using [RFC 6750](https://datatracker.ietf.org/doc/html/rfc6750)
1018
>
* (****** Usage) semantics. The client obtains the token from the
1019
>
* authorization server(s) listed in the resource's metadata and pushes it
1020
>
* to the server via this command.
1021
>
*
1022
>
* @category Commands
1023
>
* @method authenticate
1024
>
* @direction Client → Server
1025
>
* @messageType Request
1026
>
* @version 1
1027
>
* @see {@link /specification/authentication | Authentication}
1028
>
* @example
1029
>
* ```jsonc
1030
>
* // Client → Server
1031
>
* { "jsonrpc": "2.0", "id": 3, "method": "authenticate",
1032
>
* "params": { "channel": "ahp-root://", "resource": "https://api.github.com", "token": "gho_xxxx" } }
1033
>
*
1034
>
* // Server → Client (success)
1035
>
* { "jsonrpc": "2.0", "id": 3, "result": {} }
1036
>
*
1037
>
* // Server → Client (failure — invalid token)
1038
>
* { "jsonrpc": "2.0", "id": 3, "error": { "code": -32007, "message": "Invalid token" } }
1039
>
* ```
1040
>
*/
1041
>
export interface AuthenticateParams extends BaseParams {
1042
>
channel: 'ahp-root://';
1043
>
/**
1044
>
* The protected resource identifier. MUST match a `resource` value the
1045
>
* server has advertised — via `ProtectedResourceMetadata` in
1046
>
* `AgentInfo.protectedResources`, or via a live
1047
>
* `McpServerAuthRequiredState.resource` / `ToolCallAuthRequiredState.auth.resource`.
1048
>
*/
1049
>
resource: string;
1050
>
/** ****** obtained from the resource's authorization server */
1051
>
token: string;
1052
>
/**
1053
>
* OAuth scopes the token grants, when known. Lets the server determine
1054
>
* whether a specific challenge — e.g. the `requiredScopes` on a live
1055
>
* `McpServerAuthRequiredState` or `ToolCallAuthRequiredState.auth` — is
1056
>
* satisfied without decoding the (opaque, server-specific) token itself.
1057
>
* Omit when the client doesn't track granted scopes separately from the
1058
>
* token.
1059
>
*/
1060
>
scopes?: string[];
1061
>
}
1062
>
1063
>
/**
1064
>
* Result of the `authenticate` command.
1065
>
*
1066
>
* An empty object on success. If the token is invalid or the resource is
1067
>
* unrecognized, the server MUST return a JSON-RPC error (e.g. `AuthRequired`
1068
>
* `-32007` or `InvalidParams` `-32602`).
1069
>
*/
1070
>
export interface AuthenticateResult {
1071
>
}